CS 330 Lecture 28 – Interpreting
Agenda
- what ?s
- a REPL
- walking a parse tree with ANTLR’s callbacks
TODO
- Start Bifur.
Code
makefile
Note to copy and pasters: makefile rules need to be indented with real tabs, not spaces.
ANTLR = $(HOME)/bin/antlr-4.1-complete.jar
CP = -cp $(ANTLR):.
all: InterpreterBasecalc.class
BasecalcParser.class BasecalcLexer.class: Basecalc.g
java -jar $(ANTLR) Basecalc.g
javac $(CP) BasecalcLexer.java BasecalcParser.java
InterpreterBasecalc.class: InterpreterBasecalc.java BasecalcParser.class BasecalcLexer.class
javac $(CP) InterpreterBasecalc.java
run:
java $(CP) InterpreterBasecalc
clean:
rm -f *.class *.tokens BasecalcLexer.java BasecalcParser.java
Basecalc.g
grammar Basecalc;
line
: expression EOF # DecimalOutput
| expression ARROW DIGITS EOF # BaseOutput
;
expression
: LEFT_PARENTHESIS expression RIGHT_PARENTHESIS # Grouped
| NOT expression # Not
| expression MULTIPLICATIVE_OPERATOR expression # Multiply
| expression ADDITIVE_OPERATOR expression # Add
| expression AND expression # And
| expression OR expression # Or
| ID EQUALS expression # Assignment
| n=DIGITS SEPARATOR base=DIGITS # LiteralWithBase
| DIGITS # LiteralWithoutBase
| ID # Identifier
;
EQUALS: '===';
ID: '$' [a-z]+;
LEFT_PARENTHESIS: '(';
RIGHT_PARENTHESIS: ')';
NOT: '~';
OR: '|';
AND: '&';
MULTIPLICATIVE_OPERATOR: [*/%];
ADDITIVE_OPERATOR: [-+];
SEPARATOR: '_';
DIGITS: [0-9A-Za-z]+;
ARROW: '->';
WHITESPACE: [ \r\n\t]+ -> skip;
InterpreterBasecalc.java
import org.antlr.v4.runtime.*;
import java.util.Scanner;
import java.util.HashMap;
import java.util.Stack;
import java.io.IOException;
import org.antlr.v4.runtime.tree.*;
public class InterpreterBasecalc extends BasecalcBaseListener {
public static void main(String[] args) throws IOException {
InterpreterBasecalc interpreter = new InterpreterBasecalc();
Scanner in = new Scanner(System.in);
System.out.print("> ");
while (in.hasNextLine()) {
String line = in.nextLine();
ANTLRInputStream ais = new ANTLRInputStream(line);
BasecalcLexer lexer = new BasecalcLexer(ais);
CommonTokenStream tokens = new CommonTokenStream(lexer);
BasecalcParser parser = new BasecalcParser(tokens);
ParseTree tree = parser.line();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(interpreter, tree);
System.out.print("> ");
}
}
private Stack<Integer> operands = new Stack<Integer>();
private HashMap<String, Integer> variables = new HashMap<String, Integer>();
public void exitDecimalOutput(BasecalcParser.DecimalOutputContext context) {
System.out.println(operands.pop());
}
public void exitBaseOutput(BasecalcParser.BaseOutputContext context) {
int base = Integer.parseInt(context.DIGITS().getText());
System.out.println(Integer.toString(operands.pop(), base));
}
public void exitLiteralWithoutBase(BasecalcParser.LiteralWithoutBaseContext context) {
int n = Integer.parseInt(context.DIGITS().getText());
operands.push(n);
}
public void exitLiteralWithBase(BasecalcParser.LiteralWithBaseContext context) {
int base = Integer.parseInt(context.base.getText());
int n = Integer.parseInt(context.n.getText(), base);
operands.push(n);
}
public void exitNot(BasecalcParser.NotContext context) {
operands.push(~operands.pop());
}
public void exitAssignment(BasecalcParser.AssignmentContext context) {
String id = context.ID().getText();
int n = operands.peek();
variables.put(id, n);
}
public void exitIdentifier(BasecalcParser.IdentifierContext context) {
if (variables.containsKey(context.ID().getText())) {
operands.push(variables.get(context.ID().getText()));
} else {
operands.push(0);
}
}
public void exitMultiply(BasecalcParser.MultiplyContext context) {
int b = operands.pop();
int a = operands.pop();
if (context.MULTIPLICATIVE_OPERATOR().getText().equals("*")) {
operands.push(a * b);
} else if (context.MULTIPLICATIVE_OPERATOR().getText().equals("/")) {
operands.push(a / b);
} else if (context.MULTIPLICATIVE_OPERATOR().getText().equals("%")) {
operands.push(a % b);
}
}
}
Haiku
Invent or consume?
The more off-the-shelf I do
The less “off the shelf”
The more off-the-shelf I do
The less “off the shelf”