【问题标题】:How does a parser solves shift/reduce conflict?解析器如何解决移位/减少冲突?
【发布时间】:2017-07-03 06:26:03
【问题描述】:

我有一个算术表达式语法,可以解决文本文件中的表达式数量(每行一个)。在编译 YACC 时,我收到消息 2 shift 减少冲突。但我的计算是正确的。如果解析器给出正确的输出,它如何解决移位/减少冲突。就我而言,有什么方法可以在 YACC 语法中解决它。

YACC 语法

Calc  : Expr               {printf(" = %d\n",$1);} 
  | Calc Expr          {printf(" = %d\n",$2);}
  | error              {yyerror("\nBad Expression\n ");}
  ;
Expr  : Term               { $$ = $1;         }
  | Expr '+' Term      { $$ = $1 + $3;    }
  | Expr '-' Term      { $$ = $1 - $3;    }
  ;
Term  : Fact               { $$ = $1;         }
  | Term '*' Fact      { $$ = $1 * $3;    }
  | Term '/' Fact      { if($3==0){ 
                yyerror("Divide by Zero Encountered.");
            break;}
               else
                $$ = $1 / $3;    
                   }
  ;
Fact  : Prim               { $$ = $1;        }
  | '-' Prim           { $$ = -$2;       }
  ;      
Prim  : '(' Expr ')'       { $$ = $2;        }
  | Id                 { $$ = $1;        }
  ;
Id    :NUM                 { $$ = yylval;    }
  ;

我应该做些什么改变来消除我的语法中的这种冲突?

【问题讨论】:

    标签: parsing yacc shift-reduce-conflict


    【解决方案1】:

    Bison/yacc 通过选择 shift 来解决 shift-reduce 冲突。这在 Shift-Reduce 冲突部分的bison manual 中有解释。

    您的问题是您的输入只是一系列Exprs,它们之间没有任何分隔符一起运行。这意味着:

    4 - 2
    

    可以是一个表达式 (4-2) 也可以是两个表达式 (4, -2)。由于野牛生成的解析器总是喜欢移位,因此解析器会选择将其解析为一个表达式,即使它是分两行输入的:

    4
    -2
    

    如果您想让用户像这样键入他们的表达式,而不使用任何分隔符,那么您可以忍受冲突(因为它相对温和),或者您可以将其编码到您的语法中,但这还有很多工作。要将其放入语法中,您需要定义两种不同类型的Expr:一种(您在顶层使用的那种)不能以一元减号开头,另一种(您可以在其他任何地方使用) ) 允许以一元减号开头。

    我怀疑您真正想要做的是使用换行符或其他类型的表达式分隔符。这就像将换行符传递给解析器并将 Calc 更改为 Calc: | Calc '\n' | Calc Expr '\n' 一样简单。


    我确定这出现在 SO 的其他地方,但我找不到。所以这里是你如何禁止在表达式的开头使用一元减号,这样你就可以在没有分隔符的情况下一起运行表达式。以n_ 开头的非终结符不能以一元减号开头:

    input:  %empty | input n_expr { /* print $2 */ }
    
    expr:   term | expr '+' term | expr '-' term
    n_expr: n_term | n_expr '+' term | n_expr '-' term
    
    term:   factor | term '*' factor | term '/' factor
    n_term: value | n_term '+' factor | n_term '/' factor
    
    factor: value | '-' factor
    
    value:  NUM | '(' expr ')'
    

    这会解析与您的语法相同的语言,但不会产生 shift-reduce 冲突。由于它解析相同的语言,输入

    4
    -2
    

    仍将被解析为单个表达式;要获得预期的结果,您需要输入

    4
    (-2)
    

    【讨论】:

    • 我使用了这个东西,它消除了移位/减少冲突,但我有一个文本文件,它将有一个带有新行的新表达式,其中这个东西会将整个文本视为一个单一的方程,用户可以或表达式中不能使用 ( )。
    • @nikul:是的,你最好保留你的表达式语法并改变你的词法扫描器以返回换行符,这样你就可以使用Calc的换行分隔版本跨度>
    • 您可能还想看看stackoverflow.com/a/42093276/1566221,但不要复制代码:OP的代码有很多问题(否则他不会问:)),还有我的回答不处理运算符优先级问题。但它确实可以正确地换行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多