处理Flex启动条件时,Bison解析器上的令牌错误

时间:2016-10-19 00:24:31

标签: bison flex-lexer

为了重新创建缩进定义的Python块,我在开始时偶然发现了这一点。

当我单独尝试我的词法分析器/扫描仪时,它会使用我所做的开始条件正确地返回预期结果。但是当它与Bison解析器耦合时,不会保留正确的状态,并且我会从意外状态接收令牌。

对我来说,预期的行为是在行的开头返回标签/空格的“INDENT”标记,并在找到另一个符号(不是标签/空格)后为每个符号返回“OTHER”标记,直到开始新的线。

第一种情况,词法分析器返回预期结果

scanner.l

%{
  #include <iostream>
%}

%option noyywrap

%x INDENT
%%

  BEGIN(INDENT);

<INDENT>[ \t] { std::cout << "INDENT "; }
<INDENT>.|\n { yyless(0); BEGIN(INITIAL); }

\n { std::cout << std::endl; BEGIN(INDENT); }
. { std::cout << "OTHER "; }

%%

int main(){
  yylex();
  return 0;
}

输入“ test ”(“test”之前和之后的两个空格)返回“其他其他指标”。

第二种情况,解析器返回意外结果

scanner.l

%{
  #include <iostream>

  #include "parser.h"
%}

%option noyywrap

%x INDENT
%%

  BEGIN(INDENT);

<INDENT>[ \t] { return T_INDENT; }
<INDENT>.|\n { yyless(0); BEGIN(INITIAL); }

\n { BEGIN(INDENT); return T_NEWLINE; }
. { return T_OTHER; }

%%

parser.y

%{
  #include <iostream>

  extern int yylex();

  void yyerror(const char *s);
%}

%define parse.error verbose

%token T_INDENT T_OTHER T_NEWLINE

%%

program : program symbol
        | %empty
        ;

symbol : T_INDENT { std::cout << "INDENT "; }
       | T_NEWLINE { std::cout << std::endl; }
       | T_OTHER { std::cout << "OTHER "; }
       ;

%%

void yyerror(const char *s){
  std::cout << s;
}

int main(){
  yyparse();
  return 0;
}

输入“ test ”(与之前相同)返回“其他其他其他非本地人”。虽然预期结果与上述相同。

Bison解析器似乎收到了错误的令牌,好像它不符合启动条件。我已经读过一些关于解析器由于超前行为而弄乱了启动条件的事情,但是我不确定问题是在这个范围内还是我如何反击它。

1 个答案:

答案 0 :(得分:0)

因为你有

BEGIN(INDENT)

规则部分没有模式,这是逐字复制到yylex函数的顶部,因此每次调用yylex时它都会运行。因此,每次野牛调用yylex获取新令牌时,状态都会重置为INDENT并获得T_INDENT令牌。

在你的“第一种情况”示例中,词法分析器在EOF之前不会返回,所以你只需要调用一次,它只设置一次INDENT状态。

如果您希望此代码仅在您第一次调用yylex时运行,则需要将其设置为仅运行一次。类似的东西:

        { static bool not_first_time;
          if (!not_first_time) {
            BEGIN(INDENT);
            not_first_time = true; } }

或者,进行设置以使INITIAL成为预期的初始状态。