P =>程序 K =>块
S =>单命令
C =>命令
E =>表达
B =>布尔EXPR
I =>标识符
N>标号
P :: = K。
K :: =开始C结束
C :: = C1; C2 |小号
S :: = I:= E |如果(B)则S |如果(B)那么S1否则S2 |而(B)做S |重复C直到(B)| K |打印E
E :: = - E | E1 + E2 | E1 - E2 | E1 E2 | E1 div E2 | E1 mod E2 | (E)|我| Ñ
B :: = E1 = E2 | E1> E2 | E1< E2 | E1!= E2 |不是B | B1和B2 | B1或B2 | (B)
我应该消除E和B中的歧义,以便我可以在prolog中编写DCG解析器。
答案 0 :(得分:5)
Prolog评估自上而下,然后可以调整LL grammar techniques。 DCG比LL(1)更强大,但仍然必须消除左递归。
B
更容易处理:左侧因素生产。
B ::= E Bx | not B | (B)
Bx ::= = E | > E | < E | != E | and B | or B
E更难,因为miss mul
令牌引入了更多歧义。姑且
E ::= − E | (E) | I | N | El
El ::= Ex E | epsilon
Ex ::= + El | − El | div El | mod El
DCG中的epsilon(空生产)可以这样写出
epsilon --> [].
如果您需要处理优先级和关联性(在B和E中),您将需要更多的工作。您可以参考this旧答案了解工作架构。
答案 1 :(得分:3)
@chac已经给了你很好的答案,向你展示解决这个问题的常用方法。
让我用另一种方式来阅读你的问题:你“应该消除E和B中的歧义,以便”你“可以在Prolog中编写DCG解析器”。这意味着,只需要在Prolog中编写DCG解析器即可消除歧义。有一个好消息:您根本不需要删除任何歧义来编写DCG解析器!以下是:
歧义的来源是像
这样的作品C :: = C; ç
或其他运算符+ - 并置div mod和
让我坚持一个简化的语法:
E :: = E + E | “1”
我们可以将其编码为
e --> "1".
e --> e, "+", e.
不幸的是,Prolog不会因
之类的查询而终止?- 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的一个程序问题,不能直接处理左递归。这是一种让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,但并非所有中缀运算符都是如此。