与输入的其余部分匹配的 DCG [英] A DCG that matches the rest of the input
问题描述
这是做它应该做的事情的谓词,即,当 DCG 的一部分时,收集输入中剩下的任何内容:
This is the predicate that does what it should, namely, collect whatever is left on input when part of a DCG:
rest([H|T], [H|T], []).
rest([], [], []).
但我很难将其定义为 DCG... 或者它完全可行吗?
but I am struggling to define this as a DCG... Or is it at all doable?
这当然不一样(尽管以相同的方式使用时它的作用相同):
This of course is not the same (although it does the same when used in the same manner):
rest([H|T]) --> [H], !, rest(T).
rest([]) --> [].
我认为我需要这个的原因是 rest//1
是我需要解析输入的一组 DCG 规则的一部分.我可以做 phrase(foo(T), Input, Rest)
,但是我必须调用另一个 phrase(bar(T1), Rest)
.
The reason I think I need this is that the rest//1
is part of a set of DCG rules that I need to parse the input. I could do phrase(foo(T), Input, Rest)
, but then I would have to call another phrase(bar(T1), Rest)
.
假设我知道我在输入上只剩下一串我想要作为整数的数字:
Say I know that all I have left on input is a string of digits that I want as an integer:
phrase(stuff_n(Stuff, N), `some other stuff, 1324`).
stuff_n(Stuff, N) -->
stuff(Stuff),
rest(Rest),
{ number_codes(N, Rest),
integer(N)
}.
推荐答案
回答我自己的愚蠢问题:
Answering my own silly question:
@CapelliC 给出了一个有效的解决方案 (+1).它做了一些我不明白的事情:-(,但真正的问题是我不明白我试图解决的问题.真正的问题是:
@CapelliC gave a solution that works (+1). It does something I don't understand :-(, but the real issue was that I did not understand the problem I was trying to solve. The real problem was:
您有一个需要解析的代码列表作为输入.结果应该是一个术语.您在此代码列表的开头非常了解其余部分的样子.换句话说,它以定义内容的关键字"开头.在某些情况下,在输入中的某个点之后,其余内容不需要解析:相反,它们作为代码列表收集在结果术语中.
You have as input a code list that you need to parse. The result should be a term. You know quite close to the beginning of this list of codes what the rest looks like. In other words, it begins with a "keyword" that defines the contents. In some cases, after some point in the input, the rest of the contents do not need to be parsed: instead, they are collected in the resulting term as a code list.
一种可能的解决方案是将解析分解为对 phrase/3
的两次调用(因为没有理由不这样做?):
One possible solution is to break up the parsing in two calls to phrase/3
(because there is no reason not to?):
- 读取关键字(第一次调用
phrase/3
)并使其成为一个原子; - 在表格中查找其余部分应该是什么样子;
- 解析只解析需要解析的内容(第二次调用
phrase/3
).
- Read the keyword (first call to
phrase/3
) and make it an atom; - Look up in a table what the rest is supposed to look like;
- Parse only what needs to be parsed (second call to
phrase/3
).
代码
因此,使用 (O'Keefe 1990) 中的方法并利用 SWI-Prolog 中可用的 library(dcg/basics)
和文件 rest.pl
>:
:- use_module(library(dcg/basics)).
codes_term(Codes, Term) :-
phrase(dcg_basics:nonblanks(Word), Codes, Codes_rest),
atom_codes(Keyword, Word),
kw(Keyword, Content, Rest, Term),
phrase(items(Content), Codes_rest, Rest).
kw(foo, [space, integer(N), space, integer(M)], [], foo(N, M)).
kw(bar, [], Text, bar(Text)).
kw(baz, [space, integer(N), space], Rest, baz(N, Rest)).
items([I|Is]) -->
item(I),
items(Is).
items([]) --> [].
item(space) --> " ".
item(integer(N)) --> dcg_basics:integer(N).
重要的是,其余"完全不需要由 DCG 规则处理.
这个解决方案很好,因为它是确定性的,而且很容易扩展:只需将子句添加到 kw/4
表和 item//1
规则.(注意在启动 SWI-Prolog 时使用 --traditional
标志,用于双引号分隔的代码列表)
This solution is nice because it is deterministic, and very easy to expand: just add clauses to the kw/4
table and item//1
rules. (Note the use of the --traditional
flag when starting SWI-Prolog, for double-quote delimited code lists)
$ swipl --traditional --quiet
?- [rest].
true.
?- codes_term("foo 22 7", T).
T = foo(22, 7).
?- codes_term("bar 22 7", T).
T = bar([32, 50, 50, 32, 55]).
?- codes_term("baz 22 7", T).
T = baz(22, [55]).
这篇关于与输入的其余部分匹配的 DCG的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!