Is there a way or an algorithm to convert DCG into

2019-02-18 10:02发布

I am a newbie in Prolog, and I am trying to understand how a grammar can be translated into a normal definite clause from a DCG. I understood that DCG notation is just syntactic sugar for normal definite clauses in Prolog. I started to depict some similarities between the normal definite grammars, and the DCGs, but failed to apply the same pattern, so I am asking is there some rules that I am missing or an algorithm of conversion that might work.

Here is the grammar that I am working on, and here is what I did in order to translate that grammar:

expr --> term, addterm.
addterm --> [].
addterm --> [+], expr.
term --> factor, multfactor.
multfactor --> [].
multfactor --> [*], term.
factor --> [I], {integer(I)}.
factor --> ['('], expr, [')'].

This grammar actually checks the syntactic correctness of arithmetic operations. The first rule is actually easy to convert as its pattern is similar to normal definite grammars, and so is the 4th one. However I have no clue about the other four. Here is How I converted the rule:

expr(E0,E) :- term(E0,E1), addterm(E1,E).

3条回答
Melony?
2楼-- · 2019-02-18 10:23

You are on the right track! Keep on going and you will get to something like this:

expr(Xs0,Xs) :-                         % expr -->
   term(Xs0,Xs1),                       %    term,
   addterm(Xs1,Xs).                     %    addterm.

addterm(Xs0,Xs) :-                      % addterm --> 
   Xs0 = Xs.                            %    [].
addterm(Xs0,Xs) :-                      % addterm -->
   Xs0 = [+|Xs1],                       %    [+], 
   expr(Xs1,Xs).                        %    expr. 

term(Xs0,Xs) :-                         % term --> 
   factor(Xs0,Xs1),                     %    factor,
   multfactor(Xs1,Xs).                  %    multfactor.

multfactor(Xs0,Xs) :-                   % multfactor -->
   Xs0 = Xs.                            %    [].
multfactor(Xs0,Xs) :-                   % multfactor -->
   Xs0 = [*|Xs1],                       %    [*],
   term(Xs1,Xs).                        %    term.  

factor(Xs0,Xs) :-                       % factor --> 
   Xs0 = [I|Xs],                        %    [I],
   integer(I).                          %    {integer(I)}.
factor(Xs0,Xs) :-                       % factor --> 
   Xs0 = ['('|Xs1],                     %    ['('], 
   expr(Xs1,Xs2),                       %    expr,
   Xs2 = [')'|Xs]. `                    %    [')'].      
查看更多
成全新的幸福
3楼-- · 2019-02-18 10:28

Some Prolog systems translate DCGs to clauses in a way that is different from the one in the answers by @repeat and @PauloMoura: direct unification of terminals with members of the list that is being analyzed/generated is replaced by a call to a predicate 'C'/3. For instance

a(X) --> b(X), [x, y], c(X).

is translated to

a(A,B,C) :-
  b(A,B,D),
  'C'(D,x,E),
  'C'(E,y,F),
  c(A,F,C).

This predicate is predefined in those systems to do the unification as in those answers, by the clause

'C'([X|S],X,S).

but it can be redefined by the user if needed.

This is part of the definition of DCGs, first put forth in Fernando Pereira and David Warren paper Definite clause grammars for language analysis, in Artificial Intelligence, 13, 1980, and is one of the differences to Alain Colmerauer et al. previous paper Metamorphosis Grammars. The use of the 'C'/3 predicate, originaly named connects, makes the DCG independent of the way the string to be parsed/generated is represented: in the translation given above there is nothing that requires that the variables B to F stand for lists, and 'C'/3 can be redefined to interpret them as other kind of terms. In order not to avoid efficiency losses the paper recommends preprocessing of DCGs clauses during compilation in case lists are used.

查看更多
时光不老,我们不散
4楼-- · 2019-02-18 10:36

If your Prolog system provides an expand_term/2 built-in predicate, you can use usually to expand grammar rules into clauses. For example:

?- expand_term((a --> b, c), Clause).
Clause = (a(_G1012, _G1013):-b(_G1012, _G1028), c(_G1028, _G1013)).

For a bit more readable output (and for this purpose only), try:

?- expand_term((a --> b, c), Clause), numbervars(Clause, 0, _).
Clause = (a(A, B):-b(A, C), c(C, B)).

numbervars/3 is a de facto standard predicate found on most Prolog systems.

查看更多
登录 后发表回答