private void declaracion(TablaSimbolo tabla, ParseNode raiz, string ambito) { pila_ambito.Push(ambito);//nuevo string tipo_dato; tipo_dato = raiz.childNodes[0].ToString(); Nodo resultado = null; if (raiz.childNodes.Count > 2)//de la forma <tipodato><id><asignacion> { //asignacion es de la forma <condicion> solo tiene un hijo resultado = calculo(raiz.childNodes[2].izq()); //<declaracion>-><asignacion>-><condicion> if ("<error>".Equals(resultado.Tipo)) //si hay un error semantico en el calculo { resultado = null; //calculo ya se encarga de agregar el error } } //revisamos los ids para agregarlos ParseNode ids = raiz.childNodes[1]; Simbolo nuevo; foreach (ParseNode hijo in ids.childNodes) { nuevo = new Simbolo(tipo_dato, hijo.ToString(), ambito, hijo.Fila, hijo.Columna); //genero un nuevo simbolo addError(nuevo.asignar(resultado)); //si tuviese un error en la asignacion, lo agrega, si no hay no hace nada la funcion adderror if (!tabla.add(nuevo)) //si no se logra agregar(por eso el !) { addError(new ParseNode(nuevo.Fila, nuevo.Columna, "La variable:" + hijo.ToString() + " ya fue declarada", "<error>")); } } }
private void dibujarTS(string ambito, TablaSimbolo tabla) { //1.-Guardamos el dot Archivo.guardar(tabla.graficaTabla(ambito), ruta + "TS_" + ambito + ".dot");//obviamos que devuelve, asumimos que todo funciona //2.-Llamamos el comando para generar la imagen Archivo.generarGrafica(ruta, "TS_" + ambito + ".dot"); }
public void cambiarAmbito(TablaSimbolo general /*List<Error> errores*/) { foreach (Simbolo simbolo in general.simbolos) { simbolos.Add(simbolo); } }
private void inicializarListas() { lista_errores = new List <Error_>(); lista_metodos = new List <Metodo>(); pila_ambito = new Stack <string>(); tabla_global = new TablaSimbolo(); tabla_local = new TablaSimbolo(); pila_subambito = new Stack <string>();//nuevo }
private Nodo si(ParseNode raiz) { Nodo retorno = null; //los hijos de if son de la forma: Si <condicion> <sentencia> <else>, sentencia y else son opcionales if (raiz.childNodes.Count <= 2) { pila_subambito.Pop(); //nuevo return(null); //no hago nada, no tiene ni sentencia ni else } ParseNode si = null; ParseNode sino = null; foreach (ParseNode hijo_ in raiz.childNodes)//recupero las sentencias si,sino { if ("<SENTENCIAW>".Equals(hijo_.ToString())) { si = hijo_; } else if ("<ELSE>".Equals(hijo_.ToString())) { sino = hijo_; } } Nodo resultado = calculo(raiz.childNodes[1]);//calculo el valor de la condicion if ("<error>".Equals(resultado.Tipo)) { pila_subambito.Pop(); //nuevo return(null); //dejo de revisar el if } if (!"Bool".Equals(resultado.Tipo)) { pila_subambito.Pop();//nuevo addError(new Nodo(raiz.Fila, raiz.Columna, "La condicion del mientras no retorna un booleano", "<error>")); return(null); } TablaSimbolo aux = tabla_local; //se guarda la tabla actual tabla_local = new TablaSimbolo(); //pasamos a una tabla para if tabla_local.cambiarAmbito(aux); //pasamos los valores de aux a local if (MyMath.toBool(resultado.ToString())) { retorno = ejecutar(si);//si es null no hace nada } else { //los hijos de <else> tienen la forma: sino <sentencia> if (sino != null) { retorno = ejecutar(sino.der()); } } tabla_local = aux; //recuperamos la tabla local pila_subambito.Pop(); //nuevo return(retorno); }
public Nodo asignarValor(string identificador, Nodo valor, TablaSimbolo global) { Simbolo aux = getSimbolo(identificador); //busca en esta tabla if (aux == null) //si el simbolo no esta en esta tabla { aux = global.getSimbolo(identificador); //busca en la tabla global } if (aux == null) { return(new Nodo(0, 0, "La variable:" + identificador + " no existe", "<error>")); } return(aux.asignar(valor));//se retorna null si todo salio bien }
public Nodo getValor(string identificador, TablaSimbolo global) //tomado como base el ejemplo { Simbolo aux = getSimbolo(identificador); //busca en esta tabla if (aux == null) //si el simbolo no esta en esta tabla { aux = global.getSimbolo(identificador); //busca en la tabla global } if (aux == null) //si aun asi no lo encuentra { return(null); //<error> la variable no existe } return(aux.Valor); //si el simbolo no tuviese un valor asignado, el se encarga de mandarme un ParseNode con mensaje de error }
private void asignar(TablaSimbolo tabla, ParseNode raiz, string ambito) { pila_ambito.Push(ambito);//nuevo //los hijos del nodo asignar son de la forma: id <asignacion> string id = raiz.izq().ToString(); //el nodo <asignacion> solo tiene al hijo <condicion> ParseNode asignacion = raiz.der(); Nodo resultado = calculo(asignacion.izq()); //reitero, calculo ya se encarga de guardar errores if ("<error>".Equals(resultado.Tipo)) //si es error no asigno nada { return; } addError(tabla.asignarValor(id, resultado, tabla_global));//si no hay error solo asigna el valor }
public void mas_menos(string identificador, TablaSimbolo global, bool mas) { Simbolo aux = getSimbolo(identificador); //busca en esta tabla if (aux == null) //si el simbolo no esta en esta tabla { aux = global.getSimbolo(identificador); //busca en la tabla global } if (aux == null) { return; } double valor = double.Parse(aux.Valor.ToString()); if (mas) { valor++; } else { valor--; } aux.asignar(new Nodo(0, 0, valor.ToString(), "Double")); }
private Nodo mientras_o_Hasta(ParseNode raiz, bool mientras = true) { Nodo retorno = null; //los hijos de while son de la forma: mientras <condicion> <sentencia>, sentencia es opcional if (raiz.childNodes.Count <= 2) //si no hay sentencia, el while podria ser infinito { pila_subambito.Pop(); //nuevo addError(new Nodo(raiz.Fila, raiz.Columna, "La funcion mientras no tiene forma de salir", "<error>")); return(null); } Nodo resultado = calculo(raiz.der()); if ("<error>".Equals(resultado.Tipo)) { pila_subambito.Pop(); //nuevo return(null); //dejo de revisar } if (!"Bool".Equals(resultado.Tipo)) { pila_subambito.Pop();//nuevo addError(new Nodo(raiz.Fila, raiz.Columna, "La condicion del mientras no retorna un booleano", "<error>")); return(null); } TablaSimbolo aux = tabla_local; //se guarda la tabla actual tabla_local = new TablaSimbolo(); //pasamos a una tabla para if tabla_local.cambiarAmbito(aux); //pasamos los valores de aux a local if (mientras) { while (MyMath.toBool(resultado.ToString())) { retorno = ejecutar(raiz.childNodes[2]); //Verificamos si no hay un continue/break/etc if (retorno != null) { if ("<DETENER>".Equals(retorno.Tipo)) { break;//detengo el while } if ("<CONTINUAR>".Equals(retorno.Tipo)) { retorno = null;//ya adentro se encarga de saltar el resto de sentencias asi que solo regreso retorno a ser null } if ("<RETORNO>".Equals(retorno.Tipo)) { break; } } resultado = calculo(raiz.der()); } } else { while (!MyMath.toBool(resultado.ToString())) { retorno = ejecutar(raiz.childNodes[2]); resultado = calculo(raiz.der()); } } tabla_local = aux;//recuperamos la tabla local if (retorno != null && "<DETENER>".Equals(retorno.Tipo)) { retorno = null; //limpio el detener, si no se podria propagar a otras cosas } pila_subambito.Pop(); //nuevo return(retorno); }
private Nodo para(ParseNode raiz, string ambito) { if (raiz.childNodes.Count < 7) //no tiene sentencia { pila_subambito.Pop(); //nuevo return(null); } Nodo retorno = null; //los hijos de for son de la forma: para Double id E <condicion> <op> <sentenciaw>, sentencia es opcional string nombre = raiz.childNodes[2].ToString(); //el nombre de la variable para la condicion Simbolo i = new Simbolo("Double", nombre, ambito, raiz.childNodes[2].Fila, raiz.childNodes[2].Columna); //genero un nuevo simbolo Nodo valor_i = calculo(raiz.childNodes[3]); if ("<error>".Equals(valor_i.Tipo) || "String".Equals(valor_i.Tipo)) { pila_subambito.Pop(); //nuevo return(null); //si hay error dejo de revisar el for } i.asignar(valor_i); //no deberia haber problema con el type casting TablaSimbolo aux = tabla_local; //se guarda la tabla actual tabla_local = new TablaSimbolo(); //pasamos a una tabla para if tabla_local.cambiarAmbito(aux); //pasamos los valores de aux a local if (!tabla_local.add(i)) //si la variable de reconocimiento ya existe { pila_subambito.Pop(); //nuevo addError(new Nodo(i.Fila, i.Columna, "La variable:" + i.Identificador + " ya fue definida en este ambito", "<error>")); return(null); } Nodo resultado = calculo(raiz.childNodes[4]); //calculo la condicion if ("<error>".Equals(resultado.Tipo)) //verifico que la condicion si sea un booleano { pila_subambito.Pop(); //nuevo return(null); //dejo de revisar } if (!"Bool".Equals(resultado.Tipo)) { pila_subambito.Pop();//nuevo addError(new Nodo(raiz.Fila, raiz.Columna, "La condicion del mientras no retorna un booleano", "<error>")); return(null); } while (MyMath.toBool(resultado.ToString())) { retorno = ejecutar(raiz.childNodes[6]); if (retorno != null) { if ("<DETENER>".Equals(retorno.Tipo)) { break;//detengo el while } if ("<CONTINUAR>".Equals(retorno.Tipo)) { retorno = null;//ya adentro se encarga de saltar el resto de sentencias asi que solo regreso retorno a ser null } if ("<RETORNO>".Equals(retorno.Tipo)) { break; } } if ("+".Equals(raiz.childNodes[5].izq().ToString())) //++ { tabla_local.mas_menos(nombre, tabla_global, true); //funcion extra que hice para facilitar el ++/-- } else//-- { tabla_local.mas_menos(nombre, tabla_global, false); } resultado = calculo(raiz.childNodes[4]); //recalculamos la condicion } tabla_local = aux; //recuperamos la tabla local if (retorno != null && "<DETENER>".Equals(retorno.Tipo)) { retorno = null; } pila_subambito.Pop();//nuevo return(retorno); }
private Nodo llamada(ParseNode raiz) { //los hijos de llamada tienen la forma: nombre_funcion <VALORES> //1.-recuperamos el nombre del metodo string id_metodo = raiz.izq().ToString(); //2.-Verificamos si existe el metodo, en este punto todavia no vemos si el no. de parametros es correcto if (!existeMetodo(id_metodo)) { return(null); } //3.-Una vez que revisamos que existe el metodo revisamos si hay valores para recuperar el metodo Metodo funcion = null; Nodo retorno = null; if (raiz.der() == null)//no hay valores { funcion = getMetodo(id_metodo); //4.-Si no encontramos un metodo sin parametros, es error if (funcion == null) { addError(new Nodo(raiz.Fila, raiz.Columna, "El metodo:" + id_metodo + " no existe", "<error>")); return(new Nodo(raiz.Fila, raiz.Columna, "1", "Int"));//retornamos un entero por si acaso, para continuar con la ejecucion } //5.-Si no es null entonces ejecutamos el metodo sin parametros TablaSimbolo aux = tabla_local; //se guarda la tabla actual tabla_local = new TablaSimbolo(); //pasamos a una tabla para if tabla_local.cambiarAmbito(aux); //pasamos los valores de aux a local pila_ambito.Push(id_metodo); //agregamos el nuevo ambito retorno = ejecutar(funcion.Sentencia); //llamamos la raiz de las sentencias de funcion y las mandamos a ejecutar //6.-Solo aqui sabemos el tipo de la funcion y el tipo de retorno, asi que revisamos y lanzamos un error de ser necesario tabla_local = aux;//recuperamos la tabla local } else//si hay valores { //4.-calculamos los valores y los metemos en una lista List <Nodo> valores = new List <Nodo>(); Nodo resultado = null; foreach (ParseNode valor in raiz.der().childNodes) //llamada->valores { resultado = calculo(valor); //calculo agrega cualquier error, no retorna null en ningun caso valores.Add(resultado); } //5.-Teniendo los valores generamos el id extra string id_extra = ""; foreach (Nodo val in valores) { id_extra += val.Tipo; } //6.-Con el id extra buscamos otra vez a funcion pero con id_metodo+id_extra funcion = getMetodo(id_metodo + id_extra); //7.-Si no encontramos un metodo con esos parametros, es error, no se puede hacer typecasting para parametros, eso se haria con templates y no lo maneja nuestra gramatica if (funcion == null) { addError(new Nodo(raiz.Fila, raiz.Columna, "El metodo:" + id_metodo + "con parametros:" + id_extra + " no existe", "<error>")); pila_ambito.Pop(); //nuevo return(new Nodo(raiz.Fila, raiz.Columna, "1", "Int")); //retornamos un entero por si acaso, para continuar con la ejecucion } //8.-Si no es null ejecutamos el metodo, pero antes agregamos a su tabla, simbolos que corresponden a sus parametros //esta forma de agregar es distinda, pues si el metodo es recursivo y declara una variable, en lugar de intentar declararla otra vez, cambiamos su valor TablaSimbolo aux = tabla_local; //se guarda la tabla actual tabla_local = new TablaSimbolo(); //pasamos a una tabla para if tabla_local.cambiarAmbito(aux); //pasamos los valores de aux a local pila_ambito.Push(id_metodo); //agregamos el nuevo ambito //8.1.-Aqui agregamos los parametros como simbolo int limite = valores.Count; Simbolo actual = null; Nodo valor_actual = null; for (int i = 0; i < limite; i++) { actual = funcion.parametros[i]; valor_actual = valores[i]; actual.asignar(valor_actual); tabla_local.replace(actual);//esta es la funcion que agrega o reemplaza cuando es requerido } //9.-ejecutamos retorno = ejecutar(funcion.Sentencia); //llamamos la raiz de las sentencias de funcion y las mandamos a ejecutar tabla_local = aux; //recuperamos la tabla local } if ("<RETORNO>".Equals(retorno.Tipo)) { retorno.Tipo = retorno.Sub_tipo; } pila_ambito.Pop(); return(retorno); }