Beaver分析器生成器的shift-reduce冲突与悬挂的其他情况有关

问题描述

我正在将(生成的)语法提供给Beaver解析器生成器。此规则中似乎存在悬而未决的其他问题,从而导致多次移位-减少冲突:

Condition
    = IF LPAR Expression.expression RPAR Statement.trueStatement OptionalStatement_1.elem2  
    ;
OptionalStatement_1
    = ELSE StatementArray3.falseStatement   
    |   
    ;

我认为悬空其他问题不会成为问题,因为该工具认选择SHIFT,这是悬空其他问题AFAIK的公认解决方案。但是,存在一些问题,因为我还有其他16条警告,而且我不明白为什么:

grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (ELSE: SHIFT; goto 93) over (ELSE: REDUCE OptionalStatement_1 = ) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (LBR: SHIFT; goto 5) over (LBR: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (IF: SHIFT; goto 18) over (IF: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (RETURN: SHIFT; goto 95) over (RETURN: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (DO: SHIFT; goto 100) over (DO: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (READ: SHIFT; goto 107) over (READ: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (WRITE: SHIFT; goto 110) over (WRITE: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (SEMICOLON: SHIFT; goto 113) over (SEMICOLON: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (WHILE: SHIFT; goto 114) over (WHILE: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (LPAR: SHIFT; goto 63) over (LPAR: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (PLUSPLUS: SHIFT; goto 71) over (PLUSPLUS: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (PLUS: SHIFT; goto 73) over (PLUS: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (EXCL: SHIFT; goto 75) over (EXCL: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (MINUS: SHIFT; goto 77) over (MINUS: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (MINUSMINUS: SHIFT; goto 79) over (MINUSMINUS: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (VALUE: SHIFT; goto 81) over (VALUE: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.
grammar.grammar: Warning: Resolved Shift-Reduce conflict by selecting (IDENT: SHIFT; goto 82) over (IDENT: REDUCE OptionalStatement_1 = ELSE StatementArray3.falseStatement) using precedence.

结果是在StatementArray3中将垃圾注入到else分支中(完全错误的类型,用List而不是Optional填充,填充了以下语句中的内容)。 有人可以请我解释一下这些移位减少冲突是由什么引起的(除了明显的第一个冲突之外)?请注意,语法是从类模型生成的,因此没有针对此问题的非常具体的解决方案最好的情况是,我通常需要解决此类问题,或者更改语法。


由另一种方法生成的前一个语法(我想避免)产生了该语法:

Condition
    = IF LPAR Expression.expression RPAR Statement.trueStatement    
    | IF LPAR Expression.expression RPAR Statement.trueStatement ELSE Statement.falseStatement  
    ;

在编译过程中没有冲突,但是对于以下输入:

{
  if(b == 21)
    c = 10;
  else
    c = 15;
}

解析器在运行时失败,只是跳过else并将第二个分配视为顶级:

4,4-4,7: Syntax Error: unexpected token "else"
4,7: Recovered: removed unexpected token "else"

完整的有问题的语法(去除了%import,%typeof和{: ... :}):

%terminals PERC,ASSIGNDIV,LT,RPAR,VALUE,DO,ASSIGN,PLUSPLUS,QUESTION,MINUS,WRITE,RETURN,LPAR,SEMICOLON,ASSIGNADD,ELSE,LBR,IF,COMMA,RBR,OR,SLASH,MINUSMINUS,COLON,EQ,GT,READ,ASSIGNMUL,STAR,IDENT,ASSIGNSUB,ASSIGNMOD,AND,GTE,WHILE,NEQ,EXCL,LTE,PLUS;

%left LPAR,RPAR;
%nonassoc PLUSPLUS,MINUSMINUS;
%left PREC_13_1,PREC_13_2;
%left PERC,STAR;
%left PLUS,MINUS;
%left LT,GTE;
%left NEQ,EQ;
%left AND;
%left OR;
%left QUESTION,COLON;
%right ASSIGN,ASSIGNMOD;


%goal Program;

Number
    = VALUE.value   
    ;

Program
    = FunctionArray1.functions Block.main   
    ;

UnaryOperation
    = PLUSPLUS Expression.expression    
    | PLUS Expression.expression @ PREC_13_1    
    | EXCL Expression.expression    
    | MINUS Expression.expression @ PREC_13_2   
    | MINUSMINUS Expression.expression  
    ;

Block
    = LBR StatementArray3.statements RBR    
    ;

BinaryOperation
    = Expression.expression1 NEQ Expression.expression2 
    | Expression.expression1 OR Expression.expression2  
    | Expression.expression1 PERC Expression.expression2    
    | Expression.expression1 EQ Expression.expression2  
    | Expression.expression1 PLUS Expression.expression2    
    | Expression.expression1 LT Expression.expression2  
    | Expression.expression1 MINUS Expression.expression2   
    | Expression.expression1 LTE Expression.expression2 
    | Expression.expression1 SLASH Expression.expression2   
    | Expression.expression1 GT Expression.expression2  
    | Expression.expression1 ASSIGN Expression.expression2  
    | Expression.expression1 STAR Expression.expression2    
    | AssignmentGeneric.val 
    | Expression.expression1 GTE Expression.expression2 
    | Expression.expression1 AND Expression.expression2 
    ;

Expression
    = LPAR Expression.val RPAR  
    | Expression.expression1 QUESTION Expression.expression2 COLON Expression.expression3   
    | UnaryOperation.val    
    | Number.val    
    | Variable.val  
    | FunctionCall.val  
    | BinaryOperation.val   
    ;

Parameterarray2
    = Parameterarray2.list COMMA Parameter.elem 
    |   
    | Parameter.elem    
    ;

Statement
    = Block.val 
    | Condition.val 
    | ReturnFunction.val    
    | ExpressionStatement.val   
    | DoWhile.val   
    | Read.val  
    | Write.val 
    | EmptyStatement.val    
    | WhileStatement.val    
    ;

Parameter
    = IDENT.ident   
    ;

Write
    = WRITE Expression.expression SEMICOLON 
    ;

OptionalStatement_1
    = ELSE StatementArray3.falseStatement   
    |   
    ;

FunctionArray1
    = FunctionArray1.list Function.elem 
    |   
    ;

WhileStatement
    = WHILE LPAR Expression.expression RPAR Statement.statement 
    ;

ExpressionArray4
    = ExpressionArray4.list COMMA Expression.elem   
    |   
    | Expression.elem   
    ;

ExpressionStatement
    = Expression.expression SEMICOLON   
    ;

Variable
    = IDENT.ident   
    ;

EmptyStatement
    = SEMICOLON 
    ;

Read
    = READ IDENT.ident SEMICOLON    
    ;

FunctionCall
    = IDENT.ident LPAR ExpressionArray4.expressions RPAR    
    ;

Condition
    = IF LPAR Expression.expression RPAR Statement.trueStatement OptionalStatement_1.elem2  
    ;

DoWhile
    = DO Statement.statement WHILE LPAR Expression.expression RPAR SEMICOLON    
    ;

Function
    = IDENT.ident LPAR Parameterarray2.parameters RPAR Block.body   
    ;

ReturnFunction
    = RETURN Expression.expression SEMICOLON    
    ;

StatementArray3
    = StatementArray3.list Statement.elem   
    |   
    ;

AssignmentGeneric
    = Expression.expression1 ASSIGNADD Expression.expression2   
    | Expression.expression1 ASSIGNMUL Expression.expression2   
    | Expression.expression1 ASSIGNDIV Expression.expression2   
    | Expression.expression1 ASSIGNSUB Expression.expression2   
    | Expression.expression1 ASSIGNMOD Expression.expression2   
    ;

解决方法

语法生成中存在问题。应该是

OptionalStatement_1
    = ELSE Statement.falseStatement   
    |   
    ;

不是StatementArray3.falseStatement


正确生成ELSE Statement.falseStatement替代项后,仅会发生一次shift-reduce冲突,并且我可以依靠默认的SHIFT动作。