Я создал парсер через Flex / Bison, который неожиданно завершился неудачей при разборе.Вот упрощенный пример, который показывает проблему
Lexer.l:
%{
#include "Parser.h"
%}
%option noyywrap nodefault
%%
"foo" { return FOO; }
"bar" { return BAR; }
"(" { return OP; }
")" { return CP; }
[ \t\n]+ { /* DO NOTHING */ }
. { YY_FATAL_ERROR("unknown character"); }
%%
И Parser.y (с включенной трассировкой и многословием):
%{
#include <stdio.h>
int yylex();
void yyerror (char const *s);
%}
%debug
%verbose
%error-verbose
%token FOO BAR OP CP
%%
program_expr : foo_expr bar_expr {}
;
foo_expr : /* NOTHING */ {}
| OP FOO CP {}
;
bar_expr : /* NOTHING */ {}
| OP BAR CP {}
;
%%
int main(int argc, char** argv)
{
yydebug = 1;
yyparse();
return 0;
}
void yyerror (char const *s) { fprintf(stderr, "%s\n", s); }
Но сгенерированный парсерпотерпит неудачу, если я укажу ввод типа (bar)
- дерево разбора в этом случае должно содержать выражение foo
, которое является пустым.Он сообщает:
Начальный анализ
Состояние входа 0
Чтение токена: Следующий токен является токеном OP ()
Сдвиг токена OP ()
Состояние входа 1
Чтение токена: следующий токен - токен BAR ()
синтаксическая ошибка, непредвиденный BAR, ожидание FOO
Ошибка: выталкиваниеТокен OP ()
Стек сейчас 0
Очистка: отбрасывание лексемы с меткой упреждения BAR ()
Стек сейчас 0
Вот фрагмент текстаиз сгенерированного описания shift/reduce automata
:
state 0
0 $accept: . program_expr $end
OP shift, and go to state 1
OP [reduce using rule 2 (foo_expr)]
$default reduce using rule 2 (foo_expr)
program_expr go to state 2
foo_expr go to state 3
state 1
3 foo_expr: OP . FOO CP
FOO shift, and go to state 4
state 2
0 $accept: program_expr . $end
$end shift, and go to state 5
state 3
1 program_expr: foo_expr . bar_expr
OP shift, and go to state 6
$default reduce using rule 4 (bar_expr)
bar_expr go to state 7
Но я не могу понять значение / синтаксис таких состояний.В чем проблема с моей грамматикой / парсером?