[我正在尝试使用flex和bison编写语法识别器,以确定输入字符串是否在L(G)中,其中语言是以下各项的并集:
L(G)= {a ^ i b ^ j c ^ k d ^ l e ^ m},其中i,j,k,l,m> 0且i = m和k = l
和
L(G)= {e ^ i d ^ j c ^ k b ^ l a ^ m},其中i,j,k,l,m> 0且i = 2m k = 3l和j = 2
现在,我可以正常工作,但仅当在语言中使用标记时才可以。如果我包含任何其他令牌,它似乎会被忽略,并且测试会基于其他允许的令牌通过或失败。这是有问题的,因为即使“ f”不在语言中,它也允许诸如“ abcdef”之类的字符串通过解析。
我正在测试的错误输入是“ abcdef”。 “ abcde”部分是正确的,并且给出正确的输出,但是在末尾添加“ f”会导致yyerror(“ syntax error”)的语法错误消息,以及从main到“祝贺;解析成功”的打印语句打印。
使用“ fabcde”执行与上述相同的操作。它给了我错误,但也给了我成功的打印说明。我正在使用“ if(yyparse()== 0))”来打印main中的成功语句,并且我认为这可能是罪魁祸首,尽管当我将打印语句移至中时遇到了同样的问题。 y文件,只在main中使用了yyparse()和return(1)。
这里是我的.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 */
%%
这是我的.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;}
;
%%
我的.c文件很简单,如果yyparse()== 0,则返回“祝贺;解析成功”,否则返回“输入字符串不在L(G)中。”
当输入字符串仅包含a,b,c,d和e时,一切工作都很好。我只需要弄清楚如果输入字符串中除了标记之外就没有成功的话,如何使解析器给出语法错误而没有成功的声明。
以下图片将有助于显示我的问题:The first two parses work as intended. The third one shows my issue.
如果(f)lex规则未返回任何内容,则它匹配的标记将被忽略。这适用于注释,但不适用于您想出错的标记。如果您将全部弹性规则更改为
. return *yytext;
然后将返回输入中所有无法识别的字符(换行符除外,这是唯一.
不匹配的字符),并且很可能会导致解析器出现Syntax error
消息(并且yyparse返回失败。如果您的语法包含文字字符标记(例如'#'
以匹配该字符),那么它当然会匹配。
[野牛/ yacc生成的解析器希望解析整个正确的输入,直到并包括输入结束标记,然后才返回成功指示(返回值为0)。
当然,如果输入在语法上不正确,则解析器可能会提早返回错误指示(对于语法错误,该指示始终为1;如果内存不足,则为2)。在这种情况下,解析器返回之前,它将清理其内部状态并释放所有分配的内存。
重要的是让解析器执行此操作。从bison / yacc解析器中的语义动作返回最好是不明智的(因为这几乎肯定是内存泄漏),并且还可能产生混乱,因为它可能会在产生错误消息后成功返回,因此也会产生混乱。
例如,考虑输入abcdea
的情况,它是一个有效字符串,后跟一个无效a
。由于解析器表压缩(为了保存表条目而推迟了错误操作),string
的语义动作很可能在解析器尝试处理最后一个a
时运行。但是您的语义动作实际上返回0,从而绕过了解析器的错误报告和清理。如果输入为abcdef
,而您的扫描仪为无效令牌调用了yyerror
(这也不是一个好主意),那么操作的顺序将是:
string
语义操作,该操作返回0。return
语句绕过了正确的错误处理和清理。所以不要那样做。如果要报告语义操作中的错误,请使用YYABORT
,它将干净地终止分析并返回错误。另一方面,如果您的最高产量是正确的,则什么也不做。然后,解析器将验证下一个输入令牌是输入结束标记,并返回成功。