From e702fe5c686ae1ddf3936a557ed0cb816d5f344f Mon Sep 17 00:00:00 2001 From: Markus Triska Date: Sat, 6 Jan 2024 09:21:22 +0100 Subject: [PATCH] ADDED: Support for higher-order non-terminals phrase//[2,3] These non-terminals take a grammar rule body and additional arguments as arguments. These arguments are appended to the first argument. A key motivation for the introduction of these non-terminals is found in the discussion and sample code provided by @bakaq in: https://github.com/mthom/scryer-prolog/discussions/2260 In this way, portable higher-order DCG programming is possible while keeping the logical grammar rule expansion implementation dependent. Example: ?- phrase(phrase('.', a, []), Cs). Cs = "a". --- src/lib/dcgs.pl | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/lib/dcgs.pl b/src/lib/dcgs.pl index ef2e82533..9f7dfacfb 100644 --- a/src/lib/dcgs.pl +++ b/src/lib/dcgs.pl @@ -12,6 +12,8 @@ [op(1105, xfy, '|'), phrase/2, phrase/3, + phrase/4, + phrase/5, seq//1, seqq//1, ... //0, @@ -27,6 +29,10 @@ :- meta_predicate phrase(2, ?, ?). +:- meta_predicate phrase(2, ?, ?, ?). + +:- meta_predicate phrase(2, ?, ?, ?, ?). + %% phrase(+Body, ?Ls). % % True iff Body describes the list Ls. Body must be a DCG body. @@ -76,6 +82,34 @@ ; call(M:GRBody1, S0, S) ). +phrase(GRBody, Arg, S0, S) :- + strip_module(GRBody, M, GRBody1), + ( var(GRBody) -> + instantiation_error(phrase/4) + ; nonvar(GRBody1), + GRBody1 =.. GRBodys1, + append(GRBodys1, [Arg], GRBodys2), + GRBody2 =.. GRBodys2, + dcg_constr(GRBody2), + dcg_body(GRBody2, S0, S, GRBody3) -> + call(M:GRBody3) + ; call(M:GRBody1, Arg, S0, S) + ). + +phrase(GRBody, Arg1, Arg2, S0, S) :- + strip_module(GRBody, M, GRBody1), + ( var(GRBody) -> + instantiation_error(phrase/5) + ; nonvar(GRBody1), + GRBody1 =.. GRBodys1, + append(GRBodys1, [Arg1,Arg2], GRBodys2), + GRBody2 =.. GRBodys2, + dcg_constr(GRBody2), + dcg_body(GRBody2, S0, S, GRBody3) -> + call(M:GRBody3) + ; call(M:GRBody1, Arg1, Arg2, S0, S) + ). + % The same version of the below two dcg_rule clauses, but with module scoping. dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :- dcg_non_terminal(NonTerminal, S0, S, Head), @@ -139,6 +173,8 @@ dcg_constr({_}). % 7.14.7 dcg_constr(call(_)). % 7.14.8 dcg_constr(phrase(_)). % 7.14.9 +dcg_constr(phrase(_,_)). % extension of 7.14.9 +dcg_constr(phrase(_,_,_)). % extension of 7.14.9 dcg_constr(!). % 7.14.10 %% dcg_constr(\+ _). % 7.14.11 - not (existence implementation dep.) dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.) @@ -166,6 +202,8 @@ dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )). dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)). dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)). +dcg_cbody(phrase(Body, Arg), S0, S, phrase(Body, Arg, S0, S)). +dcg_cbody(phrase(Body, Arg1, Arg2), S0, S, phrase(Body, Arg1, Arg2, S0, S)). dcg_cbody(!, S0, S, ( !, S0 = S )). % dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )). dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :-