繁体   English   中英

在Bison错误后如何跳过一行中的其余令牌

[英]How to skip the rest of the tokens in a line after an error in Bison

我正在为使用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                      ;
.                       ;
%%

我的Bison代币和规则:

%union{

    char *print;

}

%token EQU
%token <print> ID
%token EOL
%token <print> OP
%token OPEN
%token CLOSE

%%

lines: line
    |   lines line
;

line: ass {cout << " VALID" << endl;}
    |   exp {cout << " VALID" << endl;}
    |   error '\n' {yyerrok;}
;

ass: id EQU {cout << " ="; } exp EOL {cout << ";";}
;

exp: term
    |   exp op term 
;

term: id 
    |   OPEN {cout << "(";} exp op term CLOSE {cout << ")";}
;

id: ID {cout << $1; }

op: OP {cout << $1; }


%%

我的yyerror()仅显示“错误”。

我的解析输入:

-- Good (valid) statements:

first = one1 + two2 - three3 / four4 ;
second = one1 * (two2 * three3) ;
one1 * i8766e98e + bignum
second = (one1 * two2) * three3 ;
third = ONE + twenty - three3 ;
third = old * thirty2 / b567 ;

-- Bad (invalid) statements:

first = = one1 + two2 - three3 / four4 ;
first = one1 + - two2 - three3 / four4 ;
first = one1 + two2 - three3 / four4
first = one1 + two2 ? three3 / four4 ;
second = 4 + ( one1 * two2 ) * ( three3 + four4 ;
third = one1 + 24 - three3 ;
one1 +- delta
sixty6 / min = fourth ;

我希望输出会显示错误,然后移至下一行

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 ,告诉语法分析器跳过标记,直到看到换行符,才会导致其跳过文件的其余部分。

但是,您可以(几乎)通过使词法分析器识别换行符来实现此目的,但仅限于在错误恢复期间。 (签入\\n然后忽略该操作或将其发送。)

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

a = 1
while (a > 0) {
    …

但是,只有在读取while才会检测到该错误。 (如果下一个标记是+ ,则分析应继续。)因此,跳到该行的末尾意味着在第三行继续分析,从而引入了不平衡的括号。

即使这样,这仍可能是一个有趣的开始。

使用'\\n'无效,因为您的词法分析器从不返回'\\n' ,因此令牌流中将永远不会有任何'\\n'令牌。 基本上,如果词法分析器忽略某些字符,则不能以任何方式在解析器中使用它们,包括用于错误恢复。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM