@chac はすでに非常に良い回答を提供しており、これを解決する通常の方法を示しています。
あなたの質問を別の方法で読んでみましょう。「Prolog で DCG パーサーを記述できるように、E と B のあいまいさを取り除く必要があります」。つまり、Prolog で DCG パーサーを記述できる範囲でのみあいまいさを取り除く必要があります。良いニュースがあります。DCG パーサーを作成するためにあいまいさをまったく取り除く必要はありません。方法は次のとおりです。
あいまいさの原因は、次のようなプロダクションです
C ::= 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", フレーズ(e(L,[]),L).
L = "1+1+1" ;
L = "1+1+1" ;
間違い。
?- L = "1", 句(e(L,[]),L)。
L = "1" ;
間違い。
現時点では、文法のみを定義していますが、ほとんどの場合、対応する構文ツリーも確認する必要があります。
e(整数(1), [_|S],S) --> "1".
e( plus(L,R), [_|S0],S) --> e( L, S0,S1), "+", e( R, S1,S).
?- L = "1+1+1", フレーズ(e(ツリー, L,[]),L).
L = "1+1+1",
ツリー = プラス (整数 (1)、プラス (整数 (1)、整数 (1))) ;
L = "1+1+1",
ツリー = プラス (プラス (整数 (1)、整数 (1))、整数 (1)) ;
間違い。
plus
ここで、 !にはあいまいさがあることがわかります。元の文法では、(1+1)+1 と 1+(1+1) の両方が受け入れられましたが、対応するセマンティクスが結合性を保証している限り、それ自体は問題ありません。ほとんどの場合、これは左結合、つまり (1+1)+1 を意味するように明確化されますが、これはすべての中置演算子に当てはまるわけではありません。