这个问题可能听起来有些混乱。我正在使用Flex将令牌传递给Bison。
我想要的行为是Flex匹配最长的正则表达式并传递该令牌(它就像这样工作),但是如果该令牌不能用于语法,那么它匹配第二个最长的正则表达式并传递令牌。
我正在努力想办法创造这种行为。我怎么能做到这一点?
例如,澄清说我有两条规则:
"//" return TOKEN_1;
"///" return TOKEN_2;
给定字符串"///"
,我希望首先传递TOKEN_2
(确实如此)。
如果TOKEN_2
不符合Bison中指定的语法,则会传递TOKEN_1
(这也是有效的)。
如何创建此行为?
答案 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
选项来解决这些问题。