JavaCC - Sintaxis JavaCC: Detalles: Producciones production

Las especificaciones léxicas y sintácticas de JavaCC se describen por medio de las producciones production.

production
En JavaCC existen cuatro tipos de producciones diferentes:

production ::= javacode_production
| regular_expr_production
| bnf_production
| token_manager_decls

javacode_production y bnf_production se utilizan para definir la gramática para la cual se genera el parser, mientras que regular_expr_production se utiliza para definir los tokens de la gramática, en base a los cuales se genera el token manager, y token_manager_decls se utiliza para introducir declaraciones que serán insertadas en el token manager.

El parser que se genera posee la declaración de un método público para cada no terminal del archivo de la gramática, y para ello se utilizan las producciones javacode y/o bnf, explicadas más abajo. El parseo puede realizarse en relación a cualquier no terminal, siempre que se lo explicite en la gramática.

regular_exp_production
Las producciones expresión regular se utilizan para definir entidades léxicas del lenguaje, que podrán ser procesadas por el token manager.
Cada expresión regular comienza con la especificación de la lista de estados léxicos para los que puede aplicarse dicha producción. Existe un estado léxico standard denominado "DEFAULT", y si la lista de estados se omite, se asume que la producción se aplica al estado DEFAULT.
Seguidamente se indica qué clase tipo de producción es (TOKEN, SPECIAL_TOKEN, SKIP o MORE).
Posteriormente, puede hallarse un IGNORE_CASE opcional. Si está presente, la producción no distingue mayúsculas de minúsculas, es decir que tiene el mismo efecto que la opción de personalización IGNORE_CASE, pero en este caso es de aplicación local a la producción que está modificando.
Las nociones referidas a expresiones regulares, se hallan desarrolladas con mayor detalle en la sección dedicada al análisis léxico.
javacode_production
Las producciones javacode son una forma de escribir código Java para alguna producción, en lugar de escribir las producciones BNF o BNF extendidas que se utilizan normalmente. Mayormente, son utilizadas cuando debe reconocerse alguna entidad que no es libre de contexto. Sin embargo, deben ser utilizadas con cuidado, dado que aunque permiten realizar acciones definidas por el usuario, JavaCC las considera una caja negra, lo cual las transforma en un problema cuando aparecen como lookahead de alguna rama condicional dentro de las producciones, porque JavaCC no puede saber qué opción escoger; para evitar dicho problema, debería preverse la utilización de algún lookahead antes del nombre de la producción.
Por ejemplo, si se define una acción que chequea que las llaves de apertura y cierre de una expresión estén balanceadas, se obtendría el siguiente código:
Pero si esta acción se invoca en una producción con varias opciones en su parte derecha, como por ejemplo:
JavaCC no sabrá qué opción elegir entre las dos, ya que ninguna especifica un token inicial que distinga a la producción de la otra.
bnf_production
Las producciones BNF son las producciones usadas para la especificación de la sintaxis del lenguaje. Normalmente, cada producción BNF tiene una parte izquierda constituída por un no terminal, que se define mediante las expansiones del lado derecho. Un ejemplo de producción BNF sería el siguiente:

expresion() ::= factor() "*" factor()

donde expresion es el no terminal que se expande como la multiplicación de dos factores (lado derecho de la producción).
En JavaCC, las producciones BNF se escriben como métodos, donde el nombre del método se corresponde con el nombre del no terminal, y el cuerpo de dicho método, se corresponde con la parte derecha de la producción, y la aparición de otros no terminales en el cuerpo de la producción, se considera una invocación a los métodos que poseen dichos nombres. Los parámetros y valores de retorno declarados son los medios para pasar los valores de los atributos heredados y sintetizados, respectivamente, en el árbol de parsing. En el caso del ejemplo anterior, la producción se escribiría de la siguiente manera (carece de parámetros y valores de retorno, dado que sólo se pretende efectuar un reconocimiento sintáctico):
void expresion() : {}
{
factor()
"*"
factor()
}
En el lado derecho de las producciones BNF se distinguen dos partes.

La primera está compuesta por un conjunto de código y declaraciones Java , el java_block. Dicho código, se genera al comienzo del método generado por el no-terminal Java. A partir de allí, cada vez que el no terminal se usa en el proceso de parsing, las declaraciones y el código son ejecutados. Las declaraciones en esta parte son visibles en todo el código Java de las acciones asociadas a las expansiones de las producciones BNF.

La segunda parte del lado derecho de la producción, es propiamente la expansión del no terminal.
token_manager_decls
Las declaraciones para el token manager comienzan con la palabra reservada TOKEN_MGR_DECLS seguida por ":" y a continuación un conjunto de declaraciones y sentencias Java, conformando un Java Block. Estas declaraciones y sentencias se escriben en el token manager generado y son accesibles desde las acciones léxicas.