Antlr:识别日期和数字的最简单方法?

Antlr:识别日期和数字的最简单方法?,antlr,grammar,Antlr,Grammar,在同一语法中解析有效日期和数字的最简单(最短、最少规则和无警告)方法是什么?我的问题是,匹配有效月份(1-12)的lexer规则将匹配1-12的任何事件。因此,如果我只想匹配一个数字,我需要一个解析规则,如: number: (MONTH|INT); 当我为日和年添加lexer规则时,它只会变得更复杂。我想要一个日期解析规则,如下所示: date: month '/' day ( '/' year )? -> ^('DATE' year month day); date: month=

在同一语法中解析有效日期和数字的最简单(最短、最少规则和无警告)方法是什么?我的问题是,匹配有效月份(1-12)的lexer规则将匹配1-12的任何事件。因此,如果我只想匹配一个数字,我需要一个解析规则,如:

number: (MONTH|INT);
当我为日和年添加lexer规则时,它只会变得更复杂。我想要一个日期解析规则,如下所示:

date: month '/' day ( '/' year )? -> ^('DATE' year month day);
date: month=INT '/' day=INT ( year='/' INT )? { year==null ? (/* First check /*) : (/* Second check */)}
我不在乎月、日和年是解析规则还是lexer规则,只要我得到的是相同的树结构。我还需要能够识别其他地方的数字,例如:

foo: STRING OP number -> ^(OP STRING number);
STRING: ('a'..'z')+;
OP: ('<'|'>');
foo:字符串操作编号->^(操作字符串编号);
字符串:('a'..'z')+;
OP:('');

问题在于,您似乎希望在词法分析器和/或解析器中执行语法和语义检查。这是一个常见的错误,而且只有在非常简单的语言中才可能出现

您真正需要做的是更广泛地接受lexer和parser,然后执行语义检查。词法分析的严格程度取决于您自己,但您有两个基本选项,这取决于您是否需要接受月日前的零:1)真正接受整数,2)定义DATENUM以仅接受有效天数的标记,而不是有效整数。我建议使用第二种方法,因为代码后面需要的语义检查会更少(因为INT将在语法级别上进行验证,并且您只需要对日期执行语义检查。第一种方法:

INT: '0'..'9'+;
DATENUM: '0' '1'..'9';
INT: '0' | SIGN? '1'..'9' '0'..'9'*;
第二种方法:

INT: '0'..'9'+;
DATENUM: '0' '1'..'9';
INT: '0' | SIGN? '1'..'9' '0'..'9'*;
在lexer中接受使用这些规则后,日期字段将为:

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

之后,您将对AST执行语义运行,以确保日期有效

但是,如果您一心想在语法中执行语义检查,ANTLR允许在解析器中使用语义谓词,因此您可以创建一个日期字段来检查如下值:

date: month '/' day ( '/' year )? -> ^('DATE' year month day);
date: month=INT '/' day=INT ( year='/' INT )? { year==null ? (/* First check /*) : (/* Second check */)}

但是,当您这样做时,您将在语法中嵌入特定于语言的代码,并且无法跨目标移植。

使用ANTLR4,这里是我使用的一个简单的组合语法。它使用lexer只匹配简单的标记,而让解析器规则解释日期和数字

// 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];