%---------------------------------------------------------
% Interprete de C++ mediante Prolog.
%
% Autor: 
%---------------------------------------------------------

% El programa en primer lugar traduce el programa en C++
% a terminos Prolog. Posteriormente interpreta los terminos
% Prolog. Estos terminos podrian servir igualmente para 
% compilar.

% Libreria de compatibilidad con el ISO-Prolog.
% De esta forma los strings son listas de codigos ASCII.
:-lib(iso).	% Solo para Eclipse

% Predicado para almacenar los valores de las variables
:-dynamic valor/2.

%------------------------------------------------------
% Traductor de C++ a terminos Prolog
%------------------------------------------------------








% Conversor de expresiones para numeros de una unica cifra

expr(X+Y)-->term(X),s0,"+",s0,expr(Y).
expr(X-Y)-->term(X),s0,"-",s0,expr(Y).
expr(Z)-->term(Z).

term(Y*Z)-->num(Y),s0,"*",s0,term(Z).
term(Y/Z)-->num(Y),s0,"/",s0,term(Z).
term(X)-->num(X).

num(N)-->"+",num(N).
num(-X)-->"-",num(X).
num(N)-->[C],{ name(N,[C]), integer(N)}.
num(Id)--> ident(Id).

% Identificadores
% Solo se admiten identificadores de una letra minuscula
ident(Id)-->
	[C], {name(Id, [C]), Id @>= 'a', Id @=< 'z' }.

% Separadores
separa--> " " | [10] | [13] | "	".

% Separador obligado
s--> separa, s, !.
s--> [].

% Separador opcional
s0--> s, !.  
s0--> [].

%----------------------------------------------------
% Interprete de C++
%----------------------------------------------------

% interprete(+ Lista_de_instrucciones)
interprete([]).
interprete([I|P] ):-
%	write('Instruccion: '), write(I), nl,  % Para depurar
	ejecuta(I),
%	lista_var,	% Para depurar
	interprete(P).

% ejecuta(+ Instruccion)
ejecuta(asigna(Var, Exp) ):-
	asig(Var, Exp).

ejecuta(while(B,I) ):-
	ev_bol(B),
	!,
	interprete(I),
	interprete([while(B,I)] ).
ejecuta(while(_,_) ).

ejecuta(lee(Var) ):-
	read(Valor),
	asig(Var, Valor).

ejecuta(escribe(Exp) ):-
	evalua(Exp, Valor),
	write(Valor), nl.

asig(Var, Exp):-
	valor(Var,_),
	!,
	evalua(Exp, Valor),
	retract( valor(Var, _) ), !,
	assert( valor(Var, Valor) ).
asig(Var, Exp):-
	evalua(Exp, Valor),
	assert( valor(Var, Valor) ).

% Evaluador de expresiones aritmetica
% evalua(+Expresion, ? Resultado)
evalua(A+B, V):-
	evalua(A,V1),
	evalua(B,V2),
	V is V1+V2.
evalua(A-B, V):-
	evalua(A,V1),
	evalua(B,V2),
	V is V1-V2.
evalua(A*B, V):-
	evalua(A,V1),
	evalua(B,V2),
	V is V1*V2.
evalua(A/B, V):-
	evalua(A,V1),
	evalua(B,V2),
	V is V1/V2.
evalua(V,V):-
	number(V).
evalua(A,V):-
	atom(A),
	valor(A,V),
	!.

% Evaluador de expresiones booleanas
% ev_bol(+Expresion)
ev_bol(A<B):-
	evalua(A,V1),
	evalua(B,V2),
	V1<V2.
ev_bol(A=<B):-
	evalua(A,V1),
	evalua(B,V2),
	V1=<V2.
ev_bol(A>=B):-
	evalua(A,V1),
	evalua(B,V2),
	V1>=V2.
ev_bol(A>B):-
	evalua(A,V1),
	evalua(B,V2),
	V1>V2.
ev_bol(A==B):-
	evalua(A,V1),
	evalua(B,V2),
	V1==V2.
ev_bol(A\==B):-
	evalua(A,V1),
	evalua(B,V2),
	V1\==V2.

% Listado de las variables
lista_var:-
	valor(Var, Valor),
	write(Var), write(': '), write(Valor),nl,
	fail.
lista_var:-
	nl.

%--------------------------------------------------

% Predicado principal

main:-
	open('f.cpp',read,Fich),
	fich_lista(Fich,L1),
	close(Fich), !,
%	string_list(S,L1), write(S),nl,	% Muestra el fichero leido
	programa(P,L1,[]), write(P),nl,
	interprete(P).

%fich_lista(+Fich,-Lista_salida)
%Fich: sera el fichero que queremos leer
%Lista_salida: lista con los caracteres leidos del fichero

fich_lista(Fich,Lista):-
	get(Fich,Ch),
	(Ch==(-1),
	Lista=[]
	;
	Ch\==(-1),
	fich_lista(Fich,L),
	Lista=[Ch|L]
	).

