Docsity
Docsity

Prepara tus exámenes
Prepara tus exámenes

Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity


Consigue puntos base para descargar
Consigue puntos base para descargar

Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium


Orientación Universidad
Orientación Universidad


pclexpcyacc, Apuntes de Ingeniería Infórmatica

Asignatura: Compiladores e Interpretes, Profesor: , Carrera: Ingeniería Informática, Universidad: UAX

Tipo: Apuntes

Antes del 2010

Subido el 28/05/2007

_vivayo_
_vivayo_ 🇪🇸

3.7

(117)

149 documentos

1 / 25

Toggle sidebar

Esta página no es visible en la vista previa

¡No te pierdas las partes importantes!

bg1
PCLEX Y PCYACC
Guía Resumen
Profesor: J.A.Román
Abril 2002
1
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19

Vista previa parcial del texto

¡Descarga pclexpcyacc y más Apuntes en PDF de Ingeniería Infórmatica solo en Docsity!

PCLEX Y PCYACC

Guía Resumen

Profesor: J.A.Román Abril 2002

1.- INTRODUCCIÓN

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

  • %start axioma (por defecto : símbolo de la izquierda de la 1ª regla )
  • %union { tipo1 campo1; tipo2 campo2; ........ ........... } Con %union se declara el tipo de los atributos; queda definida esta unión en el tipo YYSTYPE y pcyacc utiliza la variable yylval , de dicho tipo, para guardar los atributos de los tokens (por ejemplo en “yylval.campo2”si el atributo del token es del tipo2 declarado en %union). Si no se usara %union yylval sería entera. Este tipo YYSTYPE se escribe en el fichero yytab.h.
  • %type NOTERMINAL1, NOTERMINAL2, ......utilizado para definir los tipos de los símbolos no terminales. Si no hubiese declaración %union, desaparecería.
  • %token token1 token2 token3 ...... utilizado para definir los tokens y asociar sus atributos con el tipo declarado en %union, a través de . Las definiciones de los tokens se escriben en el fichero yytab.h. Si no hubiese declaración %union , desaparecería. Ejemplo: %union { /* suponer enumop enumerado previamente definido*/ enumop opval; double dval; char *sval; } %tokenNUMERAL %token RISTRA %token OPREL El analex debe guardar el atributo de NUMERAL en yylval.dval, el de RISTRA en yylval.sval y el de OPREL en yylval.opval
  • También se pueden declarar tokens mediante : %right, %left, %nonassoc cuando estos sean símbolos de reglas de expresiones aritméticas. Son utilizados para declarar además del token su asociatividad.

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:

  • Si se usa en las reglas ‘c’, c es tomado como terminal y cualquier cadena sin “ “, no declarada previamente, es tomada como Noterminal.

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 :

  1. reducción-reducción : el parse elige la regla situada en primer lugar en la especificación.
  2. desplazamiento-reducción: el parse elige el desplazamiento ( recordar que así se resuelve el else ambiguo). En el caso de expresiones aritméticas permite utilizar declaraciones de operadores para resolver estos conflictos. La ambigüedad en las expresiones aritméticas viene por el uso de una gramática muy sencilla pero que no incorpora ni prioridades entre operadores, ni asociatividades: E F 0E 0 E + E | E - E | E * E | E / E | id Hay un mecanismo para la ambigüedad en expresiones aritméticas: en las declaraciones de los tokens se declara la asociatividad mediante %rigth, %left, %nonassoc (por la derecha, por la izquierda y ninguna asociatividad respectivamente). Los tokens declarados en las últimas líneas tienen mayor prioridad que las que se hacen en primer lugar. Ejemplo: Mayor precedencia igual precedencia %left ‘+’ ‘-‘ %right ‘=’ %nonassoc ‘<’ /* no asociativo */

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:

  • Si ambos tienen la misma precedencia observa la asociatividad
  • Si ambos son de asociatividad por la izquierda, reduce.
  • Si son de asociatividad por la derecha, desplaza.
  • Si ambos no tiene asociatividad genera un mensaje de error. Un caso que merece una mención especial es el del menos unario. Para que tenga una precedencia mayor que el binario y que los demás operadores se utiliza %prec. Ejemplo para una calculadora: %token NUM %left ‘+’ ‘-‘ %left ‘’ ‘/’ %right MENOSU /mayor precedencia que las demás reglas : es la última/ %% E: E ’+’ E {$$= $1 +$3;} | E ‘-‘ E { $$= $1 -$3;} | E ’’ E {$$= $1 $3;} | E ’/’ E {$$= $1 /$3;} | ‘-‘ E %prec MENOSU {$$=-$2;} / la regla toma la precedencia de MENOSU gracias a %prec/ | NUM ; Si en la pila hay –E y a la entrada aparece un operador ‘ ’ ( más prioritario que el’ –‘) el conflicto es de desplazamiento-reducción. No hay desplazamiento gracias a que la regla toma la precedencia de MENOSU y por tanto mayor que la del operador ‘*’ , así que se reduce, cambiando de signo antes que realizar cualquier otra operación.

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

8.- EXPRESIONES REGULARES

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: “ \ [ ] ^ -?. * | ( ) $ / { } < > +

  • El lexema que concuerda con el patrón i se guarda en el array de caracteres: yytext[ ].
  • La longitud del lexema guardado en yytext se encuentra en yyleng
  • La función yyless( n) es usada para retener en yytext los n primeros caracteres, el resto podrán ser “machacados” en la siguiente entrada.
  • (^) yywrap( ) , es llamada por pclex al alcanzar el EOF. Si devuelve 1 el escáner finaliza (predeterminado), si devuelve 0 el escáner continúa con otros ficheros como inputs.
  • input( ) devuelve el siguiente carácter en la entrada
  • unput(c) reinserta el carácter ‘c’ a la entrada. Puede ser leído posteriormente por input( ).
  • ECHO equivalente a printf(“%s”,yytext);
  • Los flujos por defecto stdin y stdout:
    • File *yyin
    • File *yyout
  • REJECT salta a la siguiente regla sin cambiar el contenido de yytext. Usado con solapamiento de patrones: Ejemplo: pink {npink++; REJECT;} ink {nink++; } sin REJECT nunca se incrementaría nink, ya que de los dos patrones pclex concuerda el patrón más largo.

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:

  1. primero en cada línea que empieza por a
  2. segundo “ “ “ “ “ “ b
  3. tercero “ “ “ “ “ “ c

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++;} “” ;

CUADRO RESUMEN pclex

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);}