Recursion 使用DCG删除左递归语法

Recursion 使用DCG删除左递归语法,recursion,prolog,grammar,dcg,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 ::= 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 '>'

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

您必须从解析为一组独特、有限的终端符号的语法规则开始。您可以使用非终端,但每个终端必须解析为这样一个集合(没有隐藏的左递归)。原始语法中符合此要求的规则是E1(左paren)、E2(not)和Func(Ter…假设没有左递归)

是的,这需要在某些时候对语法进行一些不舒服的修改。将一条规则转换为三条(或六条)并创建新的非终端是一件烦琐的事情。但是,某些解析方法需要这样做

你已经学会如何将BNF转换成GNF(格雷巴赫范式)了吗?这有点过分了,但效果很好。GNF要求每个规则的右侧以一个终端符号开始。我给你找了一个关于这个过程的讲座和报告


这会让你动起来吗?

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

您必须从解析为一组独特、有限的终端符号的语法规则开始。您可以使用非终端,但每个终端必须解析为这样一个集合(没有隐藏的左递归)。原始语法中符合此要求的规则是E1(左paren)、E2(not)和Func(Ter…假设没有左递归)

是的,这需要在某些时候对语法进行一些不舒服的修改。将一条规则转换为三条(或六条)并创建新的非终端是一件烦琐的事情。但是,某些解析方法需要这样做

你已经学会如何将BNF转换成GNF(格雷巴赫范式)了吗?这有点过分了,但效果很好。GNF要求每个规则的右侧以一个终端符号开始。我给你找了一个关于这个过程的讲座和报告


这会让你动起来吗?

你可以试着从下到上解析

这是处理器:

:- 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似乎没有得到很好的指定,并且没有优先级或关联性规范…)

示例运行

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

但这可能对您的任务没有多大用处…

您可以尝试自下而上进行分析

这是处理器:

:- 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似乎没有得到很好的指定,并且没有优先级或关联性规范…)

示例运行

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

但这可能对您的任务没有多大用处…

请始终包括一个可用的示例查询、系统的当前答案和预期答案。我已经通过term_扩展将@false suggestion(请参阅)编码为DCG扩展,但我使用的是SWi Prolog。您对SICSTUS Prolog中的alpha测试感兴趣吗?@capelical我测试了哪个示例?算了吧,在SICSTUS中,接口dcg_translate_rule/2丢失了…请始终包含可用的示例查询、系统的当前答案和预期答案。我已经通过term_扩展将@false suggestion(请参阅)编码为dcg扩展,但我用的是SWi Prolog。你对SICSTUS Prolog中的alpha测试感兴趣吗?@capelical我测试了哪个示例?算了吧,在SICSTUS中,接口dcg_translate_rule/2丢失了……谢谢你回答我,但是有没有一个通用的策略来避免这些类型的问题,并提供与上述语法最接近的示例?是的:通过两个链接查看我的更新。然后我们应该删除这些注释。在我找到一个将CFG转换为GNF的算法时,是否有一个自动将CFGRAMR转换为GNF的方法,比如
解析仿真器
,我知道有很多转换程序,因为这是研究生基础课上的一个常见编程作业。然而,我不知道具体在哪里可以找到一本出版的。您可以尝试搜索,尤其是在GitHub上。谢谢您回答我,但是有没有一个通用的策略可以通过与上述语法最接近的示例来避免这些类型的问题?是的:请通过两个链接查看我的更新。然后我们应该删除这些注释。在我找到一个将CFG转换为GNF的算法时,是否有一个自动将CFGRAMR转换为GNF的方法,比如
解析仿真器
,我知道有很多转换程序,因为这是研究生基础课上的一个常见编程作业。然而,我不知道具体在哪里可以找到一本出版的。您可以尝试搜索,尤其是在GitHub.thnks上,我认为这与类似,但您能否在第一个示例中添加一个简短的解释(lc,leaf)或
语法
,以促进理解这就是所谓的解析。按照维基百科页面上的链接获取更多解释。我认为这类似于,但您能否在第一个示例中添加一个简短的解释(lc,leaf)或
语法
,以促进理解这就是所谓的解析。按照维基百科页面的链接获取更多解释