MINI INTERPRETE 001

From Movaxes

Revision as of 22:01, 9 March 2007 by Admin (Talk | contribs)

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 //variables disponibles
{
	int 	A,
		B,
		C,
		D,
		E;
} vars;

char buffer[100]; //buffer
char fin = 0; //terminamos el programa
char permiso = 0; //permiso para ejecutar el buffer?
int total = 0; //total de caracteres del buffer usados
int temp_var; //guarda el valor de la variable a la que se esta asignando un valor
int posicion; //la posicion en la que estamos en el buffer

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:

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.

Terminar el programa y salir del interprete

Para terminar el programa usamos el punto .

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!

Personal tools