3

这个答案:非常基本的 dcg prolog 语法 帮助了我一点,但 [X] 只得到下一个字符,我想要整个辣酱玉米饼馅,继续阅读!

我正在使用 GNU Prolog 编写命令选项解析器,但我被困在 DCG 点上。例如,我有一个查找“foo --as=json”的语法规则,但我无法弄清楚如何获得“任何东西”的结果,代码:

as_opt --> "--as=", anything, { c( as_opt )}, !.
anything --> [], {c(anything_match)}.

而 gprolog 的扩展是:

as_opt([45, 45, 97, 115, 61|A], B) :-
        anything(A, C),
        c(as_opt), !,
        C = B.

anything(A, B) :-
        c(anything_match), !,
        A = B.

“c()”谓词很简单,仅用于跟踪使用 format() 到 stdout 执行的规则,因此我可以看到它运行时发生了什么。如果我手工编写代码,我会这样做:

%% for completeness here!
c(Msg) :- format("Processed ~w~n", [Msg]).

as_opt([45, 45, 97, 115, 61|A], B) :-
        anything(A, C),
        c(as_opt), !,
        C = B,
        { g_assign( gvValue, B )}. %% just for example

回到原来的DCG:

as_opt --> "--as=", anything, { c( as_opt ), gassign( gvValue, ??? )}, !.

那么“???”去哪儿了?是。有没有可能……应该有。我将重新阅读 gprolog 规则,了解它如何再次扩展 DCG 规则,以防我自己(捂脸),但与此同时,任何帮助都将受到欢迎。

谢谢,肖恩。

4

3 回答 3

3

There's a better solution than the one described by mat that is faster and avoids spurious choice points but it requires support for the call//1 built-in non-terminal as found on e.g. SWI-Prolog, GNU Prolog, and other Prolog compilers. Also on Logtalk. Consider:

as_opt(Option) --> "--as=", list(Option).

list([L|Ls]) --> [L], list(Ls).
list([]) --> [].

as_opt2(Option) --> "--as=", call(rest(Option)).

rest(Rest, Rest, _).

Using SWI-Prolog to better illustrate the differences:

?- phrase(as_opt(Option), "--as=json").
Option = [106, 115, 111, 110] ;
false.

?- phrase(as_opt2(Option), "--as=json").
Option = [106, 115, 111, 110].

?- time(phrase(as_opt(Option), "--as=json")).
% 9 inferences, 0.000 CPU in 0.000 seconds (57% CPU, 562500 Lips)
Option = [106, 115, 111, 110] ;
% 2 inferences, 0.000 CPU in 0.000 seconds (63% CPU, 133333 Lips)
false.

?- time(phrase(as_opt2(Option), "--as=json")).
% 6 inferences, 0.000 CPU in 0.000 seconds (51% CPU, 285714 Lips)
Option = [106, 115, 111, 110].

The spurious choice-point comes from the definition of the list//1 non-terminal. The performance difference is that, while call//1 allows us to simply access the implicit list argument, the list//1 non-terminal is doing a list copy element by element of that implicit argument. As a consequence, the list//1 version performance is linear on the characters following the --as= prefix while the call//1 performance is constant, independent of the number of characters after the prefix:

?- time(phrase(as_opt(Option), "--as=jsonjsonjsonjsonjsonjsonjsonjsonjsonjsonjsonjson")).
% 54 inferences, 0.000 CPU in 0.000 seconds (83% CPU, 2700000 Lips)
Option = [106, 115, 111, 110, 106, 115, 111, 110, 106|...] ;
% 4 inferences, 0.000 CPU in 0.000 seconds (69% CPU, 137931 Lips)
false.

?- time(phrase(as_opt2(Option), "--as=jsonjsonjsonjsonjsonjsonjsonjsonjsonjsonjsonjson")).
% 6 inferences, 0.000 CPU in 0.000 seconds (79% CPU, 333333 Lips)
Option = [106, 115, 111, 110, 106, 115, 111, 110, 106|...].
于 2013-09-07T11:40:24.700 回答
3

您要的是最简单的 DCG 非终端之一,它描述了任何列表:

list --> [].
list --> [_], list.

要实际访问正在描述的列表,您需要引入一个参数:

list([])    --> [].
list([L|Ls) --> [L], list(Ls)

你可以像这样使用它:

as_opt(Option) --> "--as=", list(Option).
于 2013-09-06T12:12:22.860 回答
1

我认为你不应该使用全局变量。相反,将参数添加到 DCG 子句,以取回值:

anything([C|Cs]) --> [C], anything(Cs).
anything([]) --> [].

否则,在规则成功后,剩余部分可用作短语/3 的最后一个参数,“消耗”标题匹配。

于 2013-09-06T12:09:17.873 回答