regex 如何匹配 *anything* 直到在RE-flex lexer中遇到分隔符?

ehxuflar  于 2023-02-10  发布在  其他
关注(0)|答案(1)|浏览(105)

我在我的项目中使用了RE/flex lexer。在这个项目中,我想匹配对应于('*)".*?"\1的语法。例如,它应该匹配"foo"''"bar"'',但不应该匹配''"baz"'
但是RE/flex matcher不支持lookaheads,lookbehinds和backreference,那么,有没有一种正确的方法可以使用reflex matcher来匹配呢?我能找到的最接近的方法是使用下面的lexer:

%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序列。
所以,上面的lexer的问题是,它只匹配字符串中有效的UTF8序列,而我希望它匹配字符串中的任何东西,直到分隔符。
我考虑了三种变通方法。但这三种方法似乎都有一些问题。
1.使用skip()。这将跳过所有字符,直到它到达分隔符。但是在这个过程中,它消耗了所有的字符串内容。我不能保留它们。
1.使用.*?/\"代替[^"]*。这对每个正确终止的字符串都有效。但是如果字符串没有终止,词法分析器就会卡住。
1.使用.逐个字符地消耗字符串内容。由于.是同步的,它甚至可以匹配无效的UTF8序列。但是这种方法感觉太慢了。
那么,有没有更好的解决办法呢?

a1o7rhls

a1o7rhls1#

我没有找到任何适当的方法来解决这个问题。但我只是做了一个肮脏的黑客与第二个变通办法上面提到的。
我在字符串开始规则中添加了一个自定义循环,而不是RE/flex生成的扫描器循环。在那里,我刷新了剩余的文本并显示unterminated string错误消息,而不是失败并显示scanner jammed错误消息。

%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' \n";
            return TokenKind::ERR;

        default:
            std::unreachable();

        case 2:;
        }

        textLen = size();
        matcher().more();
    }
}

<STRING>{
\"'* |
.*?/\" |
<<EOF>> std::unreachable();
}

%%

相关问题