private void add(ParseNode raiz, string ambito, string tipo_dato, Nodo resultado) { Simbolo nuevo; foreach (ParseNode hijo in raiz.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_global.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>")); } } }
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 }
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 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); }