`Invisible' grammars

By using backtrackable setarg/3 and logical global variables (lval/3) we can implement easily a superset of DCG grammars practically equivalent with Peter VanRoy's Extended DCGs. We call them invisible grammars as no preprocessor is involved in their implementation. It turns out that the technique has the advantage of `meta-programming for free' (without the expensive phrase/3), allows source level debugging and can be made more space and time efficient than the usual preprocessing based implementation. On real examples, their best use is for writting a Prolog compiler (they can contribute to the writing of compact and efficient code with very little programming effort) and for for large natural language processing systems.

Basically, they work as follows:

% tools

begin_dcg(Name,Xs):-lval(dcg,Name,Xs-Xs).

end_dcg(Name,Xs):-lval(dcg,Name,Xs-[]).

w(Word,Name):-
  lval(dcg,Name,State),
  State=_-[Word|Xs2],
  setarg(2,State,Xs2).

begin_dcg(Xs):-begin_dcg(default,Xs).
end_dcg(Xs):-end_dcg(default,Xs).
w(Word):-w(Word,default).

% grammar
x:-ng,v.

ng:-a,n.

a:-w(the).
a:-w(a).

n:-w(cat).
n:-w(dog).

v:-w(walks).
v:-w(sleeps).

% test
go:-begin_dcg(Xs),x,end_dcg(Ys),write(Ys),nl,fail.

?- go.
[the,cat,walks]
[the,cat,sleeps]
[the,dog,walks]
[the,dog,sleeps]
[a,cat,walks]
[a,cat,sleeps]
[a,dog,walks]
[a,dog,sleeps]

The program can be found in progs/setarg_dcg.pl. For reasons of efficiency (i.e. to equal or beat preprocessor based DCGs in terms of both space and time) BinProlog's `invisible grammars' have been implemented in C and are accessible through the following set of builtins:

dcg_connect/1  % works like 'C'/3 with 2 invisible arguments
dcg_def/1   % sets the first invisible DCG argument
dcg_val/1   % retrives the current state of the DCG stream
dcg_tell/1  % focus on a given DCG stream (from 0 to 255)
dcg_telling/1 % returns the number of the current DCGs stream

% INVISIBLE DCG connect operation: normally macro-expanded
'#'(Word):-dcg_connect(Word).

% example: ?-dcg_phrase(1,(#a,#b,#c),X).
dcg_phrase(DcgStream,Axiom,Phrase):-
  dcg_telling(X),dcg_tell(DcgStream),
    dcg_def(Phrase),
      Axiom,
    dcg_val([]),
  dcg_tell(X).