我正在为使用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'规则不起作用以及如何解决该问题。
答案 0 :(得分:1)
由于您的词法分析器忽略\n
,因此告诉解析器跳过标记,直到看到换行符为止,这将导致解析器跳过文件的其余部分。
但是,您可以(几乎)通过使词法分析器识别换行符来实现此目的,但是只能在错误恢复期间进行。 (签入\n
的操作,然后忽略它或将其发送。)
但是这有时会产生奇怪的结果,因为产生错误的令牌可能在下一行,在这种情况下,在检测到错误之前,换行符已被忽略。例如,这里的问题是缺少分号:
a = 1
while (a > 0) {
…
但是该错误仅在读取while
之后才能检测到。 (如果下一个标记是+
,则解析应继续。)因此,跳到该行的末尾意味着继续在第三行进行解析,从而引入不平衡的括号。
即使如此,这可能也是一个有趣的开始。
答案 1 :(得分:0)
使用'\n'
不起作用,因为您的词法分析器从不返回'\n'
,因此令牌流中将永远没有任何'\n'
令牌。基本上,如果词法分析器忽略某些字符,则不能以任何方式在解析器中使用它们,包括进行错误恢复。
因此,您的两个选择是停止忽略换行符(这可能是一个坏主意,因为您必须在语法中允许换行的地方提到它们),或使用其他一些令牌来进行错误恢复。跳过所有内容直到下一个分号可能是一个不错的选择(尽管由于并非所有行都以分号结尾,所以仍然无法产生预期的输出)。