2008-09-26 17 views
5

¿Cuál es la forma más sencilla (más corta, menos reglas y sin advertencias) de analizar ambas fechas y números válidos en la misma gramática? Mi problema es que una regla lexer para coincidir con un mes válido (1-12) coincidirá con cualquier ocurrencia de 1-12. Así que si sólo quiero que coincida con un número, necesito una regla de análisis como:Antlr: ¿La forma más simple de reconocer fechas y números?

number: (MONTH|INT); 

Sólo se pone más complejo cuando agrego reglas analizadoras para el día y el año. Quiero una regla de análisis para la fecha de la siguiente manera:

date: month '/' day ('/' year)? -> ^('DATE' year month day); 

No me importa si el mes, el día & años son las reglas de análisis sintáctico o analizadoras, con tal de que termino con la misma estructura de árbol. También tengo que ser capaz de reconocer los números en otros lugares, por ejemplo .:

foo: STRING OP number -> ^(OP STRING number); 
STRING: ('a'..'z')+; 
OP: ('<'|'>'); 

Respuesta

5

El problema es que parece que quiere realizar la comprobación tanto sintáctico y semántico en su léxico y/o su analizador. Es un error común, y algo que solo es posible en idiomas muy simples.

Lo que realmente necesita hacer es aceptar más ampliamente en el lexer y el analizador, y luego realizar comprobaciones semánticas. Qué tan estricto eres en tu lexing depende de ti, pero tienes dos opciones básicas, dependiendo de si necesitas o no aceptar ceros que preceden tus días del mes: 1) Realmente aceptas tus INTs, 2) define DATENUM para solo acepta aquellos tokens que sean días válidos, pero que no sean INT válidos. Recomiendo el segundo porque habrá menos verificaciones semánticas necesarias más adelante en el código (ya que las INT serán verificables en el nivel de sintaxis y solo tendrá que realizar comprobaciones semánticas en las fechas. El primer enfoque:

INT: '0'..'9'+; 

el segundo enfoque:

DATENUM: '0' '1'..'9'; 
INT: '0' | SIGN? '1'..'9' '0'..'9'*; 

Después de aceptar el uso de estas reglas en el léxico, su campo de fecha podría ser:

date: INT '/' INT ('/' INT)? 

o:

date: (INT | DATENUM) '/' (INT | DATENUM) ('/' (INT | DATENUM))? 

Después de eso, realizará una ejecución semántica sobre su AST para asegurarse de que sus fechas sean válidas.

Si está empeñado en realizar comprobaciones semánticas en su gramática, sin embargo, permite antlr predicados semánticos en el analizador, por lo que podría hacer que un campo de fecha que comprueba los valores de la siguiente manera:

date: month=INT '/' day=INT (year='/' INT)? { year==null ? (/* First check /*) : (/* Second check */)} 

Cuando Sin embargo, si hace esto, está incorporando un código específico del idioma en su gramática, y no será portátil entre los objetivos.

0

Usando ANTLR4, aquí hay una gramática combinada simple que he usado. Utiliza el lexer para hacer coincidir tokens simples, dejando las reglas del analizador para interpretar las fechas y los números.

// parser rules 

date 
    : INT SEPARATOR month SEPARATOR INT 
    | INT SEPARATOR month SEPARATOR INT4 
    | INT SEPARATOR INT SEPARATOR INT4; 

month : JAN | FEB | MAR | APR | MAY | JUN | JUL | AUG | SEP | OCT | NOV | DEC ; 

number : FLOAT | INT | INT4 ; 

// lexer rules 

FLOAT : DIGIT+ '.' DIGIT+ ; 

INT4 : DIGIT DIGIT DIGIT DIGIT; 
INT : DIGIT+; 

JAN : [Jj][Aa][Nn] ; 
FEB : [Ff][Ee][Bb] ; 
MAR : [Mm][Aa][Rr] ; 
APR : [Aa][Pp][Rr] ; 
MAY : [Mm][Aa][Yy] ; 
JUN : [Jj][Uu][Nn] ; 
JUL : [Jj][Uu][Ll] ; 
AUG : [Aa][Uu][Gg] ; 
SEP : [Ss][Ee][Pp] ; 
OCT : [Oo][Cc][Tt] ; 
NOV : [Nn][Oo][Vv] ; 
DEC : [Dd][Ee][Cc] ; 

SEPARATOR : [/\\\-] ; 

fragment DIGIT : [0-9]; 
Cuestiones relacionadas