
/*
  Compile EBNF rules (==>) to BNF rules (=>).
   - i.e. expanding out *, +, ?, 'or' 

stephen.cresswell@tso.co.uk
*/


ebnf_to_bnf:-
	retractall(_'=>'_),
	remember(change),
	rewrite_until_stable.

rewrite_until_stable:-
	change,
	!,
	retractall(change),
	rewrite_any,
	rewrite_until_stable.
rewrite_until_stable.

rewrite_any:-
	LHS==>RHS0,
	rewrite(RHS0,RHS1),
	remember(LHS=>RHS1),
	fail.
rewrite_any.


*(A) ===> A_star :-
	atom(A),
	format(atom(A_star),"*~w",[A]),
	remember(A_star=>[]),
	remember(A_star=>[A,A_star]).

+(A) ===> A_plus :-
	atom(A),
	format(atom(A_plus),"+~w",[A]),
	remember(A_plus==>[A,*(A)]). % Assert as EBNF - requires further wrangling

?(A) ===> A_qm :-
	atom(A),
	format(atom(A_qm),"?~w",[A]),
	remember(A_qm=>[]),
	remember(A_qm=>[A]).

A \ B '===>' A_or_B :-
	format(atom(A_or_B),"(~w or ~w)",[A,B]),
	remember(A_or_B=>[A]),
	remember(A_or_B=>[B]).

List ===> ListAtom :-
	List = [_|_],
	format(atom(ListAtom),"~w",[List]),
	remember(ListAtom=>List).

OrExpr ===> ListAtom :-
	OrExpr =.. [or|Args],
	format(atom(ListAtom),"or(~w)",[Args]),
	map_disjuncts(Args,ListAtom).

map_disjuncts([],_).
map_disjuncts([D|Ds],Head):-
	remember(Head=>[D]),
	map_disjuncts(Ds,Head).

% Apply rewrite rules starting from inside outwards
rewrite([],[]).
rewrite([T0|Ts0],[T2|Ts1]):-
	\+(T0 = [_|_]),
	T0 =.. [F|Args0],
	!,
	rewrite(Args0,Args1),
	T1 =.. [F|Args1],
	rewrite_if_poss(T1,T2),
	rewrite(Ts0,Ts1).
rewrite([T0|Ts0],[T2|Ts1]):-
	% A raw list (that is a sequence rather than an argument list)
	T0 = [_|_],
	rewrite(T0,T1),
	rewrite_if_poss(T1,T2),
	rewrite(Ts0,Ts1).

rewrite_if_poss(T0,T1):-
	T0 ===> T1,
        !.
rewrite_if_poss(T,T).

remember(X):-
	call(X),
	!.
remember(X):-
	%write(X),nl,
	assertz(change),
	assertz(X).

% Do avoid duplication, but don't assert change
remember1(X):-
	call(X),
	!.
remember1(X):-
	%write(X),nl,
	assertz(X).
