2009-04-26 13 views
5

Me enseño a utilizar JavaCC en un proyecto de hobby, y tengo una gramática simple para escribir un analizador. Parte del analizador incluye lo siguiente:Explicación y solución para la advertencia de JavaCC "Elección de expresión regular: ¿FOO nunca puede coincidir como: BAR"?

TOKEN : { < DIGIT : (["0"-"9"]) > } 
TOKEN : { < INTEGER : (<DIGIT>)+ > } 
TOKEN : { < INTEGER_PAIR : (<INTEGER>){2} > } 
TOKEN : { < FLOAT : (<NEGATE>)? <INTEGER> | (<NEGATE>)? <INTEGER> "." <INTEGER> | (<NEGATE>)? <INTEGER> "." | (<NEGATE>)? "." <INTEGER> > } 
TOKEN : { < FLOAT_PAIR : (<FLOAT>){2} > } 
TOKEN : { < NUMBER_PAIR : <FLOAT_PAIR> | <INTEGER_PAIR> > } 
TOKEN : { < NEGATE : "-" > } 

Al compilar con JavaCC me sale la salida:

Warning: Regular Expression choice : FLOAT_PAIR can never be matched as : NUMBER_PAIR 

Warning: Regular Expression choice : INTEGER_PAIR can never be matched as : NUMBER_PAIR 

Estoy seguro de que este es un concepto simple, pero no entiendo el aviso, siendo un principiante tanto en generación de analizador como en expresiones regulares.

¿Qué significa esta advertencia (en términos de "principiante como se puede obtener")?

Respuesta

4

No conozco JavaCC, pero soy un ingeniero compilador.

La regla FLOAT_PAIR es ambigua. Considere el siguiente texto:

0.0 

Esto podría ser seguido por FLOAT 0FLOAT .0; o podría ser FLOAT 0. seguido de FLOAT 0; ambos dando como resultado FLOAT_PAIR. O podría ser un solo FLOAT 0.0.

Lo que es más importante, sin embargo, está utilizando análisis léxico con composición de una manera que probablemente nunca funcionará. Considere este número:

12345 

Esto se pudo analizar como INTEGER 12, INTEGER 345 que resulta en un INTEGER_PAIR. O podría analizarse como INTEGER 123, INTEGER 45, otro INTEGER_PAIR. O podría ser INTEGER 12345, otro token. El problema existe porque no necesita espacio en blanco entre los elementos léxicos del INTEGER_PAIR (o FLOAT_PAIR).

Casi nunca debe tratar de manejar pares como este en el lexer. En su lugar, debe manejar los números simples (INTEGER y FLOAT) como tokens, y manejar cosas como la negación y el emparejamiento en el analizador, donde se ha tratado y eliminado el espacio en blanco.

(Por ejemplo, ¿cómo vas a procesar "----42"?Esta es una expresión válida en la mayoría de los lenguajes de programación, que calculará correctamente múltiples negaciones, pero no será manejada por su lexer).

Además, tenga en cuenta que los enteros de un solo dígito en su lexer no coincidirán con INTEGER, saldrán como DIGIT. No obstante, no sé la sintaxis correcta para que JavaCC lo arregle. Lo que quiere es definir DIGIT no como un token, sino simplemente algo que puede usar en las definiciones de otros tokens; alternativamente, incruste la definición de DIGIT ([0-9]) directamente dondequiera que esté usando DIGIT en sus reglas.

0

No he usado JavaCC, pero es posible que NUMBER_PAIR sea ambiguo.

Creo que el problema se debe al hecho de que puede coincidir exactamente lo mismo que FLOAT_PAIR y INTEGER_PAIR, ya que FLOAT puede coincidir con un INTEGER.

Pero esto es sólo una suposición ya que nunca había visto la sintaxis JavaCC :)

+0

No estoy seguro de eso, cambié Float para que no coincida con Integer - {)? "." | ()? "." | ()? "." >}, y todavía recibió la advertencia. Estoy sorprendido por eso, porque lo que dijiste parecía perfectamente lógico :) – Grundlefleck

+0

Hmm ... Sigo pensando que está relacionado con la ambigüedad, pero sinceramente, dado que no he probado JavaCC, no soy de ninguna utilidad para ti aquí ... Voy a diferir y espero que alguien que sabe que responderá. – Uri

0

Probablemente significa que por cada FLOAT_PAIR vas a tener una ficha FLOAT_PAIR, nunca un símbolo NUMBER_PAIR. La regla FLOAT_PAIR ya coincide con todas las entradas y JavaCC no intentará encontrar otras reglas de coincidencia. Esa sería mi interpretación, pero no conozco JavaCC, así que tómalo con un grano de sal.

Quizás pueda especificar de alguna manera que NUMBER_PAIR es la producción principal y que no desea obtener ningún otro token como resultado.

0

Gracias a la respuesta de Barry Kelly, la solución que yo he llegado con es:

SKIP : { < #TO_SKIP : " " | "\t" > } 
    TOKEN : { < #DIGIT : (["0"-"9"]) > } 
    TOKEN : { < #DIGITS : (<DIGIT>)+ > } 
    TOKEN : { < INTEGER : <DIGITS> > } 
    TOKEN : { < INTEGER_PAIR : (<INTEGER>) (<TO_SKIP>)+ (<INTEGER>) > } 
    TOKEN : { < FLOAT : (<NEGATE>)?<DIGITS>"."<DIGITS> | (<NEGATE>)?"."<DIGITS> > } 
    TOKEN : { < FLOAT_PAIR : (<FLOAT>) (<TO_SKIP>)+ (<FLOAT>) > } 
    TOKEN : { < #NUMBER : <FLOAT> | <INTEGER> > } 
    TOKEN : { < NUMBER_PAIR : (<NUMBER>) (<TO_SKIP>)+ (<NUMBER>) >} 
    TOKEN : { < NEGATE : "-" > } 

me había olvidado por completo para incluir el espacio que se utiliza para separar las dos fichas, también he utilizado el El símbolo '#' que detiene la coincidencia de los tokens, y solo se usa en la definición de otros tokens. Lo anterior es compilado por JavaCC sin advertencia o error.

Sin embargo, como señaló Barry, existen razones para no hacer esto.

Cuestiones relacionadas