% tsg_with_trace.pl
:- use_module(library(lists)).

%:- [compilateur_tsg_avec_trace].
%:- [writeclauseS].

phrase_tsg(Phrase,Axiome,Stream) :-
	set_output(Stream),
	But =.. [Axiome,0,Phrase,contexte(0,[]),contexte(_,[]),(Mot,Mot,[],_)],
	call(But).

sigma_tsg(tsg(Axiome,NonTerminaux,Grammaire),Stream) :-
	set_output(Stream),
	format("%:- [gestion_dynamique_avec_trace].~n",[]),
	format("%:- [outils_trace].~n",[]),
	assert(nonterminaux(NonTerminaux)),
%	sigma_N(Axiome),
%	format("phrase_tsg(Phrase,~a,Stream) :- ~n",[Axiome]),
%	format("set_output(Stream),~n",[]),
%	format("format(\"(~a,0)~~n\",[]),~n",[Axiome]),
%	format("~a(0,Phrase,contexte(0,[]),contexte(_,[]),(Mot,Mot,[],_)),~n",[Axiome]),
%	format("close(Stream).~n~n",[]),
	psi(Grammaire,[],Code),
	retract(nonterminaux(NonTerminaux)),
	writepaquetS(Code).


% compilateur_tsg_with_trace.pl

%:- [maps].
%:- [gestion_clauses].
%:- [sigma].
:- op(1200,xfx,'->').

% Construction du membre droit
sigma_L_md(T,E,S,(Mot,TraceCorps,DicoCibleE,DicoCibleS,Dico),C,Corps,DicoVar) :-
	sigma_L_md(T,true,E,S,(Mot,TraceCorps,DicoCibleE,DicoCibleS,Dico),C,Corps,DicoVar,[]).

sigma_L_md(NonTerminal,Corps, E, S, (Mot,VarTrace,DicoCibleE,DicoCibleS,[(VarTrace,(NonTerminal,C))]), C, (Corps,But),DicoVarE,DicoVarS) :-
	sigma_N(NonTerminal),
	sigma_V(NewVar,DicoVarE,DicoVarS),
	But =.. [NonTerminal,C,NewVar,E,S,(Mot,VarTrace,DicoCibleE,DicoCibleS)].
sigma_L_md(Atome, Corps,E,E,(_,Atome,DicoCible,DicoCible,[]),_, Corps,DicoVar,DicoVar) :-
	atom(Atome).
sigma_L_md(T, Corps, E, S,(Mot,TraceT,DicoCibleE,DicoCibleS,Dico), C, NCorps,DicoVarE,DicoVarS) :-
	compound(T),
	T =.. [Foncteur|Args],
	sigma_L_md_rec(Args, Corps, E, S,(Mot,TraceArgs,DicoCibleE,DicoCibleS,Dico), C, NCorps,DicoVarE,DicoVarS),
	TraceT=.. [Foncteur|TraceArgs].

sigma_L_md_rec([], Corps, E, E, (_Mot,[],DicoCible,DicoCible,[]), _C, Corps,DicoVar,DicoVar).
sigma_L_md_rec([T | Args], Corps, E, S, (Mot,[TraceT|TraceArgs],DicoCibleE,DicoCibleS,Dico), C, NCorps,DicoVarE,DicoVarS) :-
	sigma_L_md(T, Corps, E, I, (Mot,TraceT,DicoCibleE,DicoCibleI,DicoT), C, ICorps,DicoVarE,DicoVarI),
	sigma_L_md_rec(Args, ICorps, I, S, (Mot,TraceArgs,DicoCibleI,DicoCibleS,DicoArgs), C, NCorps,DicoVarI,DicoVarS),
	append(DicoT,DicoArgs,Dico).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Construction d'une regle LIBRE par construction d'une clause a partir du membre gauche en une tete de clause et du membre droit en un corps de clause.

% L'Indice de controle est transmis de la tete au corps.
sigma_L((Mg -> Md),(Tete :- imprime(NDicoCibleE,Mot),  Corps)) :-
	sigma_L_mg(Mg,Md,E,S,(Mot,TraceMd,DicoCibleE,DicoCibleS),C,Tete,DicoVar),
	sigma_L_md(Md,E,S,(Mot,TraceMd,NDicoCibleE,DicoCibleS,DicoMd),C,Corps,DicoVar),
	append(DicoMd,DicoCibleE,NDicoCibleE).

% Construction du membre gauche
sigma_L_mg(Mg, G_N1_Np, E, S, (Mot,TraceG_N1_Np,DicoCibleE,DicoCibleS), C, Tete,DicoVar) :-
	sigma_N(Mg),
	renomme(G_N1_Np, New_G_N1_Np,[],DicoVar),
	Tete =.. [Mg,C,New_G_N1_Np,E,S,(Mot,TraceG_N1_Np,DicoCibleE,DicoCibleS)].

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Construction d'une regle CONTEXTE par construction d'une clause a partir du membre gauche en une tete de clause et du membre droit en un corps de clause.

% L'Indice de controle, PARTAGE entre plusieurs clauses, est transmis de la tete au corps.
sigma_S_theta((Mg -> Md),(Tete :- imprime(NDicoCibleE,Mot),Corps),C,NC) :-
	sigma_L_mg(Mg,Md,E,S,(Mot,TraceMd,DicoCibleE,DicoCibleS),C,Tete,DicoVar),
	sigma_L_md(Md,E,S,(Mot,TraceMd,NDicoCibleE,DicoCibleS,DicoMd),NC,Corps,DicoVar),
	append(DicoMd,DicoCibleE,NDicoCibleE).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Construction d'une regle SYNCHRO par construction d'une PRE-clause a partir du membre gauche en une tete de clause et du membre droit en un corps de clause.

% L'Indice de controle, PARTAGE entre plusieurs clauses, mais N'est PAS transmis de la tete au corps.
% traduire_prep_synchro(++Regle,-Clause)
sigma_S((Mg -> Md),CodeDyn,(Tete :- NC is Sigma + 1, imprime(NDicoCibleE,Mot),Corps),C,NC) :-
	sigma_L_mg(Mg,Md,contexte(Sigma,E),S,(Mot,TraceMd,DicoCibleE,DicoCibleS),C,Tete,DicoVar),
	append(CodeDyn,E,NE),
	sigma_L_md(Md, contexte(NC,NE),S,(Mot,TraceMd,DicoCibleE,DicoCibleS,DicoMd),NC,Corps,DicoVar),
	append(DicoMd,DicoCibleE,NDicoCibleE).

sigma_S_dyn((Mg->_),(Dynamique :- dynamique(Mg, C, T, E, [], S,Trace))) :-
	sigma_N(Mg),
	Dynamique =.. [Mg,C,T,E,S,Trace].
	

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

psi([],PaquetS,PaquetS).
psi([Regle|RegleS],PaquetS,NPaquetS) :-
	Regle=(_->_),
	sigma_L(Regle,Clause),
	ajoute_une_clause_dans_paquets(Clause, PaquetS, IPaquetS),
	psi(RegleS,IPaquetS,NPaquetS).
psi([PaquetRegleS|RegleS],PaquetS,NPaquetS) :-
	PaquetRegleS=[_|_],
	sigma_P(PaquetRegleS,AppelS,ClauseS),
	ajoute_clauses_dyn_dans_paquets(AppelS,ClauseS,PaquetS,IPaquetS),
	psi(RegleS,IPaquetS,NPaquetS).


% Les clauses synchro partage le meme indice de controle
%sigma_P([],_,[],[],_,_).
%sigma_P([Regle|RegleS], CodeContextePrecedentS, [CodeContexte|CodeContexteSuivantS], [Clause|ClauseS],C,NC) :-
%	sigma_S_theta(Regle,CodeContexte,C,NC),
%	sigma_P(RegleS, [CodeContexte|CodeContextePrecedentS], CodeContexteSuivantS, ClauseS, C,NC),
%	append(CodeContextePrecedentS, CodeContexteSuivantS, CodeContexteS),
%	sigma_S(Regle,CodeContexteS,Clause,C,NC).

sigma_P(Regles,Appels,Clauses) :-
	map_n_dans_1(sigma_S,[C,NC],sigma_S_theta,[C,NC],Regles,Clauses),
	map(sigma_S_dyn,[],Regles,Appels).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


% maps.pl

map(_F,_Args_F,[],[]).
map(F,Args_F,[E|L],[F_E|F_L]) :-
	Call_F=..[F,E,F_E|Args_F],
	call(Call_F),
	map(F,Args_F,L,F_L).


%map_n_dans_1(f,[a ,...,a ],g,[b ,...b ],[e ]       ,
%                 1      n      1     p    i 1<=i<=n 
%             ([f(e ,[g(e ,b ,...,b )]          ,a ,...,a )]       ))
%                  i     j  1      p  1<=j<>i<=n  1      n  1<=i<=n
map_n_dans_1(F,Args_F,G,Args_G,L,R) :-
	map_n_dans_1(F,Args_F,G,Args_G,L,[],_,R).

map_n_dans_1(_F,_Args_F,_G,_Args_G,[],_,[],[]).
map_n_dans_1(F,Args_F,G,Args_G,[E|L],Av,[G_E|Ap],[F_E|MapL]) :-
	Call_G=..[G,E,G_E|Args_G],
	call(Call_G),
	map_n_dans_1(F,Args_F,G,Args_G,L,[G_E|Av],Ap, MapL),
	append(Av,Ap,Sauf_E),
	Call_F=..[F,E,Sauf_E,F_E|Args_F],
	call(Call_F).


% gestion_clauses.pl

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Ajout d'un ensemble de clauses dans le programme sans duplication.

ajoute_clauses_dyn_dans_paquets([],[],PaquetS,PaquetS).
ajoute_clauses_dyn_dans_paquets([Appel|AppelS],[Clause|ClauseS], PaquetS, NPaquetS) :-
	ajoute_une_clause_dans_paquets(Clause, PaquetS, IPaquetS),
	ajoute_une_clause_dyn_dans_paquets(Appel, IPaquetS, IIPaquetS),
	ajoute_clauses_dyn_dans_paquets(AppelS,ClauseS,IIPaquetS,NPaquetS).

ajoute_une_clause_dans_paquets(Clause,[],[paquet(SymbolePredicat,[],[Clause])]) :-
	Clause=(Tete :- _),
	functor(Tete, SymbolePredicat,_).
ajoute_une_clause_dans_paquets(Clause,[paquet(SymbolePredicat,Dynamique,ClauseS) | PaquetS], [paquet(SymbolePredicat,Dynamique,[Clause|ClauseS])|PaquetS]) :-
	Clause = (Tete :- _),
	functor(Tete, SymbolePredicat,_), !.
ajoute_une_clause_dans_paquets(Clause,[Paquet|PaquetS],[Paquet|NPaquetS]) :-
	ajoute_une_clause_dans_paquets(Clause,PaquetS,NPaquetS).

%ajoute_une_clause_dyn_dans_paquets(Clause,[],[paquet(SymbolePredicat,[Clause],[])]) :-
%	Clause=(Tete :- _),
%	functor(Tete, SymbolePredicat,_).
ajoute_une_clause_dyn_dans_paquets(Clause,[paquet(SymbolePredicat,_,ClauseS) | PaquetS], [paquet(SymbolePredicat,[Clause],ClauseS)|PaquetS]) :-
	Clause = (Tete :- _),
	functor(Tete, SymbolePredicat,_), !.
ajoute_une_clause_dyn_dans_paquets(Clause,[Paquet|PaquetS],[Paquet|NPaquetS]) :-
	ajoute_une_clause_dyn_dans_paquets(Clause,PaquetS,NPaquetS).


% sigma.pl


sigma_N(NonTerminal) :-
	atom(NonTerminal),
	nonterminaux(NonTerminaux),
	member(NonTerminal,NonTerminaux),!.

sigma_V(NewVar,[NewVar|Dico],Dico).

renomme(NonTerminal,NewVar, Dico, [NewVar|Dico]) :-
	sigma_N(NonTerminal).
renomme(Atome,Atome,Dico,Dico) :-
	atom(Atome).
renomme(Terme,NewTerme,DicoIn,DicoOut) :-
	compound(Terme),
	Terme =.. [Foncteur|Args],
	renomme_rec(Args,NewArgs,DicoIn,DicoOut),
	NewTerme=.. [Foncteur|NewArgs].

renomme_rec([],[],Dico,Dico).
renomme_rec([Arg|Args],[NewArg|NewArgs],DicoIn,DicoOut) :-
	renomme_rec(Args,NewArgs,DicoIn,DicoInter),
	renomme(Arg,NewArg,DicoInter,DicoOut).


% writeclauseS.pl


writeclauseS([]).
writeclauseS([Clause|ClauseS]) :-
	portray_clause(Clause),
	writeclauseS(ClauseS).

writepaquetS([]).
writepaquetS([paquet(_,Dynamique,ClauseS)|PaquetS]) :-
	(Dynamique=[Clause],!,portray_clause(Clause);true),
	writeclauseS(ClauseS),
	writepaquetS(PaquetS).

% gestion_dynamique_avec_trace.pl


dynamique(Foncteur,N,T, contexte(SigmaIn,[(But :- Corps)|Cj_plus_1_Cm]), C1_Cj_moins_1, contexte(SigmaOut,DeltaOut), Preuve) :-
	But =.. [Foncteur, N, T, contexte(SigmaIn,C1_Cm_sauf_Cj),contexte(SigmaOut, DeltaOut), Preuve],
	append(C1_Cj_moins_1,Cj_plus_1_Cm, C1_Cm_sauf_Cj),
	call(Corps).
dynamique(Foncteur, N,T,contexte(SigmaIn,[C_j|Cj_plus_1_Cm]), C1_Cj_moins_1, contexte(SigmaOut,DeltaOut), Preuve) :-
	dynamique(Foncteur,N,T,contexte(SigmaIn,Cj_plus_1_Cm),[C_j|C1_Cj_moins_1], contexte(SigmaOut,DeltaOut), Preuve).

% outils_trace.pl

unifie([]).
unifie([(V,T)|L]) :-
	var(V),
	V=T,
	unifie(L).
unifie([(V,_T)|L]) :-
	nonvar(V),
	unifie(L).

imprime(L,Mot) :-
	\+(\+((unifie(L),print(Mot),nl))).

