不稳定的解析器。相同的语法,相同的输入,循环产生不同的结果。我错过了什么?
Erratic parser. Same grammar, same input, cycles through different results. What am I missing?
我正在编写一个基本的解析器,它读取标准输入并将结果打印到标准输出。问题是我在使用这个语法时遇到了麻烦:
%token WORD NUM TERM
%%
stmt: /* empty */
| word word term { printf("[stmt]\n"); }
| word number term { printf("[stmt]\n"); }
| word term
| number term
;
word: WORD { printf("[word]\n"); }
;
number: NUM { printf("[number]\n"); }
;
term: TERM { printf("[term]\n"); /* \n */}
;
%%
当我 运行 程序时,我输入: hello world\n 输出是(如我所料)[word ] [word] [term] [stmt]。到目前为止一切顺利,但是如果我再次键入:hello world\n,我会收到 syntax error [word][term].
当我输入 hello world\n(第三次)时,它起作用了,然后再次失败,然后又起作用,依此类推。
我是不是遗漏了什么明显的东西?
(我有一些手动编译器的经验,但我没有使用过 lex/yacc 等)
这是主要功能:
int main() {
do {
yyparse();
} while(!feof(yyin));
return 0;
}
如有任何帮助,我们将不胜感激。谢谢!
您的语法只识别一个 stmt
。 Yacc/bison 期望语法描述整个输入,因此在语句被识别后,解析器等待 end-of-input 指示。但是它没有得到一个,因为你输入了第二个语句。这会导致解析器报告语法错误。但请注意,它现在已经读取了第二行中的第一个标记。
您正在循环调用 yyparse()
,并且在收到语法错误 return 值时没有停止。因此,当您再次调用 yyparse()
时,它将从最后一个停止的地方继续,也就是第二行中第二个标记之前。剩下的只是一个单词,然后它会正确解析。
您可能应该做的是编写您的解析器,以便它接受任意数量的语句,也许这样它就不会在遇到错误时死掉。那看起来像这样:
%%
prog: %empty
| prog line
line: stmt '\n' { puts("Got a statement"); }
| error '\n' { yyerrok; /* Simple error recovery */ }
...
请注意,只有在我知道该行已被正确解析后,我才会为语句打印一条消息。这通常会减少混淆。但最好的解决方案不是使用 printf,而是使用 Bison 的跟踪工具,这就像在 bison 命令行上输入 -t
并设置全局变量 yydebug = 1;
一样简单。参见 Tracing your parser
我正在编写一个基本的解析器,它读取标准输入并将结果打印到标准输出。问题是我在使用这个语法时遇到了麻烦:
%token WORD NUM TERM
%%
stmt: /* empty */
| word word term { printf("[stmt]\n"); }
| word number term { printf("[stmt]\n"); }
| word term
| number term
;
word: WORD { printf("[word]\n"); }
;
number: NUM { printf("[number]\n"); }
;
term: TERM { printf("[term]\n"); /* \n */}
;
%%
当我 运行 程序时,我输入: hello world\n 输出是(如我所料)[word ] [word] [term] [stmt]。到目前为止一切顺利,但是如果我再次键入:hello world\n,我会收到 syntax error [word][term].
当我输入 hello world\n(第三次)时,它起作用了,然后再次失败,然后又起作用,依此类推。
我是不是遗漏了什么明显的东西?
(我有一些手动编译器的经验,但我没有使用过 lex/yacc 等)
这是主要功能:
int main() {
do {
yyparse();
} while(!feof(yyin));
return 0;
}
如有任何帮助,我们将不胜感激。谢谢!
您的语法只识别一个 stmt
。 Yacc/bison 期望语法描述整个输入,因此在语句被识别后,解析器等待 end-of-input 指示。但是它没有得到一个,因为你输入了第二个语句。这会导致解析器报告语法错误。但请注意,它现在已经读取了第二行中的第一个标记。
您正在循环调用 yyparse()
,并且在收到语法错误 return 值时没有停止。因此,当您再次调用 yyparse()
时,它将从最后一个停止的地方继续,也就是第二行中第二个标记之前。剩下的只是一个单词,然后它会正确解析。
您可能应该做的是编写您的解析器,以便它接受任意数量的语句,也许这样它就不会在遇到错误时死掉。那看起来像这样:
%%
prog: %empty
| prog line
line: stmt '\n' { puts("Got a statement"); }
| error '\n' { yyerrok; /* Simple error recovery */ }
...
请注意,只有在我知道该行已被正确解析后,我才会为语句打印一条消息。这通常会减少混淆。但最好的解决方案不是使用 printf,而是使用 Bison 的跟踪工具,这就像在 bison 命令行上输入 -t
并设置全局变量 yydebug = 1;
一样简单。参见 Tracing your parser