recursionprologdcgleft-recursionfailure-slice

Prolog DCG: Match different symbols on a chain


I'm trying to match some sentences (e.g. 001 [0,0,1], (1+(1/0)) ['(',1,+,'(',1,/,0,')',')'], and so on.

I've made myself following small DCG.

g3 --> s3.
s3 --> e3.

e3 --> eAdd.
e3 --> eMin.
e3 --> eMul.
e3 --> eDiv.
e3 --> n3.

eAdd --> ['('],e3,['+'],e3,[')'].
eMin --> ['('],e3,['-'],e3,[')'].
eMul --> ['('],e3,['*'],e3,[')'].
eDiv --> ['('],e3,['/'],e3,[')'].


n3 --> d3.
n3 --> n3,d3.
d3 --> [0].
d3 --> [1].

Now my problem is, it won't match with sentences using -,* or / but it works for recursive sentences using only +.

E.g:

phrase(g3,['(',1,'+','(',1,'+',1,')',')']).

Will work, but

phrase(g3,['(',1,'+','(',1,'/',1,')',')']).

Won't work.

Any help would be appreciated, thanks!


Solution

  • Your problem is due to the rule

    n3 --> n3,d3.
    

    This is a so-called left recursive rule. It says that to match an n3, you must first match an n3, for which you must first match an n3, for which you must first, etc., and this never terminates.

    Basically, you want every recursive grammar rule to first match some nonterminals before performing a recursive call. (Similarly, in the bodies of "normal" Prolog predicates, you should have other goals before any recursive call.)

    If you change this rule to the right-recursive variant

    n3 --> d3,n3.
    

    your grammar becomes well-behaved:

    ?- phrase(g3,['(',1,'+','(',1,'+',1,')',')']).
    true ;
    false.
    
    ?- phrase(g3,['(',1,'+','(',1,'/',1,')',')']).
    true ;
    false.
    
    ?- length(L, 6), phrase(g3, L).
    L = ['(', 0, +, 0, 0, ')'] ;
    L = ['(', 0, +, 0, 1, ')'] ;
    L = ['(', 0, +, 1, 0, ')'] ;
    L = ['(', 0, +, 1, 1, ')'] ;
    L = ['(', 1, +, 0, 0, ')'] ;
    L = ['(', 1, +, 0, 1, ')'] ;
    L = ['(', 1, +, 1, 0, ')'] ;
    L = ['(', 1, +, 1, 1, ')'] ;
    

    etc.

    Here are a few old questions about left recursion in DCGs that might provide additional helpful information:

    DCG and left recursion

    Removing left recursion in DCG - Prolog

    Removing left recursion grammar using DCG