Suppose I want to write a custom operator for composing DCG rules in a way that would otherwise be repetitive.
For example, suppose I had I a DCG, ws
such that:
ws --> [].
ws --> " ", ws.
to match zero or more spaces. Obviously, if I want optional whitespace between each token in my grammar, it's obnoxious to have to put , ws
everywhere.
I could define a new operator to replace ,/2
.
:- op(1000, xfy, [ -- ]).
:- meta_predicate --(*,*,?,?).
--(L,R) --> ({callable(L)} -> call(L); L), ws, ({callable(R)} -> call(R); R).
This joines the left and right hand of --/2
via the optional whitespace rule. This mostly works fine, however certain things trip it up:
rule --> "foo" -- ("bar"; "quux").
If I try and execute this rule, I get an error saying that ;/4
is not defined. I have a vague idea of the problem here, but basically the question is: is there a way to define new operators for DCGs that work with the same generality as ,/2
?
Yes, this is possible.
Currently, the main problem is:
?- callable("foo"). true.
So, I suggest this simpler definition:
--(L, R) --> L, ws, R.
In addition, I suggest:
:- set_prolog_flag(double_quotes, chars).
Sample query:
?- phrase(rule, Ls). Ls = [f, o, o, b, a, r] ; Ls = [f, o, o, q, u, u, x] ; Ls = [f, o, o, ' ', b, a, r] ; Ls = [f, o, o, ' ', q, u, u, x] ; Ls = [f, o, o, ' ', ' ', b, a, r] .
As another example, let us use this rule instead:
rule --> "foo" -- ("bar" | "quux") -- "test".
Now we get for example:
?- length(Ls, _), phrase(rule, Ls). Ls = [f, o, o, b, a, r, t, e, s, t] ; Ls = [f, o, o, b, a, r, ' ', t, e, s, t] ; Ls = [f, o, o, q, u, u, x, t, e, s, t] ; Ls = [f, o, o, ' ', b, a, r, t, e, s, t] ; Ls = [f, o, o, b, a, r, ' ', ' ', t, e, s, t] ; Ls = [f, o, o, q, u, u, x, ' ', t, e, s, t] ; Ls = [f, o, o, ' ', b, a, r, ' ', t, e, s, t] ; Ls = [f, o, o, ' ', q, u, u, x, t, e, s, t] ; Ls = [f, o, o, ' ', ' ', b, a, r, t, e, s, t] ; Ls = [f, o, o, b, a, r, ' ', ' ', ' ', t, e, s, t] .
Note how iterative deepening is used for fair enumeration.