【问题标题】:How to match *anything* until a delimiter is encountered in RE-flex lexer?在 RE-flex 词法分析器中遇到定界符之前如何匹配 *anything*?
【发布时间】:2023-02-08 00:14:21
【问题描述】:

我在我的项目中使用RE/flex lexer。在那,我想匹配对应于('*)".*?"\1的语法。例如,它应该匹配"foo"''"bar"'',但不应匹配''"baz"'

但是 RE/flex 匹配器不适用于前瞻、后视和反向引用。那么,是否有使用反射匹配器来匹配它的正确方法?我能实现的最接近的是以下词法分析器:

%x STRING

%%

'*\" {
    textLen = 0uz;
    quoteLen = size();
    start(STRING);
}

<STRING> {

\"'* {
    if (size() - textLen < quoteLen) goto MORE_TEXT;
    matcher().less(textLen + quoteLen);
    start(INITIAL);
    res = std::string{matcher().begin(), textLen};
    return TokenKind::STR;
}

[^"]* {
    MORE_TEXT:
    textLen = size();
    matcher().more();
}

<<EOF>> {
    std::cerr << "Lexical error: Unterminated 'STRING' \n";
    return TokenKind::ERR;
}

}

%%

RE-flex 中的元字符. 匹配任何字符,无论是有效的还是无效的 UTF8 序列。而反转字符类 - [^...] - 仅匹配字符类中不存在的有效 UTF8 序列。

因此,上述词法分析器的问题在于,它只匹配字符串中有效的 UTF8 序列。然而,我希望它匹配字符串中的任何内容,直到分隔符。

我考虑了三种解决方法。但是这三个似乎都有一些问题。

  1. 使用skip()。这将跳过所有字符,直到到达定界符。但是在这个过程中,它消耗了所有的字符串内容。我不能保留它们。
  2. 使用 .*?/\" 而不是 [^"]*。这适用于每个正确终止的字符串。但是如果字符串没有终止,词法分析器就会卡住。
  3. 使用.逐个字符使用字符串内容。由于. 正在同步,它甚至可以匹配无效的 UTF8 序列。但是这种方法感觉太慢了。

    那么有没有更好的方法来解决这个问题?

【问题讨论】:

    标签: regex lexer parser-generator reflex


    【解决方案1】:

    我没有找到解决问题的合适方法。但是我只是用上面提到的第二种解决方法做了一个肮脏的黑客攻击。

    我在字符串开始规则中添加了一个自定义循环,而不是 RE/flex 生成的扫描器循环。在那里,我没有因 scanner jammed 错误而失败,而是刷新剩余文本并显示 unterminated string 错误消息。

    %x STRING
    
    %%
    
    '*" {
        auto textLen = 0uz;
        const auto quoteLen = size();
        matcher().pattern(PATTERN_STRING);
    
        while (true) {
            switch (matcher().scan()) {
    
            case 1:
                if (size() - textLen < quoteLen) break;
                matcher().less(textLen + quoteLen);
                res = std::string{matcher().begin(), textLen};
                return TokenKind::STR;
    
            case 0:
                if (!matcher().at_end()) matcher().set_end(true);
                std::cerr << "Lexical error: Unterminated 'STRING' 
    ";
                return TokenKind::ERR;
    
            default:
                std::unreachable();
    
            case 2:;
            }
    
            textLen = size();
            matcher().more();
        }
    }
    
    <STRING>{
    "'* |
    .*?/" |
    <<EOF>> std::unreachable();
    }
    
    %%
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-13
      • 2015-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多