Search code examples
parsinglistenerantlrantlr4grammar

Breaking head over how to get position of token with a rule - ANTLR4 / grammar


I'm writing a little grammar using ANLTR, and I have a rule like this:

operation   : OPERATION (IDENT | EXPR) ',' (IDENT | EXPR);
...

OPERATION   : 'ADD' | 'SUB' | 'MUL' | 'DIV' ;
IDENT       : [a-z]+;
EXPR        : INTEGER | FLOAT;
INTEGER     : [0-9]+ | '-'[0-9]+
FLOAT       : [0-9]+'.'[0-9]+ | '-'[0-9]+'.'[0-9]+

Now in the listener inside Java, how do I determine in the case of such a scenario where an operation consist of both IDENT and EXPR the order in which they appear? Obviously the rule can match both ADD 10, d or ADD d, 10 But in the listener for the rule, generated by ANTLR4, if there is both IDENT() and EXPR() how to get their order, since I want to assign the left and right operands correctly.

Been breaking my head over this, is there any simple way or should I rewrite the rule itself? The ctx.getTokens () requires me to give the token type, which kind of defeats the purpose, since I cannot get the sequence of the tokens in the rule, if I specify their type.


Solution

  • You can do it like this:

    operation : OPERATION lhs=(IDENT | EXPR) ',' rhs=(IDENT | EXPR);
    

    and then inside your listener, do this:

    @Override
    public void enterOperation(TParser.OperationContext ctx) {
      if (ctx.lhs.getType() == TParser.IDENT) {
        // left hand side is an identifier
      } else {
        // left hand side is an expression
      }
    
      // check `rhs` the same way
    }
    

    where TParser comes from the grammar file T.g4. Change this accordingly.

    Another solution would be something like this:

    operation
     : OPERATION ident_or_expr ',' ident_or_expr
     ;
    
    ident_or_expr
     : IDENT
     | EXPR
     ;
    

    and then in your listener:

    @Override
    public void enterOperation(TParser.OperationContext ctx) {
      Double lhs = findValueFor(ctx.ident_or_expr().get(0));
      Double rhs = findValueFor(ctx.ident_or_expr().get(1));
    
      ...
    }
    
    private Double findValueFor(TParser.Ident_or_exprContext ctx) {
      if (ctx.IDENT() != null) {
        // it's an identifier
      } else {
        // it's an expression
      }
    }