Parsing Bison出错后如何跳过一行中的其余标记

Parsing Bison出错后如何跳过一行中的其余标记,parsing,error-handling,bison,flex-lexer,Parsing,Error Handling,Bison,Flex Lexer,我正在编写一个赋值应用程序,它使用Flex和Bison来确定语句是否有效。在检测到语句中的错误后,我想打印一条错误消息并转到下一行查看下一条语句,但我尝试的一切都不起作用 通过在线研究,Bison有一个内置的错误令牌,可用于错误处理。通过使用错误“\n”{yyerrok;},我应该能够实现我想要的,但它不起作用 我的Flex代码: %{ #include <cstdio> #include <iostream> using namespace std;

我正在编写一个赋值应用程序,它使用Flex和Bison来确定语句是否有效。在检测到语句中的错误后,我想打印一条错误消息并转到下一行查看下一条语句,但我尝试的一切都不起作用

通过在线研究,Bison有一个内置的错误令牌,可用于错误处理。通过使用错误“\n”{yyerrok;},我应该能够实现我想要的,但它不起作用

我的Flex代码:

%{
  #include <cstdio>
  #include <iostream>
  using namespace std;

  #include "exp.tab.h"  // to get the token types from Bison

%}
%%

--.*                    ;
[a-zA-Z][a-zA-Z0-9]*    {yylval.print = strdup(yytext); return ID;}
;\s*                    {return EOL;}
[-+*/%]                 {yylval.print = strdup(yytext); return OP;}
=                       {return EQU;}
\(                      {return OPEN;}
\)                      {return CLOSE;}
[0-9]                   ;
\n                      ;
\r                      ;
.                       ;
%%
我希望输出打印一个错误,然后移到下一行

first =one1+two2-three3/four4; VALID
second =one1*(two2*three3); VALID
one1*i8766e98e+bignum VALID
second =(one1*two2)*three3; VALID
third =ONE+twenty-three3; VALID
third =old*thirty2/b567; VALID
first = Error
first = one1 + Error
first = one1 + two2 - three3 / four4 Error
first = one1 + two2 Error
.
.
.
但当我运行它时,它只是在第一次打印错误时停止

first =one1+two2-three3/four4; VALID
second =one1*(two2*three3); VALID
one1*i8766e98e+bignum VALID
second =(one1*two2)*three3; VALID
third =ONE+twenty-three3; VALID
third =old*thirty2/b567; VALID
first = Error
非常感谢您的帮助,但我主要想知道错误“\n”规则为什么不起作用,以及我可以做些什么来修复它。

使用“\n”不起作用,因为您的lexer永远不会返回“\n”,因此令牌流中永远不会有任何“\n”令牌。基本上,如果lexer忽略某些字符,您就不能在解析器中以任何方式使用它们,包括用于错误恢复

因此,您的两个选择是停止忽略换行符,这可能是一个坏主意,因为这样您就必须在语法中允许换行符或使用其他标记进行错误恢复的任何地方提到它们。跳过所有内容直到下一个分号可能是一个很好的选择,尽管这仍然不会产生预期的输出,因为不是所有的行都以分号结尾。

因为lexer忽略了\n,告诉解析器跳过标记直到它看到新行将导致它跳过文件的其余部分

然而,您几乎可以通过让lexer识别换行符来完成这项工作,但只能在错误恢复期间完成。签入\n的操作并忽略它或发送它

但这偶尔会产生奇怪的结果,因为产生错误的标记可能位于下一行,在这种情况下,在检测到错误之前,换行符已经被忽略。例如,这里的问题是缺少分号:

a = 1
while (a > 0) {
    …
但是,只有在读取while之后才能检测到该错误。如果下一个标记是,比如说,+,那么解析应该继续。因此,跳到行尾意味着在第三行继续解析,从而引入不平衡的大括号


尽管如此,这可能是一个有趣的开始。

Flex不将\s识别为空白字符;这只是字母s。对于空白,请使用[[:空格:]。其他的也可以用,:[:alpha:][],[:digit:][],[[:alnum:][]等等。谢谢你的帮助!我认为Bison将“\n”作为一种可以检查的文字处理,但显然不是这样。由于我的作业范围很小,我只是为换行符创建了一个标记,并指定了我希望它出现的位置。现在剩下的就是显示导致错误的具体原因。
first =one1+two2-three3/four4; VALID
second =one1*(two2*three3); VALID
one1*i8766e98e+bignum VALID
second =(one1*two2)*three3; VALID
third =ONE+twenty-three3; VALID
third =old*thirty2/b567; VALID
first = Error
a = 1
while (a > 0) {
    …