【问题标题】:Wrong tokens on Bison parser when dealing with Flex start conditions处理 Flex 开始条件时 Bison 解析器上的错误标记
【发布时间】:2016-10-19 00:24:30
【问题描述】:

在尝试重新创建由缩进定义的 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”前后两个空格)返回“INDENT INDENT INDENT OTHER OTHER OTHER OTHER OTHER OTHER”。

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

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  ”(与之前相同)返回“INDENT INDENT OTHER OTHER OTHER OTHER OTHER INDENT INDENT”。而预期的结果与上述相同。

Bison 解析器似乎接收到了错误的标记,就好像它不遵守开始条件一样。我读过一些关于解析器由于前瞻行为而弄乱启动条件的内容,但我不确定问题是否在此之内,也不确定我将如何解决它。

【问题讨论】:

  • 这是一种非常奇怪的方法。我会有^[ \t] BEGIN INDENT;,而不是从那个状态开始。

标签: bison flex-lexer


【解决方案1】:

因为你有

BEGIN(INDENT)

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

在您的“第一种情况”示例中,词法分析器直到 EOF 才返回,因此您只调用它一次,并且它只设置一次 INDENT 状态。

如果您希望此代码仅在您第一次调用 yylex 时运行,您需要将其设置为只运行一次。比如:

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

或者,设置INITIAL 是预期的初始状态。

【讨论】:

  • 谢谢,就是这样:)我完全忽略了这个细节
猜你喜欢
  • 2012-09-21
  • 1970-01-01
  • 2012-08-17
  • 2010-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多