这当然是可能的,但有一个巨大的警告。在我提供的示例中,为什么您觉得需要这样做对我来说并不明显;可能有替代方案,但如果不了解有关用例的更多详细信息,就不可能提供任何建议。
这是警告。在您提供的示例中,状态推送是由标记生成生成的;从概念上(甚至在实践中)您可以使用中间规则操作:
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
| ...
在上述情况下,状态更改不会影响词法分析器处理 / 的方式,因此如果该斜杠被识别为开始(或结束)正则表达式,则状态更改将发生就在扫描 / 令牌之前或(更有可能)之后。如果词法分析器尝试(不必要,但这似乎是一种诱惑)为 / 的两种不同用途返回不同的标记,这将不会起作用;一个好的指导原则是词法分析器对标记的语义了解得越少越好。