前缀表示法中的算术表达式语法(Java Cup)

时间:2013-09-01 01:21:19

标签: parsing arithmetic-expressions compiler-construction cup

我正在用前缀表示法编写算术表达式的语法。但是在解析负数或减法时我遇到了问题。语法的例子是:

precedence right +, -;
precedence right *, /;
precedence right uminus;

E ::= + E E
   |  - E E
   |  * E E
   |  / E E
   |  ( E )
   |  - E %prec uminus
   |  id
   |  digit
   ;

但如果我的输入为- 5 4,则会将5缩减为E,接下来会减少- E(否定),然后解析器会在{{{{}}处给出语法错误1}}。正确的一个应为4 5,下一个E4,然后E- E E。如何使用关联性来解决这个问题?还是我需要重写我的语法?

2 个答案:

答案 0 :(得分:1)

(由评论推荐)

你的语法真的很模糊,优先级声明对你没什么帮助。

考虑输入由N -令牌组成的输入,然后是M 1令牌。

- - - - - - - ... - 1 1 1 ... 1

为了使这成为一个表达式,M-1标记的-必须是二进制的,剩下的N-(M-1)一元,但是没有办法分辨哪个是({1}}除非它们都是二进制的。)

即使您任意说第一个N-(M-1) -是一元的,在您阅读整个输入之前,您无法确定N-(M-1)的值是什么,这意味着您不能用有限的前瞻来解析。

但前缀表示法的全部要点是避免使用括号。如上所述的任意声明使得无法表示替代解释,因此某些表达式无法用前缀表示法表示。这是完全错误的。

这是一个简单的案例:

- 5 - - - 4 3 1

5 - (- (4 - (3 - 1)))
5 - ((- (4 - 3)) - 1)
5 - (((- 4) - 3) - 1)

在前缀表示法中,你需要隐式地声明每个运算符的“arity”(每个运算符都有一个已知数量的参数),或者显式地使用这样的表示法,借用Prolog:

-/2 5 -/2 -/2 -/1 4 3 1

或者,您可以使用强制括号来分隔参数,就像使用Lisp / Scheme“s-exprs”:

(- 5 (- (- (- 4) 3) 1))

答案 1 :(得分:0)

首先,删除所有优先级声明。前缀语法中不需要它们。实际上,这应该足以解决任何解析器生成器中的问题。你在哪一个,BTW?

杯子前瞻性有限。正如@rici指出的那样,在这种情况下无法解决歧义。你可以做的是限制语法,这样就可以使用一个连续的一元-

    B ::= E
       |  - E
       ;
    E ::= + B B
       |  - B B
       |  * B B
       |  / B B
       |  ( B )
       |  id
       |  digit
       ;

请检查以上几次,因为我很生气。