p =>程序k =>块
s =>单个命令
c =>命令
e =>表达
b => boolean-expr
i =>标识符
n>数字
p :: = k。
k :: = begin c end
c :: = c1;C2 |S
s :: = i:= e |如果(b)然后s |如果(b)则S1 else s2 |而(b)做S |重复C直到(b)|K |打印E
e :: = - e |E1 E2 |E1 -E2 |E1 E2 |E1 Div E2 |E1 mod E2 |(E)|我|n
b :: = e1 = e2 |E1> E2 |E1<E2 |E1!= E2 |不是b |B1和B2 |B1或B2 |(b)
我应该删除E和B中的歧义,以便我可以在Prolog中编写DCG解析器。
prolog tops downuate tops down,然后可以调整LL语法技术。DCG比LL(1)强大,但仍必须消除左侧递归。
B
更容易处理:左因子生产。
B ::= E Bx | not B | (B)
Bx ::= = E | > E | < E | != E | and B | or B
e更难,因为mul
MISS的标记会引入更大的歧义。暂时
E ::= − E | (E) | I | N | El
El ::= Ex E | epsilon
Ex ::= + El | − El | div El | mod El
DCG中的Epsilon(空生产)可以以这种方式编写
epsilon --> [].
如果您需要处理优先级和关联性(在B和E中),则需要更多的工作。您可以参考工作架构的旧答案。
@chac已经给了您一个很好的答案,向您展示了解决此问题的常见方法。
让我采用另一种方法来阅读您的问题:您是"应该消除E和B中的歧义,这样"您"可以在Prolog"中撰写DCG解析器。这意味着,您只需要消除歧义,只能在Prolog中编写DCG解析器。有个好消息:您根本不需要删除任何歧义来编写DCG解析器!这是:
歧义的来源是
之类的作品c :: = c;c
或其他操作员 - 并列Div mod和
让我坚持简化的语法:
e :: = e e |&quot" 1&quot
我们可以将其编码为
e --> "1".
e --> e, "+", e.
不幸的是,Prolog并未终止
这样的查询?- L = "1+1+1", phrase(e,L).
L = "1+1+1"
; resource_error(_). % ERROR: Out of local stack
实际上,它终止了,但这仅仅是因为我的计算机的内存是有限的...
甚至不是:
?- L = "1", phrase(e,L).
L = "1"
; resource_error(_). % ERROR: Out of local stack
这是歧义的问题吗?不!这只是序言的程序问题,无法直接处理左回归。这是使序言处理的一种方法:
E([_ | S],S) ->" 1"。e([_ | s0],s) -> e(s0,s1)," ",e(s1,s)。? - l =" 1 1 1",短语(e(l,[]),l)。 l =" 1 1 1";l =" 1 1 1";错误的。? - l =" 1",短语(e(l,[]),l)。 L =" 1";错误的。
目前我们只定义了语法,在大多数情况下,您也有兴趣看到相应的语法树:
e( integer(1), [_ | s],s) ->" 1"。e( plus(l,r), [_ | s0],s) -> e( l, s0,s1)," ",e( r, s1,s)。? - l =" 1 1 1",短语(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),整数(1)),整数(1));错误的。
现在,我们看到plus
有歧义!您的原始语法都将其接受为(1 1) 1和1 (1 1),只要相应的语义保证观察到关联性,就不是问题。在大多数情况下,这是歧义为左求的,因此含义(1 1) 1,但这并不是所有Infix Operators的情况。