我正在用前缀表示法编写算术表达式的语法。但是在解析负数或减法时我遇到了问题。语法的例子是:
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
,下一个E
为4
,然后E
为- E E
。如何使用关联性来解决这个问题?还是我需要重写我的语法?
答案 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
;
请检查以上几次,因为我很生气。