解析 Prolog 中的表达式并返回抽象语法

标签 parsing prolog dcg failure-slice

我必须编写 parse(Tkns, T),它接受标记列表形式的数学表达式并找到 T,并返回表示抽象语法的语句,尊重操作顺序和关联性。

例如,

?- parse( [ num(3), plus, num(2), star, num(1) ], T ).

T = add(integer(3), multiply(integer(2), integer(1))) ;
No

我尝试按如下方式实现 + 和 *

parse([num(X)], integer(X)).
parse(Tkns, T) :-
  (  append(E1, [plus|E2], Tkns),
     parse(E1, T1),
     parse(E2, T2),
     T = add(T1,T2)
  ;  append(E1, [star|E2], Tkns),
     parse(E1, T1),
     parse(E2, T2),
     T = multiply(T1,T2)
  ).

它找到正确的答案,但也会返回不遵循关联性或运算顺序的答案。

例如)

parse( [ num(3), plus, num(2), star, num(1) ], T ). 

也返回

mult(add(integer(3), integer(2)), integer(1))

parse([num(1), plus, num(2), plus, num(3)], T)

返回 1+2+3 和 1+(2+3) 的等价物,而它应该只返回前者。

有什么办法可以让它发挥作用吗?

编辑:更多信息:我只需要实现 +、-、*、/、否定(-1、-2 等),并且所有数字都是整数。给出了一个提示,代码的结构将与语法类似

<expression> ::= <expression> + <term>
              |  <expression> - <term>
              |  <term>

      <term> ::= <term> * <factor>
              |  <term> / <factor>
              |  <factor>

    <factor> ::= num
              |  ( <expression> )

仅也实现了否定。

Edit2:我发现了一个用 Prolog 编写的语法解析器( http://www.cs.sunysb.edu/~warren/xsbbook/node10.html )。有没有一种方法可以修改它以打印语法的左手推导(“打印”是指 Prolog 解释器将输出“T=[正确答案]”)

最佳答案

正在删除 left recursion将驱使您走向基于 DCG 的语法。

但是有一个有趣的替代方法:实现自下而上解析。

这在 Prolog 中有多难?好吧,正如佩雷拉和希伯在他们精彩的书中所展示的那样 “Prolog 和自然语言分析”非常简单:来自第 6.5 章

Prolog supplies by default a top-down, left-to-right, backtrack parsing algorithm for DCGs.

It is well known that top-down parsing algorithms of this kind will loop on left-recursive rules (cf. the example of Program 2.3).

Although techniques are avail- able to remove left recursion from context-free grammars, these techniques are not readily generalizable to DCGs, and furthermore they can increase grammar size by large factors.

As an alternative, we may consider implementing a bottom-up parsing method directly in Prolog. Of the various possibilities, we will consider here the left-corner method in one of its adaptations to DCGs.

For programming convenience, the input grammar for the left-corner DCG interpreter is represented in a slight variation of the DCG notation. The right-hand sides of rules are given as lists rather than conjunctions of literals. Thus rules are unit clauses of the form, e.g.,

s ---> [np, vp].

optrel ---> [].

Terminals are introduced by dictionary unit clauses of the form word(w,PT).

考虑在继续之前完成讲座(在 info page 中按标题查找免费图书条目)。

现在让我们尝试编写一个自下而上的处理器:

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

% that's all! fairly easy, isn't it ?

% here start the grammar: replace with your one, don't worry about Left Recursion
e(sum(L,R)) ---> [e(L),sum,e(R)].
e(num(N)) ---> [num(N)].

word(N, num(N)) :- integer(N).
word(+, sum).

例如,产生

phrase(parse(P), [1,+,3,+,1]).
P = e(sum(sum(num(1), num(3)), num(1))) 

注意使用的左递归语法是 e::= e + e |数

关于解析 Prolog 中的表达式并返回抽象语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20511060/

相关文章:

Prolog - 使用 DCG 解析

prolog - 如何在 Prolog 中创建这个 DCG?

javascript - SpiderMonkey 24 : How to call Reflect. 解析()?

json - Swift - 解析多个可选 Json 答案

recursion - Prolog 中的递归搜索、累加器和计数器

prolog - 用于从 Prolog 中的复合术语中删除某些术语的谓词

Prolog DCG set_prolog_flag double_quotes 源代码指令位置很重要;文件?

java - 日期的 DateFormat 解析行为从 Java 8 更改为 Java 9,是否有任何相关的环境设置?

java - 使用 Joda Date & Time API 解析多种格式

list - Prolog - 替换列表元素