MINI INTERPRETE 001
From Movaxes
Contents |
Version 0.001
Este es el código de la version 0.001 de mi interprete (el nombre del lenguaje está pendiente).
mini.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 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 (void) { cls(); 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); } } 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=getchar())!=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 = getchar(); 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
Tutorial del uso del interprete
Asignacion
En esta versión del interprete se dispone de solo 5 variables para guardar datos numericos, las variables disponibles son A,B,C,D y E.
Para asignar una variable se escribe el nombre de la variable seguida por el caracter = que indica asignación.
Ejemplo:
A=200 ==Operaciones== Hasta ahora el interprete reconoce + (sumas) - (restas) * (multiplicaciones) / (divisiones). También pueden utilizarse los parentesis. Ejemplo: <pre> A=200+(2*2+(2+3))
Output en pantalla
Para mostrar datos en pantalla se utiliza el signo de admiración """!""" seguido por una cadena, una variable o el indicador de salto de linea ("""_""").
Ejemplo de cadena:
!"Hola Mundo"
Ejemplo de variable:
!"A es igual a "A
Esto pondrá en pantalla (suponiendo que A contiene el valor 100):
A es igual a 100
Ejemplo, muestra el contenido de todas las variables:
!A_B_C_D_E
Esto mostrará el valor de cada variable, el simbolo de salto de linea (newline) que se usa es: """_""".
Input del teclado
Para obtener datos del teclado se utiliza el caracter ? y el nombre de la variable a la que se le asignará el valor ingresado.
Ejemplo:
!"Ingrese un numero:" ?A
Pide el ingreso de un numero para asignar a la variable A.
Notas
Este es un interprete sencillo, aún falta que reciba un archivo de texto en la linea de comandos para ejecutarlo, faltan el condicional IF, y los loops FOR, WHILE...
Hasta la próxima!