简体   繁体   English

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

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

I'm writing an application for an assignment that uses Flex and Bison to determine if a statement is valid or not. 我正在为使用Flex和Bison来确定语句是否有效的作业编写应用程序。 After detecting an error in a statement, I want to print an error message and move onto the next line to look at the next statement, but everything I'm trying doesn't work. 在语句中检测到错误后,我想打印一条错误消息并移至下一行以查看下一条语句,但是我尝试的所有操作均不起作用。

Researching online, Bison has a built in error token that can be used for error handling. Bison在线研究,拥有一个内置的错误令牌,可用于错误处理。 By using error '\\n' {yyerrok;}, I should be able to achieve what I want, but it isn't working. 通过使用错误'\\ n'{yyerrok;},我应该能够实现所需的功能,但是它不起作用。

My Flex code: 我的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                      ;
.                       ;
%%

My Bison tokens and rules: 我的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; }


%%

My yyerror() just prints "Error ". 我的yyerror()仅显示“错误”。

My input for parsing: 我的解析输入:

-- 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 ;

I'd expect the output to print an error then move to the next line 我希望输出会显示错误,然后移至下一行

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
.
.
.

But when I run it, it just stops at the first Error printing 但是当我运行它时,它只会在第一次错误打印时停止

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

Any help would be appreciated, but mostly I want to know why the error '\\n' rule isn't working and what I can do to fix it. 任何帮助将不胜感激,但主要是我想知道为什么错误'\\ n'规则不起作用以及如何解决该错误。

Since your lexer ignores \\n , telling the parser to skip tokens until it sees a newline will cause it to skip the rest of the file. 由于您的词法分析器忽略\\n ,告诉语法分析器跳过标记,直到看到换行符,才会导致其跳过文件的其余部分。

However, you can (almost) make this work by getting the lexer to recognise newline characters, but only during error recovery. 但是,您可以(几乎)通过使词法分析器识别换行符来实现此目的,但仅限于在错误恢复期间。 (Check in the action for \\n and either ignore it or send it.) (签入\\n然后忽略该操作或将其发送。)

But that will occasionally produce odd results, because the token which produces the error might be on the next line, in which case the newline will already have been ignored before the error was detected. 但这有时会产生奇怪的结果,因为产生错误的令牌可能在下一行,在这种情况下,在检测到错误之前,换行符已被忽略。 For example, here the problem is a missing semicolon: 例如,这里的问题是缺少分号:

a = 1
while (a > 0) {
    …

But that error will only be detected after while has been read. 但是,只有在读取while才会检测到该错误。 (If the next token were, say, + , the parse should continue.) So skipping to the end of the line means continuing the parse at the third line, thus introducing an unbalanced brace. (如果下一个标记是+ ,则分析应继续。)因此,跳到该行的末尾意味着在第三行继续分析,从而引入了不平衡的括号。

Even so, it could be an interesting start. 即使这样,这仍可能是一个有趣的开始。

Using '\\n' isn't working because your lexer never returns '\\n' , so there will never be any '\\n' tokens in the token stream. 使用'\\n'无效,因为您的词法分析器从不返回'\\n' ,因此令牌流中将永远不会有任何'\\n'令牌。 Basically if the lexer ignores certain characters, you can't use them in the parser in any way, including for error recovery. 基本上,如果词法分析器忽略某些字符,则不能以任何方式在解析器中使用它们,包括用于错误恢复。

So your two options would be to stop ignoring line breaks (probably a bad idea because then you'd have to mention them everywhere in the grammar where you want to allow line breaks) or to use some other token for error recovery. 因此,您的两个选择是停止忽略换行符(这可能是个坏主意,因为您必须在语法中允许换行的地方提到它们),或使用其他令牌进行错误恢复。 Skipping everything until the next semicolon would probably be a good alternative (though that still won't produce your expected output since not all of your lines end with semicolons). 跳过所有内容直到下一个分号可能是一个不错的选择(尽管由于并非所有行都以分号结尾,所以仍然无法产生预期的输出)。

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

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