teaching machines

CS 330 Lecture 18 – A Logo REPL

March 4, 2013 by . Filed under cs330, lectures, spring 2013.

Agenda

TODO

Program This

Imagine you can manipulate a turtle/robot/drone with a program. In particular, you can do the following to your controllee:

Write a little program to do something interesting. You pick the syntax.

Code

Logo.g4

grammar Logo;

program
  : statement* EOF
  ;

statement
  : command '\n'
  ;

command
  : MOVE INT           # Move
  | TURN INT           # Turn
  | SLIME (ON | OFF)   # Slime
  ;

MOVE : 'move';
TURN : 'turn';
SLIME : 'slime';
ON : 'on';
OFF : 'off';
INT : '-'? [0-9]+;

WHITESPACE : [ \t\r]+ -> skip;

makefile

Note to copy and pasters: makefile rules need to be indented with real tabs, not spaces.

ANTLR_JAR = $(HOME)/bin/antlr-4.0-complete.jar
ANTLR = java -jar $(ANTLR_JAR)

LogoParser.class: Logo.g4 makefile
  $(ANTLR) Logo.g4
  javac Logo*.java

Interpreter.class: LogoParser.class Interpreter.java
  javac Interpreter.java

clean:
  rm -f *.class Logo*.java *.tokens

Interpreter.java

import org.antlr.v4.runtime.*;
import java.util.ArrayList;
import java.io.IOException;
import org.antlr.v4.runtime.tree.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.AffineTransform;

public class Interpreter extends LogoBaseListener {
  public static void main(String[] args) throws IOException { 
    ANTLRInputStream input = new ANTLRInputStream(System.in);
    LogoLexer lexer = new LogoLexer(input);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    LogoParser parser = new LogoParser(tokens);
    ParseTree tree = parser.program();

    ParseTreeWalker walker = new ParseTreeWalker();
    walker.walk(new Interpreter(500), tree);
  }

/* ------------------------------------------------------------------------- */

  private double x = 0.0;
  private double y = 0.0;
  private double theta = 0.0;
  private boolean isLeaking = true;

  public void exitMove(LogoParser.MoveContext context) {
    double distance = Double.parseDouble(context.INT().getText());

    double newX = distance * Math.cos(theta);
    double newY = distance * Math.sin(theta);
  
    display.addSegment(new Line2D.Double(x, y, newX, newY));
    display.step();

    x = newX;
    y = newY;
  }

  public void exitTurn(LogoParser.TurnContext context) {
    double angle = Double.parseDouble(context.INT().getText());
    display.setCursor(0.0, 0.0, angle);
    display.step();
  }

/* ------------------------------------------------------------------------- */

  private LogoDisplay display;
  private int delay;

  public Interpreter(int delay) {
    JFrame frame = new JFrame("Logo");

    display = new LogoDisplay();
    frame.setContentPane(display);

    frame.setSize(400, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

    this.delay = delay;
    display.step();
  }

  class LogoDisplay extends JPanel {
    private ArrayList<Line2D.Double> segments;
    private Line2D.Double arrowTop;
    private Line2D.Double arrowBottom;
    private double x;
    private double y;
    private double theta;

    public LogoDisplay() {
      segments = new ArrayList<Line2D.Double>();
      arrowTop = new Line2D.Double(-10.0f, -5.0f, 0.0f, 0.0f);
      arrowBottom = new Line2D.Double(-10.0f, 5.0f, 0.0f, 0.0f);
      x = 0.0;
      y = 0.0;
      theta = 0.0;
    }

    public void paintComponent(Graphics g) {
      super.paintComponent(g);

      Graphics2D g2 = (Graphics2D) g;
      AffineTransform xform = g2.getTransform(); 

      g2.translate(100, 100);
      for (Line2D.Double segment : segments) {
        g2.draw(segment);
      }  

      g2.translate(x, y);
      g2.rotate(theta);
      g2.draw(arrowTop);
      g2.draw(arrowBottom);
    }

    public void step() {
      repaint();
      try {
        Thread.sleep(delay);
      } catch (InterruptedException e) {}
    }

    public void setCursor(double x, double y, double theta) {
      this.x = x;
      this.y = y;
      this.theta = theta;
    }

    public void addSegment(Line2D.Double segment) {
      segments.add(segment);
    }
  }
}

Haiku

Don’t reinvent wheels
Bow before the pioneers
Their third-gen wheels rock