Katie Gerot
Katie Gerot

Reputation: 33

How to get the line of a token in parse rules?

I have searched everywhere and can't find a solution. I am new to ANTLR and for an assignment, I need to print out (using similar syntax that I have below) an error message when my parser comes across an unidentified token with the line number and token. The documentation for antlr4 says line is an attribute for Token objects that gives "[t]he line number on which the token occurs, counting from 1; translates to a call to getLine. Example: $ID.line."

I attempted to implement this in the following chunk of code:

not_valid : not_digit { System.out.println("Line " + $not_digit.line + " Contains  Unrecognized  Token " $not_digit.text)}; 
not_digit :  ~( DIGIT );

But I keep getting the error

unknown attribute line for rule not_digit in $not_digit.line

My first thought was that I was applying an attribute for a lexer token to a parser rule because the documentation splits Token and Rule attributes into two different tables. so then I change the code to be:

not_valid : NOT_DIGIT { System.out.println("Line " + $NOT_DIGIT.line + " Contains  Unrecognized  Token " $NOT_DIGIT.text)}; 
NOT_DIGIT :  ~ ( DIGIT ) ;

and also

not_valid : NOT_DIGIT { System.out.println("Line " + $NOT_DIGIT.line + " Contains  Unrecognized  Token " $NOT_DIGIT.text)}; 
NOT_DIGIT :  ~DIGIT ;

like the example in the documentation, but both times I got the error

rule reference DIGIT is not currently supported in a set

I'm not sure what I am missing. All my searches turn up how to do this in Java outside of the parser, but I need to work in the action code (I think that's what it is called) in the parser.

Upvotes: 3

Views: 993

Answers (1)

Bart Kiers
Bart Kiers

Reputation: 170227

A block like { ... } is called an action. You embed target specific code in it. So if you're working with Java, then you need to write Java between { and }

A quick demo:

grammar T;

parse
 : not_valid EOF
 ;

not_valid
 : r=not_digit
   {
     System.out.printf("line=%s, charPositionInLine=%s, text=%s\n",
         $r.start.getLine(),
         $r.start.getCharPositionInLine(),
         $r.start.getText()
     );
   }
 ;

not_digit
 :  ~DIGIT
 ;

DIGIT
 : [0-9]
 ;

OTHER
 : ~[0-9]
 ;

Test it with the code:

String source = "a";
TLexer lexer = new TLexer(CharStreams.fromString(source));
TParser parser = new TParser(new CommonTokenStream(lexer));
parser.parse();

which will print:

line=1, charPositionInLine=0, text=a

Upvotes: 1

Related Questions