java - Visitor/Listener code for a while loop in ANTLR 4 -
so far have searched whole "the definitive antlr 4 reference" book many sites answer question , still can't find on topic.
i using antlr 4 create sub-set of c language basic functionality. have no idea how implement simple while loop in visitor class. far got in grammar:
grammar expr; prog: stat+ ; stat: expr newline # printexpr | id '=' expr newline # assign | loop newline # whileloop | relational newline # relat | newline # blank ; expr: expr op=('*'|'/') expr # muldiv | expr op=('+'|'-') expr # addsub | int # int | id # id | '(' expr ')' # parens ; relational: expr op=(greater|less) expr # greaterequal ; loop: 'while' '('relational')' newline? '{'stat*'}' #while ; greater : '>' ; less : '<' ; mul : '*' ; // assigns token name '*' used above in grammar div : '/' ; add : '+' ; sub : '-' ; id : [a-za-z]+ ; // match identifiers int : [0-9]+ ; // match integers newline:'\r'? '\n' ; // return newlines parser (is end-statement signal) ws : [ \t]+ -> skip ; // toss out whitespace this way have multiple statements inside while loop. visitor class looks this:
public class evalvisitor extends exprbasevisitor<integer> { /** "memory" our calculator; variable/value pairs go here */ map<string, integer> memory; public evalvisitor() { memory = new hashmap<string, integer>(); } /** id '=' expr newline */ @override public integer visitassign(exprparser.assigncontext ctx) { string id = ctx.id().gettext(); // id left-hand side of '=' int value = super.visit(ctx.expr()); // compute value of expression on right memory.put(id, value); // store in our memory return value; } /** expr newline */ @override public integer visitprintexpr(exprparser.printexprcontext ctx) { integer value = super.visit(ctx.expr()); // evaluate expr child system.out.println(value); // print result return 0; // return dummy value } /** int */ @override public integer visitint(exprparser.intcontext ctx) { return integer.valueof(ctx.int().gettext()); } /** id */ @override public integer visitid(exprparser.idcontext ctx) { string id = ctx.id().gettext(); if ( memory.containskey(id) ) return memory.get(id); return 0; } /** expr op=('*'|'/') expr */ @override public integer visitmuldiv(exprparser.muldivcontext ctx) { int left = super.visit(ctx.expr(0)); // value of left subexpression int right = super.visit(ctx.expr(1)); // value of right subexpression if ( ctx.op.gettype() == exprparser.mul ) return left * right; return left / right; // must div } /** expr op=('+'|'-') expr */ @override public integer visitaddsub(exprparser.addsubcontext ctx) { int left = super.visit(ctx.expr(0)); // value of left subexpression int right = super.visit(ctx.expr(1)); // value of right subexpression if ( ctx.op.gettype() == exprparser.add ) return left + right; return left - right; // must sub } /** '(' expr ')' */ @override public integer visitparens(exprparser.parenscontext ctx) { return super.visit(ctx.expr()); // return child expr's value } @override public boolean visitgreaterequal(greaterequalcontext ctx) { int left = super.visit(ctx.expr(0)); int right = super.visit(ctx.expr(1)); if(ctx.op.gettype() == exprparser.greater) { return left > right; } else { return left < right; } } @override public integer visitwhileloop(whileloopcontext ctx) { if(visit(ctx.getrulecontext())) { } return super.visitwhileloop(ctx); } }
most of code in visitor class took book because starting using antlr 4. find hard believe that, aside grammar while loop, there no mention of how implement visitors/listeners or actions simple while loop in book written terence parr. can me writing visitor/listener java code while loop?
i find hard believe that, aside grammar while loop, there no mention of how implement visitors/listeners or actions simple while loop in book written terence parr.
that because antlr reference antlr, parsing, not stage after parsing.
you can't this:
@override public boolean visitgreaterequal(greaterequalcontext ctx) { ...
you've declared visitor return integers, that's every rule should return. either make custom wrapper value encapsulates language's values (numbers, string, booleans), or return 0 when relation expression 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 false (all other values true) } else { return left < right ? 1 : 0; } } then can write while follows:
@override public integer visitwhile(exprparser.whilecontext ctx) { // evaluate relational expression , continue while // loop long true (does not equal zero). while (this.visit(ctx.relational()) != 0) { // evaluate statements inside while loop. (exprparser.statcontext stat : ctx.stat()) { this.visit(stat); } } // 0 false, maybe return null instead // sort of void value (or make proper value class). return 0; } note code above fail when nesting while statements because inner while return 0 causing outer while stop looping. in such cases, you'd better off creating custom value class , introduce sort of value.void instance not cause loop stop.
running 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 @ demo language uses antlr4 , if , while statements, custom value object: https://github.com/bkiers/mu
Comments
Post a Comment