Skip to content

Instantly share code, notes, and snippets.

@eignnx
Last active April 11, 2021 01:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eignnx/87fb1c3cfc72835e536283dc698dffed to your computer and use it in GitHub Desktop.
Save eignnx/87fb1c3cfc72835e536283dc698dffed to your computer and use it in GitHub Desktop.
A Prolog `term_expansion` rule for a modified DCG arrow. It automatically builds syntax trees as it parses.
:- module(cfg_macro, [
op(1200, xfx, ++>)
]).
:- op(1200, xfx, ++>).
/*
The rule:
s ++> np(blah), vp.
translates to:
s(s(Np, Vp)) --> np(blah, Np), vp(Vp).
n ++> [N], { noun(N) }.
expands to:
n(n([N])) --> [N], { noun(N) }.
*/
user:term_expansion((Head ++> Body), Expansion) :-
plus_plus_arrow_expansion((Head ++> Body), Expansion).
plus_plus_arrow_expansion((Head0 ++> Body0), (Head --> Body)) :-
and_list(Body0, BodyList0),
phrase(terminal_body_expansion(BodyList0, BodyList), Terminals),
!,
and_list(Body, BodyList),
head_payload_expansion(Head0, [Terminals], Head).
plus_plus_arrow_expansion((Head0 ++> Body0), (Head --> Body)) :-
and_list(Body0, BodyList0),
phrase(nonterminal_body_expansion(BodyList0, BodyList), Vars),
!,
and_list(Body, BodyList),
head_payload_expansion(Head0, Vars, Head).
head_payload_expansion(Head0, Payload, Head) :-
Head0 =.. [Functor|OriginalArgs],
Syntax =.. [Functor|Payload],
Head =.. [Functor,Syntax|OriginalArgs].
and_list(X, [X]) :- X \= (_,_), !.
and_list((First, Rest0), [First|Rest]) :-
!,
and_list(Rest0, Rest).
nonterminal_body_expansion([[X|Xs]|Rest0], [[X|Xs]|Rest]) -->
!,
nonterminal_body_expansion(Rest0, Rest).
nonterminal_body_expansion([{X}|Rest0], [{X}|Rest]) -->
!,
nonterminal_body_expansion(Rest0, Rest).
nonterminal_body_expansion([Nt0|Rest0], [Nt|Rest]) -->
!,
{
Nt0 =.. [Functor|SuppliedArgs],
Functor \= ';',
Functor \= '|',
Nt =.. [Functor, Var|SuppliedArgs]
},
[Var],
nonterminal_body_expansion(Rest0, Rest).
nonterminal_body_expansion([], []) --> [].
%! terminal_body_expansion(Body0, Body)
%!
%! Expands `a ++> [x].` to `a(a(x)) --> [x].`
terminal_body_expansion([L|Rest0], [L|Rest]) -->
{ is_list(L) },
!,
list(L), % We found the terminal symbol.
terminal_body_expansion(Rest0, Rest).
terminal_body_expansion([{X}|Rest0], [{X}|Rest]) -->
!,
terminal_body_expansion(Rest0, Rest).
terminal_body_expansion([F|_], _) -->
{
functor(F, _, _),
!,
fail
}.
terminal_body_expansion([], []) --> [].
is_list([]).
is_list([_|Xs]) :- is_list(Xs).
list([]) --> [].
list([X|Xs]) --> [X], list(Xs).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment