1

我的一些语法规则有问题。

语法如下:

defLINES : carrRet
         | defLine carrRet
         | defLines defLine carrRet
         ;

defLine  : error carrRet                             {yyerrok();}
         | "DEF" kwType attrbt ID
         | "DEF" kwType ID fieldSuff
         ;

kwType   : "INT"
         | "REAL"
         ;

fieldSuff: "[" expr "]"
         | "[" expr "," expr "]"
         ;

attrbt   : /* nothing */
         | "PHU" intValue
         ;

使用输入检查:

DEF INT testvar1
DEF REAL testvar2

对于此输入,应使用以“defLine”为首的产生式的第二条规则。

为什么不呢?将始终使用第三条规则并引发错误

Unexpected 'carRet', '[' expected.

非常感谢您的帮助,亚历克斯

4

1 回答 1

1

该语法肯定会产生至少一个 shift/reduce 冲突,并警告该生产attrbt: /* nothing */由于冲突而无用。(如果不是这种情况,那是因为 GPPG 没有提供与野牛一样多的警告。但我确信它至少会标记 shift/reduce 冲突。)

冲突出现在规则中:

defLine  : "DEF" kwType attrbt ID
defLine  : "DEF" kwType ID fieldSuff

因为attrbt可以为空,但不能ID在第二条规则之前。假设解析器遇到DEF INT并且下一个符号是ID。此时,解析器不知道defLine要使用两个产生式中的哪一个,但区别很重要。在第一种情况下,解析器必须attrbt在移动ID. 在第二种情况下,创建attrbt将是一个错误。

类似 Yacc 的解析器生成器总是解决移位/减少冲突以支持移位(除非有优先声明),所以在这种情况下,ID总是会移位。这意味着永远不可能减少产量attrbt: /* nothing */。(至少,野牛会警告你这个事实。

此外,由于ID在这种情况下会发生移位,因此只有第二个产生式 fordefLine可用,因此解析器将需要fieldStuff遵循ID, 并且fieldStuff必须以[. 因此,您遇到的解析错误。

要解决此问题,您需要删除 shift/reduce 冲突。一种简单的方法是允许attrbt两种defLine产生式(您可以检测语义动作中的错误)。另一种可能性是删除空产生attrbt式并明确允许它丢失:

attrbt   : "PHU" intValue

defLine  : "DEF" kwType ID
         | "DEF" kwType attrbt ID
         | "DEF" kwType ID fieldSuff
于 2016-04-07T16:27:53.277 回答