Этот ответ: Очень простой синтаксис пролога dcg немного помог мне, но [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, на случай, если я собираюсь (facepalm) сам, но тем временем любая помощь будет очень кстати.
Спасибо, Шон.
Ответ 1 · рейтинг 3 · mat
Вы просите один из простейших нетерминалов DCG, который описывает любой список:
list --> [].
list --> [_], list.
Чтобы фактически получить доступ к описываемому списку, вы вводите аргумент:
list([]) --> [].
list([L|Ls) --> [L], list(Ls)
Вы можете использовать его следующим образом:
as_opt(Option) --> "--as=", list(Option).
Ответ 2 · рейтинг 3 · Paulo Moura
Есть лучшее решение, чем то, которое описано в мате, которое быстрее и избегает ложных точек выбора, но требует поддержки встроенного нетерминала call//1, как это найдено, например. SWI-Prolog, GNU Prolog и другие компиляторы Prolog. Также на Logtalk. Учитывать:
as_opt(Option) --> "--as=", list(Option).
list([L|Ls]) --> [L], list(Ls).
list([]) --> [].
as_opt2(Option) --> "--as=", call(rest(Option)).
rest(Rest, Rest, _).
Использование SWI-Prolog для лучшей иллюстрации различий:
?- 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].
Ложная точка выбора исходит из определения list//1 нетерминала. Разница в производительности заключается в том, что в то время как call//1 позволяет нам просто получить доступ к неявному аргументу списка, нетерминал list//1 выполняет копирование списка поэлементно этого неявного аргумента. Как следствие, производительность версии list//1 линейна для символов, следующих за префиксом --as=, в то время как производительность call//1 постоянна и не зависит от количества символов после префикса:
?- 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|...].