如何获取我的flex / bison语法解析器,以给出无法识别标记的语法错误

时间:2019-09-29 17:40:03

标签: parsing bison flex-lexer

我正在尝试使用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.

2 个答案:

答案 0 :(得分:1)

如果(f)lex规则未返回任何内容,则它匹配的标记将被忽略。这适用于注释,但不适用于您想出错的标记。如果您将全部弹性规则更改为

.    return *yytext;

然后将返回输入中所有无法识别的字符(换行符除外,这是唯一.不匹配的字符),并且很可能会导致解析器发出Syntax error消息(以及一个yyparse返回失败。如果您的语法包含文字字符标记(例如'#'以匹配该字符),则它当然会匹配。

答案 1 :(得分:0)

bison / yacc生成的解析器希望解析整个正确的输入,直到并包括输入结束标记,然后才返回成功指示(返回值为0)。

当然,如果输入在语法上不正确,则解析器可能会提前返回错误指示(语法错误的值始终为1,如果内存不足则为2)。在这种情况下,解析器返回之前,它将清理其内部状态并释放所有分配的内存。

让解析器执行此操作很重要。从bison / yacc解析器中的语义动作返回的消息充其量是不明智的(因为这几乎肯定是内存泄漏),并且还可能产生混乱,因为它可能会在产生错误消息后成功返回。

例如,考虑输入abcdea的情况,它是一个有效的字符串,后跟一个无效的astring的语义动作很可能在解析器尝试处理最后一个a之前之前运行,这是因为解析器表压缩(为了保存而推迟了错误操作)表条目)。但是您的语义动作实际上返回0,从而绕过了解析器的错误报告和清理。如果输入为abcdef,而您的扫描仪为无效令牌调用yyerror(这也不是一个好主意),那么操作顺序将是:

  1. 扫描仪打印错误
  2. 解析器执行string语义操作,该操作返回0。

再次,语义动作中的return语句绕过了正确的错误处理和清理操作。

所以不要那样做。如果要报告语义操作中的错误,请使用YYABORT,它将干净地终止解析并返回错误。另一方面,如果您的最高产量是正确的,则什么也不做。然后,解析器将验证下一个输入令牌是否为输入结束标记,并返回成功。