用微小的Lemon语法解决解析冲突

时间:2017-01-06 22:25:02

标签: parser-generator shift-reduce-conflict lemon shift-reduce

我正在尝试学习Lemon parser generator的基础知识,但我很快就陷入困境。

这是一个很小的语法:

%right PLUS_PLUS.
%left DOT.

program ::= expr.

member_expr ::= expr DOT IDENTIFIER.

lhs_expr ::= member_expr.

expr ::= lhs_expr.
expr ::= PLUS_PLUS lhs_expr.

导致1次解析冲突:

State 3:
      (3) expr ::= lhs_expr *
      (4) expr ::= PLUS_PLUS lhs_expr *

                           DOT reduce       3      expr ::= lhs_expr
                           DOT reduce       4       ** Parsing conflict **
                     {default} reduce       4      expr ::= PLUS_PLUS lhs_expr

然而,如果我按如下方式重写最后一条规则:

expr ::= PLUS_PLUS expr DOT IDENTIFIER.

然后它不会引起冲突。但我不认为这是正确的方法。

如果有人能够解释正确的方式以及原因,我会感激不尽。

1 个答案:

答案 0 :(得分:5)

所以你写了一个含糊不清的语法,接受说:

 ++ x . y

有两种解释:

 [++ x ] . y

 ++ [x . y]

其中[]只是我向分组展示的方式。

Lemon是一个L(AL)R解析器,这样的解析器根本不处理歧义(多种解释)。报告的reduce-reduce冲突是解析器到达中间点时发生的事情;它组合" ++ x" as" [++ x]。"或作为" ++ [x。]"?这两种选择都是有效的,它无法安全地选择。

如果坚持使用Lemon(或其他LALR解析器生成器),则必须通过更改语法来解决问题。 [你可以使用GLR解析器生成器;它会接受并给你两个解析。但是你所做的就是将解决歧义的问题推到解析后的短语。由于您不想要歧义,如果可以的话,您可以在解析过程中避免它。在这种情况下,我认为你可以。]

我认为您正在尝试构建类似C语言的语言。 所以你想要这样的东西:

primitive_target ::= IDENTIFIER ;
primitive_target ::= IDENTIFIER '[' expr ']' ;
access_path ::= primitive_target ;
access_path ::= access_path '.' primitive_target ;

lhs ::= access_path ;
lhs ::= PLUS_PLUS access_path ;
lhs ::= access_path PLUS_PLUS ;

program ::= expr ;

expr ::= term ;
expr ::= expr '+' term ;
term :::= '(' expr ')' ;
term ::= lhs ;
term ::= lhs '=' expr ;
term ::= constant ;