5

我正在使用 flex 和 bison 编写自己的脚本语言。我有一个语法,我能够生成一个解析器,它可以在正确的脚本上正常工作。我希望能够为特殊错误情况添加一些有意义的错误消息。例如,我希望能够识别语句块的不匹配括号或缺少的分号等。假设我有这些语句(这里的语法不完整):

...
statements: statement SEMICOLON statements
    | statement SEMICOLON;

statement: ifStatement
    | whileStatement
    ;

ifStatement: IF expression THEN statements END
    | IF expression THEN statements ELSE statements END
    ;

whileStatement:  DO statements WHILE expression END
    ;
...

我希望能够打印诸如“缺少分号”或“缺少然后关键字”等消息。我应该修改我的语法以启用错误处理吗?还是有一些 Bison 功能可以做到这一点?

4

1 回答 1

5

更新(2021 年 9 月)

由于版本 3.7 Bison 支持用户定义的错误消息:指定%define parse.error custom,并提供一个yyreport_syntax_error函数,例如:

int
yyreport_syntax_error (const yypcontext_t *ctx)
{
  int res = 0;
  YYLOCATION_PRINT (stderr, *yypcontext_location (ctx));
  fprintf (stderr, ": syntax error");
  // Report the tokens expected at this point.
  {
    enum { TOKENMAX = 10 };
    yysymbol_kind_t expected[TOKENMAX];
    int n = yypcontext_expected_tokens (ctx, expected, TOKENMAX);
    if (n < 0)
      // Forward errors to yyparse.
      res = n;
    else
      for (int i = 0; i < n; ++i)
        fprintf (stderr, "%s %s",
                 i == 0 ? ": expected" : " or", yysymbol_name (expected[i]));
  }
  // Report the unexpected token.
  {
    yysymbol_kind_t lookahead = yypcontext_token (ctx);
    if (lookahead != YYSYMBOL_YYEMPTY)
      fprintf (stderr, " before %s", yysymbol_name (lookahead));
  }
  fprintf (stderr, "\n");
  return res;
}

在文档的语法错误报告函数 yyreport_syntax_error部分中了解更多信息。

原始答案(2013 年 3 月)

Bison 不是生成自定义错误消息的合适工具,但它的标准错误消息也不错,只要您启用%error-verbose. 查看文档:http ://www.gnu.org/software/bison/manual/bison.html#Error-Reporting 。

如果您真的想提供自定义错误消息,请阅读有关 YYERROR 的文档,并为您想要捕获的模式生成规则,并自己引发错误。例如,这里除以 0 被视为语法错误(这是可疑的,但提供了自定义语法错误消息的示例)。

 exp:
   NUM           { $$ = $1; }
 | exp '+' exp   { $$ = $1 + $3; }
 | exp '-' exp   { $$ = $1 - $3; }
 | exp '*' exp   { $$ = $1 * $3; }
 | exp '/' exp
     {
       if ($3)
         $$ = $1 / $3;
       else
         {
           $$ = 1;
           fprintf (stderr, "%d.%d-%d.%d: division by zero",
                    @3.first_line, @3.first_column,
                    @3.last_line, @3.last_column);
         }
     }

另请注意,为令牌提供字符串会生成更好的错误消息:

%token NUM

会产生unexpected NUM,而

%token NUM "number"

会产生unexpected number.

于 2013-03-24T13:49:38.330 回答