Parsing 使用Prolog进行前缀解析

Parsing 使用Prolog进行前缀解析,parsing,prolog,Parsing,Prolog,所以我有这个语法: expr(op(T,B,E)) => [term(T), binop(B), expr(E)]. expr(T) => [term(T)]. term(N) => [num(N)]. term(L) => [lvalue(L)]. term(pre(O,L)) => [incrop(O), lvalue(L)]. term(post(L,O)) => [lvalue(L), incrop(O)]. term(E

所以我有这个语法:

  expr(op(T,B,E)) => [term(T), binop(B), expr(E)].
  expr(T) => [term(T)].

  term(N) => [num(N)].
  term(L) => [lvalue(L)].
  term(pre(O,L)) => [incrop(O), lvalue(L)].
  term(post(L,O)) => [lvalue(L), incrop(O)].
  term(E) => ['(', expr(E), ')'].

  lvalue($(E)) => [$, expr(E)].

  incrop(++) => [++].
  incrop(--) => [--].

  binop(+) => [+].
  binop(-) => [-].

  num(0) => [0].
  num(1) => [1].
  num(2) => [2].
  num(3) => [3].
  num(4) => [4].
  num(5) => [5].
  num(6) => [6].
  num(7) => [7].
  num(8) => [8].
  num(9) => [9].
目标是根据规则解析输入,并分离剩余的后缀。比如说,

| ?- parse_prefix(expr(E), [$,1,+,2], S).

E = op($(1),+,2)
S = [] ? ;

E = $(op(1,+,2))
S = [] ? ;

E = $(1)
S = [+,2] ? ;

no

我编写了以下谓词:

%Base Case: No Token, No Suffix
parse_prefix(_,[],[]).

%Direct Matching: ex) parse_prefix(num(9),[9],S)
parse_prefix(NT,[Head|Tail],S):-
    NT =>[Head],
    write('two '),
    parse_prefix(expr(E),Tail,S).
%General Matching: ex) parse_prefix(expr(E),_,S)
parse_prefix(NT,[Head|Tail],S):-
    NT => [Head1|Tail1],
    %write(Head1),
    %write('one\n'),
    parse_prefix(Head1,[Head|Tail],S).
我对递归和回溯有很多困惑

我将永远爱任何能帮助我的人


提前感谢您。

您已经接近解决方案了。最好定义自己的运算符=>/2来表示自己的gammar规则,而不要与-->/2冲突。但是我在语法规则体的表示上有问题。我看不出你在语法规则体中区分终端和非终端

一个建议是投票支持(A1,…,An)来代表正文中的连词,而不是[A1,…,An]。然后使用[T]表示端子,NT表示非端子。所以下面的规则

term(E) => ['(', expr(E), ')'].
然后将改为:

term(E) => ['('], expr(E), [')'].
然后,您可以调整规则并定义parse_前缀/3,如下所示。我向您展示了端子、连词和非端子情况:

parse_prefix([T],I,O) :- !, I=[T|O].
parse_prefix((A,B),I,O) :- !, parse_prefix(A,I,H), parse_prefix(B,H,O).
parse_prefix(NT,I,O) :- (NT => Body), parse_prefix(Body,I,O).
您可以为空生产([])和辅助条件({})添加其他案例,或者使其更灵活,以便能够使用终端列表([T1,…,Tn])。此外,进一步的控件构造也是可能的,但是当您尝试执行剪切(!)时,在遵循元解释器方法时,事情会变得有点糟糕

除了编写元解释器parse_prefix/3,您还可以编写自己的术语重写,以最终获得一种方法,该方法将首先将给定的gammar规则转换为普通Prolog,然后从那里执行它们。您可以在这里找到一个简单的配方:


拜拜

请描述输出应该是什么样子。我猜他所描述的“目标是根据规则解析输入,并分离剩余后缀。”是DCG中两个额外参数的常见行为。由于他没有在语法规则中使用cut或类似的东西,[$,1,+,2]可能会得到两个带有空后缀的完整解析,即op($(1),+,2)和$(op(1,+,2)),正如他示例所要求的那样。
parse_prefix([T],I,O) :- !, I=[T|O].
parse_prefix((A,B),I,O) :- !, parse_prefix(A,I,H), parse_prefix(B,H,O).
parse_prefix(NT,I,O) :- (NT => Body), parse_prefix(Body,I,O).