Bison - Archivos de Gramatica de Bison (III)

8 - Archivos de Gramatica de Bison (III)


Tutorial creado por Charles Donnelly y Richard Stallman . Extraido de: http://es.tldp.org/Manuales-LuCAS/guides/bison-guide/bison-es-1.27.html
01 Marzo 2006
< anterior | 1 .. 6 7 8 9 10 .. 16 | siguiente >
===== Declaraciones de Bison =====

La sección de declaraciones de Bison de una gramática de Bison define los símbolos utilizados en la formulación de la gramática y los tipos de datos de los valores semánticos. See section Símbolos, Terminales y No Terminales.

Todos los nombres de tipos de tokens (pero no los tokens de caracter literal simple tal como ##'+'## y ##'*'##) se deben declarar. Los símbolos no terminales deben ser declarados si necesita especificar el tipo de dato a utilizar para los valores semánticos (see section Más de Un Tipo de Valor).

La primera regla en el fichero también especifica el símbolo de arranque, por defecto. Si desea que otro símbolo sea el símbolo de arranque, lo debe declarar explícitamente (see section Lenguajes y Gramáticas independientes del Contexto).

==== Nombres de Tipo de Token ====

La forma básica de declarar un nombre de tipo de token (símbolo terminal) es como sigue:

%token nombre

Bison convertirá esto es una directiva ###define## en el analizador, así que la función ##yylex## (si está en este fichero) puede utilizar el nombre nombre para representar el código de este tipo de token.

De forma alternativa, puede utilizar ##%left##, ##%right##, o ##%nonassoc## en lugar de ##%token##, si desea especificar la precedencia. See section Precedencia de Operadores.

Puede especificar explícitamente el código numérico para un token añadiendo un valor entero en el campo que sigue inmediatamente al nombre del token:

%token NUM 300

Es generalmente lo mejor, sin embargo, permitir a Bison elegir los códigos numéricos para todos los tipos de tokens. Bison automáticamente seleccionará los códigos que no provoquen conflictos unos con otros o con caracteres ASCII.

En el caso de que el tipo de la pila sea una union, debe aumentar ##%token## u otra declaración de tokens para incluir la opción de tipo de datos delimitado por ángulos (see section Más de Un Tipo de Valor).

Por ejemplo:

%union { /* define el tipo de la pila */
double val;
symrec *tptr;
}
%token <val> NUM /* define el token NUM y su tipo */

Puede asociar un token de cadena literal con un nombre de tipo de token escribiendo la cadena literal al final de la declaración ##%type## que declare el nombre. Por ejemplo:

%token arrow "=>"

Por ejemplo, una gramática para el lenguaje C podría especificar estos nombres con los tokens de cadena literal equivalente:

%token <operator> OR "||"
%token <operator> LE 134 "<="
%left OR "<="

Una vez que iguale la cadena literal y el nombre del token, puede utilizarlo indistintamente en ulteriores declaraciones en reglas gramaticales. La función ##yylex## puede utilizar el nombre del token o la cadena literal para obtener el número de código del tipo de token (see section Convención de Llamada para ##yylex##).

==== Precedencia de Operadores ====

Use las declaraciones ##%left##, ##%right## o ##%nonassoc## para declarar un token y especificar su precedencia y asociatividad, todo a la vez. Estas se llaman declaraciones de precedencia. See section Precedencia de Operadores, para información general a cerca de la precedencia de operadores.

La sintaxis de una declaración de precedencia es la misma que la de ##%token##: bien

%left símbolos...

o

%left <tipo> símbolos...

Y realmente cualquiera de estas declaraciones sirve para los mismos propósitos que ##%token##. Pero además, estos especifican la asociatividad y precedencia relativa para todos los símbolos:

~- La asociatividad de un operador op determina cómo se anidan los repetidos usos de un operador: si `x op y op z' se analiza agrupando x con y primero o agrupando y con z primero. ##%left## especifica asociatividad por la izquierda (agrupando x con y primero) y ##%right## especifica asociatividad por la derecha (agrupando y con z primero). ##%nonassoc## especifica no asociatividad, que significa que `x op y op z' se considera como un error de sintaxis.
~- La precedencia de un operador determina cómo se anida con otros operadores. Todos los tokens declarados en una sola declaración de precedencia tienen la misma precedencia y se anidan conjuntamente de acuerdo a su asociatividad. Cuando dos tokens declarados asocian declaraciones de diferente precedencia, la última en ser declarada tiene la mayor precedencia y es agrupada en primer lugar.

==== La Colección de Tipos de Valores ====

La declaración ##%union## especifica la colección completa de posibles tipos de datos para los valores semánticos. La palabra clave ##%union## viene seguida de un par de llaves conteniendo lo mismo que va dentro de una ##union## en C.

Por ejemplo:

%union {
double val;
symrec *tptr;
}

Esto dice que los dos tipos de alternativas son ##double## y ##symrec *##. Se les ha dado los nombres ##val## y ##tptr##; estos nombres se utilizan en las declaraciones de ##%token## y ##%type## para tomar uno de estos tipos para un símbolo terminal o no terminal (see section Símbolos No Terminales).

Note que, a diferencia de hacer una declaración de una ##union## en C, no se escribe un punto y coma después de la llave que cierra.

==== Símbolos No Terminales ====

Cuando utilice ##%union## para especificar varios tipos de valores, debe declarar el tipo de valor de cada símbolo no terminal para los valores que se utilicen. Esto se hace con una declaración ##%type##, como esta:

%type <tipo> noterminal...

Aquí noterminal es el nombre de un símbolo no terminal, y tipo es el nombre dado en la ##%union## a la alternativa que desee (see section La Colección de Tipos de Valores). Puede dar cualquier número de símbolos no terminales en la misma declaración ##%type##, si tienen el mismo tipo de valor. Utilice espacios para separar los nombres de los símbolos.

Puede también declarar el tipo de valor de un símbolo terminal. Para hacer esto, utilice la misma construcción ##<tipo>## en una declaración para el símbolo terminal. Todos las clases de declaraciones de tipos permiten ##<tipo>##.

==== Suprimiendo Advertencias de Conflictos ====

Bison normalmente avisa si hay algún conflicto en la gramática (see section Conflictos de Desplazamiento/Reducción), pero la mayoría de las gramáticas reales tienen confictos desplazamiento/reducción inofensivos que se resuelven de una manera predecible y serían muy difíciles de eliminar. Es deseable suprimir los avisos a cerca de estos conflictos a menos que el número de conflictos cambie. Puede hacer esto con la declaración ##%expect##.

La declaración tiene este aspecto:

%expect n

Aquí n es un entero decimal. La declaración dice que no deben haber avisos si hay n conflictos de desplazamiento/reducción y ningún conflicto reducción/reducción. Los avisos usuales se dan si hay más o menos conflictos, o si hay algún conflicto reducción/reducción.

En general, el uso de ##%expect## implica estos pasos:

~- Compilar su gramática sin ##%expect##. Utilice la opción `-v' para obtener una lista amplia de dónde ocurrieron los conflictos. Bison también imprimirá el número de conflictos.
~- Comprobar cada uno de los conflictos para estar seguro de que la resolución por defecto de Bison es lo que realmente quiere. Si no, reescriba la gramática y vuelva al principio.
~- Añada una declaración ##%expect##, copiando el número n a partir del número que imprime Bison.

Ahora Bison dejará de molestarle con los conflictos que ha comprobado, pero le avisará de nuevo si cambia el resultado de la gramática con conflictos adicionales.

==== El Símbolo de Arranque ====

Bison asume por defecto que el símbolo de arranque para la gramática es el primer no terminal que se encuentra en la sección de especificación de la gramática. El programador podría anular esta restricción con la declaración ##%start## así:

%start símbolo

==== Un Analizador Puro (Reentrante) ====

Un programa reentrante es aquel que no cambia en el curso de la ejecución; en otras palabras, consiste enteramente de código puro (de sólo lectura). La reentrancia es importante siempre que la ejecución asíncrona sea posible; por ejemplo, un programa no reentrante podría no ser seguro al ser llamado desde un gestor de señales. En sistemas con múltiples hilos de control, un programa no reentrante debe ser llamado únicamente dentro de interbloqueos.

Normalmente, Bison genera un analizador que no es reentrante. Esto es apropiado para la mayoria de los casos, y permite la compatibilidad con YACC. (Los interfaces estandares de YACC son inherentemente no reentrantes, porque utilizan variables asignadas estáticamente para la comunicación con ##yylex##, incluyendo ##yylval## y ##yylloc##.)

Por otra parte, puede generar un analizador puro, reentrante. La declaración de Bison ##%pure_parser## dice que desea que el analizador sea reentrante. Esta aparece así:

%pure_parser

El resultado es que las variables de comunicación ##yylval## y ##yylloc## se convierten en variables locales en ##yyparse##, y se utiliza una convención de llamada diferente para la función del analizador léxico ##yylex##. See section Convenciones de Llamada para Analizadores Puros, para los detalles a cerca de esto. La variable ##yynerrs## también se convierte en local en ##yyparse## (see section La Función de Informe de Errores ##yyerror##). La convención para llamar a ##yyparse## no cambia.

Que el analizador sea o no puro no depende de las reglas gramaticales. Puede generar indistintamente un analizador puro o un analizador no reentrante a partir de cualquier gramática válida.

==== Sumario de Declaraciones de Bison ====

Aquí hay un sumario de todas las declaraciones de Bison:

##%union## Declara la colección de tipos de datos que los valores semánticos pueden poseer (see section La Colección de Tipos de Valores). ##%token## Declara un símbolo terminal (nombre de tipo de token) sin precedencia o asociatividad especificada (see section Nombres de Tipo de Token). ##%right## Declara un símbolo terminal (nombre de tipo de token) que es asociativo por la derecha (see section Precedencia de Operadores). ##%left## Declara un símbolo terminal (nombre de tipo de token) que es asociativo por la izquierda. (see section Precedencia de Operadores). ##%nonassoc## Declara un símbolo terminal (nombre de tipo de token) que es no asociativo (utilizándolo de una forma que sería asociativo es un error de sintaxis) (see section Precedencia de Operadores). ##%type## Declara el tipo de valor semántico para un símbolo no terminal. (see section Símbolos No Terminales). ##%start## Especifica el símbolo de arranque de la gramática (see section El Símbolo de Arranque). ##%expect## Declara el número esperado de conflictos desplazamiento-reducción (see section Suprimiendo Advertencias de Conflictos). ##%pure_parser## Solicita un programa de análisis puro (reentrante) (see section Un Analizador Puro (Reentrante)). ##%no_lines## No genera ningún comando ###line## del proprocesador en el fichero del analizador. Normalmente Bison escribe estos comandos en el archivo del analizador de manera que el compilador de C y los depuradores asociarán los errores y el código objeto con su archivo fuente (el archivo de la gramática). Esta directiva provoca que asocien los errores con el archivo del analizador, tratándolo como un archivo fuente independiente por derecho propio. ##%raw## El archivo de salida ##`nombre.h'## normalmente define los tokens con los números de token compatible con Yacc. Si se especifica esta opción, se utilizarán los números internos de Bison en su lugar. (Los números compatibles con Yacc comienzan en 257 excepto para los tokens de caracter simple; Bison asigna números de token secuencialmente para todos los tokens comenzando por 3.) ##%token_table## Genera un array de nombres de tokens en el archivo del analizador. El nombre del array es ##yytname##; ##yytname[i]## es el nombre del token cuyo número de código de token interno de Bison es i. Los primeros tres elementos de ##yytname## son siempre ##"$"##, ##"error"##, e ##"$illegal"##; después de estos vienen los símbolos definidos en el archivo de la gramática. Para tokens de caracter literal y tokens de cadena literal, el nombre en la tabla incluye los caracteres entre comillas simples o dobles: por ejemplo, ##"'+'"## es un literal de caracter simple y ##"\"<=\""## es un token de cadena literal. Todos los caracteres del token de cadena literal aparecen textualmente en la cadena encontrada en la tabla; incluso los caracteres de comillas-dobles no son traducidos. Por ejemplo, si el token consiste de tres caracteres `*"*', su cadena en ##yytname## contiene `"*"*"'. (En C, eso se escribiría como ##"\"*\"*\""##). Cuando especifique ##%token_table##, Bison también generará definiciones para las macros ##YYNTOKENS##, ##YYNNTS##, y ##YYNRULES## y ##YYNSTATES##; ##YYNTOKENS## El número de token más alto, más uno. ##YYNNTS## El número de símbolos no terminales. ##YYNRULES## El número de reglas gramaticales, ##YYNSTATES## El número de estados del analizador (see section Estados del Analizador).

===== Múltiples Analizadores en el Mismo Programa =====

La mayoría de los programa que usan Bison analizan sólo un lenguaje y por lo tanto contienen sólo un analizador de Bison. Pero , ¿qué pasa si desea analizar más de un lenguaje con el mismo programa? Entonces necesita evitar un conflicto de nombres entre diferentes definiciones de ##yyparse##, ##yylval##, etc.

La manera más fácil de hacer esto es utilizar la opción `-p prefijo' (see section Invocando a Bison). Esta renombra las funciones de interfaz y variables del analizador de Bison para comenzar con prefijo en lugar de `yy'. Puede utilizarlo para darle a cada analizador nombres diferentes que no provoquen conflicto.

La lista precisa de símbolos renombrados es ##yyparse##, ##yylex##, ##yyerror##, ##yynerrs##, ##yylval##, ##yychar## e ##yydebug##. Por ejemplo, si utiliza `-p c', los nombres se convierten em ##cparse##, ##clex##, etc.

El resto de las variables y macros asociadas con Bison no se renombran. Estas otras no son globales. Por ejemplo, ##YYSTYPE## no se renombra, pero definirla de diferente forma en analizadores diferentes no provoca confusión (see section Tipos de Datos para Valores Semánticos).

La opción `-p' funciona añadiendo definiciones de macros al comienzo del archivo fuente del analizador, definiendo ##yyparse## como ##prefijo##parse, etc. Esto sustituye efectivamente un nombre por el otro en todo el fichero del analizador.
< anterior | 1 .. 6 7 8 9 10 .. 16 | siguiente >

Autor y licencia de 'Bison'


Tutorial de Charles Donnelly y Richard Stallman . Extraido de: http://es.tldp.org/Manuales-LuCAS/guides/bison-guide/bison-es-1.27.html CopyLeft
Este contenido ha sido recopilado por el equipo de Wikilearning. Todo el contenido recopilado se ha obtenido respetando y comunicando en nuestro site la licencia de cada fuente.