Reputation: 4144
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
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