0
votes

I'm trying to solve a pretty simple grammar problem (I just started learning about using ANTLR to develop grammars; I'm a bit new so just bear with me) which is to define a signed even number using ANTLR.

A '+' or '-'for the start token is optional, and the number can be 1 or more digits but the last digit must be even (for example,+4394would be a valid signed even number).

The best grammar I have so far is as follows:

grammar SignedEvenNumber;

DIGIT           : '0'..'9';
EVEN_DIGIT      : '0' | '2' | '4' | '6' | '8';

signedEvenNumber    : ('+' | '-' | ) NUMBER+ EVEN_NUMBER;

My issue is defining digits in a way that forces ANTLR to check for an even digit as the last digit; i.e. it always sees the last digit as DIGIT, regardless of it being even or odd (because any digit before the final can be either). There might be a really simple solution that I'm just not getting but any help would be appreciated.

3

3 Answers

0
votes

I have more experience with ANTLR 4 but i think that the token defined first has priority over the others defined after in the grammer, so define first EVEN_DIGIT:

grammar SignedEvenNumber;

EVEN_DIGIT      : '0' | '2' | '4' | '6' | '8';
DIGIT           : '0'..'9';

signedEvenNumber    : ('+' | '-')? DIGIT+ EVEN_DIGIT;

the tokens in the .tokens file are:

DIGIT=4
T__1=1
EVEN_DIGIT=3
T__0=2
'-'=2
'+'=1

For Input test:

+1234

the tokens are:

[@0,0:0='+',<1>,1:0]
[@1,1:1='1',<4>,1:1]
[@2,2:2='2',<3>,1:2]
[@3,3:3='3',<4>,1:3]
[@4,4:4='4',<3>,1:4]

if the priority doen't work you can redefine your tokens and change the rule like this:

grammar SignedEvenNumber;

EVEN_DIGIT      : '0' | '2' | '4' | '6' | '8';
DIGIT           : '1' | '3' | '5' | '7' | '9';

signedEvenNumber    : ('+' | '-')? (DIGIT | EVEN_DIGIT)* EVEN_DIGIT;
0
votes

if you define EVEN and NOT_EVEN as disjoint tokens you could have

 SignedEvenNumber : ('+' | '-')? (NOT_EVEN* EVEN)+

since the even numbers form a regular language you can think of it as a DFA.

0
votes

Is it necessary to be distinguished by DFA? What about using rule actions?

tokens {
  EVEN_NUMBER;
  ODD_NUMBER;
};

fragment
NUMBER_FRAG: DIGIT+;

NUMBER: t = NUMBER_FRAG
{
   if ($t->getText()->lastDigitIsEven())
   {   $type = EVEN_NUMBER; }
   else
   {   $type = ODD_NUMBER; }
};