% tsg.pl

:- use_module(library(lists)).

%:- [compilateur_tsg].
%:- [writeclauseS].

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


sigma_tsg(tsg(_Axiome,NonTerminaux,Grammaire),Stream) :-
	set_output(Stream),
	format("%:- [gestion_dynamique].~n",[]),
%	format("phrase_tsg(Phrase,~a) :- ~n",[Axiome]),
%	format("~t~a(0,Phrase,0,_,[],[]).~n~n",[Axiome]),
	assert(nonterminaux(NonTerminaux)),
	psi(Grammaire,[],Code),
	retract(nonterminaux(NonTerminaux)),
	writepaquetS(Code).

% compilateur_tsg.pl

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

sigma_L_mg(Mg, G_N1_Np, SigmaIn, SigmaOut, DeltaIn, DeltaOut, C, Tete,Dico) :-
	sigma_N(Mg),
	renomme(G_N1_Np, New_G_N1_Np,[],Dico),
	Tete =.. [Mg,C,New_G_N1_Np,SigmaIn,SigmaOut,DeltaIn,DeltaOut].

sigma_L_md(T,SigmaIn,SigmaOut,DeltaIn,DeltaOut,C,Corps,Dico) :-
	sigma_L_md(T,true,SigmaIn,SigmaOut,DeltaIn,DeltaOut,C,Corps,Dico,[]).

sigma_L_md(NonTerminal,Corps, SigmaIn,SigmaOut, DeltaIn, DeltaOut,C, (Corps,But),DicoIn,DicoOut) :-
	sigma_N(NonTerminal),
	sigma_V(NewVar,DicoIn,DicoOut),
	But =.. [NonTerminal,C,NewVar,SigmaIn,SigmaOut, DeltaIn, DeltaOut].
sigma_L_md(Atome, Corps,Sigma,Sigma, Delta, Delta,_, Corps, Dico,Dico) :-
	atom(Atome).
sigma_L_md(Terme, Corps, SigmaIn,SigmaOut, DeltaIn, DeltaOut, C, NCorps, DicoIn,DicoOut) :-
	compound(Terme),
	Terme =.. [_|Args],
	sigma_L_md_rec(Args, Corps, SigmaIn,SigmaOut, DeltaIn, DeltaOut, C, NCorps, DicoIn,DicoOut).

sigma_L_md_rec([], Corps, Sigma,Sigma, Delta, Delta, _C, Corps,Dico,Dico).
sigma_L_md_rec([Terme | Args], Corps, SigmaIn,SigmaOut, DeltaIn, DeltaOut, C, NCorps, DicoIn,DicoOut) :-
	sigma_L_md(Terme, Corps, SigmaIn,SigmaInter, DeltaIn, DeltaInter, C, ICorps, DicoIn,DicoInter),
	sigma_L_md_rec(Args, ICorps, SigmaInter,SigmaOut, DeltaInter, DeltaOut, C, NCorps, DicoInter,DicoOut).

sigma_L((Mg -> Md),(Tete :- Corps)) :-
	sigma_L_mg(Mg,Md,SigmaIn,SigmaOut, DeltaIn, DeltaOut,C,Tete,Dico),
	sigma_L_md(Md,SigmaIn,SigmaOut, DeltaIn, DeltaOut,C,Corps,Dico).

sigma_S_theta((Mg -> Md),(Tete :- Corps),C,NC) :-
	sigma_L_mg(Mg,Md,SigmaIn,SigmaOut, DeltaIn, DeltaOut,C,Tete,Dico),
	sigma_L_md(Md,SigmaIn,SigmaOut, DeltaIn, DeltaOut,NC,Corps,Dico).

sigma_S((Mg -> Md),CodeDyn,(Tete :- (NC is SigmaIn + 1, Corps)),C,NC) :-
	sigma_L_mg(Mg,Md,SigmaIn,SigmaOut, DeltaIn, DeltaOut,C,Tete,Dico),
	append(CodeDyn,DeltaIn,DeltaInter),
	sigma_L_md(Md, NC,SigmaOut,DeltaInter,DeltaOut,NC,Corps,Dico).

sigma_S_dyn((Mg->_),(Dynamique :- dynamique(Mg, C, T, SigmaIn,SigmaOut, DeltaIn, [], DeltaOut))) :-
	sigma_N(Mg),
	Dynamique =.. [Mg,C,T,SigmaIn,SigmaOut, DeltaIn, DeltaOut].

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).

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).

% 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).

% 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).

% writesclauseS.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).

% 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_dynamique.pl


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Gestion des regles lineaires et de la synchronisation

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

