I find it hard to believe that, aside from the grammar for the while loop, there is no mention of how to implement any visitors/listeners or actions for a simple While loop in the book written by Terence Parr.
That is because the ANTLR reference is about ANTLR, which is about parsing, not about the stage after parsing.
You can't do this:
@Override public boolean visitGreaterEqual(GreaterEqualContext ctx) { ...
You've already declared your visitor to return Integer
s, so that's what every rule should return. Either make a custom wrapper Value
that encapsulates your language's values (numbers, string, booleans), or just return 0
when a relation expression is false:
@Override
public Integer visitGreaterEqual(ExprParser.GreaterEqualContext ctx) {
int left = this.visit(ctx.expr(0));
int right = this.visit(ctx.expr(1));
if (ctx.op.getType() == ExprParser.GREATER) {
return left > right ? 1 : 0; // 0 is false (all other values are true)
}
else {
return left < right ? 1 : 0;
}
}
Then you can write your while
as follows:
@Override
public Integer visitWhile(ExprParser.WhileContext ctx) {
// Evaluate the relational expression and continue the while
// loop as long as it is true (does not equal zero).
while (this.visit(ctx.relational()) != 0) {
// Evaluate all statements inside the while loop.
for (ExprParser.StatContext stat : ctx.stat()) {
this.visit(stat);
}
}
// 0 now also is false, so maybe return null instead which would be
// some sort of VOID value (or make a proper Value class).
return 0;
}
Note that the code above will fail when nesting while
statements because the inner while would return 0
causing the outer while to stop looping. In such cases, you'd be better off creating a custom Value
class and introduce some sort of Value.VOID
instance that would not cause the loop to stop.
Running the following main method:
public static void main(String[] args) throws Exception {
String expression = "n = 1\n" +
"while (n < 10) {\n" +
" n\n" +
" n = n + 1\n" +
"}\n";
ExprLexer lexer = new ExprLexer(new ANTLRInputStream(expression));
ExprParser parser = new ExprParser(new CommonTokenStream(lexer));
new EvalVisitor().visit(parser.prog());
}
would print:
1 2 3 4 5 6 7 8 9
Also have a look at this demo language that uses ANTLR4 and if
and while
statements, as well as a custom Value
object: https://github.com/bkiers/Mu