Antlr : 날짜와 숫자를 인식하는 가장 간단한 방법?
문제
동일한 문법에서 유효한 날짜와 숫자를 모두 구문 분석하는 가장 단순한 (가장 짧고, 가장 적은 규칙 및 경고 없음)는 무엇입니까? 내 문제는 유효한 달 (1-12)과 일치하는 Lexer 규칙이 1-12의 발생과 일치한다는 것입니다. 숫자를 일치시키려면 다음과 같은 구문 분석 규칙이 필요합니다.
number: (MONTH|INT);
낮과 연도에 Lexer 규칙을 추가 할 때만 더 복잡해집니다. 나는 다음과 같은 날짜의 구문 분석 규칙을 원한다 :
date: month '/' day ( '/' year )? -> ^('DATE' year month day);
나는 달, 요일 및 연도가 구문 분석 또는 렉서 규칙인지 상관하지 않습니다. 같은 나무 구조로 끝나는 한. 또한 다른 곳에서 숫자를 인식 할 수 있어야합니다.
foo: STRING OP number -> ^(OP STRING number);
STRING: ('a'..'z')+;
OP: ('<'|'>');
해결책
문제는 Lexer 및/또는 파서에서 구문 및 의미 적 검사를 수행하고 싶다는 것입니다. 그것은 일반적인 실수이며 매우 간단한 언어로만 가능한 것입니다.
당신이 정말로해야 할 일은 Lexer와 Parser에서 더 광범위하게 받아들이고 의미 론적 검사를 수행하는 것입니다. 당신이 당신의 록싱에 얼마나 엄격한 지, 그러나 당신은 매월의 날에 앞서 제로를 받아 들여야하는지 여부에 따라 두 가지 기본 옵션이 있습니다. 1) ints를 실제로 받아들이십시오. 유효한 날이지만 유효한 int는 유효한 토큰 만 허용합니다. 코드의 뒷부분에서 필요한 의미 론적 점검이 적을 것이기 때문에 두 번째 권장 (INTS는 구문 수준에서 확인 가능하므로 날짜에 시맨틱 검사 만 수행하면됩니다. 첫 번째 접근법 : 첫 번째 접근 방식 :.
INT: '0'..'9'+;
두 번째 접근법 :
DATENUM: '0' '1'..'9';
INT: '0' | SIGN? '1'..'9' '0'..'9'*;
Lexer 에서이 규칙을 사용하는 후에는 날짜 필드가 다음과 같습니다.
date: INT '/' INT ( '/' INT )?
또는:
date: (INT | DATENUM) '/' (INT | DATENUM) ('/' (INT | DATENUM) )?
그 후, 당신은 당신의 날짜가 유효한지 확인하기 위해 당신의 AST를 통해 시맨틱 런을 수행합니다.
그러나 문법에서 시맨틱 점검을 수행하는 데 세워진 경우 ANTLR은 구문 분석기에서 시맨틱 곤경을 허용하므로 다음과 같은 값을 확인하는 날짜 필드를 만들 수 있습니다.
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];