P =>程序K =>块
S =>单命令
C =>命令
E =>表达式
B =>布尔EXPR
I =>标识符
N>标号
P :: = K.
ķ:: =开始Ç端
Ç:: = C1; C2 | 小号
与s :: = I:= E | 如果(B),则S | 如果(B),然后S1 S2其他| (B)是做S | 重复℃直至(B)| K | 打印E
:: = E - E | E1 + E2 | E1 - E2 | E1 E2 | 格E1 E2 | E1 E2模| (E)| 我| ñ
B :: = E1 = E2 | E1> E2 | E1 <E2 | E1 = E2!| 不是B | B1和B2 | B1或B2 | (B)
我应该消除含糊在E和B,这样我可以写在序言一DCG分析器。
Prolog的评估自上而下,然后LL 语法技术可以适应。 DCG比LL(1)功能更强大,但左递归仍然必须被淘汰。
B
更容易处理: 左因子生产。
B ::= E Bx | not B | (B)
Bx ::= = E | > E | < E | != E | and B | or B
E是很难的,因为思念mul
令牌介绍更加模糊性。 姑且
E ::= − E | (E) | I | N | El
El ::= Ex E | epsilon
Ex ::= + El | − El | div El | mod El
小量(空生产)的DCG可以这样写
epsilon --> [].
如果您需要处理优先级和结合(在B和E),您将需要更多的工作。 您可以参考这个旧的答案工作模式。
@chac已经给你相当不错的答案,显示你解决这个通常的方式。
让我采取另一种方式来阅读你的问题:你是“应该去掉了E歧义和B,使”你“可以在序言写DCG分析器”。 这意味着,你只需要那么远,你可以写在序言一DCG分析器删除歧义。 有个好消息: 你并不需要在所有以消除任何含糊之处写DCG分析器! 方法如下:
歧义的源像制作
Ç:: = C; C
或其他运营商+ - 并置DIV MOD和
让我坚持一个简化的语法:
Ë:: = E + E | “1”
我们可以编码这是
e --> "1".
e --> e, "+", e.
不幸的是,序言不终止查询像
?- L = "1+1+1", phrase(e,L).
L = "1+1+1" ;
ERROR: Out of local stack
事实上,它终止,但只是因为我的电脑的内存是有限的...
甚至不是:
?- L = "1", phrase(e,L).
L = "1" ;
ERROR: Out of local stack
这是含糊不清的问题? 没有! 这是序言的只是程序问题,不能直接处理左递归。 这里有一个方法,使Prolog的处理:
e([_|S],S) --> "1".
e([_|S0],S) --> e(S0,S1), "+", e(S1,S).
?- L = "1+1+1", phrase(e(L,[]),L).
L = "1+1+1" ;
L = "1+1+1" ;
false.
?- L = "1", phrase(e(L,[]),L).
L = "1" ;
false.
因为我们只定义语法的时刻,大部分的时间,你也有兴趣看到相应的语法树:
e(integer(1), [_|S],S) --> "1".
e(plus(L,R), [_|S0],S) --> e(L, S0,S1), "+", e(R, S1,S).
?- L = "1+1+1", phrase(e(Tree, L,[]),L).
L = "1+1+1",
Tree = plus(integer(1),plus(integer(1),integer(1))) ;
L = "1+1+1",
Tree = plus(plus(integer(1),integer(1)),integer(1)) ;
false.
现在,我们看到,有歧义与plus
! 您的原始语法既接受它作为(1 + 1)+1和1+(1 + 1),其本身不是问题,只要对应的语义保证关联是观察。 大部分时间,这是消除歧义被左结合的,因此表示(1 + 1)+1,但这不是对所有中缀运算符的情况。