改写语法去除移位减lessif-then-else中的冲突

如何删除给定语法的野牛移位 – 减less冲突?

selection-stmt -> if ( expression ) statement | if ( expression ) statement else statement 

提供修改过的语法的解决scheme将受到高度赞赏。

有一个更简单的解决scheme。 如果你知道LRparsing器是如何工作的,那么你知道冲突发生在这里:

 if ( expression ) statement * else statement 

星号标记光标的当前位置。 parsing器必须回答的问题是“我应该移位还是应该减less”。 通常情况下,你想绑定else的最接近的,这意味着你现在想要移动else标记。 现在减less意味着你想要else等待被绑定到一个“老” if

现在,您要“告诉”您的parsing器生成器:“如果标记"else"和规则”stm – > if(exp)stm“之间存在移位/减less冲突,则标记必须取胜”。 为此,请为您的规则的优先级(例如"then" )指定一个名称,并指定"then"优先级低于"else" 。 就像是:

 // Precedences go increasing, so "then" < "else". %nonassoc "then" %nonassoc "else" %% stm: "if" "(" exp ")" stm %prec "then" | "if" "(" exp ")" stm "else" stm 

使用Bison语法。

其实,我最喜欢的答案是甚至给予"then""else"相同的优先顺序。 当优先级相等时,为了打破想要移位的标记与想要减less的规则之间的联系,Bison / Yacc将关注联合性。 在这里,你想要宣扬右倾关联(更确切地说,你想促进“移位”),所以:

 %right "then" "else" // Same precedence, but "shift" wins. 

就足够了。

你需要认识到if-else情况下的中间statement不能以(如果没有别的方式)悬空(或者以其他方式结束)。最简单的方法是将stmt规则分成两部分:

 stmt -> stmt-ending-with-dangling-if | stmt-not-ending-with-dangling-if stmt-not-ending-with-dangling-if -> if ( expression ) stmt-not-ending-with-dangling-if else stmt-not-ending-with-dangling-if | ...other statements not ending with dangling if... stmt-ending-with-dangling-if -> if ( expression ) stmt | if ( expression ) stmt-not-ending-with-dangling-if else stmt-ending-with-dangling-if | ...other statements ending with dangling if... 

任何其他的stmt -> whatever不以stmt stmt-not-ending-with-if规则都会在stmt-not-ending-with-if规则中出现,而以stmt结尾的任何stmt规则都会被分成两个版本; not-ending-with-if规则中not-ending-with-if规则和dangling-ifdangling-if规则中的dangling-if dangling-if版本中的not-ending-with-if

编辑

与其他作品更完整的语法:

 stmt : stmt-ending-with-dangling-if | stmt-not-ending-with-dangling-if stmt-not-ending-with-dangling-if : IF '(' expr ')' stmt-not-ending-with-dangling-if ELSE stmt-not-ending-with-dangling-if | WHILE '(' expr ')' stmt-not-ending-with-dangling-if | DO stmt WHILE '(' expr ')' ';' | expr ';' | '{' stmt-list '}' stmt-ending-with-dangling-if: IF '(' expr ')' stmt | IF '(' expr ')' stmt-not-ending-with-dangling-if ELSE stmt-ending-with-dangling-if | WHILE '(' expr ')' stmt-ending-with-dangling-if 

WHILE (expr) stmt这样的规则可以分成两部分(以stmt结尾),而像expr;这样的规则expr; 不要。

如果比正常的语句更高一些,比如:

 statements: statements lineEnd statement | statements lineEnd IfStat | statements lineEnd IfElseStat | IfStat | IfElseStat ; IfStat: if ( statement ) ; IfElse: IfStat else statement ;