In The Definitive ANTLR Reference you can find examples of complex lexers where much of the work is done. But when learning ANTLR, I would advise to consider the lexer mostly for its splitting function of the input stream into small tokens. Then do the big work in the parser. In the present case I would do :
grammar Question;
/* extract digit */
question
: tpin EOF
;
tpin
// : PREFIX EXTRA? DIGIT+ SUFFIX?
// {System.out.println("The only useful information is " + $DIGIT.text);}
: PREFIX EXTRA? number SUFFIX?
{System.out.println("The only useful information is " + $number.text);}
;
number
: DIGIT+
;
PREFIX : [abcd]'_';
EXTRA : ('xyz' | 'XYZ' );
DIGIT : [0-9] ;
SUFFIX : [ab];
WS : [ \t\r\n]+ -> skip ;
Say the input is d_xyz123456b
. With the first version
: PREFIX EXTRA? DIGIT+ SUFFIX?
you get
$ grun Question question -tokens data.txt
[@0,0:1='d_',<PREFIX>,1:0]
[@1,2:4='xyz',<EXTRA>,1:2]
[@2,5:5='1',<DIGIT>,1:5]
[@3,6:6='2',<DIGIT>,1:6]
[@4,7:7='3',<DIGIT>,1:7]
[@5,8:8='4',<DIGIT>,1:8]
[@6,9:9='5',<DIGIT>,1:9]
[@7,10:10='6',<DIGIT>,1:10]
[@8,11:11='b',<SUFFIX>,1:11]
[@9,13:12='<EOF>',<EOF>,2:0]
The only useful information is 6
Because the parsing of DIGIT+
translates to a loop which reuses DIGIT
setState(12);
_errHandler.sync(this);
_la = _input.LA(1);
do {
{
{
setState(11);
((TpinContext)_localctx).DIGIT = match(DIGIT);
}
}
setState(14);
_errHandler.sync(this);
_la = _input.LA(1);
} while ( _la==DIGIT );
and $DIGIT.text
translates to ((TpinContext)_localctx).DIGIT.getText()
, only the last digit is retained. That's why I define a subrule number
: PREFIX EXTRA? number SUFFIX?
which makes it easy to capture the value :
[@0,0:1='d_',<PREFIX>,1:0]
[@1,2:4='xyz',<EXTRA>,1:2]
[@2,5:5='1',<DIGIT>,1:5]
[@3,6:6='2',<DIGIT>,1:6]
[@4,7:7='3',<DIGIT>,1:7]
[@5,8:8='4',<DIGIT>,1:8]
[@6,9:9='5',<DIGIT>,1:9]
[@7,10:10='6',<DIGIT>,1:10]
[@8,11:11='b',<SUFFIX>,1:11]
[@9,13:12='<EOF>',<EOF>,2:0]
The only useful information is 123456
You can even make it simpler :
tpin
: PREFIX EXTRA? INT SUFFIX?
{System.out.println("The only useful information is " + $INT.text);}
;
PREFIX : [abcd]'_';
EXTRA : ('xyz' | 'XYZ' );
INT : [0-9]+ ;
SUFFIX : [ab];
WS : [ \t\r\n]+ -> skip ;
$ grun Question question -tokens data.txt
[@0,0:1='d_',<PREFIX>,1:0]
[@1,2:4='xyz',<EXTRA>,1:2]
[@2,5:10='123456',<INT>,1:5]
[@3,11:11='b',<SUFFIX>,1:11]
[@4,13:12='<EOF>',<EOF>,2:0]
The only useful information is 123456
In the listener you have a direct access to these values through the rule context TpinContext
:
public static class TpinContext extends ParserRuleContext {
public Token INT;
public TerminalNode PREFIX() { return getToken(QuestionParser.PREFIX, 0); }
public TerminalNode INT() { return getToken(QuestionParser.INT, 0); }
public TerminalNode EXTRA() { return getToken(QuestionParser.EXTRA, 0); }
public TerminalNode SUFFIX() { return getToken(QuestionParser.SUFFIX, 0); }