├── .gitignore ├── Calculator.g4 ├── CalculatorBaseVisitorImpl.java ├── Readme.md └── Run.java /.gitignore: -------------------------------------------------------------------------------- 1 | app/ 2 | -------------------------------------------------------------------------------- /Calculator.g4: -------------------------------------------------------------------------------- 1 | grammar Calculator; 2 | INT : [0-9]+; 3 | DOUBLE : [0-9]+'.'[0-9]+; 4 | PI : 'pi'; 5 | E : 'e'; 6 | POW : '^'; 7 | NL : '\n'; 8 | WS : [ \t\r]+ -> skip; 9 | ID : [a-zA-Z_][a-zA-Z_0-9]*; 10 | 11 | PLUS : '+'; 12 | EQUAL : '='; 13 | MINUS : '-'; 14 | MULT : '*'; 15 | DIV : '/'; 16 | LPAR : '('; 17 | RPAR : ')'; 18 | 19 | input 20 | : setVar NL input # ToSetVar 21 | | plusOrMinus NL? EOF # Calculate 22 | ; 23 | 24 | setVar 25 | : ID EQUAL plusOrMinus # SetVariable 26 | ; 27 | 28 | 29 | plusOrMinus 30 | : plusOrMinus PLUS multOrDiv # Plus 31 | | plusOrMinus MINUS multOrDiv # Minus 32 | | multOrDiv # ToMultOrDiv 33 | ; 34 | 35 | multOrDiv 36 | : multOrDiv MULT pow # Multiplication 37 | | multOrDiv DIV pow # Division 38 | | pow # ToPow 39 | ; 40 | 41 | pow 42 | : unaryMinus (POW pow)? # Power 43 | ; 44 | 45 | unaryMinus 46 | : MINUS unaryMinus # ChangeSign 47 | | atom # ToAtom 48 | ; 49 | 50 | atom 51 | : PI # ConstantPI 52 | | E # ConstantE 53 | | DOUBLE # Double 54 | | INT # Int 55 | | ID # Variable 56 | | LPAR plusOrMinus RPAR # Braces 57 | ; 58 | -------------------------------------------------------------------------------- /CalculatorBaseVisitorImpl.java: -------------------------------------------------------------------------------- 1 | import java.util.HashMap; 2 | 3 | public class CalculatorBaseVisitorImpl extends CalculatorBaseVisitor { 4 | private HashMap variables = new HashMap(); 5 | 6 | @Override 7 | public Double visitPlus(CalculatorParser.PlusContext ctx) { 8 | return visit(ctx.plusOrMinus()) + visit(ctx.multOrDiv()); 9 | } 10 | 11 | @Override 12 | public Double visitMinus(CalculatorParser.MinusContext ctx) { 13 | return visit(ctx.plusOrMinus()) - visit(ctx.multOrDiv()); 14 | } 15 | 16 | @Override 17 | public Double visitMultiplication(CalculatorParser.MultiplicationContext ctx) { 18 | return visit(ctx.multOrDiv()) * visit(ctx.pow()); 19 | } 20 | 21 | @Override 22 | public Double visitDivision(CalculatorParser.DivisionContext ctx) { 23 | return visit(ctx.multOrDiv()) / visit(ctx.pow()); 24 | } 25 | 26 | @Override 27 | public Double visitSetVariable(CalculatorParser.SetVariableContext ctx) { 28 | Double value = visit(ctx.plusOrMinus()); 29 | variables.put(ctx.ID().getText(), value); 30 | return value; 31 | } 32 | 33 | @Override 34 | public Double visitPower(CalculatorParser.PowerContext ctx) { 35 | if (ctx.pow() != null) 36 | return Math.pow(visit(ctx.unaryMinus()), visit(ctx.pow())); 37 | return visit(ctx.unaryMinus()); 38 | } 39 | 40 | @Override 41 | public Double visitChangeSign(CalculatorParser.ChangeSignContext ctx) { 42 | return -1*visit(ctx.unaryMinus()); 43 | } 44 | 45 | @Override 46 | public Double visitBraces(CalculatorParser.BracesContext ctx) { 47 | return visit(ctx.plusOrMinus()); 48 | } 49 | 50 | @Override 51 | public Double visitConstantPI(CalculatorParser.ConstantPIContext ctx) { 52 | return Math.PI; 53 | } 54 | 55 | @Override 56 | public Double visitConstantE(CalculatorParser.ConstantEContext ctx) { 57 | return Math.E; 58 | } 59 | 60 | @Override 61 | public Double visitInt(CalculatorParser.IntContext ctx) { 62 | return Double.parseDouble(ctx.INT().getText()); 63 | } 64 | 65 | @Override 66 | public Double visitVariable(CalculatorParser.VariableContext ctx) { 67 | return variables.get(ctx.ID().getText()); 68 | } 69 | 70 | @Override 71 | public Double visitDouble(CalculatorParser.DoubleContext ctx) { 72 | return Double.parseDouble(ctx.DOUBLE().getText()); 73 | } 74 | 75 | @Override 76 | public Double visitCalculate(CalculatorParser.CalculateContext ctx) { 77 | return visit(ctx.plusOrMinus()); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | Getting started 2 | =============== 3 | 4 | 1. Install ANTLR v4 ([manual](https://github.com/antlr/antlr4/blob/master/doc/getting-started.md#installation)) 5 | 1. Generate ANTLR files `antlr4 Calculator.g4 -no-listener -visitor -o app` 6 | 1. Copy visitor implementation `cp *.java app` 7 | 1. Compile `javac app/*.java` 8 | 9 | Run 10 | === 11 | 12 | Type in console `cd app && java Run` 13 | 14 | ``` 15 | a = 1+2 16 | b = a^2 17 | c = a + b * (a - 1) 18 | a + b + c 19 | ``` 20 | 21 | Result should be equal 33.0 22 | -------------------------------------------------------------------------------- /Run.java: -------------------------------------------------------------------------------- 1 | import org.antlr.v4.runtime.*; 2 | import org.antlr.v4.runtime.tree.*; 3 | 4 | public class Run { 5 | public static void main(String[] args) throws Exception { 6 | CharStream input = CharStreams.fromStream(System.in); 7 | CalculatorLexer lexer = new CalculatorLexer(input); 8 | CommonTokenStream tokens = new CommonTokenStream(lexer); 9 | CalculatorParser parser = new CalculatorParser(tokens); 10 | ParseTree tree = parser.input(); 11 | 12 | CalculatorBaseVisitorImpl calcVisitor = new CalculatorBaseVisitorImpl(); 13 | Double result = calcVisitor.visit(tree); 14 | System.out.println("Result: " + result); 15 | } 16 | } 17 | --------------------------------------------------------------------------------