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

问题描述 投票:0回答:2

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

parsing bison flex-lexer
2个回答
0
投票

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

.    return *yytext;

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


0
投票

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

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

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

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

    扫描仪打印错误
  • 解析器执行string语义操作,该操作返回0。
  • 再次,语义操作中的return语句绕过了正确的错误处理和清理。
  • 所以不要那样做。如果要报告语义操作中的错误,请使用YYABORT,它将干净地终止分析并返回错误。另一方面,如果您的最高产量是正确的,则什么也不做。然后,解析器将验证下一个输入令牌是输入结束标记,并返回成功。

    © www.soinside.com 2019 - 2024. All rights reserved.