teaching machines

CS 330 Lecture 30 – Logo Translation

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

Agenda

TODO

Think About This

Code

Logo.g

grammar Logo;

program
  : block EOF
  ;

block
  : (command NEWLINE)*
  ;

command
  : MOVE expression # Move
  | ROTATE expression # Rotate
  | REPEAT expression NEWLINE block END # Repeat
  | LOG expression # Log
  | IF expression NEWLINE block ELSE NEWLINE block END # If
  | TO ID ID* EQUALS NEWLINE block END # Define
  | ID expression* # Call
  | ID EQUALS expression # Assignment
  | PEN expression # Pen
  ;

expression
  : LEFT_PARENTHESIS expression RIGHT_PARENTHESIS # Grouped
  | expression POWER_OPERATOR expression # Power
  | expression MULTIPLICATIVE_OPERATOR expression # Multiply
  | expression ADDITIVE_OPERATOR expression # Add
  | LITERAL # Literal
  | ID # Identifier
  ;

// Keywords
TO: 'to';
LOG: 'log';
REPEAT: 'repeat';
END: 'end';
IF: 'if';
ELSE: 'else';
MOVE: 'move';
ROTATE: 'rotate';
PEN: 'pen';

EQUALS: '=';
LEFT_PARENTHESIS: '(';
RIGHT_PARENTHESIS: ')';
POWER_OPERATOR: '^';
MULTIPLICATIVE_OPERATOR: [*/];
ADDITIVE_OPERATOR: [-+];
LITERAL: '-'? [0-9]+ ('.' [0-9]+)?;
ID: [a-z]+;

WHITESPACE: [ \t]+ -> skip;
NEWLINE: '\r'? '\n';

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: LogoParser.java LogoLexer.java

LogoParser.java LogoLexer.java: Logo.g makefile
  java -jar $(ANTLR) -package logo330.antlr Logo.g

LogoParser.class LogoLexer.class: LogoParser.java LogoLexer.java makefile
  javac $(CP) LogoLexer.java LogoParser.java

# InterpreterLogo.class: InterpreterLogo.java LogoParser.class LogoLexer.class 
  # javac $(CP) InterpreterLogo.java 

run:
  java $(CP) InterpreterLogo

clean:
  rm -f *.class *.tokens LogoLexer.java LogoParser.java

hernagon.logo

to poly n size =
  repeat n
    move size
    rotate 180 - (360 / n)
  end
end
poly 12 50

hernagon2.logo

to poly n size =
  repeat n
    move size
    rotate 360 / n
  end
end
n = 3
repeat 40
  poly n 30
  n = n + 1
end

lewis.logo

move 10
repeat 9
  rotate 18
  move 61
end

movemovemove.logo

move 10
move 20
move 30

polyf.logo

to poly n size =
  theta = 360 / n
  repeat n
    move size
    rotate theta
  end
end
n = 3
repeat 50
  poly n 10
  n = n + 1
end

recursion.logo

to square size =
  rotate 90
  repeat 4
    move size
    rotate 90
  end
end
to recurse n =
  log n
  if n
    square n
    recurse n - 5
  else
    log -1
  end
end    
recurse 100

square.logo

repeat 4
  move 10
  rotate 90
end

square_list.logo

move 10
rotate 90
move 10
rotate 90
move 10
rotate 90
move 10
rotate 90

squaref.logo

to square size =
  repeat 4
    move size
    rotate 90
  end
end
square 50

Logo.tokens

NEWLINE=19
RIGHT_PARENTHESIS=12
TO=1
MOVE=7
LOG=2
LEFT_PARENTHESIS=11
PEN=9
ELSE=6
WHITESPACE=18
LITERAL=16
REPEAT=3
EQUALS=10
ROTATE=8
POWER_OPERATOR=13
MULTIPLICATIVE_OPERATOR=14
ID=17
ADDITIVE_OPERATOR=15
END=4
IF=5
'end'=4
'pen'=9
'else'=6
'to'=1
'log'=2
'rotate'=8
'repeat'=3
'='=10
'if'=5
'('=11
')'=12
'^'=13
'move'=7

LogoLexer.tokens

NEWLINE=19
RIGHT_PARENTHESIS=12
TO=1
MOVE=7
LOG=2
LEFT_PARENTHESIS=11
PEN=9
ELSE=6
WHITESPACE=18
LITERAL=16
REPEAT=3
EQUALS=10
ROTATE=8
POWER_OPERATOR=13
MULTIPLICATIVE_OPERATOR=14
ID=17
ADDITIVE_OPERATOR=15
END=4
IF=5
'end'=4
'pen'=9
'else'=6
'to'=1
'log'=2
'rotate'=8
'repeat'=3
'='=10
'if'=5
'('=11
')'=12
'^'=13
'move'=7

Block.java

package logo330;

import java.util.ArrayList;
import logo330.command.Command;

public class Block {
  private ArrayList<Command> commands = new ArrayList<Command>();

  public void execute(Environment env) {
    for (Command command : commands) {
      command.execute(env);
    }
  }

  public void add(Command command) {
    commands.add(command);
  }

  public int size() {
    return commands.size();
  }
}

Compiler.java

package logo330;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Stack;
import javax.swing.JFileChooser;
import logo330.antlr.LogoBaseListener;
import logo330.antlr.LogoLexer;
import logo330.antlr.LogoParser;
import logo330.antlr.LogoParser.AddContext;
import logo330.antlr.LogoParser.AssignmentContext;
import logo330.antlr.LogoParser.BlockContext;
import logo330.antlr.LogoParser.CallContext;
import logo330.antlr.LogoParser.DefineContext;
import logo330.antlr.LogoParser.IdentifierContext;
import logo330.antlr.LogoParser.IfContext;
import logo330.antlr.LogoParser.LiteralContext;
import logo330.antlr.LogoParser.LogContext;
import logo330.antlr.LogoParser.MoveContext;
import logo330.antlr.LogoParser.MultiplyContext;
import logo330.antlr.LogoParser.PenContext;
import logo330.antlr.LogoParser.PowerContext;
import logo330.antlr.LogoParser.ProgramContext;
import logo330.antlr.LogoParser.RepeatContext;
import logo330.antlr.LogoParser.RotateContext;
import logo330.command.CommandAssignment;
import logo330.command.CommandFunctionCall;
import logo330.command.CommandFunctionDefine;
import logo330.command.CommandIf;
import logo330.command.CommandLog;
import logo330.command.CommandMove;
import logo330.command.CommandPen;
import logo330.command.CommandRepeat;
import logo330.command.CommandRotate;
import logo330.expression.Expression;
import logo330.expression.ExpressionAdd;
import logo330.expression.ExpressionDivide;
import logo330.expression.ExpressionIdentifier;
import logo330.expression.ExpressionLiteral;
import logo330.expression.ExpressionMultiply;
import logo330.expression.ExpressionSubtract;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;

public class Compiler extends LogoBaseListener {
  public static void main(String[] args) throws FileNotFoundException, IOException {
    File f = new File("/Users/johnch/Desktop/recursion.logo");

    if (f == null) {
      JFileChooser chooser = new JFileChooser();
      int ok = chooser.showOpenDialog(null);
      if (ok == JFileChooser.APPROVE_OPTION) {
        f = chooser.getSelectedFile();
      }
    }

    ANTLRInputStream ais = new ANTLRInputStream(new FileInputStream(f));
    LogoLexer lexer = new LogoLexer(ais);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    LogoParser parser = new LogoParser(tokens);
    ParseTree tree = parser.program();

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

  @Override
  public void exitProgram(ProgramContext ctx) {
    Environment env = new Environment();
    Block main = blocks.pop();
    new LogoVirtualMachine(env, main);
  }

  private Stack<Expression> operands = new Stack<Expression>();
  private Stack<Block> blocks = new Stack<Block>();

  public void enterBlock(LogoParser.BlockContext context) {
    blocks.push(new Block());
  }

  public void exitIdentifier(IdentifierContext context) {
    operands.push(new ExpressionIdentifier(context.ID().getText()));
  }

  public void exitLiteral(LiteralContext context) {
    double value = Double.parseDouble(context.LITERAL().getText());
    operands.push(new ExpressionLiteral(value));
  }

  @Override
  public void exitCall(CallContext ctx) {
    ArrayList<Expression> actualParameters = new ArrayList<Expression>();
    for (int i = 0; i < ctx.expression().size(); ++i) {
      actualParameters.add(0, operands.pop());
    }
    blocks.peek().add(new CommandFunctionCall(ctx.ID().getText(), actualParameters));
  }

  @Override
  public void exitAssignment(AssignmentContext ctx) {
    Expression e = operands.pop();
    String id = ctx.ID().getText();
    blocks.peek().add(new CommandAssignment(id, e));
  }

  @Override
  public void exitBlock(BlockContext ctx) {
  }

  @Override
  public void exitMultiply(MultiplyContext ctx) {
    Expression b = operands.pop();
    Expression a = operands.pop();
    if (ctx.MULTIPLICATIVE_OPERATOR().getText().equals("*")) {
      operands.push(new ExpressionMultiply(a, b));
    } else {
      operands.push(new ExpressionDivide(a, b));
    }
  }

  @Override
  public void exitLog(LogContext ctx) {
    Expression e = operands.pop();
    blocks.peek().add(new CommandLog(e));
  }

  @Override
  public void exitPen(PenContext ctx) {
    Expression e = operands.pop();
    blocks.peek().add(new CommandPen(e));
  }

  @Override
  public void exitAdd(AddContext ctx) {
    Expression b = operands.pop();
    Expression a = operands.pop();
    if (ctx.ADDITIVE_OPERATOR().getText().equals("+")) {
      operands.push(new ExpressionAdd(a, b));
    } else {
      operands.push(new ExpressionSubtract(a, b));
    }
  }

  @Override
  public void exitMove(MoveContext ctx) {
    Expression e = operands.pop();
    blocks.peek().add(new CommandMove(e));
  }

  @Override
  public void exitRotate(RotateContext ctx) {
    Expression e = operands.pop();
    blocks.peek().add(new CommandRotate(e));
  }

  @Override
  public void exitDefine(DefineContext ctx) {
    ArrayList<String> formalParameters = new ArrayList<String>();
    for (int i = 1; i < ctx.ID().size(); ++i) {
      formalParameters.add(ctx.ID(i).getText());
    }
    System.out.println(formalParameters);
    Block block = blocks.pop();
    blocks.peek().add(new CommandFunctionDefine(ctx.ID(0).getText(), formalParameters, block));
  }

  @Override
  public void exitIf(IfContext ctx) {
    Block elseBlock = blocks.pop();
    Block thenBlock = blocks.pop();
    blocks.peek().add(new CommandIf(operands.pop(), thenBlock, elseBlock));
  }

  @Override
  public void exitRepeat(RepeatContext ctx) {
    Block block = blocks.pop();
    blocks.peek().add(new CommandRepeat(operands.pop(), block));
  }

  @Override
  public void exitPower(PowerContext ctx) {
    Expression b = operands.pop();
    Expression a = operands.pop();
    operands.push(new ExpressionAdd(a, b));
  }
}

Environment.java

package logo330;

import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.HashMap;
import logo330.command.CommandListener;

public class Environment {
  public double x = 0.0;
  public double y = 0.0;
  public double theta = 0.0;
  public boolean isDrawing = true;

  public HashMap<String, Double> locals = new HashMap<String, Double>();
  public HashMap<String, Function> functions = new HashMap<String, Function>();

  public ArrayList<Line2D.Double> segments = new ArrayList<Line2D.Double>();
  public CommandListener listener = null;
}

Function.java

package logo330;

import java.util.ArrayList;

public class Function {
  private String id;
  private ArrayList<String> formalParameters;
  private Block body;

  public Function(String id, ArrayList<String> formalParameters, Block body) {
    this.id = id;
    this.formalParameters = formalParameters;
    this.body = body;
  }

  public String getID() {
    return id;
  }

  public ArrayList<String> getFormalParameters() {
    return formalParameters;
  }

  public Block getBody() {
    return body;
  }
}

LogoVirtualMachine.java

package logo330;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.io.IOException;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import logo330.command.Command;
import logo330.command.CommandFunctionCall;
import logo330.command.CommandFunctionDefine;
import logo330.command.CommandListener;
import logo330.command.CommandMove;
import logo330.command.CommandRepeat;
import logo330.command.CommandRotate;
import logo330.expression.Expression;
import logo330.expression.ExpressionIdentifier;
import logo330.expression.ExpressionLiteral;

public class LogoVirtualMachine implements CommandListener {
  public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
//    Environment env = new Environment();
//
//    Block main = new Block();
    // main.add(new CommandMove(new ExpressionLiteral(24.0)));
    // main.add(new CommandRotate(new ExpressionLiteral(90.0)));
    // main.add(new CommandMove(new ExpressionLiteral(24.0)));
    // main.add(new CommandRotate(new ExpressionLiteral(90.0)));
    // main.add(new CommandMove(new ExpressionLiteral(24.0)));
    // main.add(new CommandRotate(new ExpressionLiteral(90.0)));
    // main.add(new CommandMove(new ExpressionLiteral(24.0)));
    // main.add(new CommandRotate(new ExpressionLiteral(90.0)));

//    Block body = new Block();
//    body.add(new CommandMove(new ExpressionIdentifier("$size")));
//    body.add(new CommandRotate(new ExpressionLiteral(90.0)));
//    Command repeat = new CommandRepeat(new ExpressionLiteral(4), body);
//
//    body = new Block();
//    body.add(repeat);
//
//    ArrayList<String> formalParameters = new ArrayList<String>();
//    formalParameters.add("$size");
//    Command c = new CommandFunctionDefine("square", formalParameters, body);
//
//    c.execute(env);
//
//    ArrayList<Expression> actualParameters = new ArrayList<Expression>();
//    actualParameters.add(new ExpressionLiteral(150));
//
//    main.add(new CommandFunctionCall("square", actualParameters));

    Environment env = new Environment();
    Block main = new Block();
    new LogoVirtualMachine(env, main);
  }

  private JFrame display;
  private JPanel panel;
  private int delay = 40;

  public LogoVirtualMachine(Environment env,
                            Block main) {
    env.listener = this;

    display = new JFrame("Logo");

    panel = new LogoDisplay(env);
    JScrollPane scroller = new JScrollPane(panel);
    display.setContentPane(scroller);

    panel.setPreferredSize(new Dimension(3000, 3000));
    panel.setSize(panel.getPreferredSize());

    display.setSize(1200, 700);
    display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    display.setVisible(true);

    try {
      Thread.sleep(100);
    } catch (InterruptedException e) {
    }

    main.execute(env);
  }

  public void onPostCommand() {
    pause();
    panel.paintImmediately(0, 0, panel.getWidth(), panel.getHeight());
  }

  private void pause() {
    try {
      Thread.sleep(delay);
    } catch (InterruptedException e) {
    }
  }

  class LogoDisplay extends JPanel {
    private Line2D.Double arrowTop;
    private Line2D.Double arrowBottom;
    private Environment env;

    public LogoDisplay(Environment env) {
      this.env = env;
      arrowTop = new Line2D.Double(-10.0f, -5.0f, 0.0f, 0.0f);
      arrowBottom = new Line2D.Double(-10.0f, 5.0f, 0.0f, 0.0f);
    }

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

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

      g2.translate(1200 / 2, 700 / 2);

      synchronized (env.segments) {
        for (Line2D.Double segment : env.segments) {
          g2.draw(segment);
        }
      }

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

      g2.setTransform(xform);
    }
  }
}

OldCompiler.java

package logo330;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Stack;
import javax.swing.JFileChooser;
import logo330.antlr.LogoBaseListener;
import logo330.antlr.LogoLexer;
import logo330.antlr.LogoParser;
import logo330.antlr.LogoParser.AddContext;
import logo330.antlr.LogoParser.AssignmentContext;
import logo330.antlr.LogoParser.BlockContext;
import logo330.antlr.LogoParser.CallContext;
import logo330.antlr.LogoParser.DefineContext;
import logo330.antlr.LogoParser.IdentifierContext;
import logo330.antlr.LogoParser.IfContext;
import logo330.antlr.LogoParser.LiteralContext;
import logo330.antlr.LogoParser.LogContext;
import logo330.antlr.LogoParser.MoveContext;
import logo330.antlr.LogoParser.MultiplyContext;
import logo330.antlr.LogoParser.PenContext;
import logo330.antlr.LogoParser.PowerContext;
import logo330.antlr.LogoParser.ProgramContext;
import logo330.antlr.LogoParser.RepeatContext;
import logo330.antlr.LogoParser.RotateContext;
import logo330.command.CommandAssignment;
import logo330.command.CommandFunctionCall;
import logo330.command.CommandFunctionDefine;
import logo330.command.CommandIf;
import logo330.command.CommandLog;
import logo330.command.CommandMove;
import logo330.command.CommandPen;
import logo330.command.CommandRepeat;
import logo330.command.CommandRotate;
import logo330.expression.Expression;
import logo330.expression.ExpressionAdd;
import logo330.expression.ExpressionDivide;
import logo330.expression.ExpressionIdentifier;
import logo330.expression.ExpressionLiteral;
import logo330.expression.ExpressionMultiply;
import logo330.expression.ExpressionSubtract;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.antlr.v4.runtime.tree.TerminalNode;

public class OldCompiler extends LogoBaseListener {
  public static void main(String[] args) throws FileNotFoundException, IOException {
    File f = new File("/Users/johnch/Desktop/lewis.logo");

    if (f == null) {
      JFileChooser chooser = new JFileChooser();
      int ok = chooser.showOpenDialog(null);
      if (ok == JFileChooser.APPROVE_OPTION) {
        f = chooser.getSelectedFile();
      }
    }

    ANTLRInputStream ais = new ANTLRInputStream(new FileInputStream(f));
    LogoLexer lexer = new LogoLexer(ais);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    LogoParser parser = new LogoParser(tokens);
    ParseTree tree = parser.program();

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

  @Override
  public void exitProgram(ProgramContext ctx) {
    Environment env = new Environment();
    Block main = blocks.pop();
    System.out.println(main.size());
    new LogoVirtualMachine(env, main);
  }

  private Stack<Expression> operands = new Stack<Expression>();
  private Stack<Block> blocks = new Stack<Block>();

  public void enterBlock(LogoParser.BlockContext context) {
    blocks.push(new Block());
  }

  public void exitIdentifier(IdentifierContext context) {
    operands.push(new ExpressionIdentifier(context.ID().getText()));
  }

  public void exitLiteral(LiteralContext context) {
    double value = Double.parseDouble(context.LITERAL().getText());
    operands.push(new ExpressionLiteral(value));
  }

  @Override
  public void exitCall(CallContext ctx) {
    ArrayList<Expression> actualParameters = new ArrayList<Expression>();
    for (int i = 0; i < ctx.expression().size(); ++i) {
      actualParameters.add(0, operands.pop());
    }
    blocks.peek().add(new CommandFunctionCall(ctx.ID().getText(), actualParameters));
  }

  @Override
  public void exitAssignment(AssignmentContext ctx) {
    Expression e = operands.pop();
    String id = ctx.ID().getText();
    blocks.peek().add(new CommandAssignment(id, e));
  }

  @Override
  public void exitBlock(BlockContext ctx) {
  }

  @Override
  public void exitMultiply(MultiplyContext ctx) {
    Expression b = operands.pop();
    Expression a = operands.pop();
    if (ctx.MULTIPLICATIVE_OPERATOR().getText().equals("*")) {
      operands.push(new ExpressionMultiply(a, b));
    } else {
      operands.push(new ExpressionDivide(a, b));
    }
  }

  @Override
  public void exitLog(LogContext ctx) {
    Expression e = operands.pop();
    blocks.peek().add(new CommandLog(e));
  }

  @Override
  public void exitPen(PenContext ctx) {
    Expression e = operands.pop();
    blocks.peek().add(new CommandPen(e));
  }

  @Override
  public void exitAdd(AddContext ctx) {
    Expression b = operands.pop();
    Expression a = operands.pop();
    if (ctx.ADDITIVE_OPERATOR().getText().equals("+")) {
      operands.push(new ExpressionAdd(a, b));
    } else {
      operands.push(new ExpressionSubtract(a, b));
    }
  }

  @Override
  public void exitMove(MoveContext ctx) {
    Expression e = operands.pop();
    blocks.peek().add(new CommandMove(e));
  }

  @Override
  public void exitRotate(RotateContext ctx) {
    Expression e = operands.pop();
    blocks.peek().add(new CommandRotate(e));
  }

  @Override
  public void exitDefine(DefineContext ctx) {
    ArrayList<String> formalParameters = new ArrayList<String>();
    for (int i = 1; i < ctx.ID().size(); ++i) {
      formalParameters.add(ctx.ID(i).getText());
    }
    System.out.println(formalParameters);
    Block block = blocks.pop();
    blocks.peek().add(new CommandFunctionDefine(ctx.name.getText(), formalParameters, block));
  }

  @Override
  public void exitIf(IfContext ctx) {
    Block elseBlock = blocks.pop();
    Block thenBlock = blocks.pop();
    blocks.peek().add(new CommandIf(operands.pop(), thenBlock, elseBlock));
  }

  @Override
  public void exitRepeat(RepeatContext ctx) {
    Block block = blocks.pop();
    blocks.peek().add(new CommandRepeat(operands.pop(), block));
  }

  @Override
  public void exitPower(PowerContext ctx) {
    Expression b = operands.pop();
    Expression a = operands.pop();
    operands.push(new ExpressionAdd(a, b));
  }
}

LogoBaseListener.java

// Generated from Logo.g by ANTLR 4.1
package logo330.antlr;

import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.TerminalNode;

/**
 * This class provides an empty implementation of {@link LogoListener},
 * which can be extended to create a listener which only needs to handle a subset
 * of the available methods.
 */
public class LogoBaseListener implements LogoListener {
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterLiteral(@NotNull LogoParser.LiteralContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitLiteral(@NotNull LogoParser.LiteralContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterPower(@NotNull LogoParser.PowerContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitPower(@NotNull LogoParser.PowerContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterCall(@NotNull LogoParser.CallContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitCall(@NotNull LogoParser.CallContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterAssignment(@NotNull LogoParser.AssignmentContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitAssignment(@NotNull LogoParser.AssignmentContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterBlock(@NotNull LogoParser.BlockContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitBlock(@NotNull LogoParser.BlockContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterGrouped(@NotNull LogoParser.GroupedContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitGrouped(@NotNull LogoParser.GroupedContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterMultiply(@NotNull LogoParser.MultiplyContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitMultiply(@NotNull LogoParser.MultiplyContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterLog(@NotNull LogoParser.LogContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitLog(@NotNull LogoParser.LogContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterPen(@NotNull LogoParser.PenContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitPen(@NotNull LogoParser.PenContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterProgram(@NotNull LogoParser.ProgramContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitProgram(@NotNull LogoParser.ProgramContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterAdd(@NotNull LogoParser.AddContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitAdd(@NotNull LogoParser.AddContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterMove(@NotNull LogoParser.MoveContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitMove(@NotNull LogoParser.MoveContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterRotate(@NotNull LogoParser.RotateContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitRotate(@NotNull LogoParser.RotateContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterDefine(@NotNull LogoParser.DefineContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitDefine(@NotNull LogoParser.DefineContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterIdentifier(@NotNull LogoParser.IdentifierContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitIdentifier(@NotNull LogoParser.IdentifierContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterIf(@NotNull LogoParser.IfContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitIf(@NotNull LogoParser.IfContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterRepeat(@NotNull LogoParser.RepeatContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitRepeat(@NotNull LogoParser.RepeatContext ctx) { }

  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void enterEveryRule(@NotNull ParserRuleContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void exitEveryRule(@NotNull ParserRuleContext ctx) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void visitTerminal(@NotNull TerminalNode node) { }
  /**
   * {@inheritDoc}
   * <p/>
   * The default implementation does nothing.
   */
  @Override public void visitErrorNode(@NotNull ErrorNode node) { }
}

LogoLexer.java

// Generated from Logo.g by ANTLR 4.1
package logo330.antlr;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.misc.*;

@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
public class LogoLexer extends Lexer {
  protected static final DFA[] _decisionToDFA;
  protected static final PredictionContextCache _sharedContextCache =
    new PredictionContextCache();
  public static final int
    TO=1, LOG=2, REPEAT=3, END=4, IF=5, ELSE=6, MOVE=7, ROTATE=8, PEN=9, EQUALS=10, 
    LEFT_PARENTHESIS=11, RIGHT_PARENTHESIS=12, POWER_OPERATOR=13, MULTIPLICATIVE_OPERATOR=14, 
    ADDITIVE_OPERATOR=15, LITERAL=16, ID=17, WHITESPACE=18, NEWLINE=19;
  public static String[] modeNames = {
    "DEFAULT_MODE"
  };

  public static final String[] tokenNames = {
    "<INVALID>",
    "'to'", "'log'", "'repeat'", "'end'", "'if'", "'else'", "'move'", "'rotate'", 
    "'pen'", "'='", "'('", "')'", "'^'", "MULTIPLICATIVE_OPERATOR", "ADDITIVE_OPERATOR", 
    "LITERAL", "ID", "WHITESPACE", "NEWLINE"
  };
  public static final String[] ruleNames = {
    "TO", "LOG", "REPEAT", "END", "IF", "ELSE", "MOVE", "ROTATE", "PEN", "EQUALS", 
    "LEFT_PARENTHESIS", "RIGHT_PARENTHESIS", "POWER_OPERATOR", "MULTIPLICATIVE_OPERATOR", 
    "ADDITIVE_OPERATOR", "LITERAL", "ID", "WHITESPACE", "NEWLINE"
  };

  public LogoLexer(CharStream input) {
    super(input);
    _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
  }

  @Override
  public String getGrammarFileName() { return "Logo.g"; }

  @Override
  public String[] getTokenNames() { return tokenNames; }

  @Override
  public String[] getRuleNames() { return ruleNames; }

  @Override
  public String[] getModeNames() { return modeNames; }

  @Override
  public ATN getATN() { return _ATN; }

  @Override
  public void action(RuleContext _localctx, int ruleIndex, int actionIndex) {
    switch (ruleIndex) {
    case 17: WHITESPACE_action((RuleContext)_localctx, actionIndex); break;
    }
  }
  private void WHITESPACE_action(RuleContext _localctx, int actionIndex) {
    switch (actionIndex) {
    case 0: skip();  break;
    }
  }

  public static final String _serializedATN =
    "\3\uacf5\uee8c\u4f5d\u8b0d\u4a45\u78bd\u1b2f\u3378\2\25\u0080\b\1\4\2"+
    "\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4"+
    "\13\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22"+
    "\t\22\4\23\t\23\4\24\t\24\3\2\3\2\3\2\3\3\3\3\3\3\3\3\3\4\3\4\3\4\3\4"+
    "\3\4\3\4\3\4\3\5\3\5\3\5\3\5\3\6\3\6\3\6\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3"+
    "\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\n\3\n\3\13\3\13\3\f\3"+
    "\f\3\r\3\r\3\16\3\16\3\17\3\17\3\20\3\20\3\21\5\21a\n\21\3\21\6\21d\n"+
    "\21\r\21\16\21e\3\21\3\21\6\21j\n\21\r\21\16\21k\5\21n\n\21\3\22\6\22"+
    "q\n\22\r\22\16\22r\3\23\6\23v\n\23\r\23\16\23w\3\23\3\23\3\24\5\24}\n"+
    "\24\3\24\3\24\2\25\3\3\1\5\4\1\7\5\1\t\6\1\13\7\1\r\b\1\17\t\1\21\n\1"+
    "\23\13\1\25\f\1\27\r\1\31\16\1\33\17\1\35\20\1\37\21\1!\22\1#\23\1%\24"+
    "\2\'\25\1\3\2\7\4\2,,\61\61\4\2--//\3\2\62;\3\2c|\4\2\13\13\"\"\u0086"+
    "\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2"+
    "\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2"+
    "\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2"+
    "\2\2\2%\3\2\2\2\2\'\3\2\2\2\3)\3\2\2\2\5,\3\2\2\2\7\60\3\2\2\2\t\67\3"+
    "\2\2\2\13;\3\2\2\2\r>\3\2\2\2\17C\3\2\2\2\21H\3\2\2\2\23O\3\2\2\2\25S"+
    "\3\2\2\2\27U\3\2\2\2\31W\3\2\2\2\33Y\3\2\2\2\35[\3\2\2\2\37]\3\2\2\2!"+
    "`\3\2\2\2#p\3\2\2\2%u\3\2\2\2\'|\3\2\2\2)*\7v\2\2*+\7q\2\2+\4\3\2\2\2"+
    ",-\7n\2\2-.\7q\2\2./\7i\2\2/\6\3\2\2\2\60\61\7t\2\2\61\62\7g\2\2\62\63"+
    "\7r\2\2\63\64\7g\2\2\64\65\7c\2\2\65\66\7v\2\2\66\b\3\2\2\2\678\7g\2\2"+
    "89\7p\2\29:\7f\2\2:\n\3\2\2\2;<\7k\2\2<=\7h\2\2=\f\3\2\2\2>?\7g\2\2?@"+
    "\7n\2\2@A\7u\2\2AB\7g\2\2B\16\3\2\2\2CD\7o\2\2DE\7q\2\2EF\7x\2\2FG\7g"+
    "\2\2G\20\3\2\2\2HI\7t\2\2IJ\7q\2\2JK\7v\2\2KL\7c\2\2LM\7v\2\2MN\7g\2\2"+
    "N\22\3\2\2\2OP\7r\2\2PQ\7g\2\2QR\7p\2\2R\24\3\2\2\2ST\7?\2\2T\26\3\2\2"+
    "\2UV\7*\2\2V\30\3\2\2\2WX\7+\2\2X\32\3\2\2\2YZ\7`\2\2Z\34\3\2\2\2[\\\t"+
    "\2\2\2\\\36\3\2\2\2]^\t\3\2\2^ \3\2\2\2_a\7/\2\2`_\3\2\2\2`a\3\2\2\2a"+
    "c\3\2\2\2bd\t\4\2\2cb\3\2\2\2de\3\2\2\2ec\3\2\2\2ef\3\2\2\2fm\3\2\2\2"+
    "gi\7\60\2\2hj\t\4\2\2ih\3\2\2\2jk\3\2\2\2ki\3\2\2\2kl\3\2\2\2ln\3\2\2"+
    "\2mg\3\2\2\2mn\3\2\2\2n\"\3\2\2\2oq\t\5\2\2po\3\2\2\2qr\3\2\2\2rp\3\2"+
    "\2\2rs\3\2\2\2s$\3\2\2\2tv\t\6\2\2ut\3\2\2\2vw\3\2\2\2wu\3\2\2\2wx\3\2"+
    "\2\2xy\3\2\2\2yz\b\23\2\2z&\3\2\2\2{}\7\17\2\2|{\3\2\2\2|}\3\2\2\2}~\3"+
    "\2\2\2~\177\7\f\2\2\177(\3\2\2\2\n\2`ekmrw|";
  public static final ATN _ATN =
    ATNSimulator.deserialize(_serializedATN.toCharArray());
  static {
    _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
    for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
      _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
    }
  }
}

LogoListener.java

// Generated from Logo.g by ANTLR 4.1
package logo330.antlr;
import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.tree.ParseTreeListener;

/**
 * This interface defines a complete listener for a parse tree produced by
 * {@link LogoParser}.
 */
public interface LogoListener extends ParseTreeListener {
  /**
   * Enter a parse tree produced by {@link LogoParser#Literal}.
   * @param ctx the parse tree
   */
  void enterLiteral(@NotNull LogoParser.LiteralContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Literal}.
   * @param ctx the parse tree
   */
  void exitLiteral(@NotNull LogoParser.LiteralContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#Power}.
   * @param ctx the parse tree
   */
  void enterPower(@NotNull LogoParser.PowerContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Power}.
   * @param ctx the parse tree
   */
  void exitPower(@NotNull LogoParser.PowerContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#Call}.
   * @param ctx the parse tree
   */
  void enterCall(@NotNull LogoParser.CallContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Call}.
   * @param ctx the parse tree
   */
  void exitCall(@NotNull LogoParser.CallContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#Assignment}.
   * @param ctx the parse tree
   */
  void enterAssignment(@NotNull LogoParser.AssignmentContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Assignment}.
   * @param ctx the parse tree
   */
  void exitAssignment(@NotNull LogoParser.AssignmentContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#block}.
   * @param ctx the parse tree
   */
  void enterBlock(@NotNull LogoParser.BlockContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#block}.
   * @param ctx the parse tree
   */
  void exitBlock(@NotNull LogoParser.BlockContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#Grouped}.
   * @param ctx the parse tree
   */
  void enterGrouped(@NotNull LogoParser.GroupedContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Grouped}.
   * @param ctx the parse tree
   */
  void exitGrouped(@NotNull LogoParser.GroupedContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#Multiply}.
   * @param ctx the parse tree
   */
  void enterMultiply(@NotNull LogoParser.MultiplyContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Multiply}.
   * @param ctx the parse tree
   */
  void exitMultiply(@NotNull LogoParser.MultiplyContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#Log}.
   * @param ctx the parse tree
   */
  void enterLog(@NotNull LogoParser.LogContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Log}.
   * @param ctx the parse tree
   */
  void exitLog(@NotNull LogoParser.LogContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#Pen}.
   * @param ctx the parse tree
   */
  void enterPen(@NotNull LogoParser.PenContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Pen}.
   * @param ctx the parse tree
   */
  void exitPen(@NotNull LogoParser.PenContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#program}.
   * @param ctx the parse tree
   */
  void enterProgram(@NotNull LogoParser.ProgramContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#program}.
   * @param ctx the parse tree
   */
  void exitProgram(@NotNull LogoParser.ProgramContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#Add}.
   * @param ctx the parse tree
   */
  void enterAdd(@NotNull LogoParser.AddContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Add}.
   * @param ctx the parse tree
   */
  void exitAdd(@NotNull LogoParser.AddContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#Move}.
   * @param ctx the parse tree
   */
  void enterMove(@NotNull LogoParser.MoveContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Move}.
   * @param ctx the parse tree
   */
  void exitMove(@NotNull LogoParser.MoveContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#Rotate}.
   * @param ctx the parse tree
   */
  void enterRotate(@NotNull LogoParser.RotateContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Rotate}.
   * @param ctx the parse tree
   */
  void exitRotate(@NotNull LogoParser.RotateContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#Define}.
   * @param ctx the parse tree
   */
  void enterDefine(@NotNull LogoParser.DefineContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Define}.
   * @param ctx the parse tree
   */
  void exitDefine(@NotNull LogoParser.DefineContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#Identifier}.
   * @param ctx the parse tree
   */
  void enterIdentifier(@NotNull LogoParser.IdentifierContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Identifier}.
   * @param ctx the parse tree
   */
  void exitIdentifier(@NotNull LogoParser.IdentifierContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#If}.
   * @param ctx the parse tree
   */
  void enterIf(@NotNull LogoParser.IfContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#If}.
   * @param ctx the parse tree
   */
  void exitIf(@NotNull LogoParser.IfContext ctx);

  /**
   * Enter a parse tree produced by {@link LogoParser#Repeat}.
   * @param ctx the parse tree
   */
  void enterRepeat(@NotNull LogoParser.RepeatContext ctx);
  /**
   * Exit a parse tree produced by {@link LogoParser#Repeat}.
   * @param ctx the parse tree
   */
  void exitRepeat(@NotNull LogoParser.RepeatContext ctx);
}

LogoParser.java

// Generated from Logo.g by ANTLR 4.1
package logo330.antlr;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.misc.*;
import org.antlr.v4.runtime.tree.*;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;

@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})
public class LogoParser extends Parser {
  protected static final DFA[] _decisionToDFA;
  protected static final PredictionContextCache _sharedContextCache =
    new PredictionContextCache();
  public static final int
    TO=1, LOG=2, REPEAT=3, END=4, IF=5, ELSE=6, MOVE=7, ROTATE=8, PEN=9, EQUALS=10, 
    LEFT_PARENTHESIS=11, RIGHT_PARENTHESIS=12, POWER_OPERATOR=13, MULTIPLICATIVE_OPERATOR=14, 
    ADDITIVE_OPERATOR=15, LITERAL=16, ID=17, WHITESPACE=18, NEWLINE=19;
  public static final String[] tokenNames = {
    "<INVALID>", "'to'", "'log'", "'repeat'", "'end'", "'if'", "'else'", "'move'", 
    "'rotate'", "'pen'", "'='", "'('", "')'", "'^'", "MULTIPLICATIVE_OPERATOR", 
    "ADDITIVE_OPERATOR", "LITERAL", "ID", "WHITESPACE", "NEWLINE"
  };
  public static final int
    RULE_program = 0, RULE_block = 1, RULE_command = 2, RULE_expression = 3;
  public static final String[] ruleNames = {
    "program", "block", "command", "expression"
  };

  @Override
  public String getGrammarFileName() { return "Logo.g"; }

  @Override
  public String[] getTokenNames() { return tokenNames; }

  @Override
  public String[] getRuleNames() { return ruleNames; }

  @Override
  public ATN getATN() { return _ATN; }

  public LogoParser(TokenStream input) {
    super(input);
    _interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
  }
  public static class ProgramContext extends ParserRuleContext {
    public TerminalNode EOF() { return getToken(LogoParser.EOF, 0); }
    public BlockContext block() {
      return getRuleContext(BlockContext.class,0);
    }
    public ProgramContext(ParserRuleContext parent, int invokingState) {
      super(parent, invokingState);
    }
    @Override public int getRuleIndex() { return RULE_program; }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterProgram(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitProgram(this);
    }
  }

  public final ProgramContext program() throws RecognitionException {
    ProgramContext _localctx = new ProgramContext(_ctx, getState());
    enterRule(_localctx, 0, RULE_program);
    try {
      enterOuterAlt(_localctx, 1);
      {
      setState(8); block();
      setState(9); match(EOF);
      }
    }
    catch (RecognitionException re) {
      _localctx.exception = re;
      _errHandler.reportError(this, re);
      _errHandler.recover(this, re);
    }
    finally {
      exitRule();
    }
    return _localctx;
  }

  public static class BlockContext extends ParserRuleContext {
    public List<TerminalNode> NEWLINE() { return getTokens(LogoParser.NEWLINE); }
    public List<CommandContext> command() {
      return getRuleContexts(CommandContext.class);
    }
    public TerminalNode NEWLINE(int i) {
      return getToken(LogoParser.NEWLINE, i);
    }
    public CommandContext command(int i) {
      return getRuleContext(CommandContext.class,i);
    }
    public BlockContext(ParserRuleContext parent, int invokingState) {
      super(parent, invokingState);
    }
    @Override public int getRuleIndex() { return RULE_block; }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterBlock(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitBlock(this);
    }
  }

  public final BlockContext block() throws RecognitionException {
    BlockContext _localctx = new BlockContext(_ctx, getState());
    enterRule(_localctx, 2, RULE_block);
    int _la;
    try {
      enterOuterAlt(_localctx, 1);
      {
      setState(16);
      _errHandler.sync(this);
      _la = _input.LA(1);
      while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << TO) | (1L << LOG) | (1L << REPEAT) | (1L << IF) | (1L << MOVE) | (1L << ROTATE) | (1L << PEN) | (1L << ID))) != 0)) {
        {
        {
        setState(11); command();
        setState(12); match(NEWLINE);
        }
        }
        setState(18);
        _errHandler.sync(this);
        _la = _input.LA(1);
      }
      }
    }
    catch (RecognitionException re) {
      _localctx.exception = re;
      _errHandler.reportError(this, re);
      _errHandler.recover(this, re);
    }
    finally {
      exitRule();
    }
    return _localctx;
  }

  public static class CommandContext extends ParserRuleContext {
    public CommandContext(ParserRuleContext parent, int invokingState) {
      super(parent, invokingState);
    }
    @Override public int getRuleIndex() { return RULE_command; }

    public CommandContext() { }
    public void copyFrom(CommandContext ctx) {
      super.copyFrom(ctx);
    }
  }
  public static class LogContext extends CommandContext {
    public TerminalNode LOG() { return getToken(LogoParser.LOG, 0); }
    public ExpressionContext expression() {
      return getRuleContext(ExpressionContext.class,0);
    }
    public LogContext(CommandContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterLog(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitLog(this);
    }
  }
  public static class PenContext extends CommandContext {
    public TerminalNode PEN() { return getToken(LogoParser.PEN, 0); }
    public ExpressionContext expression() {
      return getRuleContext(ExpressionContext.class,0);
    }
    public PenContext(CommandContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterPen(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitPen(this);
    }
  }
  public static class CallContext extends CommandContext {
    public ExpressionContext expression(int i) {
      return getRuleContext(ExpressionContext.class,i);
    }
    public TerminalNode ID() { return getToken(LogoParser.ID, 0); }
    public List<ExpressionContext> expression() {
      return getRuleContexts(ExpressionContext.class);
    }
    public CallContext(CommandContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterCall(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitCall(this);
    }
  }
  public static class AssignmentContext extends CommandContext {
    public TerminalNode EQUALS() { return getToken(LogoParser.EQUALS, 0); }
    public TerminalNode ID() { return getToken(LogoParser.ID, 0); }
    public ExpressionContext expression() {
      return getRuleContext(ExpressionContext.class,0);
    }
    public AssignmentContext(CommandContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterAssignment(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitAssignment(this);
    }
  }
  public static class MoveContext extends CommandContext {
    public TerminalNode MOVE() { return getToken(LogoParser.MOVE, 0); }
    public ExpressionContext expression() {
      return getRuleContext(ExpressionContext.class,0);
    }
    public MoveContext(CommandContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterMove(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitMove(this);
    }
  }
  public static class RotateContext extends CommandContext {
    public TerminalNode ROTATE() { return getToken(LogoParser.ROTATE, 0); }
    public ExpressionContext expression() {
      return getRuleContext(ExpressionContext.class,0);
    }
    public RotateContext(CommandContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterRotate(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitRotate(this);
    }
  }
  public static class DefineContext extends CommandContext {
    public TerminalNode NEWLINE() { return getToken(LogoParser.NEWLINE, 0); }
    public TerminalNode EQUALS() { return getToken(LogoParser.EQUALS, 0); }
    public List<TerminalNode> ID() { return getTokens(LogoParser.ID); }
    public BlockContext block() {
      return getRuleContext(BlockContext.class,0);
    }
    public TerminalNode TO() { return getToken(LogoParser.TO, 0); }
    public TerminalNode END() { return getToken(LogoParser.END, 0); }
    public TerminalNode ID(int i) {
      return getToken(LogoParser.ID, i);
    }
    public DefineContext(CommandContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterDefine(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitDefine(this);
    }
  }
  public static class IfContext extends CommandContext {
    public List<TerminalNode> NEWLINE() { return getTokens(LogoParser.NEWLINE); }
    public TerminalNode IF() { return getToken(LogoParser.IF, 0); }
    public TerminalNode NEWLINE(int i) {
      return getToken(LogoParser.NEWLINE, i);
    }
    public TerminalNode ELSE() { return getToken(LogoParser.ELSE, 0); }
    public BlockContext block(int i) {
      return getRuleContext(BlockContext.class,i);
    }
    public ExpressionContext expression() {
      return getRuleContext(ExpressionContext.class,0);
    }
    public List<BlockContext> block() {
      return getRuleContexts(BlockContext.class);
    }
    public TerminalNode END() { return getToken(LogoParser.END, 0); }
    public IfContext(CommandContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterIf(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitIf(this);
    }
  }
  public static class RepeatContext extends CommandContext {
    public TerminalNode NEWLINE() { return getToken(LogoParser.NEWLINE, 0); }
    public TerminalNode REPEAT() { return getToken(LogoParser.REPEAT, 0); }
    public ExpressionContext expression() {
      return getRuleContext(ExpressionContext.class,0);
    }
    public BlockContext block() {
      return getRuleContext(BlockContext.class,0);
    }
    public TerminalNode END() { return getToken(LogoParser.END, 0); }
    public RepeatContext(CommandContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterRepeat(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitRepeat(this);
    }
  }

  public final CommandContext command() throws RecognitionException {
    CommandContext _localctx = new CommandContext(_ctx, getState());
    enterRule(_localctx, 4, RULE_command);
    int _la;
    try {
      setState(65);
      switch ( getInterpreter().adaptivePredict(_input,3,_ctx) ) {
      case 1:
        _localctx = new MoveContext(_localctx);
        enterOuterAlt(_localctx, 1);
        {
        setState(19); match(MOVE);
        setState(20); expression(0);
        }
        break;

      case 2:
        _localctx = new RotateContext(_localctx);
        enterOuterAlt(_localctx, 2);
        {
        setState(21); match(ROTATE);
        setState(22); expression(0);
        }
        break;

      case 3:
        _localctx = new RepeatContext(_localctx);
        enterOuterAlt(_localctx, 3);
        {
        setState(23); match(REPEAT);
        setState(24); expression(0);
        setState(25); match(NEWLINE);
        setState(26); block();
        setState(27); match(END);
        }
        break;

      case 4:
        _localctx = new LogContext(_localctx);
        enterOuterAlt(_localctx, 4);
        {
        setState(29); match(LOG);
        setState(30); expression(0);
        }
        break;

      case 5:
        _localctx = new IfContext(_localctx);
        enterOuterAlt(_localctx, 5);
        {
        setState(31); match(IF);
        setState(32); expression(0);
        setState(33); match(NEWLINE);
        setState(34); block();
        setState(35); match(ELSE);
        setState(36); match(NEWLINE);
        setState(37); block();
        setState(38); match(END);
        }
        break;

      case 6:
        _localctx = new DefineContext(_localctx);
        enterOuterAlt(_localctx, 6);
        {
        setState(40); match(TO);
        setState(41); match(ID);
        setState(45);
        _errHandler.sync(this);
        _la = _input.LA(1);
        while (_la==ID) {
          {
          {
          setState(42); match(ID);
          }
          }
          setState(47);
          _errHandler.sync(this);
          _la = _input.LA(1);
        }
        setState(48); match(EQUALS);
        setState(49); match(NEWLINE);
        setState(50); block();
        setState(51); match(END);
        }
        break;

      case 7:
        _localctx = new CallContext(_localctx);
        enterOuterAlt(_localctx, 7);
        {
        setState(53); match(ID);
        setState(57);
        _errHandler.sync(this);
        _la = _input.LA(1);
        while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LEFT_PARENTHESIS) | (1L << LITERAL) | (1L << ID))) != 0)) {
          {
          {
          setState(54); expression(0);
          }
          }
          setState(59);
          _errHandler.sync(this);
          _la = _input.LA(1);
        }
        }
        break;

      case 8:
        _localctx = new AssignmentContext(_localctx);
        enterOuterAlt(_localctx, 8);
        {
        setState(60); match(ID);
        setState(61); match(EQUALS);
        setState(62); expression(0);
        }
        break;

      case 9:
        _localctx = new PenContext(_localctx);
        enterOuterAlt(_localctx, 9);
        {
        setState(63); match(PEN);
        setState(64); expression(0);
        }
        break;
      }
    }
    catch (RecognitionException re) {
      _localctx.exception = re;
      _errHandler.reportError(this, re);
      _errHandler.recover(this, re);
    }
    finally {
      exitRule();
    }
    return _localctx;
  }

  public static class ExpressionContext extends ParserRuleContext {
    public int _p;
    public ExpressionContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); }
    public ExpressionContext(ParserRuleContext parent, int invokingState, int _p) {
      super(parent, invokingState);
      this._p = _p;
    }
    @Override public int getRuleIndex() { return RULE_expression; }

    public ExpressionContext() { }
    public void copyFrom(ExpressionContext ctx) {
      super.copyFrom(ctx);
      this._p = ctx._p;
    }
  }
  public static class LiteralContext extends ExpressionContext {
    public TerminalNode LITERAL() { return getToken(LogoParser.LITERAL, 0); }
    public LiteralContext(ExpressionContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterLiteral(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitLiteral(this);
    }
  }
  public static class PowerContext extends ExpressionContext {
    public TerminalNode POWER_OPERATOR() { return getToken(LogoParser.POWER_OPERATOR, 0); }
    public ExpressionContext expression(int i) {
      return getRuleContext(ExpressionContext.class,i);
    }
    public List<ExpressionContext> expression() {
      return getRuleContexts(ExpressionContext.class);
    }
    public PowerContext(ExpressionContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterPower(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitPower(this);
    }
  }
  public static class AddContext extends ExpressionContext {
    public ExpressionContext expression(int i) {
      return getRuleContext(ExpressionContext.class,i);
    }
    public List<ExpressionContext> expression() {
      return getRuleContexts(ExpressionContext.class);
    }
    public TerminalNode ADDITIVE_OPERATOR() { return getToken(LogoParser.ADDITIVE_OPERATOR, 0); }
    public AddContext(ExpressionContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterAdd(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitAdd(this);
    }
  }
  public static class IdentifierContext extends ExpressionContext {
    public TerminalNode ID() { return getToken(LogoParser.ID, 0); }
    public IdentifierContext(ExpressionContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterIdentifier(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitIdentifier(this);
    }
  }
  public static class GroupedContext extends ExpressionContext {
    public TerminalNode LEFT_PARENTHESIS() { return getToken(LogoParser.LEFT_PARENTHESIS, 0); }
    public TerminalNode RIGHT_PARENTHESIS() { return getToken(LogoParser.RIGHT_PARENTHESIS, 0); }
    public ExpressionContext expression() {
      return getRuleContext(ExpressionContext.class,0);
    }
    public GroupedContext(ExpressionContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterGrouped(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitGrouped(this);
    }
  }
  public static class MultiplyContext extends ExpressionContext {
    public ExpressionContext expression(int i) {
      return getRuleContext(ExpressionContext.class,i);
    }
    public TerminalNode MULTIPLICATIVE_OPERATOR() { return getToken(LogoParser.MULTIPLICATIVE_OPERATOR, 0); }
    public List<ExpressionContext> expression() {
      return getRuleContexts(ExpressionContext.class);
    }
    public MultiplyContext(ExpressionContext ctx) { copyFrom(ctx); }
    @Override
    public void enterRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).enterMultiply(this);
    }
    @Override
    public void exitRule(ParseTreeListener listener) {
      if ( listener instanceof LogoListener ) ((LogoListener)listener).exitMultiply(this);
    }
  }

  public final ExpressionContext expression(int _p) throws RecognitionException {
    ParserRuleContext _parentctx = _ctx;
    int _parentState = getState();
    ExpressionContext _localctx = new ExpressionContext(_ctx, _parentState, _p);
    ExpressionContext _prevctx = _localctx;
    int _startState = 6;
    enterRecursionRule(_localctx, RULE_expression);
    try {
      int _alt;
      enterOuterAlt(_localctx, 1);
      {
      setState(74);
      switch (_input.LA(1)) {
      case LEFT_PARENTHESIS:
        {
        _localctx = new GroupedContext(_localctx);
        _ctx = _localctx;
        _prevctx = _localctx;

        setState(68); match(LEFT_PARENTHESIS);
        setState(69); expression(0);
        setState(70); match(RIGHT_PARENTHESIS);
        }
        break;
      case LITERAL:
        {
        _localctx = new LiteralContext(_localctx);
        _ctx = _localctx;
        _prevctx = _localctx;
        setState(72); match(LITERAL);
        }
        break;
      case ID:
        {
        _localctx = new IdentifierContext(_localctx);
        _ctx = _localctx;
        _prevctx = _localctx;
        setState(73); match(ID);
        }
        break;
      default:
        throw new NoViableAltException(this);
      }
      _ctx.stop = _input.LT(-1);
      setState(87);
      _errHandler.sync(this);
      _alt = getInterpreter().adaptivePredict(_input,6,_ctx);
      while ( _alt!=2 && _alt!=-1 ) {
        if ( _alt==1 ) {
          if ( _parseListeners!=null ) triggerExitRuleEvent();
          _prevctx = _localctx;
          {
          setState(85);
          switch ( getInterpreter().adaptivePredict(_input,5,_ctx) ) {
          case 1:
            {
            _localctx = new PowerContext(new ExpressionContext(_parentctx, _parentState, _p));
            pushNewRecursionContext(_localctx, _startState, RULE_expression);
            setState(76);
            if (!(5 >= _localctx._p)) throw new FailedPredicateException(this, "5 >= $_p");
            setState(77); match(POWER_OPERATOR);
            setState(78); expression(6);
            }
            break;

          case 2:
            {
            _localctx = new MultiplyContext(new ExpressionContext(_parentctx, _parentState, _p));
            pushNewRecursionContext(_localctx, _startState, RULE_expression);
            setState(79);
            if (!(4 >= _localctx._p)) throw new FailedPredicateException(this, "4 >= $_p");
            setState(80); match(MULTIPLICATIVE_OPERATOR);
            setState(81); expression(5);
            }
            break;

          case 3:
            {
            _localctx = new AddContext(new ExpressionContext(_parentctx, _parentState, _p));
            pushNewRecursionContext(_localctx, _startState, RULE_expression);
            setState(82);
            if (!(3 >= _localctx._p)) throw new FailedPredicateException(this, "3 >= $_p");
            setState(83); match(ADDITIVE_OPERATOR);
            setState(84); expression(4);
            }
            break;
          }
          } 
        }
        setState(89);
        _errHandler.sync(this);
        _alt = getInterpreter().adaptivePredict(_input,6,_ctx);
      }
      }
    }
    catch (RecognitionException re) {
      _localctx.exception = re;
      _errHandler.reportError(this, re);
      _errHandler.recover(this, re);
    }
    finally {
      unrollRecursionContexts(_parentctx);
    }
    return _localctx;
  }

  public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) {
    switch (ruleIndex) {
    case 3: return expression_sempred((ExpressionContext)_localctx, predIndex);
    }
    return true;
  }
  private boolean expression_sempred(ExpressionContext _localctx, int predIndex) {
    switch (predIndex) {
    case 0: return 5 >= _localctx._p;

    case 1: return 4 >= _localctx._p;

    case 2: return 3 >= _localctx._p;
    }
    return true;
  }

  public static final String _serializedATN =
    "\3\uacf5\uee8c\u4f5d\u8b0d\u4a45\u78bd\u1b2f\u3378\3\25]\4\2\t\2\4\3\t"+
    "\3\4\4\t\4\4\5\t\5\3\2\3\2\3\2\3\3\3\3\3\3\7\3\21\n\3\f\3\16\3\24\13\3"+
    "\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3"+
    "\4\3\4\3\4\3\4\3\4\3\4\3\4\7\4.\n\4\f\4\16\4\61\13\4\3\4\3\4\3\4\3\4\3"+
    "\4\3\4\3\4\7\4:\n\4\f\4\16\4=\13\4\3\4\3\4\3\4\3\4\3\4\5\4D\n\4\3\5\3"+
    "\5\3\5\3\5\3\5\3\5\3\5\5\5M\n\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\7"+
    "\5X\n\5\f\5\16\5[\13\5\3\5\2\6\2\4\6\b\2\2h\2\n\3\2\2\2\4\22\3\2\2\2\6"+
    "C\3\2\2\2\bL\3\2\2\2\n\13\5\4\3\2\13\f\7\2\2\3\f\3\3\2\2\2\r\16\5\6\4"+
    "\2\16\17\7\25\2\2\17\21\3\2\2\2\20\r\3\2\2\2\21\24\3\2\2\2\22\20\3\2\2"+
    "\2\22\23\3\2\2\2\23\5\3\2\2\2\24\22\3\2\2\2\25\26\7\t\2\2\26D\5\b\5\2"+
    "\27\30\7\n\2\2\30D\5\b\5\2\31\32\7\5\2\2\32\33\5\b\5\2\33\34\7\25\2\2"+
    "\34\35\5\4\3\2\35\36\7\6\2\2\36D\3\2\2\2\37 \7\4\2\2 D\5\b\5\2!\"\7\7"+
    "\2\2\"#\5\b\5\2#$\7\25\2\2$%\5\4\3\2%&\7\b\2\2&\'\7\25\2\2\'(\5\4\3\2"+
    "()\7\6\2\2)D\3\2\2\2*+\7\3\2\2+/\7\23\2\2,.\7\23\2\2-,\3\2\2\2.\61\3\2"+
    "\2\2/-\3\2\2\2/\60\3\2\2\2\60\62\3\2\2\2\61/\3\2\2\2\62\63\7\f\2\2\63"+
    "\64\7\25\2\2\64\65\5\4\3\2\65\66\7\6\2\2\66D\3\2\2\2\67;\7\23\2\28:\5"+
    "\b\5\298\3\2\2\2:=\3\2\2\2;9\3\2\2\2;<\3\2\2\2<D\3\2\2\2=;\3\2\2\2>?\7"+
    "\23\2\2?@\7\f\2\2@D\5\b\5\2AB\7\13\2\2BD\5\b\5\2C\25\3\2\2\2C\27\3\2\2"+
    "\2C\31\3\2\2\2C\37\3\2\2\2C!\3\2\2\2C*\3\2\2\2C\67\3\2\2\2C>\3\2\2\2C"+
    "A\3\2\2\2D\7\3\2\2\2EF\b\5\1\2FG\7\r\2\2GH\5\b\5\2HI\7\16\2\2IM\3\2\2"+
    "\2JM\7\22\2\2KM\7\23\2\2LE\3\2\2\2LJ\3\2\2\2LK\3\2\2\2MY\3\2\2\2NO\6\5"+
    "\2\3OP\7\17\2\2PX\5\b\5\2QR\6\5\3\3RS\7\20\2\2SX\5\b\5\2TU\6\5\4\3UV\7"+
    "\21\2\2VX\5\b\5\2WN\3\2\2\2WQ\3\2\2\2WT\3\2\2\2X[\3\2\2\2YW\3\2\2\2YZ"+
    "\3\2\2\2Z\t\3\2\2\2[Y\3\2\2\2\t\22/;CLWY";
  public static final ATN _ATN =
    ATNSimulator.deserialize(_serializedATN.toCharArray());
  static {
    _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
    for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
      _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
    }
  }
}

Command.java

package logo330.command;

import logo330.Environment;

public abstract class Command {
  protected abstract void reallyExecute(Environment env);

  public void execute(Environment env) {
    reallyExecute(env);
    if (env.listener != null) {
      env.listener.onPostCommand();
    }
  }
}

CommandAssignment.java

package logo330.command;

import logo330.Environment;
import logo330.expression.Expression;

public class CommandAssignment extends Command {
  private String id;
  private Expression expr;

  public CommandAssignment(String id, Expression expr) {
    this.id = id;
    this.expr = expr;
  }

  @Override
  protected void reallyExecute(Environment env) {
    env.locals.put(id, expr.evaluate(env));
  }
}

CommandFunctionCall.java

package logo330.command;

import java.util.ArrayList;
import java.util.HashMap;
import logo330.Environment;
import logo330.Function;
import logo330.expression.Expression;

public class CommandFunctionCall extends Command {
  private String id;
  private ArrayList<Expression> actualParameters;

  public CommandFunctionCall(String id, ArrayList<Expression> actualParameters) {
    this.id = id;
    this.actualParameters = actualParameters;
  }

  @Override
  protected void reallyExecute(Environment env) {
    Function f = env.functions.get(id);

    HashMap<String, Double> outerLocals = env.locals;

    HashMap<String, Double> innerLocals = new HashMap<String, Double>();
    for (int i = 0; i < actualParameters.size(); ++i) {
      innerLocals.put(f.getFormalParameters().get(i), actualParameters.get(i).evaluate(env));
    }

    env.locals = innerLocals;
    f.getBody().execute(env);
    env.locals = outerLocals;
  }
}

CommandFunctionDefine.java

package logo330.command;

import java.util.ArrayList;
import logo330.Block;
import logo330.Environment;
import logo330.Function;

public class CommandFunctionDefine extends Command {
  private Function f;

  public CommandFunctionDefine(String id, ArrayList<String> formalParameters, Block body) {
    f = new Function(id, formalParameters, body);
  }

  @Override
  protected void reallyExecute(Environment env) {
    env.functions.put(f.getID(), f);
  }
}

CommandIf.java

package logo330.command;

import logo330.Block;
import logo330.Environment;
import logo330.expression.Expression;

public class CommandIf extends Command {
  private Expression expr;
  private Block thenBlock;
  private Block elseBlock;

  public CommandIf(Expression expr, Block thenBlock, Block elseBlock) {
    this.expr = expr;
    this.thenBlock = thenBlock;
    this.elseBlock = elseBlock;
  }

  @Override
  protected void reallyExecute(Environment env) {
    if (Math.abs(expr.evaluate(env)) > 1.0e-3f) {
      thenBlock.execute(env);
    } else {
      elseBlock.execute(env);
    }
  }
}

CommandListener.java

package logo330.command;
public interface CommandListener {
  public void onPostCommand();
}

CommandLog.java

package logo330.command;

import logo330.Environment;
import logo330.expression.Expression;

public class CommandLog extends Command {
  private Expression expr;

  public CommandLog(Expression expr) {
    this.expr = expr;
  }

  @Override
  protected void reallyExecute(Environment env) {
    System.out.println(expr.evaluate(env));
  }
}

CommandMove.java

package logo330.command;

import java.awt.geom.Line2D;
import logo330.Environment;
import logo330.expression.Expression;

public class CommandMove extends Command {
  private Expression expr;

  public CommandMove(Expression expr) {
    this.expr = expr;
  }

  @Override
  protected void reallyExecute(Environment env) {
    double newX = env.x + Math.cos(env.theta) * expr.evaluate(env);
    double newY = env.y + Math.sin(env.theta) * expr.evaluate(env);

    if (env.isDrawing) {
      synchronized (env.segments) {
        env.segments.add(new Line2D.Double(env.x, env.y, newX, newY));
      }
    }

    env.x = newX;
    env.y = newY;
  }
}

CommandPen.java

package logo330.command;

import logo330.Environment;
import logo330.expression.Expression;

public class CommandPen extends Command {
  private Expression expr;

  public CommandPen(Expression expr) {
    this.expr = expr;
  }

  @Override
  protected void reallyExecute(Environment env) {
    env.isDrawing = Math.abs(expr.evaluate(env)) < 1.0e-3f;
  }
}

CommandRepeat.java

package logo330.command;

import logo330.Block;
import logo330.Environment;
import logo330.expression.Expression;

public class CommandRepeat extends Command {
  private Expression expr;
  private Block block;

  public CommandRepeat(Expression expr, Block block) {
    this.expr = expr;
    this.block = block;
  }

  @Override
  protected void reallyExecute(Environment env) {
    int n = (int) expr.evaluate(env);
    for (int i = 0; i < n; ++i) {
      block.execute(env);
    }
  }
}

CommandRotate.java

package logo330.command;

import logo330.Environment;
import logo330.expression.Expression;

public class CommandRotate extends Command {
  private Expression expr;

  public CommandRotate(Expression expr) {
    this.expr = expr;
  }

  @Override
  protected void reallyExecute(Environment env) {
    env.theta += Math.toRadians(expr.evaluate(env));
  }
}

Expression.java

package logo330.expression;

import logo330.Environment;

public abstract class Expression {
  public abstract double evaluate(Environment env);
}

ExpressionAdd.java

package logo330.expression;

import logo330.Environment;

public class ExpressionAdd extends Expression {
  private Expression l;
  private Expression r;

  public ExpressionAdd(Expression l, Expression r) {
    this.l = l;
    this.r = r;
  }

  public double evaluate(Environment env) {
    return l.evaluate(env) + r.evaluate(env);
  }
}

ExpressionDivide.java

package logo330.expression;

import logo330.Environment;

public class ExpressionDivide extends Expression {
  private Expression l;
  private Expression r;

  public ExpressionDivide(Expression l, Expression r) {
    this.l = l;
    this.r = r;
  }

  public double evaluate(Environment env) {
    return l.evaluate(env) / r.evaluate(env);
  }
}

ExpressionIdentifier.java

package logo330.expression;

import java.util.NoSuchElementException;
import logo330.Environment;

public class ExpressionIdentifier extends Expression {
  private String id;

  public ExpressionIdentifier(String id) {
    this.id = id;
  }

  public double evaluate(Environment env) {
    if (env.locals.containsKey(id)) {
      return env.locals.get(id);
    } else {
      throw new NoSuchElementException(id);
    }
  }
}

ExpressionLiteral.java

package logo330.expression;

import logo330.Environment;

public class ExpressionLiteral extends Expression {
  private double value;

  public ExpressionLiteral(double value) {
    this.value = value;
  }

  public double evaluate(Environment env) {
    return value;
  }
}

ExpressionMultiply.java

package logo330.expression;

import logo330.Environment;

public class ExpressionMultiply extends Expression {
  private Expression l;
  private Expression r;

  public ExpressionMultiply(Expression l, Expression r) {
    this.l = l;
    this.r = r;
  }

  public double evaluate(Environment env) {
    return l.evaluate(env) * r.evaluate(env);
  }
}

ExpressionPower.java

package logo330.expression;

import logo330.Environment;

public class ExpressionPower extends Expression {
  private Expression l;
  private Expression r;

  public ExpressionPower(Expression l, Expression r) {
    this.l = l;
    this.r = r;
  }

  public double evaluate(Environment env) {
    return Math.pow(l.evaluate(env), r.evaluate(env));
  }
}

ExpressionSubtract.java

package logo330.expression;

import logo330.Environment;

public class ExpressionSubtract extends Expression {
  private Expression l;
  private Expression r;

  public ExpressionSubtract(Expression l, Expression r) {
    this.l = l;
    this.r = r;
  }

  public double evaluate(Environment env) {
    return l.evaluate(env) - r.evaluate(env);
  }
}

Haiku

Without rules, I cheat
Without discipline, I slave
Without exceptions, I fly through the error on wings of deviance