如何使flex尝试第二个最长匹配的正则表达式?

时间:2011-07-21 23:54:19

标签: regex token bison flex-lexer

这个问题可能听起来有些混乱。我正在使用Flex将令牌传递给Bison。

我想要的行为是Flex匹配最长的正则表达式并传递该令牌(它就像这样工作),但是如果该令牌不能用于语法,那么它匹配第二个最长的正则表达式并传递令牌。

我正在努力想办法创造这种行为。我怎么能做到这一点?

例如,澄清说我有两条规则:

"//"    return TOKEN_1;
"///"   return TOKEN_2;

给定字符串"///",我希望首先传递TOKEN_2(确实如此)。 如果TOKEN_2不符合Bison中指定的语法,则会传递TOKEN_1(这也是有效的)。

如何创建此行为?

4 个答案:

答案 0 :(得分:3)

flex中,您可以制定一条规则尝试执行某些操作但失败并使用REJECT宏尝试次优规则:

  

REJECT指示扫描仪继续进行操作             与输入相匹配的“第二好”规则(或者             输入的前缀)。该规则被选为             如上所述“输入如何匹配”,以及             yytext和yyleng设置得恰当。有可能             或者是与文本匹配的文本             最初选择的规则,但后来在flex中             输入文件,或匹配较少文本的文件。

(来源:The Flex Manual Page)。

所以为了回答你关于获得第二长表达式的问题,你可以使用REJECT来做到这一点(尽管你必须要小心,因为它可以选择具有相同优先级的相同长度)。

请注意flex在使用REJECT时运行速度会变慢,因为它需要维持额外的逻辑以在任何时候“退回”到更差的匹配。如果没有别的方法可以解决你的问题,我建议你只使用它。

答案 1 :(得分:0)

抱歉,你不能这样做。我实际上不确定有多少弹性与野牛交谈。我知道有一种REPL解析模式,我知道还有另一种解析它的模式。

你必须内联规则。例如,而不是//和/你编写一个接受///的规则然后另一个假设///表示// /。但这变得很混乱,我只在我的代码中的特定情况下这样做。

答案 2 :(得分:0)

我只是让词法分析器扫描两个标记///,然后让解析器处理它们应被视为一个标记或单独的情况。即以///开头的语法规则实际上可以重构为以///开头的规则。换句话说,根本没有TOKEN_2。在同样的情况下,这种事情可能会很棘手,因为LARL(1)解析器只有一个前瞻标记。它必须根据仅查看//进行转换或减少决策,而不考虑后面的/

我有一个想法,用一种涉及词汇搭配的hacky方法解决这个问题,但事实证明这是不可行的。

这个想法的主要缺陷是没有任何简单的方法在yacc中进行错误恢复,这对用户是隐藏的。如果触发语法错误,则可见。 yyerror函数可能包含一个试图隐藏它的hack,但它缺少上下文信息。

换句话说,您无法真正使用Yacc错误操作来触发对另一个解析的回溯搜索。

答案 3 :(得分:0)

这对野牛/ yacc来说很难处理,因为它没有回溯。即使您使用像btyacc这样的回溯解析器生成器,它也没有用,除非它还通过词法分析器回溯(这可能需要具有集成词法分析器的解析器生成器。)

我的建议是让词法分析器识别一个斜线,然后立即斜杠,并返回一个不同的标记:

\//\/       return SLASH;
\/          return '/';   /* not needed if you have the catch-all rule: */
.           return *yytext;

现在你需要在语法中“组合”多斜杠'标记'作为非终结符。

single_slash:  SLASH | '/' ;
double_slash:  SLASH SLASH | SLASH '/' ;
triple_slash:  SLASH SLASH SLASH | SLASH SLASH '/' ;

但是,由于1令牌前瞻不够,您现在可能会发现语法中存在冲突。您可以使用btyacc或bison %glr-parser选项来解决这些问题。