是否可以从野牛生成的解析器中调用yy_push_state()
?怎么办呢?
context:
/* empty */ { $$ = NULL; yy_push_state(SOME_STATE); }
;
rule:
context operator STRING { create_expr($2, $3); }
;
我希望能够从解析器中调用yy_push_state()
,并且想知道它是否是可接受的做法。如果没有,那么传播词法分析器的替代方案是什么?它应该推动一个州?
在这种特定情况下,只有解析器知道何时推送
SOME_STATE
。
答案 0 :(得分:1)
这当然是可能的,但是有一个巨大的警告。对我来说一点也不明显,为什么你觉得你需要在你提供的例子中这样做;可能有另一种选择,但如果不了解有关用例的更多细节,就无法提供任何建议。
这是警告。在您提供的示例中,状态推送由标记生成生成;在概念上(甚至在实践中)你可以使用中规则动作:
rule: { yy_push_state(SOME_STATE); }
operator STRING { create_expr($2, $3); }
当空产量减少时,将发生状态推动;在读取operator
的第一个标记之前可能会或可能不会发生,但在大多数情况下,它将在之后发生。因此,例如,如果意图改变词法分析器以识别(或不识别)特定于上下文的操作符,那么它可能会失败。
bison
通常会立即减少(没有超前令牌),但不保证这种行为,并且不应该依赖恕我直言。其他解析器(例如yacc)不这样做;较早的野牛版本没有IIRC,并且至少可能不同的解析器类型(IELR,GLR)可能对前瞻标记是否必要有不同的看法。
所以总的来说,最好为可能的情况做好准备,即已经读取了先行令牌(这就是为什么有必要复制yytext
),同时小心不要做假设它已被阅读。
如果您的状态更改足够强大,请继续执行解析器中的yy_push_state
。
例如,假设operation
不可为空,状态更改将更改识别STRING
的规则,但不会对可能出现的任何令牌的词法扫描产生任何影响在operator
。在这种情况下,yy_push_state
是安全的。
我发现这个黑客尝试的一个地方是尝试解析像awk和javascript这样的语言,其中/
可能是一个除法运算符或正则表达式字面值的开头。在这种情况下,可以让解析器在正则表达式中更改词法状态:
// Lexer
"/" { return '/';
/* No semantics, the parser will know what it means */
}
<REGEX> {
/* Lots of rules here. But unescaped / is just the same as above */
"/" { return '/';
/* No semantics, the parser will know what it means */
}
}
// Parser
expr: { BEGIN(REGEX); } '/' regex { BEGIN(INITIAL); } '/'
| expr '/' expr
| ...
在上面的例子中,状态更改对词法分析器处理 / 的方式没有影响,因此如果该斜杠被识别为正则表达式的开始(或结束),则状态更改将发生就在扫描 / 标记之前或之后(更有可能)。如果词法分析者尝试(不必要地,但似乎是一种诱惑)为 / 的两种不同用途返回不同的标记,这将不起作用;一个好的准则是,词法分析器对令牌语义的了解越少越好。