

















Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Prepara tus exámenes
Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Prepara tus exámenes con los documentos que comparten otros estudiantes como tú en Docsity
Encuentra los documentos específicos para los exámenes de tu universidad
Estudia con lecciones y exámenes resueltos basados en los programas académicos de las mejores universidades
Responde a preguntas de exámenes reales y pon a prueba tu preparación
Consigue puntos base para descargar
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Comunidad
Pide ayuda a la comunidad y resuelve tus dudas de estudio
Ebooks gratuitos
Descarga nuestras guías gratuitas sobre técnicas de estudio, métodos para controlar la ansiedad y consejos para la tesis preparadas por los tutores de Docsity
Asignatura: Compiladores e Interpretes, Profesor: , Carrera: Ingeniería Informática, Universidad: UAX
Tipo: Apuntes
1 / 25
Esta página no es visible en la vista previa
¡No te pierdas las partes importantes!


















Profesor: J.A.Román Abril 2002
Pclex y Pcyacc son herramientas diseñadas para generar compiladores e intérpretes aunque puedan ser útiles para otras aplicaciones, como aquellas que reconocen patrones en su entrada o tengan un lenguaje de comandos. Permiten realizar prototipos rápidamente, modificaciones fácilmente y un cómodo mantenimiento de las aplicaciones. Pclex genera Analizadores Léxicos a partir de un conjunto de "descripciones" de posibles Componentes Léxicos , produciendo una rutina en C. Dichas "descripciones" son conocidas como expresiones regulares , que son transformadas a un formato que el Analizador Léxico usa para explorar, muy rápidamente, el texto de entrada Pcyacc toma una " descripción concisa " de la gramática del lenguaje y produce una rutina en C : un Analizador Sintáctico ascendente, que detectará automáticamente si una secuencia de Componentes Léxicos concuerda con alguna de las reglas de la gramática o , en caso negativo, un error sintáctico. Además, si el análisis sintáctico ha sido correcto, puede generar el código del traductor.
2.- UTILIZACIÓN CONJUNTA DE pclex y pcyacc Pueden ser utilizados aisladamente, aunque el pcyacc necesita entonces incluir el código de un analizador léxico como una función más. Lo natural es utilizar estas herramientas conjuntamente. Se genera un ANASINT ascendente mediante pcyacc y un ANALEX mediante pclex, ambos en lenguaje C a partir de sus propias especificaciones. El proceso es el siguiente: .1 (^) Escribir las especificaciones para pcyacc_._ .2 Obtener la fuente pcyacc en un fichero ( por ejemplo “anasint.y") .3 Aplicar el comando "pcyacc" a dicho fichero con la opción -d , obteniendo el fichero “yytab.h”, donde quedan definidos los componentes léxicos y el tipo de sus atributos. ( También se obtiene otro fichero “anasint.c” pero tiene intercalados #line...., haciendo referencia a las líneas fuente que puede dificultar la lectura del código). .4 Si se quiere obtener la tabla LALR (es aconsejable) se aplica el comando pcyacc con la opción –v , obteniéndose dicha tabla en el fichero “yy.lrt”. .5 Para obtener la rutina en C del ANASINT se aplica el comando pcyacc con la opción –n obteniéndose el fichero anasint.c ( sin #line...) que contendrá la función yyparse( )(que así se llamará el ANASINT generado. .6 Escribir las especificaciones para pclex. .7 Obtener la fuente lex en un fichero ( por ejemplo “analex.l"), sin olvidar incluir #include yytab.h, para que el analizador léxico tenga definidos los mismo tokens y atributoas que el analizador sintáctico. .8 Aplicar el comando "pclex" a dicho fichero con la opción –l (sin #line....), para obtener el programa fuente del ANALEX en C, en el fichero “analex.c”, que contiene la rutina C del analizador léxico yylex(),
3.- ESTRCTURA DE LAS ESPECIFICACIONES pcyacc La fuente pyacc consta de tres secciones: Declaraciones, Reglas y Procedimientos Auxiliares del Usuario. La sección de las Reglas es la única obligatoria , las otras dos son opcionales , aunque, si están presentes, deben aparecer en el orden indicado y con los delimitadores %%.
Declaraciones %{ #include #define int .... }% %start axioma %token…… %union...... %right ..... %left…
Dos subsecciones: 1.-Declaraciones ordinarias en lenguaje C entre %{ y }%. Todas estas líneas son copiadas al principio del fichero C que se genera. 2.- Declaraciones de los tokens, tipos de los atributos, asociatividad de las expresiones aritméticas, etc %% Reglas
ladoizquierdo : alternativa1 { acción1} | alternativa2 {acción2} | alternativa3 {acción} ;
Esta sección obligatoria ha de comenzar con %%. Incluye un conjunto de reglas, (reflejo de las de la gramática, por las cuales se describe la estructura de la entrada al ANASINT), un código (un fragmento en C), llamado acción, que será invocado cada vez que una regla sea reconocida. %% Rutinas auxiliares de usuario
Si hay rutinas de usuario la sección de las Reglas ha de terminar con %%.
3.1.- declaraciones propias del pcyacc
3.2.- Sección de reglas para pcyacc. El formato para especificar las reglas, alternativas y acciones ya ha sido mostrado en la tabla anterior. Ahora, entre otras informaciones, se debe indicar cómo trabajar con los atributos de los los tokens y de los símbolos Noterminales:
3.3.- Rutinas auxiliares del usuario en pcyacc. Son totalmente opcionales, aunque se recomienda invocar funciones en el código de las acciones y escribir estas en esta sección. Si no se utilizara una ANALEX exterior se deberá escribir el código de un analizador léxico como una función de esta sección. En este caso también debe llamarse yylex( ).
4.- AMBIGÜEDAD Y CONFLICTOS en pcyacc Aunque todas las gramáticas que pcyacc trate debieran ser no ambiguas, algunas veces lo son, porque son más fáciles de usar. Las gramáticas ambiguas causan conflictos que pclex resuelve mediante reglas de decisión por defecto. A veces estas decisiones por defecto no producen los resultados deseados. Los posibles conflictos pueden verse en el fichero yy.lrt ( opción –v de pcyacc), donde se describe la tabla del parse. Por defecto los conflictos se resuelven :
Los tokens declarados con esas declarativas no tienen que ser declarados con % token. Cada token operador puede tener asignadas una precedencia y una asociatividad También cada regla tiene una precedencia y una asociatividad mediante :
. %prec en la regla, en su ausencia toma la del token más a la derecha
Cuando pcyac tiene un conflicto de desplazamiento-reducción compara la precedencia del token que puede ser desplazado con la de la regla que puede ser reducida:
5.- TRATAMIENTO DE ERRORES Y RECUPERACIÓN en pcyacc Para permitir al usuario algún control sobre el proceso de recuperación de errores, pcyacc dispone de un "complex" llamado error , que puede ser usado en las reglas de la especificación. El ANASINT utiliza el modo de recuperación llamado por "producciones de error": El usuario decide qué no terminales tendrán recuperación de errores asociados a ellos. Las elecciones típicas son algún subconjunto de los no terminales que generan expresiones, proposiciones, bloques y procedimientos. Entonces el usuario añade a la gramática producciones de error del tipo:
Después del delimitador %} se colocan los nombres que se quieran asociar a cada expresión regular, nombres que serán referenciados en la segunda sección entre { y }.
Ejemplo de nombres asociados a expresiones regulares %{
%} letra [A-Za-z] digito [0-9] identificador {letra} ({letra}|{digito})* %% {identificador} {yylval=inserta_en_TDS(); /* yylval por defecto es int/ return ID;} / ID definido en yytab.h*/
7.2.- Sección de Reglas de pclex Esta sección tiene sus líneas con la siguiente estructura:.
EXPRESION REGULAR Acciones (fragmentos de código C)
patrón1 {acción1} patrón2 {acción2}
patrón n {acciónN}
La acción i son fragmentos de código C que describen el comportamiento del ANALEX cuando un lexema de la entrada concuerda con el patrón i. Cuando el ANALEX ( yylex( ) ) es activado por el ANASINT, lee carácter a carácter su entrada hasta que encuentra el mayor prefijo de la entrada que concuerda con el patrón i. Si hay ambigüedad para decidir qué regla tener en cuenta cuando se reconocen dos patrones de la misma longitud, el ANALEX seleccionará el de la regla escrita en primer lugar. Si el fragmento de código tiene varias sentencias, ha de ser encerrado entre { y } para indicar al pclex que todo es una regla.
7.3.- Rutinas de usuario en pclex Es posible que el usuario utilice sus propias rutinas de la misma manera que se usan en otros lenguajes de programación. El código de una acción que va a ser usado en varias reglas puede ser escrito una vez como una función y ser llamado cuantas veces sea necesario. El código de la función es escrito en la sección tercera tras el segundo %% y puede ser invocado en cualquier regla de la sección segunda.
Un caso típico para identificadores: %% …….. [a-zA-Z][a-zA-Z0-9]* {yylval = inserta_en_TDS(); return ID;} …….. %% int inserta_en_TDS() {….. código de la función…..} asumiendo que yylval es una variable de tipo entero y la función devuelve el índice del array de la tabla
Es una notación utilizada para especificar patrones. Un patrón se forma escribiendo ristras de caracteres con o sin operadores de expresión regular. El patrón más simple sería una ristra de caracteres sin ningún operador, pero la mayoría de los patrones usados en un ANALEX han de utilizarse con operadores que expresen repeticiones, alternativas, selecciones, optatividad, etc. Los operadores de expresión regular son: “ \ [ ] ^ -?. * | ( ) $ / { } < > +
10.- CONDICIONES DE ARRANQUE en pclex Proporciona una manera de realizar diferentes acciones cuando reconozca un patrón en función de ciertas condiciones que son denominadas de arranque. Se definen nombres de las diferentes condiciones de arranque mediante: %start nombre1 nombre2 ............. nombren en la sección de definiciones ( en vez de start puede usarse s o S ) En la sección de reglas la condición es referenciada por su nombre: expresión Para que se arranque dicha condición se ha de ejecutar la acción que sigue a : BEGIN nombre Cambiando así a la condición nombre Para volver a un estado normal se ha de ejecutar BEGIN 0 Ejemplo: %start A B C %% ^a { ECHO ; BEGIN (A);} ^b { ECHO ;: BEGIN (B);} ^c { ECHO ; BEGIN (C);} \n { ECHO; BEGIN 0;} abracalabra {printf(“primero”);} abracalabra {printf(“segundo”);}
abracalabra {printf(“tercero”);} Copia la entrada a la salida (ECHO) pero cambia la palabra abracalabra por:
La condición de arranque exclusiva sería con %x. Se diferencia con %s en que cualquier otra regla que no está entre < > no está activa, mientras que con %s sí lo está.
Otro ejemplo: %x COMENTARIO %% “/* “ {BEGÍN(COMENTARIO);} “/” {BEGIN(0);} [^\n]+ ; /* si se pusiera [^\n]+ en el caso abc......k */\n no se detectaría */ sólo lo haría si */ estuviera al principio de la línea, ya que la línea entera tendría un patrón con longitud mayor que */ / \n {contlinea++;} “” ;
Un caso práctico
digito [0-9] blanco [ \t\n] %% {letra}+ {return ID;} {digito}+ {return NUME;} [+-] {return OPSR;} [*/] {return OPMD;} [(] {return PA;} [)] {return PC;} blanco . La fuente pclex analex.txt incluye el archivo yytab.h para que al reconocer a cada patrón, devuelva el token como está definido en el anasint.txt. Apliquemos los comandos según se mencionó al principio del documento: pcyacc –n anasint.txt anasint.c ( yyparse ( ) ) pclex –l analex.txt analex.c (yylex( ) ) Los dos programas generados, anasint.c y analex.c , se unen para formar un solo ejecutable que realizará el análisis sintáctico. Supongamos ahora que se añade un traductor. No sólo se quiere saber si la expresión aritmética es correcta gramaticalmente sino que además se espera evaluarla. Se dispondrá de un valor numérico entero para cada operando en la expresión (atributo) y un carácter para saber qué operador se ha de aplicar (atributo) para los casos de OPSR ( suma o resta) y OPMD (multiplicación do división). En pcyacc esto debe especificarse mediante %union { int valor; char operador; } Ahora hay que asignar qué tipo de atributo se aplicará a cada símbolo en la gramática; un operando puede ser ID, NUME, expresión, termino, factor, por lo que estos tendrán el atributo valor; sin embargo los operadores OPSR y OPMD tendrán como atributo el campo operador. En pcyacc debe especificarse: %token ID NUME %token OPSR OPMD %type expresión, termino, factor Ni PA ni PC tienen atributos. En la sección de reglas de pcyacc habrá que asociar a cada regla de la gramática una acción codificada en C; si en esa acción se quiere referirse a los atributos que un símbolo posee, se hace referencia a él mediante $$, S1, S2, etc según se explico con anterioridad.
Así pues la fuente pcyacc quedará ahora:
%start expresion %union{ int valor; char operador; } %token PA PC %token ID NUME %token OPSR OPMD %type expresión, termino, factor %% expresión : expresión OPSR termino { $$=opera($2,$1,$3); printf(“%d %c %d = %d\n”, $1,$2,$3,$$);} | termino {$$ = $1;} ; termino : termino OPMD factor {$$ = opera($2,$1,$3); printf(“%d %c %d = %d\n”, $1,$2,$3,$$);} | factor {$$ = $1;} ; factor : ID {$$ = $1;} : NUME {$$ = $1;} : PA expression PC {$$=$2;} ;
main( ) { yyparse( );} opera(char a, int b, int c){ switch(a) { case ‘+’: return (b+c) ; break; case ‘-’: return (b-c) ; break; case ‘’: return (bc) ; break; case ‘/’: return (b/c) ; break; } } yyerror(char *s) {printf (“%s \n , s);}