使用DCG删除左递归语法

时间:2016-02-19 10:43:32

标签: recursion prolog grammar dcg

以下语法有左递归

语法:

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)+","
...

我试图以这种方式删除LR;

Expr ::= E1|...

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

但问题仍然存在,如何修复它以使该程序正常工作?

示例查询和测试

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

预期答案

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

2 个答案:

答案 0 :(得分:4)

您可以尝试自下而上解析。

这是处理器:

:- 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).

语法规范的一个例子(但是func看起来很糟糕,并且没有优先级或关联性规范......)

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).

示例运行

?- 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.

但也许这对你的任务没那么有用......

答案 1 :(得分:2)

您根本没有删除左递归。你只是用间接替换直接递归;解析规则仍然没有终止。

您必须使用可解析为不同的有限终端符号集的内容来启动每个语法规则。您可以使用非终端,但每个终端必须解析为这样的集合(没有埋没的左递归)。原始语法中符合此要求的规则是E1(左paren),E2(不)和Func(Ter ...假设 没有左递归)。

是的,这需要你的语法上的一些令人不舒服的变化。将一条规则变为三条(或六条)并创建新的非终端是一件苦差事。但是,一些解析方法需要这个。

您是否还学会了如何将BNF转换为GNF(Greibach普通形式)?这有点矫枉过正,但效果很好。 GNF 要求每个规则右侧都以终端符号开头。我找到了YouTube讲座和关于这个过程的PowerPoint演讲。

这会让你感动吗?