Jason
Jason

Reputation: 4144

ANTLR Date and Integer Matching

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?

Upvotes: 3

Views: 1080

Answers (1)

Bart Kiers
Bart Kiers

Reputation: 170227

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 ...
 ;

Upvotes: 4

Related Questions