La tarea de construir un analizador sintctico es lo suficientemente simple como para ser
automatizada. En el captulo anterior hemos descrito los aspectos de anlisis lxico de JavaCC y SableCC. Aqu vamos a discutir los aspectos del generador de anlisis de estas herramientas. La documentacin para JavaCC y SableCC estn disponibles a travs del sitio Web de este libro. JavaCC es un LL (k) generador de analizadores sintcticos. Sus producciones son de la forma: void Assignment() : {} { Identifier() "=" Expression() ";" } Donde el lado izquierdo es de Asignacin (); el lado derecho est encerrado entre los dos ltimos corchetes; Asignacin (), identificador (), y la expresin () son smbolos no terminales; y "=" y ";" son smbolos terminales.
La gramtica 3.30 puede ser representada como una gramtica JavaCC como se muestra en la gramtica 3.31. Tenga en cuenta que si hubiramos escrito para la produccin StmList () en el estilo de gramtica 3.30 es
A continuacin, la gramtica se dej recursiva. En este caso, JavaCC dara el siguiente error:
Utilizamos las tcnicas mencionadas anteriormente para eliminar la recursividad por la izquierda y llegar a la gramtica 3.31. SABLECC SableCC es un LALR (1) generador de analizadores sintcticos. Sus Producciones son de la forma:
Donde el lado izquierdo es la asignacin; el lado derecho est encerrado entre = y ;; asignacin, identificador, y la expresin son smbolos no terminales; y assing y coma son smbolos terminales que se definen en una parte anterior de la especificacin de sintaxis. La gramtica 3.30 se puede representar como una gramtica en SableCC como se muestra en la gramtica 3.32. Cuando hay ms de un alternativa SableCC Requiere un nombre para cada alternativa. Un nombre se le da a una alternativa en la gramtica prefijando un identificador con la alternativa entre corchetes. Adems, si el mismo smbolo gramatical aparece dos veces en la misma alternativa de una produccin, SableCC requiere un nombre para al menos uno de los dos elementos. Los nombres de elementos se especifican anteponiendo el elemento con un identificador entre corchetes seguido de dos puntos. Ese reporte de SableCC en la Gramtica 3.32 tiene un desplazamiento y reduccin de conflictos. El conflicto puede ser examinado por la lectura del mensaje de error detallado que SableCC produce, como se muestra en la Figura 3:33.
SableCC usa prefijos para sus producciones con una "P" mayscula y tokens con una mayscula "T", y sustituye la primera letra con mayscula cuando hace los objetos para los tokens y producciones. Esto es lo que se ve en la pila en el mensaje de error en la Figura 3:33. S que tenemos las fichas en la pila para if, id, then, y en la produccin de stm que se coincide, y ahora tenemos una sentencia else token. Es evidente que esto revela que el conflicto es causado por else. Con el fin de resolver este conflicto tenemos que reescribir la gramtica, la eliminacin de la ambigedad como en la gramtica 3,34.
DIRECTIVAS DE PRIORIDAD Una gramtica no ambigua es LR (k) para cualquier k; la tabla de anlisis sintctico LR (k) de una gramtica ambigua siempre tendr conflictos. Sin embargo, las gramticas ambiguas todava pueden ser tiles si podemos encontrar la manera de resolver los conflictos. Por ejemplo, Gramtica 3.5 es muy ambigua. Mediante el uso de esta gramtica para describir un lenguaje de programacin, se pretende que sea analizada de manera que * y / unirse fuertemente a moras + y -, y que cada operador se asocia a la izquierda. Podemos expresar esta reescribiendo la inequvoca Gramtica 3.8 Pero podemos evitar la introduccin de los smbolos T y F y sus correspondientes reducciones "triviales" E T y T F. En su lugar, vamos a empezar por la construccin de la (1) tabla de anlisis sintctico LR para Gramtica 3.5, como se muestra en la Tabla 3.35. Encontramos muchos conflictos. Por ejemplo, en el estado 13 con bsqueda hacia delante + nos encontramos con un conflicto entre el cambio en 8 y estbamos de nuevo por la regla 3. Dos de los artculos estamos en el estado 13
En esto fue la parte superior de la pila es E * E. Shifting conducir a una pila E * E + y E * Finalmente E + E con una reduccin de E + E para E. Reduccin ahora dar lugar a la pila E y luego el + se desplazar. Los rboles de anlisis se obtiene desplazando y reduciendo
* Si queremos unir ms apretado que +, debemos veterano en lugar de turno. As que llenamos la entrada (13 +) en la tabla con r3 y descartamos la accin s8. Por el contrario, en el estado de 9 de preanlisis *, debemos cambiar en lugar de reducir, por lo que la resolucin del conflicto mediante la cumplimentacin de la entrada (9, *) con s12. Las casas eran de 9 + preanlisis es
Desplazamiento har que el operador asociativo por la derecha; reduccin har que sea dejado asociativo. Desde que salimos de asociatividad que desee, rellene w (9 +) con r5. Considere la posibilidad de la expresin a - b - c. En la mayora de los lenguajes de programacin, esto se asocia a la izquierda, como si estuviese escrita (a - b) - c. Pero se supone que debemos creer que esta expresin es intrnsecamente confuso, y queremos forzar al programador para poner en explcita parntesis, (a - b) - c o - (b - c). Se dice entonces que el operador menos es no asociativo, y nos gustara llenar el (11 -) entrada con una entrada de error.
El resultado de todas estas decisiones es una tabla de anlisis sintctico con todos los conflictos resueltos (Cuadro 3:36). Tiene directivas de precedencia yacc establecer la resolucin de esta clase de conflictos por desplazamiento y reduccin. (Desafortunadamente, SableCC no tiene directivas de precedencia.) Una serie de declaraciones: como precedence nonassoc EQ, NEQ; precedence left PLUS, MINUS; precedence left TIMES, DIV; precedence right EXP;
Indica que las teclas + y - se asociativo por la izquierda y se unen igualmente bien; que * y / quedan asociativo y se unen fuertemente a + moras; Eso es asociativo por la derecha y se une ms fuertemente; y Que = y? = son no asociativo, moras y se unen dbilmente a +. Al examinar una por desplazamiento y reduccin de conflictos: como
existe la opcin de cambiar una ficha y la reduccin por una regla. En caso de que la regla o el token se otorgue una mayor prioridad? . Las declaraciones de precedencia (de precedencia izquierda, etc) Dar a las prioridades a las fichas; la prioridad de una regla est dada por la ltima ficha que ocurre en el lado derecho de la regla. Por lo tanto la eleccin aqu es entre una regla y una ficha con prioridad con prioridad * +; Tiene la regla de mayor prioridad, por lo que el conflicto se resuelve a favor de la reduccin.
Cuando la regla y tokens tienen la misma prioridad, entonces favores de precedencia que reducen a la izquierda, derecha, favorece el cambio y nonassoc produce una accin de error.
En lugar de utilizar el valor predeterminado "regla tiene precedencia de su ltima ficha," podemos asignar una prioridad a una regla especfica usando la directiva prec%. Esto es comnmente utilizado para resolver el problema "menos unario". En la mayora de los lenguajes de programacin para menos unario une ms apretado que cualquier operador binario, por lo -6 * 8 se analiza como (- 6) * 8, no - (6 * 8). Gramtica 03:37 muestra un ejemplo.
El UMINUS smbolo nunca es devuelto por el analizador lxico; es slo un marcador de posicin en la cadena de declaraciones de precedencia. La directiva da la regla UMINUS% anterior exp :: = exp MINUS la ms alta prioridad, por lo que la reduccin por esta regla tiene prioridad sobre todos los operadores de desplazamiento, incluso en el signo menos.
Reglas de precedencia son tiles en la resolucin de los conflictos, pero no se debe abusar. Si tiene problemas para explicar el efecto de un uso inteligente de las reglas de prioridad, tal vez en su lugar debe reescribir la gramtica para ser inequvoco. SEMNTICA VERSUS SINTAXIS Considere la posibilidad de un lenguaje de programacin con expresiones aritmticas: como x + y, y expresiones booleanas: tal como x + y = z or a & (b = c). Los operadores aritmticos enlazan ms estricto que los operadores booleanos; hay variables aritmticas y variables booleanas; y una expresin booleana no se puede aadir a una expresin aritmtica. Gramtica 3.38 da una sintaxis de este lenguaje. La gramtica tiene un conflicto de reduccin-reduccin. Cmo debemos reescribir la gramtica para eliminar este conflicto?
Es ese el problema aqu Cuando el intrprete ve un identificador en: por ejemplo, no tiene forma de saber si se trata de una variable de clculo o una variable boolean - se ven sintcticamente idnticos. La solucin es aplazar este anlisis hasta la fase de "semntica" del compilador; Eso no es un problema se puede manejar de forma natural con las gramticas libres de contexto. A moras gramtica apropiada es
Ahora la expresin a + b es sintcticamente legal y 5, y una fase posterior del compilador tendr que rechazarlo e imprimir un mensaje de error semntico. RECUPERACIN DE ERRORES LR (k) tablas de anlisis sintctico Contienen cambio, reducir, aceptar, y las acciones de error. En la pgina 58 hemos afirmado que cuando un analizador LR se encuentra con una accin de error que se detenga el anlisis y el fracaso informes. Este comportamiento sera cruel con el programador, que le gustara tener todos los errores indicados en su programa, no slo el primer error.
RECUPERACIN DE ERRORES DE USAR EL SMBOLO Mecanismos de recuperacin de errores locales trabajan mediante el ajuste de la pila de anlisis sintctico y la entrada en el punto donde se detect el error en una forma que permita el anlisis para reanudar. Uno de los mecanismos de recuperacin local - que se encuentra en muchas versiones del generador de analizadores sintcticos YACC - utiliza un error de smbolo especial para controlar el proceso de recuperacin. Dondequiera que el smbolo de error especial aparece en una regla gramatical, una secuencia de tokens de entrada errneas puede ser igualada. Por ejemplo, en un Yacc las producciones gramaticales: como puede ser que tengamos
Informalmente, se puede especificar que si se encuentra un error de sintaxis en el medio de una expresin, el analizador debe saltar al siguiente punto y coma o parntesis derecho (Estos se llaman sincroniza tokens) y reanudar el anlisis. Hacemos esto mediante la adicin de las producciones de recuperacin de errores: por ejemplo,
Qu hace el generador de analizador con el smbolo de error? En la generacin de analizadores sintcticos, error es considerado un smbolo terminal, y acciones de transferencia se introducen en la tabla de anlisis sintctico para ella como si se tratara de un smbolo ordinario. Cuando el analizador LR alcanza un estado de error, toma las acciones siguientes:
1. Pop la pila (si es necesario) hasta que se alcanza un estado en el que la accin para el token error es cambio. 2. Cambie el token error. 3. Deseche smbolos de entrada (si es necesario) hasta que se alcanz una bsqueda hacia delante que lo tiene una accin nonerror en el estado actual. 4. Reanudar el anlisis normal.
En las dos producciones de error ilustrados anteriormente, hemos tenido el cuidado de seguir el smbolo con un smbolo de sincronizacin de error correspondiente - en este caso, un parntesis o punto y coma bien. Por lo tanto, la "accin nonerror" tomada en el paso 3 siempre cambiar. Si en cambio se utiliz el error exp produccin, la "accin nonerror" estara de vuelta, y (en una SLR o LALR parser) Que es posible la (errnea) smbolo de preanlisis originales causara otro error despus de la accin de veterano, sin tener avanzado la entrada. Por lo tanto, las reglas gramaticales que contienen errores no Seguido por una ficha deben ser apenada Slo cuando no hay una buena alternativa.
Precaucin
Uno puede adjuntar acciones semnticas a las reglas gramaticales Yacc; Cada vez que se reduce una regla, se ejecuta su accin semntica. Captulo 4 explica el uso de las acciones semnticas. Popping estados de la pila puede llevar a acciones semnticas aparentemente "imposibles", especialmente si las acciones Contener los efectos secundarios. Considere este fragmento de gramtica:
"Obviamente," es cierto que cada vez que se alcanza un punto y coma, el valor de un nido es cero, puesto que se incrementa y disminuye de manera equilibrada de acuerdo a la gramtica funcional de las expresiones. Pero si se encuentra un error de sintaxis despus de algunos parntesis de izquierda no se han analizado, a continuacin, los estados se extraen de la pila sin "Finalizacin", lo que lleva a un valor distinto de cero de un nido. La mejor solucin a este problema es tener de efectos secundarios acciones semnticas gratuitas que construye rboles de sintaxis abstracta, tal como se describe en el Captulo 4. Desafortunadamente, JavaCC ni apoya ni SableCC el mtodo de recuperacin de errores smbolo de error, ni el tipo de reparacin de errores global se describe a continuacin. REPARACIN ERROR GLOBAL Reparacin de errores Global encuentra el conjunto ms pequeo de las inserciones y deleciones que convertira la cadena de origen en una cadena sintcticamente correcta, incluso si las inserciones y eliminaciones no estn en un punto en el que una o LL LR parser primero informar de un error.
Reparacin de errores Burke-Fisher. Vamos a describir una forma limitada pero til de la reparacin de errores global, que intenta todo lo posible la insercin nico token, eliminacin o sustitucin en cada punto Eso no antes de K se produce fichas antes del punto en el analizador de informar del error. As, con K = 15, si el motor de anlisis se queda atascado en la ficha nmero 100 de la entrada, entonces se intentar todo lo posible la reparacin entre el 85o y 100o tokens. La correccin que permite que el analizador para analizar ms lejos ms all del error reportado original se toma como la mejor reparacin del error. Por lo tanto, si una sola sustitucin de tokens de var para el tipo en el token 98a Permite que el motor de anlisis de proceder ms all de la seal 104a sin atorarse, esta reparacin es un xito. Generalmente, si el analizador para la reparacin lleva R = 4 tokens all donde originalmente se atasc, esto es "lo suficientemente bueno."
La ventaja de esta tcnica es que el LL (k) o LR (k) (o LALR, etc). Gramtica no se modifica en absoluto (no hay producciones de error), ni las tablas de anlisis se modifican. Slo el motor de anlisis, que interpreta las tablas de anlisis sintctico, se modifica.
El motor de anlisis debe ser capaz de copia de seguridad de los tokens K y reanlisis. Para ello, es necesario recordar lo que la pila de anlisis sintctico que pareca tokens K en agosto Por lo tanto, el algoritmo mantiene dos pilas de anlisis sintctico: la pila actual y la antigua pila. Una cola de tokens K se mantiene; ya que cada nuevo token se desplaza, se inserta en la pila actual y tambin poner en la cola de la cola; al mismo tiempo, se retira la cabeza de la cola y se movi hacia la vieja pila. Con cada cambio en la edad o la corriente de pila, el veterano apropiada tambin se llevan a cabo las acciones. Figura 3:39 Ilustra las dos pilas y colas.
Ahora supongamos que se detecta un error de sintaxis en el smbolo actual. Para cada posible insercin, eliminacin o sustitucin de una ficha en cualquier posicin de la cola, el taller de reparacin de errores Burke-Fisher Eso hace que el cambio de dentro (una copia de) la cola, a continuacin, intenta reanlisis de la vieja pila. El xito de una modificacin es en el nmero de tokens pasados token actual se pueden analizar; Generalmente, si tres o cuatro nuevas fichas se pueden analizar, esto se considera una reparacin totalmente exitosa.
En un lenguaje con N tipos de fichas, hay K + K + K N N posibles supresiones, inserciones y sustituciones dentro de la ventana de smbolo K. Intentar esto muchas reparaciones no es muy costoso, que, sobre todo teniendo en cuenta que slo se da cuando se descubre un error de sintaxis, no ordinaria durante el anlisis.
Acciones semnticas. Shift y reducir las acciones se juzgan y se desechan en varias ocasiones durante la bsqueda de la mejor reparacin del error. Generadores de analizadores sintcticos por lo general usted realizar acciones semnticas programador especificados junto con cada accin de veterano, pero el programador no espera que estas acciones se llevarn a cabo varias veces y se descartan - pueden tener efectos secundarios. Por lo tanto, a Burke-Fisher parser no ejecuta ninguna de las acciones semnticas como reducciones se realizan en la pila actual, sino que espera hasta que las mismas se llevan a cabo reducciones (de forma permanente) en la vieja pila.
Esto significa que el analizador lxico puede ser de hasta tokens K + R para apuntar a la cabeza de la cual las acciones semnticas no han sido realizados. Si las acciones semnticas afectan anlisis lxico - como lo hacen en C, compilar la funcin typedef - esto puede ser un problema con el enfoque de Burke-Fisher. Para idiomas con un enfoque de la gramtica libre de contexto puro a la sintaxis, las acciones semnticas de la demora no plantea ningn problema.
Valores semnticos para inserciones.
En la reparacin de un error de insercin, el intrprete necesita Previsto valor semntico de cada token se inserta, de manera que las acciones semnticas se pueden realizar como si el testigo haba venido desde el analizador lxico. Para fichas de puntuacin sin valor es necesario, pero cuando tokens: como nmeros o identificadores deben insertarse, en donde el valor puede venir? El generador de analizadores ML-Yacc, que utiliza Burke correccin Fischer-error, tiene una directiva valor%, lo que permite al programador especificar qu valor se debe utilizar cuando la insercin de cada tipo de token:
Programador sustituciones especificadas. Algunos tipos comunes de errores no pueden ser reparados por la insercin o delecin de un nico token, ya veces una sola insercin smbolo especial o sustitucin es muy general, son necesarios y deben ser juzgados primero. Por lo tanto, en una especificacin de la gramtica ML-Yacc el programador puede utilizar la directiva% de cambio para sugerir correcciones de errores a ser juzgado en primer lugar, antes del default "eliminar o insertar cada token posible" reparaciones.
Aqu el programador est sugiriendo que a menudo los usuarios escriben "; otro ", donde su significado" else "y as sucesivamente. Estas correcciones de errores particulares son a menudo tiles para analizar el lenguaje de programacin ML. La insercin de 0 en el extremo Particularmente importante es un tipo de correccin, conocido como un mbito de aplicacin ms cerca. Programas Comnmente han dejado adicional o derecho Parntesis Los parntesis, corchetes o extrajudicial izquierda oa la derecha, y as sucesivamente. En ML, otro tipo de construccin de anidacin es dejar entrar final. Si el programador se olvida de cerrar un alcance que fue abierto por un parntesis izquierdo, luego el singletoken automtica heurstica de insercin puede cerrar este mbito donde es necesario. Pero para cerrar dejar escobas requiere la insercin de tres fichas, que no se puede hacer de forma automtica A menos que el compilador de escritor ha sugerido "cambiar nada para terminar en 0" como se ilustra en el comando de cambio% por encima.