MINI INTERPRETE 001F
From Movaxes
Line 1: | Line 1: | ||
=Version 0.001f= | =Version 0.001f= | ||
+ | |||
+ | ==NOTA== | ||
+ | |||
+ | Estoy creando la versión 0.002 que utiliza pilas en lugar de la recursividad tan difícil de entender de esta versión (al menos a simple vista), el código se reduce mucho y es más fácil de entender, solo debes ver la sección de la wiki de estructuras de datos (pilas). Estará listo en unos días. | ||
+ | |||
+ | ==Implementación== | ||
Este es el código de la version 0.001f de el interprete, la única diferencia con la [http://www.editthis.info/movaxes/MINI_INTERPRETE_001 version 0.001] es que esta no es interactiva sino que acepta como argumento un nombre de archivo con el código. | Este es el código de la version 0.001f de el interprete, la única diferencia con la [http://www.editthis.info/movaxes/MINI_INTERPRETE_001 version 0.001] es que esta no es interactiva sino que acepta como argumento un nombre de archivo con el código. | ||
Aún así pongo el código completo del interprete (solo cambian unas cuatro líneas de código comparado con la versión interactiva). Para más información ver la [http://www.editthis.info/movaxes/MINI_INTERPRETE_001 version 0.001]. | Aún así pongo el código completo del interprete (solo cambian unas cuatro líneas de código comparado con la versión interactiva). Para más información ver la [http://www.editthis.info/movaxes/MINI_INTERPRETE_001 version 0.001]. | ||
+ | |||
+ | ===Código Fuente=== | ||
'''minif.c''' | '''minif.c''' |
Current revision as of 22:58, 13 March 2007
Contents |
Version 0.001f
NOTA
Estoy creando la versión 0.002 que utiliza pilas en lugar de la recursividad tan difícil de entender de esta versión (al menos a simple vista), el código se reduce mucho y es más fácil de entender, solo debes ver la sección de la wiki de estructuras de datos (pilas). Estará listo en unos días.
Implementación
Este es el código de la version 0.001f de el interprete, la única diferencia con la version 0.001 es que esta no es interactiva sino que acepta como argumento un nombre de archivo con el código.
Aún así pongo el código completo del interprete (solo cambian unas cuatro líneas de código comparado con la versión interactiva). Para más información ver la version 0.001.
Código Fuente
minif.c
/* * MINI INTERPRETE v0.001 * POR: movaxes 2007 * Licencia: GPL */ #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #ifdef linux #define cls() system("clear") #else #define cls() system("cls") #endif #define COMM '$' //comentario #define PARI '(' //parentesis izquierdo #define PARD ')' //parentesis derecho #define ASIG '=' //operador de asignacion+ #define DIV '/' //operador de division #define MUL '*' //operador de multiplicacion #define RES '-' //operador de resta #define SUM '+' //operador de suma #define OUT '!' //output #define IN '?' //input #define SNL '_' //salto de linea en cadena #define FINP '.' //indica el final del programa #define FINBUF '@' //indica el final de la expresion #define ESP ' ' //espacio #define PROMPT "> "//prompt #define TAB '\\t' //tab #define NL '\ ' //newline FILE *archivo; //puntero al archivo struct variables { int A, B, C, D, E; } vars; char buffer[100]; char fin = 0; char permiso = 0; int total = 0; int temp_var; int posicion; void error(char *str); //muestra un error char comparar(char c, char x);//compara dos caracteres void obtener(void); //obtiene la expresion actual void mostrar(void); //muestra la expresion obtenida char es_var(char c); //vamos a asignar? char es_out(char c); //vamos a imprimir en pantalla? char es_in(char c); //vamos a pedir ingreso desde el teclado? char es_comentario(char c); //es un comentario? char es_salto(char c); //es salto de linea en cadena? char es_cadena(char c); //es una cadena? char es_parentesis(char pos); //es parentesis? char mas_menos(char c); //es +,-? char por_entre(char c); //es /,*? void revisar(void); //revisamos que la expresion sea correcta void ejecutar(int pos); //ejecutamos int obtener_var(char c); //regresa el valor de una variable void poner_var(char c, int n);//pone el valor de una variable int multi_divi(int pos); //es multiplicacion o division int subexpresion(int pos); //subexpresion int expresion(int pos); //expresion char asignar(char c, int pos);//asignamos el valor de la expresion a la variable int out_cadena(int inicio, char final);//pone cadena en pantalla void output(int pos); //output en pantalla void input(int pos); //pedimos al usuario el ingreso de un valor (input) int main (int argc, char** argv) { cls(); archivo = fopen(argv[1], "r"); if(!archivo) { error("no se encontro el archivo!!"); return 0; } if(!buffer) { error("no se pudo crear buffer..."); return 0; } //printf("MINI INTERPRETE v0.001\ "); while(!fin) { //printf(PROMPT); obtener(); if(!fin) { //mostrar(); //Si se quiere ver la expresion (para depurar) revisar(); if(permiso) ejecutar(0); } } fclose(archivo); return 0; } void error(char *str) { printf("\\aERROR: %s\ ",str); } char es_var(char c) { switch(c) { case 'A': case 'B': case 'C': case 'D': case 'E': return 1; default : return 0; } } char comparar(char c, char x) { return(c==x); } char es_out(char c){ return(c==OUT); } char es_in(char c){ return(c==IN); } char es_comentario(char c){ return(c==COMM); } char es_cadena(char c){ return(c=='\''||c=='\\"'); } char es_salto(char c){ return(c==SNL); } char es_parentesis(char c){ return(c=='('); } char mas_menos(char c){ return(c=='+' || c=='-'); } char por_entre(char c){ return(c=='*' || c=='/'); } void obtener(void) //Obtenemos una expresion del usuario { char c; int i = 0; char comentario = 0; while((c=fgetc(archivo))!=NL) //Mientras no lleguemos al final de la linea { if(c==FINP && !comentario) //Si encontramos un FINP y no es un comentario { fin = 1; //el programa termina return; } else if(c!=ESP && c!=TAB && c!=FINBUF) //Copiamos todo menos espacios, tab y el signo de FINBUF @ { if(es_cadena(c)) //Si es una cadena la copiamos literalmente { char comilla = c; do { buffer[i] = c; c = fgetc(archivo); i++; } while(!comparar(comilla,c)); //Revisamos si la cadena termino buffer[i] = c; i++; } else if(es_comentario(c)) //Si es un comentario lo copiamos, seria mejor si no (pendiente) { comentario = 1; buffer[i] = c; i++; } else //cualquier otro caracter lo copiamos { buffer[i] = c; i++; } } } total = i; //el total de caracteres del buffer buffer[i]=FINBUF; //indicamos en el arreglo el fin de la expresion } void mostrar(void) //Muestra el buffer { int i = 0; printf(": "); if(buffer[0]!=COMM) //Si no es un comentario { while(buffer[i]!=FINBUF) { printf("%c",buffer[i]); i++; } printf(" (%i)\ ",total); } else printf("comentario\ "); //Si es un comentario } void revisar(void) //Revisa que la expresion sea valida { int i = 0; char temp = buffer[i]; while(temp!=FINBUF) //Mientras no lleguemos al final de la expresion { if(temp==COMM) //Si es un comentario { permiso = 0; //no lo ejecutamos return; } else if(temp==IN) //Si es un input { ++i; temp = buffer[i]; if(es_var(temp)) //Revisamos que despues de IN este el nombre de una variable { permiso = 1; return; } else { permiso = 0; error("se esperaba una variable"); return; } } else if(es_cadena(temp)) //Revisamos si es una cadena { char comilla = temp; do { ++i; temp = buffer[i]; } while(!comparar(comilla,temp)); //Revisamos si la cadena termino } else if(!strchr("ABCDE0123456789+-*/()_=?!=&",temp)) //Vemos si es un caracter valido { permiso = 0; error("token no reconocida"); return; } i++; temp = buffer[i]; } permiso = 1; } void ejecutar(int pos) //Ejecuta la expresion { char c = buffer[pos]; if(es_var(c)) asignar(c,pos+1); //asignacion else if(es_out(c)) output(pos+1); //output else if(es_in(c)) input(pos+1); //input else if(es_comentario(c)); //comentario } int obtener_var(char c) { switch(c) { case 'A': return vars.A; case 'B': return vars.B; case 'C': return vars.C; case 'D': return vars.D; case 'E': return vars.E; } return 0; } void poner_var(char c, int n) { switch(c) { case 'A': vars.A = n; break; case 'B': vars.B = n; break; case 'C': vars.C = n; break; case 'D': vars.D = n; break; case 'E': vars.E = n; break; } } int subexpresion(int pos) { int num = 0; int i = pos; char actual = buffer[i]; if(actual==PARI) //Estamos entre parentesis? { num = expresion(i+1); //Calculamos toda la expresion entre parentesis i = posicion; actual = buffer[i]; if(actual!=PARD) //Si no encontramos el cierre de parentesis { if(actual!=FINBUF) { error("se esperaba \')\'"); posicion = i; return temp_var; } error("se esperaba \')\'"); posicion = i; return temp_var; } else //Encontramos el cierre de parentesis { i++; posicion = i; return num; } } else if(es_var(actual)) //Es una variable? { num = obtener_var(actual); i++; posicion = i; return num; } else if(isdigit(actual)) //Es un numero? { char c = actual; while(isdigit(c)) { i++; num = 10*num+c-'0'; c = buffer[i]; } posicion = i; return num; } else if(actual==FINBUF) //Llegamos al final del buffer? { error("expresion invalida"); } posicion = i; return temp_var; } int multi_divi(int pos) //Calcula multiplicaciones y divisiones { int num = subexpresion(pos); int i = posicion; char actual = buffer[i]; if(actual!=FINBUF) while(por_entre(actual)) //Mientras encontremos multiplicacion o division { switch(actual) { case MUL: num*=subexpresion(i+1); break; //Multiplicar case DIV: num/=subexpresion(i+1); break; //Dividir } i = posicion; actual = buffer[i]; } return num; } int expresion(int pos) //Calcula el valor de una expresion { int num = 0; int i = pos; char actual = buffer[i]; char continuar = 0; if(isdigit(actual)) //es un numeto? { while(isdigit(actual)) //Mientras encontremos digitos { i++; num = 10*num+actual-'0'; actual = buffer[i]; } continuar = 1; } else if(es_var(actual)) //Es variable { i++; num = obtener_var(actual); actual = buffer[i]; continuar = 1; } else if(actual==PARI) //Es un parentesis? { actual = buffer[i-1]; if(strchr("+-*/=",actual)) num = subexpresion(i); //Obtener subexpresion else { error("expresion incorrecta, se esperaba: +-*/="); return temp_var; } i = posicion; actual = buffer[i]; continuar = 1; } if(continuar) //Podemos continuar? { if(actual==FINBUF) return num; while(mas_menos(actual) || por_entre(actual) || es_parentesis(actual)) //Operar { switch(actual) { case SUM: num+=multi_divi(i+1); break; case RES: num-=multi_divi(i+1); break; case MUL: num*=multi_divi(i+1); break; case DIV: num/=multi_divi(i+1); break; } i = posicion; actual = buffer[i]; } posicion = i; return num; } return num; } char asignar(char c,int pos) { if(buffer[pos]==ASIG) //Si es asignacion { switch(c) { case 'A': temp_var = vars.A; vars.A = expresion(pos+1); break; case 'B': temp_var = vars.B; vars.B = expresion(pos+1); break; case 'C': temp_var = vars.C; vars.C = expresion(pos+1); break; case 'D': temp_var = vars.D; vars.D = expresion(pos+1); break; case 'E': temp_var = vars.E; vars.E = expresion(pos+1); break; } return 1; } else error("se esperaba \'=\' para asignacion"); return 0; } int out_cadena(int inicio, char comilla) //Pone una cadena en pantalla { int i = inicio+1; int j = 1; char c; do { c = buffer[i]; if(c!=comilla && c!=NL) printf("%c",c); //Mientras no encontremos la comilla y no sea \ j++; i++; } while(c!=comilla && c!=FINBUF); if(es_cadena(c)) return j; //La cadena es valida else return 0; //Cadena invalida } void output(int pos) //Pone en pantalla { char c; int i = pos; while(i<=(total-1)) { c = buffer[i]; if(c!=FINBUF) //Mientras no termine el buffer { if(es_var(c)) //Es variable { printf("%i",obtener_var(c)); //mostrarla i++; } else if(es_cadena(c)) //Es una cadena { int caracteres = out_cadena(i,c); if(caracteres==0) { printf("\ "); error("cadena invalida, posiblemente falto terminarla"); return; } i += caracteres; } else if(es_salto(c)) //si encuentra un SNL en la expresion { printf("\ "); i++; } else { error("expresion invalida en output"); return; } } else return; } printf("\ "); } void input(int pos) //Asigna un valor a una variable dependiendo del input del usuario { int num = 0; char c; char v = buffer[pos]; if(es_var(v)) //revisamos que es una variable { printf(":"); while(!isdigit(c=getchar()) && c!=NL); while(isdigit(c)) //obtenemos numero { num = 10*num+c-'0'; c = getchar(); } poner_var(v,num); //Ponemos el valor a la variable while(c!=NL) c = getchar(); //todo lo demas es ignorado } }
Compilar
Para compilarlo en GCC:
$gcc -Wall -O mini.c -o mini
Uso
Suponiendo que tenemos un archivo llamado hola_mundo.m con el código:
!"Hola Mundo!!!" !"Por favor ingrese su edad" ?A !"Su edad es: "A .
Para ejecutar nuestro código ponemos en un terminal:
$mini hola_mundo.m
Como resultado de ejecutar el programa sale en pantalla:
Hola Mundo!!! Por favor ingrese su edad :# Su edad es: #
El primer signo # que escribí indica el lugar en donde el usario ingresa un numero y el segundo es en donde se muestra el valor.