Removing left recursion grammar using DCG

夙愿已清 提交于 2019-12-11 10:48:14

问题


The following Grammar has left-recursion

Grammar :

Expr ::= E1|E2|E3|E4|E5|E6|E7

E1 ::= "(" Expr ")"
E2 ::= "not""(" Expr ")"
E3 ::= Expr "=>" Expr
E4 ::= Expr "=/=" Expr
E5 ::= Expr "*" Expr
E6 ::= Func "=>" Func
Func ::= Ter  (Ters)+","
...

and I'm trying to remove the LR in this manner ;

Expr ::= E1|...

E1 ::= Expr "*" Expr ==>   E1   ::= Expr Expr'
                           Expr'::= *Expr Expr'

but the problem still exists, How to fix it to get this program working?

example query and test

| ?- phrase(e(T),"not((2+3)=/=5))").
! Resource error: insufficient memory

expected answer

 | ?- phrase(e(T),"not((2+3)=/=5))").
    error 13 ')'
 | ?- phrase(e(T),"(2+3)=>>5))").
    error 7 '>'

回答1:


You could try to bottom parse bottom up.

This is the processor:

:- op(150, xfx, ---> ).

parse(Phrase) -->
    leaf(SubPhrase),
    lc(SubPhrase, Phrase).

leaf(Cat) --> [Word], {word(Word,Cat)}.
leaf(Phrase) --> {Phrase ---> []}.

lc(Phrase, Phrase) --> [].

lc(SubPhrase, SuperPhrase) -->
    {Phrase ---> [SubPhrase|Rest]},
    parse_rest(Rest),
    lc(Phrase, SuperPhrase).

parse_rest([]) --> [].
parse_rest([Phrase|Phrases]) -->
    parse(Phrase),
    parse_rest(Phrases).

An example of grammar specification (but func seems ill specified, and there is no precedence or associativity specification...)

expr(E) ---> [opp, expr(E), clp].
expr(not(E)) ---> [not, opp, expr(E), clp].
expr(impl(L,R)) ---> [expr(L), impl, expr(R)].
expr(ne(L,R)) ---> [expr(L), ne, expr(R)].
expr(mul(L,R)) ---> [expr(L), mul, expr(R)].
expr(add(L,R)) ---> [expr(L), add, expr(R)].
expr(func(L,R)) ---> [func(L), impl, func(R)].
expr(num(N)) ---> [num(N)].

func(f(F, As)) ---> [name(F), args(As)].

args([A|As]) ---> [arg(A), comma, args(As)].
args([A]) ---> [arg(A)].
arg(E) ---> [expr(E)].


word(N, name(N)) :- atom(N).
word(N, num(N)) :- integer(N).
word(=>, impl).
word('(', opp).
word(')', clp).
word(*, mul).
word(+, add).
word(not, not).
word(=/=, ne).
word(',', comma).

an example run

?- phrase(parse(E), [not,'(',2,+,2,*,3,')']).
E = func(f(not, [mul(add(num(2), num(2)), num(3))])) ;
E = func(f(not, [add(num(2), mul(num(2), num(3)))])) ;
E = expr(not(mul(add(num(2), num(2)), num(3)))) ;
E = arg(not(mul(add(num(2), num(2)), num(3)))) ;
E = args([not(mul(add(num(2), num(2)), num(3)))]) ;
E = expr(not(add(num(2), mul(num(2), num(3))))) ;
E = arg(not(add(num(2), mul(num(2), num(3))))) ;
E = args([not(add(num(2), mul(num(2), num(3))))]) ;
false.

but maybe this is no so useful for your task...




回答2:


You didn't remove the left recursion at all. You merely replaced direct recursion with indirect; the parsing rules still don't terminate.

You have to start each grammar rule with something that resolves to a distinct, finite set of terminal symbols. You can use non-terminals, but each must resolve to such a set (no buried left recursion). The rules in your original grammar that fit this requirement are E1 (left paren), E2 (not) and Func (Ter ... assuming that has no left-recursion).

Yes, this requires some uncomfortable changes in your grammar at points. Turning one rule into three (or six) and creating new non-terminals is a chore. However, some parsing methods require this.

Have you yet learned how to turn BNF into GNF (Greibach normal form)? That's a little overkill, but it works quite well. GNF requires that each rules right-hand side begin with a terminal symbol. I found you a YouTube lecture and a PowerPoint presentation on the process.

Does this get you moving?



来源:https://stackoverflow.com/questions/35503334/removing-left-recursion-grammar-using-dcg

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!