所以我有这个语法:
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
和
| ?- parse_prefix(expr(E), [9], S).
E = 9
S = [] ? ;
no
| ?- parse_prefix(expr(E), [9,+,$,1,+], S).
E = op(9,+,$(1))
S = [+] ? ;
E = 9
S = [+,$,1,+] ? ;
我写了以下谓词:
%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).
我对递归和回溯感到很困惑..
我会永远爱任何可以帮助我的人。
提前谢谢。
答案 0 :(得分:2)
您已接近解决方案。最好定义你自己的operator => / 2来表示你自己的gammar规则,而不是与 - > / 2发生冲突。但我在语法规则体的表示方面遇到了问题。我没有看到你在语法规则体中区分终端和非终端。
一个建议是投票给(A1,......,An)代表身体中的一个连词,而不是[A1,..,An]。然后将[T]用于终端,将NT用于非终端。所以遵循以下规则,
term(E) => ['(', expr(E), ')'].
然后会读到:
term(E) => ['('], expr(E), [')'].
然后,您可以调整规则并定义parse_prefix / 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,然后从那里执行它们。你在这里找到一个简单的食谱:
http://www.jekejeke.ch/idatab/doclet/blog/en/docs/int/jan/098_2011/097_dcg_expansion/package.html
再见