Reference
The Definitive ANTLR 4 Reference, 2nd Edition.
0 Features
labeled grammar definition, i.e. # eq
;
Visitor
pattern.
1 The Grammar
grammar RuleSet;
prog: stmt+ ;
stmt: expr '=' expr NEWLINE #eq
|expr '<' expr NEWLINE #lt
|expr '<=' expr NEWLINE # le
|expr '>' expr NEWLINE # gt
|expr '>=' expr NEWLINE # ge
;
expr: expr op=('*'|'/') expr # MulDiv
| expr op=('+'|'-') expr # AddSub
| INT # int
| '(' expr ')' # parens
;
MUL : '*' ; // assigns token name to '*' used above in grammar
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
NEWLINE : [\r\n]+ ;
INT : [0-9]+ ; // match integers
WS : [ \t]+ -> skip ; // toss out whitespace
2 Play around with ANTLR 4
export CLASSPATH=".:./antlr-4.5.1-complete.jar:$CLASSPATH"
# generate listner
#java -jar ./antlr-4.5.1-complete.jar RuleSet.g4
# generate visitor
java -jar ./antlr-4.5.1-complete.jar -no-listener -visitor RuleSet.g4
3 The Interpreter
Put the generate java files in pakage com.spike.antlr4.rs
.
3.1 The Visitor
package com.spike.antlr4.rs;
import com.spike.antlr4.rs.RuleSetParser.ExprContext;
public class EvalVisitor extends RuleSetBaseVisitor<Integer> {
private boolean result = false;
public boolean getResult() {
return result;
}
public void setResult(boolean result) {
this.result = result;
}
/** = */
@Override
public Integer visitEq(RuleSetParser.EqContext ctx) {
// Integer result = visitChildren(ctx);
ExprContext left = ctx.expr(0);
ExprContext right = ctx.expr(1);
int result = visit(left) - visit(right);
if (result == 0) {
this.setResult(true);
} else {
this.setResult(false);
}
return result;
}
/** <= */
@Override
public Integer visitLe(RuleSetParser.LeContext ctx) {
// Integer result = visitChildren(ctx);
ExprContext left = ctx.expr(0);
ExprContext right = ctx.expr(1);
int result = visit(left) - visit(right);
if (result <= 0) {
this.setResult(true);
} else {
this.setResult(false);
}
return result;
}
/** < */
@Override
public Integer visitLt(RuleSetParser.LtContext ctx) {
ExprContext left = ctx.expr(0);
ExprContext right = ctx.expr(1);
int result = visit(left) - visit(right);
if (result < 0) {
this.setResult(true);
} else {
this.setResult(false);
}
return result;
}
/** >= */
@Override
public Integer visitGe(RuleSetParser.GeContext ctx) {
ExprContext left = ctx.expr(0);
ExprContext right = ctx.expr(1);
int result = visit(left) - visit(right);
if (result >= 0) {
this.setResult(true);
} else {
this.setResult(false);
}
return result;
}
/** > */
@Override
public Integer visitGt(RuleSetParser.GtContext ctx) {
ExprContext left = ctx.expr(0);
ExprContext right = ctx.expr(1);
int result = visit(left) - visit(right);
if (result > 0) {
this.setResult(true);
} else {
this.setResult(false);
}
return result;
}
/** INT */
@Override
public Integer visitInt(RuleSetParser.IntContext ctx) {
return Integer.valueOf(ctx.INT().getText());
}
/** expr op=('*'|'/') expr */
@Override
public Integer visitMulDiv(RuleSetParser.MulDivContext ctx) {
int left = visit(ctx.expr(0)); // get value of left subexpression
int right = visit(ctx.expr(1)); // get value of right subexpression
if (ctx.op.getType() == RuleSetParser.MUL)
return left * right;
return left / right; // must be DIV
}
/** expr op=('+'|'-') expr */
@Override
public Integer visitAddSub(RuleSetParser.AddSubContext ctx) {
int left = visit(ctx.expr(0)); // get value of left subexpression
int right = visit(ctx.expr(1)); // get value of right subexpression
if (ctx.op.getType() == RuleSetParser.ADD)
return left + right;
return left - right; // must be SUB
}
/** '(' expr ')' */
@Override
public Integer visitParens(RuleSetParser.ParensContext ctx) {
return visit(ctx.expr()); // return child expr's value
}
}
3.2 The Main Entrance
package com.spike.antlr4.rs;
import java.util.ArrayList;
import java.util.List;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
/**
* The Interpreter
*
* @author zhoujiagen<br/>
* Aug 26, 2015 1:20:34 AM
*/
public class Calc {
static String NEWLINE = "\r\n";
public static void main(String[] args) {
System.out.println(eval("123=100+12+11" + NEWLINE, "124 + 125 = 123 + 126" + NEWLINE, "345 <= 346 + 347 + 348"
+ NEWLINE));
}
static List<Boolean> eval(String... stmts) {
if (stmts != null && stmts.length > 0) {
List<Boolean> result = new ArrayList<Boolean>();
for (String stmt : stmts) {
result.add(eval(stmt));
}
return result;
}
return null;
}
static boolean eval(String stmt) {
boolean result = false;
if (stmt != null && stmt.length() > 0) {
ANTLRInputStream input = new ANTLRInputStream(stmt);
RuleSetLexer lexer = new RuleSetLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
RuleSetParser parser = new RuleSetParser(tokens);
ParseTree tree = parser.stmt(); // parse
EvalVisitor eval = new EvalVisitor();
System.out.println(eval.visit(tree));
// get the final result
result = eval.getResult();
}
return result;
}
}