Parece que a veces el lector de Antlr hace una mala elección sobre la regla que se debe usar al tokenizar una secuencia de caracteres ... Estoy tratando de encontrar la manera de ayudar a Antlr a tomar la decisión más obvia a la humana. Quiero analizar el texto así:Antlr lexer tokens que coinciden con cadenas similares, ¿y si el codicioso lexer comete un error?
d/dt(x)=a
a=d/dt
d=3
dt=4
Esta es una sintaxis de un lenguaje desafortunado que los actuales usos y estoy tratando de escribir un analizador de. La "d/dt (x)" representa el lado izquierdo de una ecuación diferencial. Ignora la jerga si debes, solo debes saber que no está "d" dividida por "dt". Sin embargo, la segunda aparición de "d/dt" realmente es "d" dividida por "dt".
Aquí es mi gramática:.!
grammar diffeq_grammar;
program : (statement? NEWLINE)*;
statement
: diffeq
| assignment;
diffeq : DDT ID ')' '=' ID;
assignment
: ID '=' NUMBER
| ID '=' ID '/' ID
;
DDT : 'd/dt(';
ID : 'a'..'z'+;
NUMBER : '0'..'9'+;
NEWLINE : '\r\n'|'\r'|'\n';
Al utilizar esta gramática del analizador léxico agarra el primer "d/dt (" y lo convierte al DDT símbolo perfecto ahora más tarde, el analizador léxico ve la segunda "d" seguido de un "/" y dice "hmmm, puedo unir esto como un ID y un '/' o puedo ser codicioso y unir DDT". El lexer elige ser codicioso ... pero poco sabe, hay no "(" algunos caracteres más adelante en la secuencia de entrada. Cuando el lexer busca la falta "(" arroja una excepción MismatchedToken!
La única solución que he encontrado hasta ahora, es mover todas las reglas al analizador con un la gramática como:
grammar diffeq_grammar;
program : (statement? NEWLINE)*;
statement
: diffeq
| assignment;
diffeq : ddt id ')' '=' id;
assignment
: id '=' number
| id '=' id '/' id
;
ddt : 'd' '/' 'd' 't' '(';
id : CHAR+;
number : DIGIT+;
CHAR : 'a'..'z';
DIGIT : '0'..'9';
NEWLINE : '\r\n'|'\r'|'\n';
Ésta es una buena solución si no tuviera ya miles de líneas de código de trabajo que dependen de la primera gramática de trabajo. Después de pasar 2 días investigando este problema, he llegado a la conclusión de que un lexer ... realmente debería ser capaz de distinguir los dos casos. En algún momento, Antlr lexer está decidiendo entre dos reglas: DDT e ID. Elige DDT porque el lexer es codicioso. Pero cuando falla la coincidencia de DDT, me gustaría que el lexer vuelva a usar ID.
Estoy de acuerdo con el uso de predicados u otros trucos, siempre y cuando la gramática permanezca básicamente igual (es decir, las reglas en el lexer, permanecer en el lexer. Y la mayoría de las reglas no se tocan).
Idealmente, puedo modificar la regla de lexer para DDT con cualquier código Antlr válido ... y listo.
Mi idioma de destino es Java.
Gracias!
ACTUALIZACIÓN
Gracias chicos por algunos grandes respuestas !! Acepté la respuesta que mejor se ajustaba a mi pregunta. La solución real que utilicé está en mi propia respuesta (no la respuesta aceptada), y hay más respuestas que podrían haber funcionado. Lectores, revisen todas las respuestas; algunos de ellos pueden adaptarse a su caso mejor que el mío.
@dasblinkenlight, ya lo recomendó, por lo que el OP es consciente de ello: no es necesario que me convenza. Ya que el OP preguntó específicamente si la gramática podría seguir siendo mismo, publiqué esto. –
Tiene razón, me perdí la parte sobre "miles de líneas de código de trabajo" en la primera lectura. – dasblinkenlight
@dasblinkenlight, ¡aunque no quise que eliminaras tu respuesta! Aunque el OP quería cambiar su gramática lo menos posible, usted plantea un punto válido que merece una respuesta. –