1.24 Escriba un programa para revisar los errores de sintaxis rudimentarios de un programa en C, como paréntesis, llaves y corchetes no alineados. No olvide las comillas ni los apóstrofos, las secuencias de escape y los comentarios. (Este programa es difícil si se hace completamente general.)
/* Este programa verifica que las entradas de un programa no contengan errores de sintaxis elementales, como verificar que las llaves, corchetes y parentesis se cierren correctamente */ // Definicion de constantes simbolicas y encabezados # define OK 0 # define ERROR -1 # define FALSO 0 # define VERDADERO 1 # define LLENA 1 # define PILAMAX 100 # define ADENTRO 1 # define AFUERA 0 # include <stdio.h> int superior = -1; // Un par de variables externas int pila[PILAMAX]; empujar( int nuevo ) // La funcion empujar tiene mete elementos en la pila { // abre la funcion empujar if ( superior + 1 >= PILAMAX ) return( LLENA); pila[ ++superior ] = nuevo; return( OK); } // Cierra la funcion empujar int extraer() { // La funcion extrae elementos de la pila return( pila[superior--] ); } // Cierra la funcion extraer int vacio() { // Abre vacio if( superior < 0 ) return(VERDADERO); return(FALSO); } // Cierra vacio // Aqui se define la funcion a la que se hara referencia // Esta funcion realiza la tarea fundamental de revisar que los // parentesis se cierren adecuadamente int Revisa_Parentesis( int datos[]) { // ABre la funcion Revisa_Parentesis int i; int comentario = AFUERA; /* Esta variable se usa para tener en cuenta siempre si se esta o no dentro de un comentario, en caso de estarlo, no debe realizarse nada mas que seguir leyendo los caracteres hasta que se encuentre la secuencia de terminacion de comentario De entrada se empieza fuera de un comentario */ for ( i = 0; datos[i] != 0; i++ ) // En C++ si es posible declarar la variabl int en la primera parte // de for; en C la declaracion no puede hacerse en el ciclo // Este ciclo for pasa por alto los caracteres que no sean parentesis // Los parentesis de apertura se guardan en una pila { // ABre for switch( datos[i]) { // ABre switch case '{': case '[': case '(': if ( AFUERA == comentario ) { empujar( datos[i]); break; } case '}': if ( AFUERA == comentario ) { if (vacio() || extraer() != '{') return (ERROR); break; } case ']': if ( AFUERA == comentario ) { if (vacio() || extraer() != '[') return (ERROR); break; } case ')': if ( AFUERA == comentario ) { if (vacio() || extraer() != '(') return (ERROR); break; } case '/': if ( AFUERA == comentario ) { if ( '*' == datos[i + 1] ) comentario = ADENTRO; } if (ADENTRO == comentario) if ( '*' == datos[ i - 1]) comentario = AFUERA; break; } // Cierra switch } // Cierra for if ( ADENTRO == comentario ) // Es decir, si nunca se cerro un inicio de comentario, entonces es un errror return (ERROR); if ( vacio()) return (OK); return (ERROR); } // Cierra la funcion Revisa_Parentesis int main() { // Abre main int cadena[PILAMAX]; int c; int x = 0; int j; printf("\nEste programa funciona como una especie de preprocesador. "); printf("\nPor favor introduzca una cadena con comentarios y le dire si "); printf(" los parentesis, corchetes, llaves o comentarios estan bien cerrados o no.\n"); while( (c = getchar()) != EOF ) cadena[ x++ ] = c; j = Revisa_Parentesis( cadena); if ( OK == j ) printf("\nLos parentesis estan bien escritos.\n"); else if( ERROR == j ) printf("\nLos parentesis estan mal escritos.\n"); } // Cierra main /* Defectos del programa: En realidad el programa incluye varias partes, las cuales no pueden ser tratadas de igual manera. Lo mas sencillo es revisar si los parentesis (, [, { se cierran de manera adecuada. La manera de hacerlo es un ejemplo tipico del poder de las pilas, este programa incluye partes de los ejemplos que vienen en el libro de Bowman ( Algoritmos y Estructuras de D atos. Una Aproximacion en C) ademas la parte principal ( la funcion Revisa_Parentesis) es una modificacion de la que se presenta en ese libro. El siguiente punto es la revision de los comentarios. Para eso se introdujo la variable comentario, que indica si se esta o no dentro de uno. Si se esta entonces no vale apilar parentesis ni nada mas, lo unico importante es ver si en algun momento aparece la condicion de cierre. Se ha utilizado solamente la forma de /* porque es la tipica de el lenguaje C, sin embargo, deberia tambien incluirse el caso de //, el cual es la forma de comentario en C++ pero que tambien es valido en C, para este caso la condicion de terminacion es '\n'. Este programa no considera el caso de las comillas ni los apostrofos ni las secuencias de escape. Las secuencias de escape tienen validez dentro de una cadena, esto, por lo menos en la forma en que se me ocurre,implica crear una variable cadena a la que se le asigne ADENTRO o AFUERA. Sin embargo, no es posible apilar las comillas porque en cualquier punto el programa no sabe si esta es de apertura o de cierre, hay que atender ese problema con otra variable. Si se esta dentro de una cadena, es necesario atender las entradas \ y ver que siga alguna secuencia de escape. El problema es mas o menos el mismo para los apostrofos. En el caso de un compilador, este debe ademas indicar la linea y el caracter en el que aparece el problema, ademas de decir exactamente cual de todas las secuencias no se cerro de manera adecuada, para esto tambien hay que introducir nuevas variables..... Solo se me ocurre decir, con Kernighan y Ritchie: "Este programa es dificil si se hace completamente general" */
No hay comentarios:
Publicar un comentario