MINI INTERPRETE 001F

From Movaxes

(Difference between revisions)
 
(One intermediate revision not shown)
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.  
Line 5: Line 11:
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].
-
"""minif.c"""
+
===Código Fuente===
 +
 
 +
'''minif.c'''
<pre>
<pre>
/*
/*
Line 540: Line 548:
=Uso=
=Uso=
-
Suponiendo que tenemos un archivo llamado """hola_mundo.m""" con el código:
+
Suponiendo que tenemos un archivo llamado '''hola_mundo.m''' con el código:
<pre>
<pre>
!"Hola Mundo!!!"
!"Hola Mundo!!!"

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.

Personal tools