teaching machines

CS 330 Lecture 28 – Interpreting

April 9, 2014 by . Filed under cs330, lectures, spring 2014.

Agenda

TODO

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”