% vim:ft=prolog

dic(":").
dic("=").
dic(">").
dic("<").
dic("(").
dic(")").
dic("/").
dic("*").
dic("+").
dic("-").
dic(";").
dic(" ").
dic("%").
dic("!").
dic("\n").
dic("\t").
dic(":").

dicPR("IF").
dicPR("THEN").
dicPR("ELSE").
dicPR("WHILE").
dicPR("DO").
dicPR("WRITE").
dicPR("READ").

op_comp(Falha, Final) -->
	"<",
	{
		juntar("\tjnc ", Falha, Interm1),
		juntar(["\tadd R1, R0, #1", "\tsubb R0, R1, Acc"], [Interm1], Final)
	}.
op_comp(Falha, Final) -->
	"<=", %Acc <= R0
	{
		juntar("\tjnc ", Falha, Interm1),
		juntar(["\tmov R1, R0", "\tsubb R0, R1, Acc"], [Interm1], Final)
	}.
op_comp(Falha, Final) -->
	">", %Acc > R0
	{
		juntar("\tjnc ", Falha, Interm1),
		juntar(["\tadd R1, R0, #1", "\tsubb R0, Acc, R1"], [Interm1], Final)
	}.
op_comp(Falha, Final) -->
	">=", %Acc >= R0
	{
		juntar("\tjnc ", Falha, Interm1),
		juntar(["\tmov R1, Acc", "\tsubb Acc, R1, R0"], [Interm1], Final)
	}.
op_comp(Falha, [Final]) -->
	"=", 
	{
		juntar("\tcjne Acc, R0, ", Falha, Final)
	}.
op_comp(Falha, Final) -->
	"<>" ,
	{
		juntar(["\tmov R1, Acc"], ["\tsub Acc, R1, R0"], Interm1), 
		juntar("\tjz ", Falha, Interm2), 
		juntar(Interm1, [Interm2], Final)
	}.

op2(["\tpop R0", "\tmov R1, Acc", "\tmul Acc, R0, R1"]) -->
	"*".
op2(["\tpop R0", "\tmov R1, Acc", "\tdiv Acc, R0, R1"]) -->
	"/".

op1(["\tpop R0", "\tmov R1, Acc", "\tadd Acc, R0, R1"]) -->
	"+".
op1(["\tpop R0", "\tmov R1, Acc", "\tsub Acc, R0, R1"]) -->
	"-".


compilar(FxEntrada, FxSaida):-
	open(FxEntrada,read,StreamEntrada),
        get0(StreamEntrada,Char),
        leFicheiro(Char,Chars,StreamEntrada),
	compilarC(Exp, ExpE, Erro, Chars, []), !,
	(Erro == 0, escreveFx(FxSaida, Exp);
	escreveFx(FxSaida, ExpE)),
	close(StreamEntrada).
 
% Codigo dos Caracteres:
%	Return 10
%	Espaco 32
%	TAB 9
%	EOF -1


leFicheiro(-1, [], _) :- !.  % Fim do Ficheiro
leFicheiro(end_of_file, [], _) :- !.
leFicheiro(Char, [Char|Chars], StreamEntrada) :-
        get0(StreamEntrada, Prox),
        leFicheiro(Prox, Chars, StreamEntrada).


compilarC(Exp, ExpE, Erro) -->
	declaracoes(Exp, ExpE, 1, _, 0, Erro, 0, _).

declaracoes(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF) -->
	parteString(X1, Y2, ";"),
	{
		
		(
			parentesis(X1,Z1), Z1==0
			; 
			parentesis(Y2,Z2), Z2==0
		),
		nome(_, NlsI, X, _, NlsF, 0, X1, []),
		nome(_, NlsI2, Y, _, NlsF2, 0, Y2, []),
		X\=[], Y\=[],
		LinhaIT1 is LinhaI + NlsI,
		declaracao(Decl, ExpE1, LinhaIT1, LinhaFT1, ErroI, ErroF1, LabelIdI, LabelIdFT, X, []),
		LinhaIT2 is LinhaFT1 + NlsF + NlsI2,
		declaracoes(Decls, ExpE2, LinhaIT2, LinhaFT2, ErroF1, ErroF, LabelIdFT, LabelIdF, Y, []), 
		LinhaF is LinhaFT2 + NlsF2, 
		(
			ErroF = 0, juntar(Decl, Decls, Exp), ExpE = []
			; 
			juntar(ExpE1, ExpE2, ExpE), Exp = []
		)
	}.
declaracoes(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF) -->
	nome(_, NlsI, X, _, NlsF, 0), 
	{
		LinhaIT is LinhaI + NlsI,
		declaracao(Exp, ExpE, LinhaIT, LinhaFT, ErroI, ErroF, LabelIdI, LabelIdF, X, []),
		LinhaF is LinhaFT + NlsF
	}.

declaracao(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdI) -->
	nome(fim, _, NlsF, X, 1),
	":=", 
	nome(ini, _, NlsI, Y, 0),
	{
		NlsF=0, NlsI=0,
		verifica(X), verificaNaoPR(X),  
		X\=[], Y\=[], 
		expressao(Z1, ExpE, LinhaI, LinhaF, ErroI, ErroF, Y, []), 
		(
			ErroF = 0, 
			juntar("\tmov ", X, EXP1), 
			juntar(EXP1, ", Acc", EXP2), 
			juntar(Z1, [EXP2], Exp)
			;
			Exp = []
		)
	}.

declaracao(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF) -->
	"IF", nome(ini, EspI, NlsI, X, 0), 
	{
		LabelIdIT is LabelIdI + 1,
		EspI + NlsI > 0,
		LinhaIT is LinhaI + NlsI,
		if1(Exp, ExpE, LinhaIT, LinhaF, ErroI, ErroF, LabelIdIT, LabelIdF, X,[])
	}.
if1(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF) -->
	nome(fim, EspF, NlsF, X, 1),
	{
		EspF + NlsF > 0
	}, 
	"THEN", 
	nome(ini, EspI, NlsI, Y, 0),
	{
		cadeiaValida(X, []),
		
		EspI + NlsI > 0,
		juntar("If", "Certo", IfTrueT),
		number_codes(LabelIdI, LabelIdIa),
		juntar(IfTrueT, LabelIdIa, IfTrue),
		juntar("label ", IfTrue, LblTrue),
		LinhaIT is LinhaI,
		if_teste(Teste, ExpE1, LinhaIT, LinhaFT1, ErroI, ErroF1, LabelIdI, LabelIdFT, X, []), 
		LinhaIT2 is LinhaFT1 + NlsI + NlsF,
		if2(Exp2, ExpE2, LinhaIT2, LinhaF, ErroF1, ErroF, LabelIdFT, LabelIdF, Y, []), 
		(
			ErroF = 0,
			juntar(Teste, Exp2, Exp3),
			juntar(Exp3, [LblTrue], Exp),
			ExpE = []
			; 
			juntar(ExpE1, ExpE2, ExpE), Exp = []
		)
	}.
if1(_, ExpE, LinhaI, LinhaF, _, 1, LabelIdI, LabelIdI) -->
	contaLinhas(X, Nls),
	{
		trataErros(X, Nls, "Erro: If sem Then!", ExpE, LinhaI, LinhaF)
	}.

if_teste(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdI) -->
	{
		juntar("If", "Falha", IfFalseT),
		number_codes(LabelIdI, LabelIdIa),
		juntar(IfFalseT, LabelIdIa, IfFalse)
	},
	teste(IfFalse, Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF).

if2(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF) -->
	nome(fim, EspF, NlsF, X, 1),
	{
		EspF + NlsF > 0
	},
	"ELSE", 
	nome(ini, EspI, NlsI, Y, 0),
	{
		cadeiaValida(X, []),
		NlsI + EspI > 0,
		juntar("If", "Falha", IfFalseT),
		number_codes(LabelIdI, LabelIdIa),
		juntar(IfFalseT, LabelIdIa, IfFalse),
		juntar("label ", IfFalse, LblFalse),
		juntar("If", "Certo", IfTrueT),
		juntar(IfTrueT, LabelIdIa, IfTrue),
		LinhaIT is LinhaI,
		if_then(Exp1, ExpE1, LinhaIT, LinhaFT1, ErroI, ErroF1, LabelIdI, LabelIdFT, X, []), 
		LinhaIT2 is LinhaFT1 + NlsI + NlsF,
		if_else(Exp2, ExpE2, LinhaIT2, LinhaF, ErroF1, ErroF, LabelIdFT, LabelIdF, Y, []), 
		(
			ErroF = 0, 
			juntar("\tjump ", IfTrue, ExpI), 
			juntar(Exp1, [ExpI, LblFalse], Interm), 
			juntar(Interm, Exp2, Exp), ExpE = []
			; 
			juntar(ExpE1, ExpE2, ExpE), Exp = []
		)
	}.
if2(_, ExpE, LinhaI, LinhaF, _, 1, LabelIdI, LabelIdI) -->
	contaLinhas(X, Nls),
	{
		trataErros(X, Nls, "Erro: If sem Else!", ExpE, LinhaI, LinhaF)
	}.

if_then(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF) -->
	declaracao(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF).

if_else(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF) -->
	declaracao(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF).

declaracao(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF) -->
	"WHILE", nome(ini, EspI, NlsI, X, 0), 
	{
		LabelIdIT is LabelIdI + 1,
		EspI + NlsI > 0,
		LinhaIT is LinhaI + NlsI,
		while1(Exp, ExpE, LinhaIT, LinhaF, ErroI, ErroF, LabelIdIT, LabelIdF, X, [])
	}.
while1(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF) -->
	nome(fim, EspF, NlsF, X, 1), 
	{
		EspF + NlsF > 0
	}, 
	"DO", 
	nome(ini, EspI, NlsI, Y, 0),  
	{
		cadeiaValida(X, []),
		EspI + NlsI > 0,
		juntar("While", "Certo", WhileTrueT),
		number_codes(LabelIdI, LabelIdIa),
		juntar(WhileTrueT, LabelIdIa, WhileTrue),
		juntar("label ", WhileTrue, LblTrue),
		juntar("While", "Falha", WhileFalseT),
		juntar(WhileFalseT, LabelIdIa, WhileFalse),
		juntar("label ", WhileFalse, LblFalse),
		juntar("\tjump ", WhileFalse, Exp1),
		LinhaIT1 is LinhaI,
		while_teste(Teste, ExpE1, LinhaIT1, LinhaFT1, ErroI, ErroF1, LabelIdI, LabelIdFT, X, []), 
		LinhaIT2 is LinhaFT1 + NlsI + NlsF,
		while2(Decl, ExpE2, LinhaIT2, LinhaF, ErroF1, ErroF, LabelIdFT, LabelIdF, Y, []),
		(
			ErroF = 0,
			juntar([LblFalse], Teste, Interm1),
			juntar(Interm1, Decl, Interm2),
			juntar(Interm2, [Exp1, LblTrue], Exp), ExpE = []
			; 
			juntar(ExpE1, ExpE2, ExpE), Exp = []
		)
	}.
while1(_, ExpE, LinhaI, LinhaF, _, 1, LabelIdI, LabelIdI) -->
	contaLinhas(X, Nls),
	{
		trataErros(X, Nls, "Erro: While sem Do!", ExpE, LinhaI, LinhaF)
	}.

while_teste(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdI) -->
	{
		juntar("While", "Certo", WhileTrueT),
		number_codes(LabelIdI, LabelIdIa),
		juntar(WhileTrueT, LabelIdIa, WhileTrue)
	}, 
	teste(WhileTrue, Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF).

while2(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF) -->
	declaracao(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF).

declaracao([Exp], _, LinhaI, LinhaI, ErroI, ErroI, LabelIdI, LabelIdI) -->
	"READ", nome(ini, EspI, _, X, 0),
	{
		EspI>0,
		X\=[],
		verifica(X),
		not(inteiro(_, X, [])),
		juntar("\tread ", X, Exp)
	}.
declaracao([Exp], _, LinhaI, LinhaI, ErroI, ErroI, LabelIdI, LabelIdI) -->
	"WRITE", nome(ini, EspI, _, X, 0),
	{
		EspI>0,
		X\=[],
		verifica(X),
		not(inteiro(_, X, [])),
		juntar("\twrite ", X, Exp)
	}.
declaracao(Decls, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF) -->

	parente(Decls, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF).

parente(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF) -->
 
	"(", nome(ini, _, NlsI, X, 0), 
	{
		LinhaIT is LinhaI + NlsI,
		parent(Exp, ExpE, LinhaIT, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF, X, [])
	}.

parent(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, LabelIdI, LabelIdF) -->
	nome(fim, _, NlsI, X, 1), ")", 
	{
		parentesis(X,0), 
		declaracoes(Exp, ExpE, LinhaI, LinhaFT, ErroI, ErroF, LabelIdI, LabelIdF, X, []),
		LinhaF is LinhaFT + NlsI
	}.
parent(_, ExpE, LinhaI, LinhaF, _, 1, LabelIdI, LabelIdI) -->
	contaLinhas(X, Nls),
	{
		trataErros(X, Nls, "Erro nos parentesis!", ExpE, LinhaI, LinhaF)
	}.
	
declaracao(_, ExpE, LinhaI, LinhaF, _, 1, LabelIdI, LabelIdI) -->
	contaLinhas(X, Nls),
	{
		trataErros(X, Nls, "Erro!", ExpE, LinhaI, LinhaF)
	}.

teste(Cab, Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF) -->
	nome(fim, _, NlsF, X, 1), op_comp(Cab, Z3), nome(ini, _, NlsI, Y, 0), 
	{	
		X\=[], Y\=[], 
		
		LinhaIT is LinhaI + NlsF,
		expressao(Z1, ExpE1, LinhaIT, LinhaFT1, ErroI, ErroF1, X, []),
		LinhaIT2 is LinhaFT1 + NlsI, 
		expressao(Z2, ExpE2, LinhaIT2, LinhaF, ErroF1, ErroF, Y, []), 
		(
			ErroF = 0, 
			juntar(Z1, ["\tpush Acc"], Z4),
			juntar(Z4, Z2, Z5),
			juntar(Z5, ["\tmov R0, Acc", "\tpop Acc"], Z6),
			juntar(Z6, Z3, Exp), ExpE = []
			;
			Exp= [],
			juntar(ExpE1, ExpE2, ExpE)
		)
	}.

teste(_, _, ExpE, LinhaI, LinhaF, _, 1) -->
	contaLinhas(X, Nls),
	{
		trataErros(X, Nls, "Erro na expressao de teste!", ExpE, LinhaI, LinhaF)
	}.

expressao(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF) -->
	nome(fim, _, NlsF, X, 1), op2(Z), nome(ini, _, NlsI, Y, 0),
	{
		X\=[], Y\=[], 
		LinhaIT is LinhaI + NlsF,
		expressao(A, ExpE1, LinhaIT, LinhaFT1, ErroI, ErroF1, X, []), 
		LinhaIT2 is LinhaFT1 + NlsI, 
		expressao1(B, ExpE2, LinhaIT2, LinhaF, ErroF1, ErroF, Y, []),
		(
			ErroF=0, 
			juntar(A, ["\tpush Acc"], A1),
			juntar(A1, B, B1),
			juntar(B1, Z, Exp), ExpE = []
			;
			juntar(ExpE1, ExpE2, ExpE),
			Exp=[]
		)
	}.
expressao(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF) -->
	nome(X), 
	{
		!, 
		X\=[], 
		expressao1(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, X, [])
	}.

expressao1(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF) -->
	nome(fim, _, NlsF, X, 1), op1(Z), nome(ini, _, NlsI, Y, 0),% nome(Y), 
	{
		X\=[], Y\=[],
		LinhaIT is LinhaI + NlsF,
		expressao1(A, ExpE1, LinhaIT, LinhaFT1, ErroI, ErroF1, X ,[]), 
		LinhaIT2 is LinhaFT1 + NlsI, 
		expressao0(B, ExpE2, LinhaIT2, LinhaF, ErroF1, ErroF, Y, []),
		(
			ErroF = 0, 
			juntar(A, ["\tpush Acc"], A1),
			juntar(A1, B, B1),
			juntar(B1, Z, Exp), ExpE = []
			; 
			juntar(ExpE1, ExpE2, ExpE), Exp=[]
		)
	}.
expressao1(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF) -->
	nome(X), 
	{
		!, X\=[], 
		expressao0(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF, X, [])
	}.

expressao0(Exp, ExpE, LinhaI, LinhaF, ErroI, ErroF) -->
	"(", nome(ini, _, NlsI, Y, 0),
	{
		LinhaIT is LinhaI + NlsI,
		parente2(Exp, ExpE, LinhaIT, LinhaF, ErroI, ErroF, Y, [])
	}.

parente2([Exp], ExpE, LinhaI, LinhaF, ErroI, ErroF) -->
	nome(fim, _, NlsF, X, 1), ")",
	{
		X\=[], 
		parentesis(X, Z), Z==0,
		(
			LinhaF is LinhaI + NlsF,
			inteiro(XT, X, []),
			juntar("\tmov Acc, #", XT, Exp),
			ErroF is ErroI,
			ExpE = []
		);
		(
			expressao(Exp, ExpE, LinhaI, LinhaFT, ErroI, ErroF, X ,[]),
			LinhaF is LinhaFT + NlsF
		)
	}.
parente2(_, ExpE, LinhaI, LinhaF, _, 1) -->
	contaLinhas(X, Nls),
	{
		trataErros(X, Nls, "Erro nos parentesis!", ExpE, LinhaI, LinhaF)
	}.
	

expressao0([Exp], _, LinhaI, LinhaI, ErroI, ErroI) -->
	nome(X), 
	{
		verifica(X), verificaNaoPR(X), X\=[],
		not(inteiro(_, X, [])),
		juntar("\tmov Acc, ", X, Exp)
	}.

nome([X|Y]) -->
	[X], nome(Y).
nome([]) -->
	[].

inteiro([X|Y]) -->
	[X], inteiro(Y),  {X>="0",X=<"9"}.
inteiro([]) -->
	[].

verifica([]).
verifica([X|Y]):-
	not(dic([X])), verifica(Y).

verifica([], _).
verifica([X|Y], Car):-
	X\=Car, verifica(Y).

imprime([]).
imprime([X|Xs]):-
	atom_chars(XF,X),
	write(XF), nl,
	imprime(Xs).

juntar([], L, L). 
juntar([H|T], L, [H|NT]):- 
	juntar(T, L, NT).

espacos(Ret) --> " ", espacos(X), {Ret is X + 1}.
espacos(Ret) --> "", {Ret is 0}.
	
nls(Ret) --> "\n", nls(X), {Ret is X + 1}.
nls(Ret) --> " ", nls(Ret).
nls(Ret) --> "", {Ret is 0}.

nls(Ret, Ret2) --> "\n", nls(X, Ret2), {Ret is X + 1}.
nls(Ret, Ret2) --> " ", nls(Ret, Y), {Ret2 is Y + 1}.
nls(Ret, Ret2) --> "\t", nls(Ret, Y), {Ret2 is Y + 1}.
nls(0, 0) --> "".

espNlsTabs(Sum, Sum) -->
	nls(Sum, 0).

espNlsTabs(Sum, 0) -->
	nls(0, Sum).
espNlsTabs(Sum, X) -->
	nls(X, Y), {Sum is X + Y}.

esp(X, Y) -->
	espNlsTabs(X, Y).

not(X):- 
	X, !, fail.
not(_).


parentesis([40|Y], Z):- !,
	parentesis(Y, Z1),
	Z1=<0,
	Z is Z1 + 1.
parentesis([41|Y], Z):- !, 
	parentesis(Y, Z1),
	Z1=<0,
	Z is Z1 - 1.
parentesis([_|Y], Z1):- !,
	parentesis(Y, Z1).
parentesis([], 0).

%Le uma das partes da cadeia, eliminando e contando as ocorrencias d espacos, \n e \t no inicio e no fim
nome(0,0,[],0,0,_) --> [].
nome(EspI, NlsI, Letras, EspF, NlsF, A) -->
	delt(A, F, Esp, Nl, _), {F=0},
	nome(EspIT, NlsIT, Letras, EspFT, NlsFT, F),
	{
		EspI is EspIT + Esp,
		NlsI is NlsIT + Nl,
		EspF is EspFT,
		NlsF is NlsFT
	}.

nome(EspI, NlsI, Letras, EspF, NlsF, A) -->
	delt(A, F, Esp, Nl, _), {F=2},
	nome(EspIT, NlsIT, Letras, EspFT, NlsFT, F),
	{
		EspI is EspIT,
		NlsI is NlsIT,
		EspF is EspFT + Esp,
		NlsF is NlsFT + Nl
	}.

nome(EspI, NlsI, [LetrasI|LetrasF], EspF, NlsF, A) -->
	delt(A, F, _, _, LetrasI), {F=1},
	nome(EspIT, NlsIT, LetrasF, EspFT, NlsFT, F),
	{
		EspI is EspIT,
		NlsI is NlsIT,
		EspF is EspFT,
		NlsF is NlsFT
	}.

%Le uma das partes da cadeia, eliminando e contando as ocorrencias d espacos, \n e \t no inicio
nome(ini,0,0,[],_) --> [].
nome(ini,EspI, NlsI, Letras, 0) -->
	delt(0, F, Esp, Nl, _), {F=0}, {!},
	nome(ini,EspIT, NlsIT, Letras, F),
	{
		EspI is EspIT + Esp,
		NlsI is NlsIT + Nl
	}.

nome(ini,EspI, NlsI, [LetrasI|LetrasF], _) -->
	{!},
	[LetrasI],
	%delt(A, F, Esp, Nl, LetrasI), {F=1},
	nome(ini,EspIT, NlsIT, LetrasF, 1),
	{
		EspI is EspIT,
		NlsI is NlsIT
	}.

%Le uma das partes da cadeia, eliminando e contando as ocorrencias d espacos, \n e \t no fim
nome(fim, 0,0,[],_) --> [].
nome(fim, EspF, NlsF, Letras, A) -->
	delt(A, F, Esp, Nl, _), {F=2},
	nome(fim, EspFT, NlsFT, Letras, F),
	{
		EspF is EspFT + Esp,
		NlsF is NlsFT + Nl
	}.

nome(fim, EspF, NlsF, [LetrasI|LetrasF], A) -->
	delt(A, F, _, _, LetrasI), {F=1},
	nome(fim, EspFT, NlsFT, LetrasF, F),
	{
		EspF is EspFT,
		NlsF is NlsFT
	}.

delt(0, 0, 1, 0, _) --> " ".
delt(0, 0, 1, 0, _) --> "\t".
delt(0, 0, 0, 1, _) --> "\n".
delt(0, 1, _, _, X) --> [X], {[X]\=" ", [X]\="\t", [X]\="\n"}.
delt(1, 2, 1, 0, _) --> " ".
delt(1, 2, 1, 0, _) --> "\t".
delt(1, 2, 0, 1, _) --> "\n".
delt(1, 1, _, _, X) --> [X].
delt(2, 2, 1, 0, _) --> " ".
delt(2, 2, 1, 0, _) --> "\t".
delt(2, 2, 0, 1, _) --> "\n".


contaLinhas([X|Y], LF) -->
	[X], contaLinhas(Y, LI), {([X]=="\n", LF is LI + 1); LF is LI}.
contaLinhas([], 0) -->
	[].


escreveFx(NomeFx, Lista):-
	tell(NomeFx),
	escreveLinhas(Lista),
	told.

escreveLinhas([]).
escreveLinhas([LinhaI|LinhaS]):-
	escreveCaract(LinhaI),
	put("\n"),
	escreveLinhas(LinhaS).

escreveCaract([]).
escreveCaract([CaractI|CaractS]):-
	put(CaractI),
	escreveCaract(CaractS).

trataErros(Cadeia, Nls, ExpreErro, [ExpE], LinhaI, LinhaF):-
	number_codes(LinhaI, LinhaIa),
	(
		Nls > 0,
		LinhaF is LinhaI + Nls,
		number_codes(LinhaF, LinhaFa),
		juntar(ExpreErro, "\n\tLinhas ", Interm1),
		juntar(Interm1, LinhaIa, Interm2),
		juntar(" a ", LinhaFa, Interm3),
		juntar(Interm2, Interm3, ExpEt)
		;
		LinhaF is LinhaI,
		juntar(ExpreErro, "\n\tLinha ", Interm1),
		juntar(Interm1, LinhaIa, ExpEt)
	),
	juntar("\n\tCodigo: ", Cadeia, Interm),
	juntar(ExpEt, Interm, ExpE).

cadeiaValida --> cadeiaValida(X, P), {X==1, P==0}.
cadeiaValida(Ret, P) --> "IF", cadeiaValida(X, P), {Ret is X // 4, !}.
cadeiaValida(Ret, P) --> "THEN", cadeiaValida(X, P), {Ret is X * 2, !}.
cadeiaValida(Ret, P) --> "ELSE", cadeiaValida(X, P), {Ret is X * 2, !}.
cadeiaValida(Ret, P) --> "WHILE", cadeiaValida(X, P), {Ret is X // 3, !}.
cadeiaValida(Ret, P) --> "DO", cadeiaValida(X, P), {Ret is X * 3, !}.
cadeiaValida(Ret, P) --> "(", cadeiaValida(X, P1), {Ret is X // 5, P is P1 + 1,  !}.
cadeiaValida(Ret, P) --> ")", cadeiaValida(X, P1), {Ret is X * 5, P is P1 - 1, !}.
cadeiaValida(Ret, P) --> [_], cadeiaValida(Ret, P), {!}.
cadeiaValida(Ret, 0) --> "", {Ret is 1, !}.

cadeiaValida2 --> cadeiaValida2(X), {X==1}.
cadeiaValida2(Ret) --> "IF", cadeiaValida2(X), {Ret is X // 4, !}.
cadeiaValida2(Ret) --> "THEN", cadeiaValida2(X), {Ret is X * 2, !}.
cadeiaValida2(Ret) --> "ELSE", cadeiaValida2(X), {Ret is X * 2, !}.
cadeiaValida2(Ret) --> "WHILE", cadeiaValida2(X), {Ret is X // 3, !}.
cadeiaValida2(Ret) --> "DO", cadeiaValida2(X), {Ret is X * 3, !}.
cadeiaValida2(Ret) --> [_], cadeiaValida2(Ret), {!}.
cadeiaValida2(Ret) --> "", {Ret is 1, !}.

separador -->
	separador(_, _).
separador(X, Y) -->
	nome(_, _, X, _, _, 0),
	";",
	nome(_, _, Y, _, _, 0),
	{cadeiaValida(Xv, X, []), Xv=1, cadeiaValida(Yv, Y, []), Yv=1}.

parteString([], X, Z) -->
	Z, nome(X).
parteString([K|Ys], X, Z) -->
	[K], parteString(Ys, X, Z).

verificaNaoPR(X):- not(dicPR(X)).

