Search code examples
compiler-constructionantlr4

Using Listener with Antlr4: How does the compiler know how to treat a variable lvalue as opposed to a rvalue?


In my grammar, variables start with the $, so

$a = 10

is valid. Of course, so is the following statement:

$c = $a + $b

My grammar treats variables with this (partial) definition;

start: (expr | stmt)* EOF ;

stmt
    : lvalue=id EQUAL assignexpr=expr # AssignId
    | declare EQUAL assignexpr=expr #DeclareAndAssign
    | declare # DeclareVar
    ;

expr
    : sign=(PLUS|MINUS) expr # signed_expr
    | LPAREN expr RPAREN # paren_exp
    | id # idval
    | value #constval
    | lvalue=expr op=(PLUS | MINUS | MULT |DIV) rvalue=expr # arith
    ;

Up until now, when I encounter a constant value in my listener, I simply issue an ICONST (assuming it's an integer) which pushes the value to the stack. When I get to a variable, I issue an ILOAD to grab the variable value and push it to the stack - which is fine as long as it's on the right side of a statement.

The problem I have is: when the variable is on the left side .. I need to not issue an ILOAD because the value is going to be overwritten and not popped from the stack at any point. So upon reaching this variable in code, I need a way of knowing how it's going to be used.

How can I know how to treat this variable $c? Do I need to change my grammar to more specifically treat this case? Do I need to walk the tree twice? How do people usually treat what must be a trivial, common case?


Solution

  • As you clarified in your comment, you're listening for ids, which is used by both assignments and variable expressions. If you listen for idvals instead, you'll only get variables that are used as expressions / rvalues.

    You can handle variables as lvalues directly in the listener for AssignId.