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); }
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 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 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); }