从bison解析器调用flex yy_push_state()

时间:2015-02-06 04:32:25

标签: bison flex-lexer

是否可以从野牛生成的解析器中调用yy_push_state()?怎么办呢?

context:
    /* empty */ { $$ = NULL; yy_push_state(SOME_STATE); }
;

rule:
    context operator STRING { create_expr($2, $3); }
;

我希望能够从解析器中调用yy_push_state(),并且想知道它是否是可接受的做法。如果没有,那么传播词法分析器的替代方案是什么?它应该推动一个州?

  

在这种特定情况下,只有解析器知道何时推送SOME_STATE

1 个答案:

答案 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
    | ...

在上面的例子中,状态更改对词法分析器处理 / 的方式没有影响,因此如果该斜杠被识别为正则表达式的开始(或结束),则状态更改将发生就在扫描 / 标记之前或之后(更有可能)。如果词法分析者尝试(不必要地,但似乎是一种诱惑)为 / 的两种不同用途返回不同的标记,这将不起作用;一个好的准则是,词法分析器对令牌语义的了解越少越好。