在其他的抽象语法中删除Ambiguity来编写DCG解析器Prolog

时间:2012-10-30 00:33:27

标签: prolog dcg left-recursion

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解析器。

2 个答案:

答案 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,但并非所有中缀运算符都是如此。