At first glance, the main problem is that you are uncleanly mixing DCG with regular Prolog predicates.
Stay in DCG to identify all non-terminals. For instance:
optional (NT) -> [] | NT.
once_or_more (NT) -> NT, or_more (NT).
or_more (NT) -> [] | NT, or_more (NT).
In the following example:
a -> [a].
We can publish messages:
? - phrase (optional (a), Ls).
Ls = [];
Ls = [a].
? - phrase (once_or_more (a), Ls).
Ls = [a];
Ls = [a, a];
Ls = [a, a, a];
Ls = [a, a, a, a];
Ls = [a, a, a, a, a].
This seems to work the way you need it.
For a callback, you can simply bypass the predicate you need to call with a common outline:
parse_with_callback (Goal) ->
...,
{Goal},
...
It looks quite normal.
If such patterns occur frequently, you can always consider creating such DCGs from another view that allows you to complete the task more cleanly.
source share