MINI INTERPRETE 001

From Movaxes

(Difference between revisions)
(Version 0.001)
(Version 0.001)
Line 3: Line 3:
Este es el código de la version 0.001 de mi interprete (el nombre del lenguaje está pendiente).
Este es el código de la version 0.001 de mi interprete (el nombre del lenguaje está pendiente).
-
""mini.c:""
+
''mini.c:''
<pre>
<pre>
/*
/*

Revision as of 21:08, 9 March 2007

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

Ejemplos de programas validos

Personal tools