/**************************************************************** COMPILADOR DE LENGUAJE KAREL PARA LINUX Autor: Ing. CUAUHTEMOC RIVERA LOAIZA Rutinas de generacion del lenguaje ensamblador Karel elaboradas por el Ing. Rafael R. Ochoa rochoa@scfie.eie.umich.mx Universidad Michoacana de San Nicolas de Hidalgo Seccion de Graduados de la Facultad de Ingenieria Electrica Maestria en Sistemas Computacionales crivera@scfie.eie.umich.mx ****************************************************************** Proposito: Este programa permite la compilacion de programas hechos en el lenguaje Karel, dentro del ambiente de Linux. En caso de una compilacion sin errores, se produce a la salida un archivo con extension *.ok, el cual puede ser visualizado en la interfaz hecha en Tcl/Tk (se requiere contar con el inter- prete de este lenguaje). ****************************************************************** Uso del Programa: Se requiere de un compliador de C++. Para la com- pilacion del programa fuente se necesita hacer lo siguiente: g++ -o <karel> <karel.cpp> Por ejemplo, para correr el archivo 6.kar: /<path>/karel 6 Al correr el programa se pide al usuario que de el nombre del archivo karel, pero sin la extension exito se obtiene un archivo en lenguaje ensamblador de Karel (nombre_archivo.ok), el cual se visualiza en el interprete. En caso de errores en el programa *.kar se produce un mensaje de error. *****************************************************************/ #include <stdlib.h> #include <string.h> #include <stdio.h> #include <iostream.h> #include <fstream.h> char *token(int, char *); char *instr_primitivas (char *); char *pruebas_karel (char *); char *genera_etiqueta(void); char gen_etiq(void); class tabla_de_simbolos{ char *instr; tabla_de_simbolos *sig; public: void nueva_instruccion(char *); int existe_instruccion(char *); }; class ensamblador { int linea; char *comando; ensamblador *sig; public: void archivo_virtual(char *,int); friend void archivo_ensamblador (char *); friend void genera_nva_instr(); }; class entrada{ public: char *linea; int num; entrada *sig; void inserta_nodo (int , char *); void textLoadFile (char *); }; class instrucciones:public entrada{ void instruccion (); void genera_nva_instr(); void repite (); void fin_bloque(); void mientras (); void si (); friend void genera_nva_instr(); friend void programa(); }; class ambiente:public entrada{ void karel_inicio(); void forma_entorno(); void inicio_de_ambiente(); void instrucciones_de_ambiente (); void fin_de_ambiente(); friend void archivo_ensamblador (char *); }; class ejecucion:public entrada{ void inicia_programa(); void inicia_ejecucion(); void fin_ejecucion(); void fin_programa(); friend void archivo_ensamblador (char *); friend void programa(); }; entrada *start, *nodo; ensamblador *karel; tabla_de_simbolos *proxima_nva_instr; int etiqueta; /*********************************************************** Nombre de la funcion: textLoadFile Proposito: Apertura del archivo *.kar para Entrega: Nada Funciones externas: inserta_nodo ************************************************************/ void entrada::textLoadFile(char *fileName){ char ch, car[1], linea[80]; int numero_linea = 1; ifstream inicio(fileName); if(!inicio){ cout<<"Error de lectura!"; exit (0); } inicio.get(ch); while (ch != EOF){ linea[0] = '\0'; while (ch == ' ' || ch == '\t' ) inicio.get(ch); while (ch != '\n' && ch != EOF){ car[0] = ch; car[1] = '\0'; strcat(linea, car); inicio.get(ch); } if (strlen(linea) > 0) inserta_nodo(numero_linea, linea); numero_linea++; inicio.get(ch); } inicio.close(); } /*********************************************************** Nombre de la funcion: INSERTA_NODO Proposito: Formar la lista lineal con un nodo para cada renglon del programa inicial Entrega: Nada Funciones externas: Ninguna. ************************************************************/ void entrada::inserta_nodo (int num_linea, char linea[80]){ entrada *act = NULL, *ant = NULL, *nodo_nuevo = NULL; if (!(nodo_nuevo = new entrada)){ cout<<"\nError de asignacion"; exit(1); } nodo_nuevo->linea = strdup(linea); nodo_nuevo->num = num_linea; nodo_nuevo->sig = NULL; if(!start) start = nodo_nuevo; else { act = start; while (act) { ant = act; act = act->sig; } nodo_nuevo->linea = strdup(linea); nodo_nuevo->num = num_linea; nodo_nuevo->sig = NULL; ant->sig = nodo_nuevo; } } //////////////////////////////////////////////////////////////// // RUTINAS DE CREACION DE AMBIENTE // //////////////////////////////////////////////////////////////// /*********************************************************** Nombre de la funcion: FORMA_ENTORNO etiqueta "jc kini", que le indica al Entrega: Nada ************************************************************/ void ambiente::forma_entorno() { ensamblador haz; inicio_de_ambiente(); karel_inicio(); instrucciones_de_ambiente(); fin_de_ambiente(); haz.archivo_virtual("jc kini", nodo->num); } /*********************************************************** Nombre de la funcion: KAREL_INICIO Entrega: Nada Funciones externas: archivo_virtual, token ************************************************************/ void ambiente::karel_inicio(){ ensamblador haz; if (strncmp(nodo->linea, "KAREL_ESTA_EN_CALLE", 19) != 0 ){ exit(1); } haz.archivo_virtual("k", nodo->num); haz.archivo_virtual(token(2,nodo->linea), nodo->num); // calle haz.archivo_virtual(token(4,nodo->linea), nodo->num); // avenida haz.archivo_virtual(token(6,nodo->linea), nodo->num); // direccion haz.archivo_virtual(token(8,nodo->linea), nodo->num); // monedas nodo = nodo->sig; } /*********************************************************** Nombre de la funcion: INSTRUCCIONES DE AMBIENTE Entrega: Nada Funciones externas: archivo_virtual, token ************************************************************/ void ambiente::instrucciones_de_ambiente() { ensamblador haz; while (strncmp(nodo->linea, "FIN_DE_AMBIENTE", 15) != 0 ) { if (strncmp(nodo->linea, "PARED_JUNTO_A_CALLE", 19) == 0 ) { haz.archivo_virtual("pc", nodo->num); haz.archivo_virtual(token(2,nodo->linea), nodo->num); haz.archivo_virtual(token(4,nodo->linea), nodo->num); haz.archivo_virtual(token(6,nodo->linea), nodo->num); } if (strncmp(nodo->linea, "PARED_JUNTO_A_AVENIDA", 21) == 0 ){ haz.archivo_virtual("pa", nodo->num); haz.archivo_virtual(token(2,nodo->linea), nodo->num); haz.archivo_virtual(token(4,nodo->linea), nodo->num); haz.archivo_virtual(token(6,nodo->linea), nodo->num); } if (strncmp(nodo->linea, "HAY", 3) == 0 ){ haz.archivo_virtual("m", nodo->num); haz.archivo_virtual(token(2,nodo->linea), nodo->num); haz.archivo_virtual(token(4,nodo->linea), nodo->num); haz.archivo_virtual(token(6,nodo->linea), nodo->num); } nodo = nodo->sig; } if (strncmp(nodo->linea, "FIN_DE_AMBIENTE", 15) != 0 ){ cout<<"\nNo se encuentra el FIN_DE_AMBIENTE"; exit(1); } } /*********************************************************** Nombre de la funcion: INICIO_AMBIENTE AMBIENTE Entrega: Nada ************************************************************/ void ambiente::inicio_de_ambiente(){ if (strncmp(nodo->linea, "INICIO_DE_AMBIENTE", 18) != 0 ){ cout<<"No se encuentra INICIO_DE_AMBIENTE"; exit(1); } nodo = nodo->sig; } /*********************************************************** Nombre de la funcion: FIN_AMBIENTE AMBIENTE Entrega: Nada Funciones externas: Ninguna ************************************************************/ void ambiente::fin_de_ambiente(){ if (strncmp(nodo->linea, "FIN_DE_AMBIENTE", 15) != 0 ){ cout<<"No se encuentra FIN_DE_AMBIENTE"; exit(1); } nodo = nodo->sig; } /*********************************************************** Nombre de la funcion: TOKEN Funciones externas:Ninguna ************************************************************/ char *token(int localizacion, char *renglon){ char simbolo[1], palabra[80],*cadena = NULL, c=' ',*cad; int posicion=0; cadena = strdup(renglon); while(localizacion>1){ cadena= strchr(cadena,c); cadena = cadena++; localizacion--; } palabra[0] = '\0'; cad=strchr(cadena,c); posicion=cad-cadena; for (int i=0;i<posicion;i++){ if (cadena[i]!=';' && cadena[i]!=' '){ simbolo[0]=cadena[i]; simbolo[1]='\0'; strcat(palabra,simbolo);} } return palabra; } /*********************************************************** Nombre de la funcion: INSTR_PRIMITIVAS instruccion primitiva de karel Funciones externas: token ************************************************************/ char *instr_primitivas(char *cadena){ tabla_de_simbolos checa; if ((strlen(token(1,cadena)) == 19) && (strncmp(token(1,cadena), "gira_a_la_izquierda", 19) == 0 ) ) return "gi"; if ((strlen(token(1,cadena)) == 7) && (strncmp(token(1,cadena), "apagate",7) == 0 ) ) return "ap"; if ((strlen(token(1,cadena)) == 13) && (strncmp(token(1,cadena), "coloca_moneda",13) == 0 ) ) return "cm"; if ((strlen(token(1,cadena)) == 6) && (strncmp(token(1,cadena), "avanza", 6) == 0 ) ) return "av"; if ((strlen(token(1,cadena)) == 13) && (strncmp(token(1,cadena), "recoge_moneda", 13) == 0 ) ) return "rm"; if (checa.existe_instruccion(token(1, cadena))) return token(1, cadena); return "\0"; } /*********************************************************** Nombre de la funcion: PRUEBAS_KAREL prueba de karel prueba en ensamblador Karel Funciones externas:Ninguna ************************************************************/ char *pruebas_karel(char *cadena){ if (strncmp(cadena, "frente_despejado", 16) == 0 ) return "fd"; if (strncmp(cadena, "frente_bloqueado", 16) == 0 ) return "fn"; if (strncmp(cadena, "izquierda_despejada", 19) == 0 ) return "id"; if (strncmp(cadena, "izquierda_bloqueada", 19) == 0 ) return "ib"; if (strncmp(cadena, "derecha_despejada", 17) == 0 ) return "dd"; if (strncmp(cadena, "derecha_bloqueada", 17) == 0 ) return "db"; if (strncmp(cadena, "junto_a_moneda", 14) == 0 ) return "jm"; if (strncmp(cadena, "no_junto_a_moneda", 17) == 0 ) return "njm"; if (strncmp(cadena, "hacia_el_norte", 14) == 0 ) return "hn"; if (strncmp(cadena, "no_hacia_el_norte", 17) == 0 ) return "nhn"; if (strncmp(cadena, "hacia_el_sur", 12) == 0 ) return "hs"; if (strncmp(cadena, "no_hacia_el_sur", 15) == 0 ) return "nhs"; if (strncmp(cadena, "hacia_el_este", 13) == 0 ) return "he"; if (strncmp(cadena, "no_hacia_el_este", 16) == 0 ) return "nhe"; if (strncmp(cadena, "hacia_el_oeste", 14) == 0 ) return "ho"; if (strncmp(cadena, "no_hacia_el_oeste", 17) == 0 ) return "nho"; if (strncmp(cadena, "con_monedas_en_su_bolsa", 23) == 0 ) return "din"; if (strncmp(cadena, "sin_monedas_en_su_bolsa", 23) == 0 ) return "smb"; else { cout<<"\nInstruccion desconocida!"; exit(1); } return "\0"; } /*********************************************************** Nombre de la funcion: ARCHIVO_VIRTUAL Entrega: Nada. coloca todo el programa en ensamblador Karel Funciones externas:Ninguna ************************************************************/ void ensamblador::archivo_virtual(char *mnemonico,int num_linea){ ensamblador *ant = NULL, *act = karel; while(act) { ant = act; act = act->sig; } if (!(act = new ensamblador)) { cout<<"\nError de asignacion"; exit(1); } act->comando = strdup(mnemonico); act->linea = num_linea; act->sig = NULL; if(!karel) karel = act; else ant->sig = act; } //////////////////////////////////////////////////////////////// // RUTINAS PARA LA EJECUCION DE KAREL // //////////////////////////////////////////////////////////////// void programa(){ ensamblador haz; instrucciones ejecuta; ejecucion corre; corre.inicia_programa(); ejecuta.genera_nva_instr(); corre.inicia_ejecucion(); while (strncmp(nodo->linea, "FIN_DE_EJECUCION", 16) != 0) ejecuta.instruccion(); corre.fin_ejecucion(); corre.fin_programa(); haz.archivo_virtual("ok", 1); } /*********************************************************** Nombre de la funcion: INICIA_PROGRAMA Proposito: Verifica la existencia del token "INICIO_DE_PROGRAMA" Entrega: Nada Funciones externas: Ninguna ************************************************************/ void ejecucion::inicia_programa(){ if (strncmp(nodo->linea, "INICIO_DE_PROGRAMA", 18) != 0 ){ cout<<"\nNo se encuentra INICIO_DE_PROGRAMA"; exit(1); } nodo = nodo->sig; } /*********************************************************** Nombre de la funcion: INICIA_EJECUCION Proposito: Verifica la existencia del token "INICIO_DE_EJECUCION" y agrega al programa en ensamblador la etiqueta "kini", la cual indica karel. Entrega: Nada Funciones externas: archivo_virtual ************************************************************/ void ejecucion::inicia_ejecucion(){ ensamblador haz; if (strncmp(nodo->linea, "INICIO_DE_EJECUCION", 19) != 0 ){ cout<<"\nNo se encuentra INICIO_DE_EJECUCION"; exit(1); } haz.archivo_virtual("kini", nodo->num); nodo = nodo->sig; } /*************************************************************** Nombre de la funcion: GENERA_NVA_INSTR ensamblador Karel Entrega: Nada Funciones externas: nueva_instruccion,instruccion archivo_virtual. ****************************************************************/ void instrucciones::genera_nva_instr(){ instrucciones ejecuta; ensamblador haz; tabla_de_simbolos checa; while ( (nodo) && (strncmp(nodo->linea, "INICIO_DE_EJECUCION", 19) != 0) ) { if (strncmp(nodo->linea, "DEFINE_NUEVA_INSTRUCCION", 24) == 0 ) { haz.archivo_virtual(token(2, nodo->linea), nodo->num); checa.nueva_instruccion(token(2, nodo->linea)); nodo = nodo->sig; ejecuta.instruccion(); } haz.archivo_virtual("rs", nodo->num); } if ( !nodo ){ cout<<"\nError en la linea"<<nodo->num<<" => "<<nodo->linea; exit(1); } } /*************************************************************** Nombre de la funcion: INSTRUCCION o condicionales. Entrega: Nada Funciones externas: si, mientras, repite, archivo_virtual, existe_instruccion ****************************************************************/ void instrucciones::instruccion(){ char *id = NULL, *brinco = NULL; ensamblador haz; tabla_de_simbolos checa; if ( (strncmp(nodo->linea, "INICIO_DE_EJECUCION", 19) == 0 ) || (strncmp(nodo->linea, "FIN_DE_EJECUCION", 16) == 0 ) || (strncmp(nodo->linea, "DEFINE_INSTRUCCION_NUEVA",24) == 0 ) || (strncmp(nodo->linea, "FIN", 3) == 0 ) ) return; if (strncmp(nodo->linea, "INICIO", 6) == 0 ){ fin_bloque(); return; } if (strncmp(nodo->linea, "SI", 2) == 0 ){ si(); return; } if (strncmp(nodo->linea, "REPITE", 6) == 0 ){ repite(); return; } if (strncmp(nodo->linea, "MIENTRAS", 8) == 0 ){ mientras(); return; } if (strlen(id = strdup(instr_primitivas(nodo->linea))) == 0){ cout<<"\nError en la linea"<<nodo->num<<" => "<<nodo->linea; exit(1); } if (checa.existe_instruccion(token(1, nodo->linea))){ sprintf(brinco, "js %s", id); haz.archivo_virtual(brinco, nodo->num); } else haz.archivo_virtual(id, nodo->num); nodo = nodo->sig; } /*********************************************************** Nombre de la funcion: MIENTRAS MIENTRAS con ensamblador Karel. Entrega: Nada Funciones externas: pruebas_karel, instruccion, archivo_virtual, genera_etiqueta ************************************************************/ void instrucciones::mientras(){ char *id = NULL, *etiq_ciclo, *etiq_no_ok, brinco[30],etic; ensamblador haz; instrucciones ejecuta; etiq_ciclo[0] = '\0'; etiq_no_ok[0] = '\0'; if ( strlen(id = strdup(pruebas_karel(token(2,nodo->linea)))) == 0 ){ cout<<"\nError en la linea"<<nodo->num<<" => "<<nodo->linea; exit(1); } etiq_ciclo = genera_etiqueta(); // etic=gen_etiq(); haz.archivo_virtual(etiq_ciclo, nodo->num); haz.archivo_virtual(id, nodo->num); etiq_no_ok = genera_etiqueta(); sprintf(brinco,"jc %s", etiq_no_ok); haz.archivo_virtual(brinco, nodo->num); nodo = nodo->sig; ejecuta.instruccion(); sprintf(brinco, "jc %s", etiq_ciclo); haz.archivo_virtual(brinco, nodo->num); haz.archivo_virtual(etiq_no_ok, nodo->num); } /*********************************************************** Nombre de la funcion: REPITE REPITE con ensamblador Karel. Entrega: Nada Funciones externas: instruccion ************************************************************/ void instrucciones::repite(){ instrucciones ejecuta; entrada *ciclo = NULL; int n; n = atoi( token(2, nodo->linea) ); nodo = nodo->sig; ciclo = nodo; while (n) { nodo = ciclo; ejecuta.instruccion(); n--; } } /*********************************************************** Nombre de la funcion: SI y SINO con ensamblador Karel. Entrega: Nada Funciones externas: genera_etiqueta,instruccion, archivo_virtual, pruebas_karel ************************************************************/ void instrucciones::si(){ char *id = NULL, *etiq_0, *etiq_1, brinco_0[30], brinco_1[30]; ensamblador haz; instrucciones ejecuta; if ( strlen(id = strdup(pruebas_karel(token(2,nodo->linea)))) == 0 ){ cout<<"\nError en la linea"<<nodo->num<<" => "<<nodo->linea; exit(1); } etiq_0 = genera_etiqueta(); etiq_1 = genera_etiqueta(); sprintf(brinco_0,"jc %s", etiq_0); sprintf(brinco_1,"jc %s", etiq_1); haz.archivo_virtual(id, nodo->num); haz.archivo_virtual(brinco_0, nodo->num); nodo = nodo->sig; ejecuta.instruccion(); haz.archivo_virtual(brinco_1, nodo->num); haz.archivo_virtual(etiq_0, nodo->num); if (strncmp(nodo->linea,"SINO",4) == 0){ nodo = nodo->sig; ejecuta.instruccion(); } haz.archivo_virtual(etiq_1, nodo->num); } /*********************************************************** Nombre de la funcion: GENERA_ETIQUETA en ensamblador Karel Funciones externas: Ninguna ************************************************************/ char *genera_etiqueta(void){ char etiq[10]; sprintf(etiq, "etiq_%d", etiqueta); etiqueta++; return strdup(etiq); } char gen_etiq(void){ char etiq[10]; sprintf(etiq, "etiq_%d", etiqueta); etiqueta++; return *etiq; } /*********************************************************** Nombre de la funcion: FIN_BLOQUE Entrega: Nada Funciones externas: instruccion ************************************************************/ void instrucciones::fin_bloque(){ nodo = nodo->sig; entrada ir; instrucciones ejecuta; while ((strncmp(nodo->linea,"FIN", 3) != 0) && (nodo)) ejecuta.instruccion(); if (strncmp(nodo->linea, "FIN", 3) != 0 ){ cout<<"\nError en la linea"<<nodo->num<<" => "<<nodo->linea; exit(1); } nodo = nodo->sig; } /*********************************************************** Nombre de la funcion: FIN_EJECUCION Proposito: Verifica la existencia del token "FIN_DE_EJECUCION" Entrega: Nada Funciones externas: Ninguna ************************************************************/ void ejecucion::fin_ejecucion(){ if (strncmp(nodo->linea, "FIN_DE_EJECUCION", 16) != 0 ){ cout<<"\nNo se encuentra FIN_DE_EJECUCION"; exit(1); } nodo = nodo->sig; } /*********************************************************** Nombre de la funcion: FIN_PROGRAMA Proposito: Verifica la existencia del token "FIN_DE_PROGRAMA" Entrega: Nada Funciones externas: Ninguna ************************************************************/ void ejecucion::fin_programa(){ if (strncmp(nodo->linea, "FIN_DE_PROGRAMA", 15) != 0 ){ cout<<"\nNo se encuentra FIN_DE_PROGRAMA"; exit(1); } nodo = nodo->sig; } //////////////////////////////////////////////////////////////// // RUTINAS PARA LA CREACION DE UNA TABLA DE // // SIMBOLOS EN DONDE PONER LAS NUEVAS // // INSTRUCCIONES // //////////////////////////////////////////////////////////////// /*********************************************************** Nombre de la funcion: NUEVA_INSTRUCCION Proposito: Insertar una nueva instruccion en la tabla de simbolos Entrega: Nada. Funciones externas: Ninguna ************************************************************/ void tabla_de_simbolos::nueva_instruccion(char *instruccion){ tabla_de_simbolos *act = NULL; if (!(act = new tabla_de_simbolos)){ cout<<"Error de asignacion!"; exit(1); } act->instr = strdup(instruccion); act->sig = proxima_nva_instr; proxima_nva_instr = act; } /*********************************************************** Nombre de la funcion: EXISTE_INSTRUCCION simbolos Proposito: Realizar la escritura del archivo Entrega: 1 si la palabra existe, 0 en caso contrario Funciones externas: Ninguna ************************************************************/ int tabla_de_simbolos::existe_instruccion(char *cadena){ tabla_de_simbolos *act = proxima_nva_instr; while (act){ if ((strncmp(act->instr,cadena,strlen(cadena))== 0) && (strlen(act->instr) == strlen(cadena))) return 1; act = act->sig; } return 0; } /*********************************************************** Nombre de la funcion: ARCHIVO_ENSAMBLADOR Proposito: Realizar la escritura del archivo *.ok, el cual esta en lenguaje ensamblador tipo Karel Entrega: Nada. ************************************************************/ void archivo_ensamblador(char *archivo_terminado) { nodo = start; char *num_linea, *mnemonico; int i; ambiente crea; crea.forma_entorno(); //programa(); ofstream salida(archivo_terminado); if (!salida){ cout<<"Error de escritura en "<<archivo_terminado<<"!\n"; return; } while(karel){ sprintf(num_linea,"%d",karel->linea); mnemonico = strdup(karel->comando); i = 0; while (num_linea[i]) { salida.put(num_linea[i]); i++; } salida<<" "; i = 0; while (mnemonico[i]) { salida.put(mnemonico[i]); i++; } salida<<"\n"; karel = karel->sig; } salida.close(); cout<<"\nExito"; delete mnemonico; delete karel; delete nodo; delete start; } /*************************************************************** //////////////////////////////////////////////////////////////// // P R O G R A M A P R I N C I P A L // //////////////////////////////////////////////////////////////// ***************************************************************/ void main(){ char *temp, fileName[20], archivo_ok[20],*cadena,*p; entrada ir; start = NULL; karel = NULL; etiqueta = 0; proxima_nva_instr = NULL; cout<<"\nkar "; cin>>temp; //cout<<"\n aparte"; gets(cadena); //p=strtok(cadena," "); strcpy(fileName,temp); sprintf(archivo_ok, "%s.ok",strtok(temp,".")); ir.textLoadFile(fileName); archivo_ensamblador(archivo_ok); exit (1); }