我在我的项目中使用了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序列。但是这种方法感觉太慢了。
那么,有没有更好的解决办法呢?
1条答案
按热度按时间a1o7rhls1#
我没有找到任何适当的方法来解决这个问题。但我只是做了一个肮脏的黑客与第二个变通办法上面提到的。
我在字符串开始规则中添加了一个自定义循环,而不是RE/flex生成的扫描器循环。在那里,我刷新了剩余的文本并显示
unterminated string
错误消息,而不是失败并显示scanner jammed
错误消息。