可能使用DCG的Prolog中的无上下文语法(CFG)的序列生成器

时间:2013-12-07 18:26:18

标签: parsing prolog sequence grammar dcg

我想在Prolog中编写gen(G,S)来为给定的语法G生成有效的序列S,其中G是格式语法([非终结者列表],[终端列表],[列表]规则],[起始顺序])。规则采用格式规则(nt,[x]),其中x可以是任何非终结符和/或终端列表。

e.g。     gen(语法([a,b],[t,q,y,z],[规则(a,[t]),规则(a,[z]),规则(b,[y]),规则( b,[a,q])],[a,b]),X)。

返回:     X = [t,y]。     X = [t,t,q]。     X = [t,z,q]。     X = [z,y]。     X = [z,t,q]。     X = [z,z,q]。

在CFG上为Prolog提供了所有信息(已经尝试了2天),我可以找出至少一种方法来做到这一点,使用内置的 - >和短语/ 2或从头开始,但没有运气。 (从未发布过SO b4&我是初学者,所以如果这个Q不合适我很抱歉。)

2 个答案:

答案 0 :(得分:1)

无需诉诸特殊的非逻辑谓词。这就是诀窍:

gen(grammar(_NTE, _TE, _Rules, []), []).

gen(grammar(NTE, TE, Rules, [H|T]), X) :-
    member(H, NTE),
    member(rule(H, Res), Rules),
    append(Res, T, NewT),
    gen(grammar(NTE, TE, Rules, NewT), X).

gen(grammar(NTE, TE, Rules, [H|T]), [H|X2]) :-
    member(H, TE),
    gen(grammar(NTE, TE, Rules, T), X2).

答案 1 :(得分:0)

这是一个至少应该指向正确方向的解决方案。它是不同的,因为我直接将终端,非终端和规则定义为Prolog事实:

nt(a). nt(b).

t(t). t(q). t(y). t(z).

rule(a, [t]).
rule(a, [z]).
rule(b, [y]).
rule(b, [a,q]).

从这里开始,您需要一个带有起始序列并应用规则的谓词:

gen([], []).
gen([A|As], S) :-
    (   t(A)
    ->  S = [A|Ts]
    ;   nt(A)
    ->  rule(A, Bs),
        gen(Bs, Cs),
        append(Cs, Ts, S)
    ),
    gen(As, Ts).

如果符号是终端,则它属于结束序列。如果它是非终端,则对其应用规则,然后将gen/2应用于结果。我假设您知道Prolog中的递归如何工作,if-else以及append/3的作用。

?- [gen].
% gen compiled 0.00 sec, 13 clauses
true.

?- gen([a,b], S).
S = [t, y] ;
S = [t, t, q] ;
S = [t, z, q] ;
S = [z, y] ;
S = [z, t, q] ;
S = [z, z, q].

要将其转换为您要查找的谓词,请考虑以下事项:

可以使用member/2枚举列表:

?- member(NT, [a,b]).
NT = a ;
NT = b.

您可以使用assertz/1

向数据库添加事实和规则
?- assertz(t(t)), assertz(t(q)). % etc

您可以使用forall/2来避免编写显式循环:

?- forall(member(R, Rules), assertz(R)).

如果需要,您可以直接在列表中使用member/2

我相信还有另一种方式。