[英]How do I get my flex/bison grammar parser to give a syntax error for unrecognized tokens
我正在尝试使用 flex 和 bison 编写语法识别器来确定输入字符串是否在 L(G) 中,其中语言是以下各项的并集:
L(G) = {a^ib^jc^kd^le^m} 其中 i,j,k,l,m > 0 且 i=m 且 k=l
和
L(G) = {e^id^jc^kb^la^m} 其中 i,j,k,l,m > 0 且 i=2m k=3l 且 j=2
现在我让它工作正常,但只有在使用语言中的标记时。 如果我包含任何其他令牌,它似乎会被忽略,并且测试会根据其他允许的令牌通过或失败。 这是有问题的,因为它允许诸如“abcdef”之类的字符串通过解析,即使“f”不在该语言中。
我现在正在测试的错误输入是“abcdef”。 “abcde”部分是正确的,并给出了正确的 output,但在末尾添加“f”会导致来自 yyerror(“syntax error”) 的语法错误消息和“恭喜;解析成功”打印语句从 main 到打印。
使用“fabcde”与我上面描述的一样。 它给了我错误,但它也给了我成功的打印声明。 我正在使用“if(yyparse() == 0))”在 main 中打印成功语句,我认为这可能是这里的罪魁祸首,尽管当我将打印语句移入时遇到了同样的问题。 y 文件,只在 main.y 文件中使用了 yyparse() 和 return(1)。
这是 my.in 文件(减去包括):
%%
a return A;
b return B;
c return C;
d return D;
e return E;
. yyerror("syntax error\n\nSorry, Charlie, input string not in L(G)\n"); /* working but still prints success message too */
%%
这是 my.y 文件(减去包括):
%token A
%token B
%token C
%token D
%token E
%% /* Grammar Rules */
string: as bs cs ds es
{
if(($1 == $5) && ($3 == $4)) {
return(0);
}
else
{
return(-1);
}
}
;
string: es ds cs bs as
{
if(($1 == (2 * $5) && ($3 == (3 * $4)) && ($2 = 2)) {
return(0);
}
else
{
return(-1);
}
}
;
as: A as {$$ = $2 +1;}
;
as: A {$$ = 1;}
;
bs: B bs {$$ = $2 +1;}
;
bs: B {$$ = 1;}
;
cs: C cs {$$ = $2 +1;}
;
cs: C {$$ = 1;}
;
ds: D ds {$$ = $2 +1;}
;
ds: D {$$ = 1;}
;
es: E es {$$ = $2 +1;}
;
es: E {$$ = 1;}
;
%%
my.c 文件很简单,如果 yyparse() == 0 则返回“恭喜;解析成功”,否则返回“输入字符串不在 L(G) 中”。
当输入字符串仅包含 a、b、c、d 和 e 时,一切正常。 如果输入字符串中除了它们之外还有任何标记,我只需要弄清楚如何使解析器在没有成功语句的情况下给出语法错误。
这是一张有助于显示我的问题的图像:前两个解析按预期工作。 第三个显示我的问题。
如果 (f)lex 规则不返回任何内容,则它匹配的标记将被忽略。 这适用于注释,但不适用于您希望成为错误的标记。 如果您将包罗万象的弹性规则更改为
. return *yytext;
然后将返回输入中所有无法识别的字符(换行符除外,这是唯一的.
不匹配),并且可能会导致解析器发出Syntax error
消息(以及 yyparse 的返回失败。如果您的语法包含文字字符标记(例如, '#'
来匹配那个字符),那么它当然会匹配。
bison/yacc 生成的解析器期望解析整个正确的输入,直到并包括输入结束标记,然后才返回成功指示(返回值 0)。
当然,如果输入在语法上不正确,解析器可能会提前返回一个错误指示(对于语法错误,该值始终为 1,如果内存不足,则为 2)。 在这种情况下,在解析器返回之前,它将清理其内部 state 并释放任何已分配的 memory。
让解析器执行此操作很重要。 从 bison/yacc 解析器中的语义操作返回充其量是不明智的(因为它几乎可以肯定是 memory 泄漏)并且还可能产生混淆,因为它可能导致在生成错误消息后成功返回。
例如,考虑输入abcdea
的情况,它是一个有效字符串后跟一个无效a
。 由于解析器表压缩(延迟错误操作以保存表条目),因此string
的语义操作可能会在解析器尝试处理最后a
之前运行。 但是您的语义操作实际上返回 0,绕过了解析器的错误报告和清理。 如果输入是abcdef
并且您的扫描程序为无效令牌调用yyerror
(这也不是一个特别好的主意),那么操作序列将是:
string
语义操作,返回 0。 同样,语义操作中的return
语句绕过了正确的错误处理和清理。
所以不要那样做。 如果您想报告语义操作中的错误,请使用YYABORT
,它将干净地终止解析并返回错误。 另一方面,如果您的顶级生产是正确的,则什么也不做。 然后解析器将验证下一个输入标记是否是输入结束标记并返回成功。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.