package Portugol.Language.Criar;
import Portugol.Language.Analisador.Expressao;
import Portugol.Language.Analisador.Keyword;
import Portugol.Language.Analisador.ParteDeExpresion;
import Portugol.Language.Analisador.Simbolo;
import Portugol.Language.Analisador.Variavel;
import Portugol.Language.Utilitario.LanguageException;
import java.util.Vector;
public class ExpandPara {
public static String VERSION = "Versão:2.0 \t(c)Augusto Bilabila e David Silva Barrera";
//-------------------------------------------------------------------------------------
//------------ ----------------------------
//------------ I N S T R U C A O P A R A ----------------------------
//------------ ---------------------------
//-------------------------------------------------------------------------------------
/**
* expande o ciclo
*
* @param forNode nodo de inicio do ciclo
* @param level nivel
* @param memory vector de memoria
* @throws Portugol.Language.Utils.LanguageException erro
*/
public static void ExpandFOR(NodeInstruction forNode, int level, Vector memory) throws LanguageException {
String PARA = Keyword.GetTextKey(Keyword.PARA);
String DE = " " + Keyword.GetTextKey(Keyword.DE) + " ";
String ATE = " " + Keyword.GetTextKey(Keyword.ATE) + " ";
String PASSO = " " + Keyword.GetTextKey(Keyword.PASSO) + " ";
String exp = forNode.GetText().toUpperCase().trim();
//--------------------------------------------------------------------------------
// -------------------- extrair a variavel----------------------------------
//--------------------------------------------------------------------------------
int endVar = exp.indexOf(DE);
if (endVar < 0) {
throw new LanguageException(
forNode.GetCharNum(), forNode.GetText(),
"Ciclo PARA sem DE",
"Escreva PARA variavel <DE> inicio ATE fim PASSO p");
}
String variable = forNode.GetText().substring(PARA.length(), endVar).trim();
//extrair a variavel da memoria
ParteDeExpresion var = Variavel.getVariable(variable, memory);
if (var == null || !(var instanceof Simbolo)) {
throw new LanguageException(
forNode.GetCharNum(), forNode.GetText(),
"\"" + variable + "\" não esta definida",
"Defina a variavel numerica \"" + variable + "\" antes deste ciclo ");
}
if (((Simbolo) var).isConstant()) {
throw new LanguageException(
forNode.GetCharNum(), forNode.GetText(),
"\"" + variable + "\" é uma constante ",
"Altere o tipo de \"" + variable + "\" de constante para variavel ");
}
if (!((Simbolo) var).isNumber()) {
throw new LanguageException(
forNode.GetCharNum(), forNode.GetText(),
"\"" + variable + "\" não é numérica",
"Altere o tipo de \"" + variable + "\" para real ou inteiro ");
}
//--------------------------------------------------------------------------------
// -------------------- extrair o valor de inicializacao --------------------------
//--------------------------------------------------------------------------------
int endValue = exp.indexOf(ATE);
if (endValue < 0) {
throw new LanguageException(
forNode.GetCharNum(), forNode.GetText(),
"Ciclo PARA sem ATE",
"Escreva PARA variável DE inicio <ATE> fim PASSO p");
}
String value = forNode.GetText().substring(endVar + DE.length(), endValue).trim();
//--------------------------------------------------------------------------------
// -------------------- extrair o Passo e LIMITE --------------------------
//--------------------------------------------------------------------------------
int begPasso = exp.indexOf(PASSO);
String limite;
String passo = new String("1");
//se nao houver passo leio apenas o limite
if (begPasso == -1) {
limite = forNode.GetText().substring(endValue + ATE.length()).trim();
} // ler limite e passo
else {
limite = forNode.GetText().substring(endValue + ATE.length(), begPasso).trim();
passo = forNode.GetText().substring(begPasso + PASSO.length()).trim();
}
//--------------------------------------------------------------------------------
//--------------------------- VERIFICAR se sao expressoes numericas ---------------
//--------------------------------------------------------------------------------
int type = Expressao.TypeExpression(value, memory);
if (type != Simbolo.INTEIRO && type != Simbolo.REAL) {
throw new LanguageException(
forNode.GetCharNum(), forNode.GetText(),
"\"" + value + "\" não é uma expressão numérica",
"Verifique se a expressão está bem escrita");
}
type = Expressao.TypeExpression(passo, memory);
if (type != Simbolo.INTEIRO && type != Simbolo.REAL) {
throw new LanguageException(
forNode.GetCharNum(), forNode.GetText(),
"\"" + passo + "\" nao é uma expressão numérica",
"Verifique se a expressão está bem escrita");
}
type = Expressao.TypeExpression(limite, memory);
if (type != Simbolo.INTEIRO && type != Simbolo.REAL) {
throw new LanguageException(
forNode.GetCharNum(), forNode.GetText(),
"\"" + limite + "\" não é uma expressão numérica",
"Verifique se a expressão está bem escrita");
}
forNode.SetText(variable + " " + Keyword.ATRIBUI + " " + value);
forNode.SetType(Keyword.CALCULAR);
forNode.SetLevel(level);
//--------------------------------------------------------------------------------
//------------------ fazer o no da actualizaçao da variavel ----------------------
//--------------------------------------------------------------------------------
NodeInstruction passNode = new NodeInstruction(passo, forNode.GetCharNum(), level);
passNode.SetType(Keyword.PASSO);
passNode.SetLevel(level);
//--------------------------------------------------------------------------------
//------------------ fazer o no da condicao ----------------------
//--------------------------------------------------------------------------------
NodeInstruction condic = new NodeInstruction(variable + " <= " + limite, forNode.GetCharNum(), level);
condic.SetType(Keyword.ENQUANTO);
condic.SetLevel(level);
//--------------------------------------------------------------------------------
//------------------ fazer as ligaçoes ----------------------
//--------------------------------------------------------------------------------
NodeInstruction tmp = forNode.GetNext();
//---------------- ligar o init e a condic -------------
forNode.SetNext(passNode);
passNode.SetNext(condic);
//-------- ligar a condic e o bloco ------
condic.SetIfTrue(tmp);
while (tmp != null && tmp.GetType() != Keyword.FIMPARA
&& tmp.GetNext() != null && tmp.GetNext().GetType() != Keyword.FIMPARA) {
tmp.SetLevel(level + 1);
tmp = tmp.GetNext();
}
NodeInstruction endFor = tmp.GetType() == Keyword.FIMPARA ? tmp : tmp.GetNext();
//------- no antes do proximo ------
if (tmp.GetType() != Keyword.FIMPARA) {
tmp.SetLevel(level + 1);
//-------- fazer o no de actualizaçao da var a var -------
NodeInstruction actualize = new NodeInstruction(variable + " " + Keyword.ATRIBUI + " " + variable + " + " + passo, forNode.GetCharNum(), level + 1);
actualize.SetLevel(level + 1);
actualize.SetType(Keyword.CALCULAR);
//---------fim do for-------------------
// ligar actualize a condic
actualize.SetNext(condic);
//--------------- ligar o corpo do ciclo a actualize -------
//no caso de ser um enquanto o terminar ligar o falso
if (tmp.GetIfFalse() != null && tmp.GetIfFalse().GetType() == Keyword.FIMPARA) {
tmp.SetIfFalse(actualize);
}
//no caso de ser um Repeat o terminar ligar o verdadeiro
if (tmp.GetIfTrue() != null && tmp.GetIfTrue().GetType() == Keyword.FIMPARA) {
tmp.SetIfTrue(actualize);
}
// ligar o next do tmp
tmp.SetNext(actualize);
}
//ligar o true de condic
condic.SetIfFalse(endFor);
//modificar o endFor para JOIN
endFor.SetType(Keyword.CONECTOR);
//nivel do endfor
endFor.SetLevel(level);
//instrução seguinte ao ciclo
condic.SetNext(endFor);
//-------------------------
}
}