Bison语法转移/减少冲突处理因子以及其他一元运算符

时间:2018-06-06 17:25:50

标签: bison yacc

当我读一本关于它的书时,我正在和野牛一起乱画,我正在研究一个简单的中缀计算器,我使用语法来指示优先权,而不是使用%left/%right和此类声明的顺序。

我见过的大多数野牛计算器都将因子作为函数而不是运算符,因此这些示例没有用处。

目前我有:

 15 calclist:
 16   | calclist expr EOL { printf(" = %d\n", $2); }
 17   | calclist EOL { /* nada */ }
 18   ;
 19 expr:
 20     term
 21   | expr '+' term { $$ = $1 + $3; }
 22   | expr '-' term { $$ = $1 - $3; }
 23   ;
 24 term:
 25     factor
 26   | term '*' factor { $$ = $1 * $3; }
 27   | term '/' factor { $$ = $1 / $3; }
 28   ;
 29 factor:
 30     '|' factor { $$ = $2 > 0 ? $2 : -$2; }
 31   | '-' factor { $$ = 0 - $2; }
 32   | '(' expr ')' { $$ = $2; }
 33   | '(' expr ')' '!' { $$ = factorial($2); }
 34   | NUMBER '!' { $$ = factorial($1); }
 35   | NUMBER
 36   ;

第33和34行似乎过于冗长。我觉得这样做的正确方法是用以下内容替换33/34:

33   | factor '!' { $$ = factorial($1); }

然后我得到了使用否定/ abs值运算符的移位/减少冲突,这在我查看使用calc.output生成的bison -v文件时有意义。

在维护定义运算符优先级的expr / term / factor语法时,是否有更简洁的方法?或者我的工作解决方案是我能够做到的最好的约束(自我强加或其他)。

1 个答案:

答案 0 :(得分:2)

-2!是什么意思?如果您添加factor: factor '!',则会产生歧义,因为您可以将其解析为- <factor: 2 !><factor: - 2> !,这显然在语义上不同。 [注1]

我认为正常的理解是后缀运算符(例如)优先于任何前缀运算符,因此应该-2!作为-(2!)的自然解释。 [注2]

因此必须有一个优先级比一元前缀运算符更紧密地绑定。每次引入新的优先级时,都需要引入一个新的相应的非终端(除非你使用优先级声明;有关详细信息和示例,请参阅bison手册)。

这导致:

expr:
    term
  | expr '+' term { $$ = $1 + $3; }
  | expr '-' term { $$ = $1 - $3; }
  ;
term:
  factor
  | term '*' factor { $$ = $1 * $3; }
  | term '/' factor { $$ = $1 / $3; }
  ;
factor:
    postfix
  | '|' postfix { $$ = $2 > 0 ? $2 : -$2; }
  | '-' postfix { $$ = 0 - $2; }
  ;
postfix:
    postfix '!'  { $$ = factorial($1); }
  | '(' expr ')' { $$ = $2; }
  | NUMBER
  ;

注释

  1. (-2)!可能是也可能不是语义错误,但似乎没有任何可能使它成为语法错误,因为语法无法知道(3-5)!可能是什么。从语义上讲,如果要将阶乘推广到欧拉伽马函数,那么它对于负数是有意义的,条件是负整数的Γ是无穷大的。但这是一个完整的题外话。

  2. 在具有后缀++的C语言中,此规则也正常; -x++表示-(x++)。更常见的是,在这种情况下,前缀运算符将是 *