GPPG-Grammar - 规则永远不会使用

时间:2016-04-07 13:54:32

标签: c# grammar gppg

我的一些语法规则出了问题。

语法如下:

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.

非常感谢你的帮助,  亚历

1 个答案:

答案 0 :(得分:1)

该语法肯定会产生至少一次转移/减少冲突,同时警告生产attrbt: /* nothing */因冲突而无效。 (如果情况并非如此,那是因为GPPG没有提供与野牛一样多的警告。但我确信它至少会标记转移/减少冲突。)

冲突出现在规则中:

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

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

类似Yacc的解析器生成器总是解决移位/减少冲突而转移(除非有优先级声明),因此在这种情况下ID将始终被移位。这意味着不可能减少生产attrbt: /* nothing */。 (至少,野牛会警告你这个事实。

此外,由于在这种情况下会发生ID的转换,因此只有defLine的第二次生成可用,因此解析器需要fieldStuff来跟随ID并且fieldStuff必须以[开头。因此,您遇到的解析错误。

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

attrbt   : "PHU" intValue

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