简体   繁体   中英

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?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM