ANTLR Date and Integer Matching
antlr
Solution
After the lexer matches a `INTEGER`, you can inspect its matched text (referenced through `$text`), and based on that custom check, decide to change it's type from `INTEGER` to `DATE`. The `DATE` rule can be made as an empty `fragment` rule, and can then be used inside a parser rule just as if it were a normal lexer rule.
A quick demo:
INTEGER
: DIGIT+
{
// If this token starts with either '19' or '20', followed
// by 6 digits, change it to a DATE-token.
if ($text.matches("(19|20)\\d{6}")) {
$type = DATE;
}
}
;
fragment DATE : /* empty! */ ;
And then in a parser rule, you can just use `DATE`:
dateEvaluation
: DATE ...
;
Problem
I am evaluating a relatively simple IF/THEN language but have run into a problem: I need to match both integers AND dates that are in the format YYYYMMDD. If I could write a real regular expression I could solve this pretty easily, but haven't figured out an ANTLR solution. Grammar looks like this: ``` //overall rule to evaluate a single expression singleEvaluation returns [boolean evalResult] : integerEvaluation {$evalResult = $integerEvaluation.evalResult;} | dateEvaluation {$evalResult = $dateEvaluation.evalResult;} // etc ; dateEvaluation returns [boolean evalResult] : expr1=(INTEGER|'TODAY'|DATE_FIELD_IDENTIFIER) (leftOp=('+'|'-') leftModifier=INTEGER leftQualifier=DATE_QUALIFIER)? operator=(EQ|NE|LT|LE|GT|GE) expr2=(INTEGER|'TODAY'|DATE_FIELD_IDENTIFIER) (rightOp=('+'|'-') rightModifier=INTEGER rightQualifier=DATE_QUALIFIER)? { // code } integerEvaluation returns [boolean evalResult] : expr1=(NUM_FIELD_IDENTIFIER|INTEGER) operator=(EQ|NE|LT|LE|GT|GE) expr2=(NUM_FIELD_IDENTIFIER|INTEGER) { // code } ; fragment DIGIT: '0'..'9'; INTEGER: DIGIT+; DATE_FIELD_IDENTIFIER: ('DOB'|'DATE_OF_HIRE'); NUM_FIELD_IDENTIFIER: ('AGE'|'DEPARTMENT_ID'); DATE_QUALIFIER:('YEAR'|'YEARS'|'MONTH'|'MONTHS'|'DAY'|'DAYS'|'TODAY'); EQ:'='; NE: '<>'; LT: '<'; LE: '<='; GT: '>'; GE: '>='; ``` An example of a statement needing to be parsed would be something like "65 > AGE" or "AGE < 65", or "DOB > 19500101". Can someone suggest a way to make the parser differentiate between an INTEGER and the 8 digit date format?