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 に答える