CS 330 Lecture 13 – Control Statements
Agenda
- what ?s
- what’s a program look like?
- adding moves and rotates
- adding loops and conditionals
- adding functions
TODO
- Start the CSE homework. Sync and pull to get the grader as described in post @16.
- Extra credit participation: download the Logo Eclipse project and write a Logo program. PostĀ it on Piazza (filed under folder
logo
) before Wednesday’s lecture.
Code
Logo.g
grammar Logo;
program
: block EOF
;
block
: (statement? NEWLINE)*
;
statement
: MOVE expr # Move
| ROTATE expr # Rotate
| IF expr NEWLINE block ELSE block END # If
| TO IDENTIFIER IDENTIFIER* NEWLINE block END # FunctionDefine
| IDENTIFIER expr* # FunctionCall
| REPEAT expr NEWLINE block END # Repeat
| IDENTIFIER ASSIGNMENT expr # Assignment
;
expr
: LEFT_PARENTHESIS expr RIGHT_PARENTHESIS # Grouped
| NEGATIVE expr # Negate
| expr POWER expr # Power
| expr MULTIPLICATIVE_OPERATOR expr # Multiply
| expr ADDITIVE_OPERATOR expr # Add
| NUMBER # Literal
| IDENTIFIER # Identifier
;
IF: 'if';
ELSE: 'else';
TO: 'to';
MOVE: 'move';
ROTATE: 'rotate';
REPEAT: 'repeat';
END: 'end';
LEFT_PARENTHESIS: '(';
RIGHT_PARENTHESIS: ')';
POWER: '^';
NEGATIVE: '-';
MULTIPLICATIVE_OPERATOR: [*/%];
ADDITIVE_OPERATOR: '+' | '- ';
ASSIGNMENT: '=';
IDENTIFIER: [a-z]+ [a-z_]*;
NUMBER: '-'? [0-9]+ ('.' [0-9]+)?;
NEWLINE: '\n';
WHITESPACE: [ \t]+ -> skip;
Block.java
import java.util.ArrayList;
public class Block {
private ArrayList<Statement> statements;
public Block() {
statements = new ArrayList<>();
}
public void add(Statement s) {
statements.add(s);
}
public int size() {
return statements.size();
}
public void execute(Environment env) {
for (Statement s : statements) {
s.executeWithTrigger(env);
}
}
}
Function.java
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;
}
}
Statement.java
public abstract class Statement {
protected abstract void execute(Environment env);
protected void executeWithTrigger(Environment env) {
execute(env);
if (env.listener != null) {
env.listener.onPostExecute();
}
}
}
Environment.java
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.HashMap;
public class Environment {
public double x = 0.0;
public double y = 0.0;
public double heading = 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 StatementListener listener = null;
}
Expr.java
public abstract class Expr {
public abstract double evaluate(Environment env);
}
ExprAdd.java
public class ExprAdd extends Expr {
private Expr a;
private Expr b;
public ExprAdd(Expr a, Expr b) {
this.a = a;
this.b = b;
}
public double evaluate(Environment env) {
return a.evaluate(env) + b.evaluate(env);
}
}
ExprDivide.java
public class ExprDivide extends Expr {
private Expr a;
private Expr b;
public ExprDivide(Expr a, Expr b) {
this.a = a;
this.b = b;
}
public double evaluate(Environment env) {
return a.evaluate(env) / b.evaluate(env);
}
}
ExprIdentifier.java
public class ExprIdentifier extends Expr {
private String id;
public ExprIdentifier(String id) {
this.id = id;
}
public double evaluate(Environment env) {
return env.locals.get(id);
}
}
ExprLiteral.java
public class ExprLiteral extends Expr {
public double i;
public ExprLiteral(double i) {
this.i = i;
}
public double evaluate(Environment env) {
return i;
}
}
ExprMultiply.java
public class ExprMultiply extends Expr {
private Expr a;
private Expr b;
public ExprMultiply(Expr a, Expr b) {
this.a = a;
this.b = b;
}
public double evaluate(Environment env) {
return a.evaluate(env) * b.evaluate(env);
}
}
ExprNegate.java
public class ExprNegate extends Expr {
private Expr a;
public ExprNegate(Expr a) {
this.a = a;
}
public double evaluate(Environment env) {
return -a.evaluate(env);
}
}
ExprPower.java
public class ExprPower extends Expr {
private Expr a;
private Expr b;
public ExprPower(Expr a, Expr b) {
this.a = a;
this.b = b;
}
public double evaluate(Environment env) {
return Math.pow(a.evaluate(env), b.evaluate(env));
}
}
ExprRemainder.java
public class ExprRemainder extends Expr {
private Expr a;
private Expr b;
public ExprRemainder(Expr a, Expr b) {
this.a = a;
this.b = b;
}
public double evaluate(Environment env) {
return a.evaluate(env) % b.evaluate(env);
}
}
ExprSubtract.java
public class ExprSubtract extends Expr {
private Expr a;
private Expr b;
public ExprSubtract(Expr a, Expr b) {
this.a = a;
this.b = b;
}
public double evaluate(Environment env) {
return a.evaluate(env) - b.evaluate(env);
}
}
Statement.java
public abstract class Statement {
protected abstract void execute(Environment env);
protected void executeWithTrigger(Environment env) {
execute(env);
if (env.listener != null) {
env.listener.onPostExecute();
}
}
}
StatementAssignment.java
public class StatementAssignment extends Statement {
private String id;
private Expr expr;
public StatementAssignment(String id, Expr expr) {
this.id = id;
this.expr = expr;
}
public void execute(Environment env) {
double value = expr.evaluate(env);
env.locals.put(id, value);
}
}
StatementFunctionCall.java
import java.util.ArrayList;
import java.util.HashMap;
public class StatementFunctionCall extends Statement {
private String id;
private ArrayList<Expr> actualParameters;
public StatementFunctionCall(String id, ArrayList<Expr> actualParameters) {
this.id = id;
this.actualParameters = actualParameters;
}
@Override
protected void execute(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;
}
}
StatementFunctionDefine.java
import java.util.ArrayList;
public class StatementFunctionDefine extends Statement {
private Function f;
public StatementFunctionDefine(String id, ArrayList<String> formalParameters, Block body) {
f = new Function(id, formalParameters, body);
}
@Override
protected void execute(Environment env) {
env.functions.put(f.getID(), f);
}
}
StatementIf.java
import java.awt.geom.Line2D;
public class StatementIf extends Statement {
private Expr expr;
private Block thenBlock;
private Block elseBlock;
public StatementIf(Expr expr, Block thenBlock, Block elseBlock) {
this.expr = expr;
this.thenBlock = thenBlock;
this.elseBlock = elseBlock;
}
protected void execute(Environment env) {
int condition = (int) expr.evaluate(env);
if (condition == 0) {
elseBlock.execute(env);
} else {
thenBlock.execute(env);
}
}
}
StatementListener.java
public interface StatementListener {
public void onPostExecute();
}
StatementMove.java
import java.awt.geom.Line2D;
public class StatementMove extends Statement {
private Expr expr;
public StatementMove(Expr expr) {
this.expr = expr;
}
protected void execute(Environment env) {
double distance = expr.evaluate(env);
double newX = env.x + distance * Math.cos(env.heading);
double newY = env.y + distance * Math.sin(env.heading);
synchronized (env.segments) {
env.segments.add(new Line2D.Double(env.x, env.y, newX, newY));
}
env.x = newX;
env.y = newY;
}
}
StatementRepeat.java
import java.awt.geom.Line2D;
public class StatementRepeat extends Statement {
private Expr expr;
private Block block;
public StatementRepeat(Expr expr, Block block) {
this.expr = expr;
this.block = block;
}
protected void execute(Environment env) {
int n = (int) expr.evaluate(env);
for (int i = 0; i < n; ++i) {
block.execute(env);
}
}
}
StatementRotate.java
import java.awt.geom.Line2D;
public class StatementRotate extends Statement {
private Expr expr;
public StatementRotate(Expr expr) {
this.expr = expr;
}
protected void execute(Environment env) {
env.heading += Math.toRadians(expr.evaluate(env));
}
}
LogoBaseListener.java
// Generated from Logo.g by ANTLR 4.5
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.</p>
*/
@Override public void enterProgram(LogoParser.ProgramContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitProgram(LogoParser.ProgramContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterBlock(LogoParser.BlockContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitBlock(LogoParser.BlockContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterMove(LogoParser.MoveContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitMove(LogoParser.MoveContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterRotate(LogoParser.RotateContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitRotate(LogoParser.RotateContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterIf(LogoParser.IfContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitIf(LogoParser.IfContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterFunctionDefine(LogoParser.FunctionDefineContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitFunctionDefine(LogoParser.FunctionDefineContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterFunctionCall(LogoParser.FunctionCallContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitFunctionCall(LogoParser.FunctionCallContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterRepeat(LogoParser.RepeatContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitRepeat(LogoParser.RepeatContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterAssignment(LogoParser.AssignmentContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitAssignment(LogoParser.AssignmentContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterAdd(LogoParser.AddContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitAdd(LogoParser.AddContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterIdentifier(LogoParser.IdentifierContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitIdentifier(LogoParser.IdentifierContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterLiteral(LogoParser.LiteralContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitLiteral(LogoParser.LiteralContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterMultiply(LogoParser.MultiplyContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitMultiply(LogoParser.MultiplyContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterNegate(LogoParser.NegateContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitNegate(LogoParser.NegateContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterGrouped(LogoParser.GroupedContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitGrouped(LogoParser.GroupedContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterPower(LogoParser.PowerContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitPower(LogoParser.PowerContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterEveryRule(ParserRuleContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitEveryRule(ParserRuleContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void visitTerminal(TerminalNode node) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void visitErrorNode(ErrorNode node) { }
}
LogoLexer.java
// Generated from Logo.g by ANTLR 4.5
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 {
static { RuntimeMetaData.checkVersion("4.5", RuntimeMetaData.VERSION); }
protected static final DFA[] _decisionToDFA;
protected static final PredictionContextCache _sharedContextCache =
new PredictionContextCache();
public static final int
IF=1, ELSE=2, TO=3, MOVE=4, ROTATE=5, REPEAT=6, END=7, LEFT_PARENTHESIS=8,
RIGHT_PARENTHESIS=9, POWER=10, NEGATIVE=11, MULTIPLICATIVE_OPERATOR=12,
ADDITIVE_OPERATOR=13, ASSIGNMENT=14, IDENTIFIER=15, NUMBER=16, NEWLINE=17,
WHITESPACE=18;
public static String[] modeNames = {
"DEFAULT_MODE"
};
public static final String[] ruleNames = {
"IF", "ELSE", "TO", "MOVE", "ROTATE", "REPEAT", "END", "LEFT_PARENTHESIS",
"RIGHT_PARENTHESIS", "POWER", "NEGATIVE", "MULTIPLICATIVE_OPERATOR", "ADDITIVE_OPERATOR",
"ASSIGNMENT", "IDENTIFIER", "NUMBER", "NEWLINE", "WHITESPACE"
};
private static final String[] _LITERAL_NAMES = {
null, "'if'", "'else'", "'to'", "'move'", "'rotate'", "'repeat'", "'end'",
"'('", "')'", "'^'", "'-'", null, null, "'='", null, null, "'\n'"
};
private static final String[] _SYMBOLIC_NAMES = {
null, "IF", "ELSE", "TO", "MOVE", "ROTATE", "REPEAT", "END", "LEFT_PARENTHESIS",
"RIGHT_PARENTHESIS", "POWER", "NEGATIVE", "MULTIPLICATIVE_OPERATOR", "ADDITIVE_OPERATOR",
"ASSIGNMENT", "IDENTIFIER", "NUMBER", "NEWLINE", "WHITESPACE"
};
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
/**
* @deprecated Use {@link #VOCABULARY} instead.
*/
@Deprecated
public static final String[] tokenNames;
static {
tokenNames = new String[_SYMBOLIC_NAMES.length];
for (int i = 0; i < tokenNames.length; i++) {
tokenNames[i] = VOCABULARY.getLiteralName(i);
if (tokenNames[i] == null) {
tokenNames[i] = VOCABULARY.getSymbolicName(i);
}
if (tokenNames[i] == null) {
tokenNames[i] = "<INVALID>";
}
}
}
@Override
@Deprecated
public String[] getTokenNames() {
return tokenNames;
}
@Override
public Vocabulary getVocabulary() {
return VOCABULARY;
}
public LogoLexer(CharStream input) {
super(input);
_interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
}
@Override
public String getGrammarFileName() { return "Logo.g"; }
@Override
public String[] getRuleNames() { return ruleNames; }
@Override
public String getSerializedATN() { return _serializedATN; }
@Override
public String[] getModeNames() { return modeNames; }
@Override
public ATN getATN() { return _ATN; }
public static final String _serializedATN =
"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2\24~\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\3\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\4\3\4\3\4\3\5\3\5\3\5\3\5"+
"\3\5\3\6\3\6\3\6\3\6\3\6\3\6\3\6\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3"+
"\b\3\b\3\t\3\t\3\n\3\n\3\13\3\13\3\f\3\f\3\r\3\r\3\16\3\16\3\16\5\16W"+
"\n\16\3\17\3\17\3\20\6\20\\\n\20\r\20\16\20]\3\20\7\20a\n\20\f\20\16\20"+
"d\13\20\3\21\5\21g\n\21\3\21\6\21j\n\21\r\21\16\21k\3\21\3\21\6\21p\n"+
"\21\r\21\16\21q\5\21t\n\21\3\22\3\22\3\23\6\23y\n\23\r\23\16\23z\3\23"+
"\3\23\2\2\24\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16"+
"\33\17\35\20\37\21!\22#\23%\24\3\2\7\5\2\'\',,\61\61\3\2c|\4\2aac|\3\2"+
"\62;\4\2\13\13\"\"\u0085\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\3\'\3\2\2\2\5*\3\2\2\2\7/\3\2\2"+
"\2\t\62\3\2\2\2\13\67\3\2\2\2\r>\3\2\2\2\17E\3\2\2\2\21I\3\2\2\2\23K\3"+
"\2\2\2\25M\3\2\2\2\27O\3\2\2\2\31Q\3\2\2\2\33V\3\2\2\2\35X\3\2\2\2\37"+
"[\3\2\2\2!f\3\2\2\2#u\3\2\2\2%x\3\2\2\2\'(\7k\2\2()\7h\2\2)\4\3\2\2\2"+
"*+\7g\2\2+,\7n\2\2,-\7u\2\2-.\7g\2\2.\6\3\2\2\2/\60\7v\2\2\60\61\7q\2"+
"\2\61\b\3\2\2\2\62\63\7o\2\2\63\64\7q\2\2\64\65\7x\2\2\65\66\7g\2\2\66"+
"\n\3\2\2\2\678\7t\2\289\7q\2\29:\7v\2\2:;\7c\2\2;<\7v\2\2<=\7g\2\2=\f"+
"\3\2\2\2>?\7t\2\2?@\7g\2\2@A\7r\2\2AB\7g\2\2BC\7c\2\2CD\7v\2\2D\16\3\2"+
"\2\2EF\7g\2\2FG\7p\2\2GH\7f\2\2H\20\3\2\2\2IJ\7*\2\2J\22\3\2\2\2KL\7+"+
"\2\2L\24\3\2\2\2MN\7`\2\2N\26\3\2\2\2OP\7/\2\2P\30\3\2\2\2QR\t\2\2\2R"+
"\32\3\2\2\2SW\7-\2\2TU\7/\2\2UW\7\"\2\2VS\3\2\2\2VT\3\2\2\2W\34\3\2\2"+
"\2XY\7?\2\2Y\36\3\2\2\2Z\\\t\3\2\2[Z\3\2\2\2\\]\3\2\2\2][\3\2\2\2]^\3"+
"\2\2\2^b\3\2\2\2_a\t\4\2\2`_\3\2\2\2ad\3\2\2\2b`\3\2\2\2bc\3\2\2\2c \3"+
"\2\2\2db\3\2\2\2eg\7/\2\2fe\3\2\2\2fg\3\2\2\2gi\3\2\2\2hj\t\5\2\2ih\3"+
"\2\2\2jk\3\2\2\2ki\3\2\2\2kl\3\2\2\2ls\3\2\2\2mo\7\60\2\2np\t\5\2\2on"+
"\3\2\2\2pq\3\2\2\2qo\3\2\2\2qr\3\2\2\2rt\3\2\2\2sm\3\2\2\2st\3\2\2\2t"+
"\"\3\2\2\2uv\7\f\2\2v$\3\2\2\2wy\t\6\2\2xw\3\2\2\2yz\3\2\2\2zx\3\2\2\2"+
"z{\3\2\2\2{|\3\2\2\2|}\b\23\2\2}&\3\2\2\2\13\2V]bfkqsz\3\b\2\2";
public static final ATN _ATN =
new ATNDeserializer().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.5
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#program}.
* @param ctx the parse tree
*/
void enterProgram(LogoParser.ProgramContext ctx);
/**
* Exit a parse tree produced by {@link LogoParser#program}.
* @param ctx the parse tree
*/
void exitProgram(LogoParser.ProgramContext ctx);
/**
* Enter a parse tree produced by {@link LogoParser#block}.
* @param ctx the parse tree
*/
void enterBlock(LogoParser.BlockContext ctx);
/**
* Exit a parse tree produced by {@link LogoParser#block}.
* @param ctx the parse tree
*/
void exitBlock(LogoParser.BlockContext ctx);
/**
* Enter a parse tree produced by the {@code Move}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void enterMove(LogoParser.MoveContext ctx);
/**
* Exit a parse tree produced by the {@code Move}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void exitMove(LogoParser.MoveContext ctx);
/**
* Enter a parse tree produced by the {@code Rotate}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void enterRotate(LogoParser.RotateContext ctx);
/**
* Exit a parse tree produced by the {@code Rotate}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void exitRotate(LogoParser.RotateContext ctx);
/**
* Enter a parse tree produced by the {@code If}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void enterIf(LogoParser.IfContext ctx);
/**
* Exit a parse tree produced by the {@code If}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void exitIf(LogoParser.IfContext ctx);
/**
* Enter a parse tree produced by the {@code FunctionDefine}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void enterFunctionDefine(LogoParser.FunctionDefineContext ctx);
/**
* Exit a parse tree produced by the {@code FunctionDefine}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void exitFunctionDefine(LogoParser.FunctionDefineContext ctx);
/**
* Enter a parse tree produced by the {@code FunctionCall}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void enterFunctionCall(LogoParser.FunctionCallContext ctx);
/**
* Exit a parse tree produced by the {@code FunctionCall}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void exitFunctionCall(LogoParser.FunctionCallContext ctx);
/**
* Enter a parse tree produced by the {@code Repeat}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void enterRepeat(LogoParser.RepeatContext ctx);
/**
* Exit a parse tree produced by the {@code Repeat}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void exitRepeat(LogoParser.RepeatContext ctx);
/**
* Enter a parse tree produced by the {@code Assignment}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void enterAssignment(LogoParser.AssignmentContext ctx);
/**
* Exit a parse tree produced by the {@code Assignment}
* labeled alternative in {@link LogoParser#statement}.
* @param ctx the parse tree
*/
void exitAssignment(LogoParser.AssignmentContext ctx);
/**
* Enter a parse tree produced by the {@code Add}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void enterAdd(LogoParser.AddContext ctx);
/**
* Exit a parse tree produced by the {@code Add}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void exitAdd(LogoParser.AddContext ctx);
/**
* Enter a parse tree produced by the {@code Identifier}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void enterIdentifier(LogoParser.IdentifierContext ctx);
/**
* Exit a parse tree produced by the {@code Identifier}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void exitIdentifier(LogoParser.IdentifierContext ctx);
/**
* Enter a parse tree produced by the {@code Literal}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void enterLiteral(LogoParser.LiteralContext ctx);
/**
* Exit a parse tree produced by the {@code Literal}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void exitLiteral(LogoParser.LiteralContext ctx);
/**
* Enter a parse tree produced by the {@code Multiply}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void enterMultiply(LogoParser.MultiplyContext ctx);
/**
* Exit a parse tree produced by the {@code Multiply}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void exitMultiply(LogoParser.MultiplyContext ctx);
/**
* Enter a parse tree produced by the {@code Negate}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void enterNegate(LogoParser.NegateContext ctx);
/**
* Exit a parse tree produced by the {@code Negate}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void exitNegate(LogoParser.NegateContext ctx);
/**
* Enter a parse tree produced by the {@code Grouped}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void enterGrouped(LogoParser.GroupedContext ctx);
/**
* Exit a parse tree produced by the {@code Grouped}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void exitGrouped(LogoParser.GroupedContext ctx);
/**
* Enter a parse tree produced by the {@code Power}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void enterPower(LogoParser.PowerContext ctx);
/**
* Exit a parse tree produced by the {@code Power}
* labeled alternative in {@link LogoParser#expr}.
* @param ctx the parse tree
*/
void exitPower(LogoParser.PowerContext ctx);
}
LogoParser.java
// Generated from Logo.g by ANTLR 4.5
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 {
static { RuntimeMetaData.checkVersion("4.5", RuntimeMetaData.VERSION); }
protected static final DFA[] _decisionToDFA;
protected static final PredictionContextCache _sharedContextCache =
new PredictionContextCache();
public static final int
IF=1, ELSE=2, TO=3, MOVE=4, ROTATE=5, REPEAT=6, END=7, LEFT_PARENTHESIS=8,
RIGHT_PARENTHESIS=9, POWER=10, NEGATIVE=11, MULTIPLICATIVE_OPERATOR=12,
ADDITIVE_OPERATOR=13, ASSIGNMENT=14, IDENTIFIER=15, NUMBER=16, NEWLINE=17,
WHITESPACE=18;
public static final int
RULE_program = 0, RULE_block = 1, RULE_statement = 2, RULE_expr = 3;
public static final String[] ruleNames = {
"program", "block", "statement", "expr"
};
private static final String[] _LITERAL_NAMES = {
null, "'if'", "'else'", "'to'", "'move'", "'rotate'", "'repeat'", "'end'",
"'('", "')'", "'^'", "'-'", null, null, "'='", null, null, "'\n'"
};
private static final String[] _SYMBOLIC_NAMES = {
null, "IF", "ELSE", "TO", "MOVE", "ROTATE", "REPEAT", "END", "LEFT_PARENTHESIS",
"RIGHT_PARENTHESIS", "POWER", "NEGATIVE", "MULTIPLICATIVE_OPERATOR", "ADDITIVE_OPERATOR",
"ASSIGNMENT", "IDENTIFIER", "NUMBER", "NEWLINE", "WHITESPACE"
};
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
/**
* @deprecated Use {@link #VOCABULARY} instead.
*/
@Deprecated
public static final String[] tokenNames;
static {
tokenNames = new String[_SYMBOLIC_NAMES.length];
for (int i = 0; i < tokenNames.length; i++) {
tokenNames[i] = VOCABULARY.getLiteralName(i);
if (tokenNames[i] == null) {
tokenNames[i] = VOCABULARY.getSymbolicName(i);
}
if (tokenNames[i] == null) {
tokenNames[i] = "<INVALID>";
}
}
}
@Override
@Deprecated
public String[] getTokenNames() {
return tokenNames;
}
@Override
public Vocabulary getVocabulary() {
return VOCABULARY;
}
@Override
public String getGrammarFileName() { return "Logo.g"; }
@Override
public String[] getRuleNames() { return ruleNames; }
@Override
public String getSerializedATN() { return _serializedATN; }
@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 BlockContext block() {
return getRuleContext(BlockContext.class,0);
}
public TerminalNode EOF() { return getToken(LogoParser.EOF, 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 TerminalNode NEWLINE(int i) {
return getToken(LogoParser.NEWLINE, i);
}
public List<StatementContext> statement() {
return getRuleContexts(StatementContext.class);
}
public StatementContext statement(int i) {
return getRuleContext(StatementContext.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(17);
_errHandler.sync(this);
_la = _input.LA(1);
while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << IF) | (1L << TO) | (1L << MOVE) | (1L << ROTATE) | (1L << REPEAT) | (1L << IDENTIFIER) | (1L << NEWLINE))) != 0)) {
{
{
setState(12);
_la = _input.LA(1);
if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << IF) | (1L << TO) | (1L << MOVE) | (1L << ROTATE) | (1L << REPEAT) | (1L << IDENTIFIER))) != 0)) {
{
setState(11);
statement();
}
}
setState(14);
match(NEWLINE);
}
}
setState(19);
_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 StatementContext extends ParserRuleContext {
public StatementContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
}
@Override public int getRuleIndex() { return RULE_statement; }
public StatementContext() { }
public void copyFrom(StatementContext ctx) {
super.copyFrom(ctx);
}
}
public static class AssignmentContext extends StatementContext {
public TerminalNode IDENTIFIER() { return getToken(LogoParser.IDENTIFIER, 0); }
public TerminalNode ASSIGNMENT() { return getToken(LogoParser.ASSIGNMENT, 0); }
public ExprContext expr() {
return getRuleContext(ExprContext.class,0);
}
public AssignmentContext(StatementContext 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 RotateContext extends StatementContext {
public TerminalNode ROTATE() { return getToken(LogoParser.ROTATE, 0); }
public ExprContext expr() {
return getRuleContext(ExprContext.class,0);
}
public RotateContext(StatementContext 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 MoveContext extends StatementContext {
public TerminalNode MOVE() { return getToken(LogoParser.MOVE, 0); }
public ExprContext expr() {
return getRuleContext(ExprContext.class,0);
}
public MoveContext(StatementContext 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 RepeatContext extends StatementContext {
public TerminalNode REPEAT() { return getToken(LogoParser.REPEAT, 0); }
public ExprContext expr() {
return getRuleContext(ExprContext.class,0);
}
public TerminalNode NEWLINE() { return getToken(LogoParser.NEWLINE, 0); }
public BlockContext block() {
return getRuleContext(BlockContext.class,0);
}
public TerminalNode END() { return getToken(LogoParser.END, 0); }
public RepeatContext(StatementContext 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 static class FunctionCallContext extends StatementContext {
public TerminalNode IDENTIFIER() { return getToken(LogoParser.IDENTIFIER, 0); }
public List<ExprContext> expr() {
return getRuleContexts(ExprContext.class);
}
public ExprContext expr(int i) {
return getRuleContext(ExprContext.class,i);
}
public FunctionCallContext(StatementContext ctx) { copyFrom(ctx); }
@Override
public void enterRule(ParseTreeListener listener) {
if ( listener instanceof LogoListener ) ((LogoListener)listener).enterFunctionCall(this);
}
@Override
public void exitRule(ParseTreeListener listener) {
if ( listener instanceof LogoListener ) ((LogoListener)listener).exitFunctionCall(this);
}
}
public static class IfContext extends StatementContext {
public TerminalNode IF() { return getToken(LogoParser.IF, 0); }
public ExprContext expr() {
return getRuleContext(ExprContext.class,0);
}
public TerminalNode NEWLINE() { return getToken(LogoParser.NEWLINE, 0); }
public List<BlockContext> block() {
return getRuleContexts(BlockContext.class);
}
public BlockContext block(int i) {
return getRuleContext(BlockContext.class,i);
}
public TerminalNode ELSE() { return getToken(LogoParser.ELSE, 0); }
public TerminalNode END() { return getToken(LogoParser.END, 0); }
public IfContext(StatementContext 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 FunctionDefineContext extends StatementContext {
public TerminalNode TO() { return getToken(LogoParser.TO, 0); }
public List<TerminalNode> IDENTIFIER() { return getTokens(LogoParser.IDENTIFIER); }
public TerminalNode IDENTIFIER(int i) {
return getToken(LogoParser.IDENTIFIER, i);
}
public TerminalNode NEWLINE() { return getToken(LogoParser.NEWLINE, 0); }
public BlockContext block() {
return getRuleContext(BlockContext.class,0);
}
public TerminalNode END() { return getToken(LogoParser.END, 0); }
public FunctionDefineContext(StatementContext ctx) { copyFrom(ctx); }
@Override
public void enterRule(ParseTreeListener listener) {
if ( listener instanceof LogoListener ) ((LogoListener)listener).enterFunctionDefine(this);
}
@Override
public void exitRule(ParseTreeListener listener) {
if ( listener instanceof LogoListener ) ((LogoListener)listener).exitFunctionDefine(this);
}
}
public final StatementContext statement() throws RecognitionException {
StatementContext _localctx = new StatementContext(_ctx, getState());
enterRule(_localctx, 4, RULE_statement);
int _la;
try {
setState(60);
switch ( getInterpreter().adaptivePredict(_input,4,_ctx) ) {
case 1:
_localctx = new MoveContext(_localctx);
enterOuterAlt(_localctx, 1);
{
setState(20);
match(MOVE);
setState(21);
expr(0);
}
break;
case 2:
_localctx = new RotateContext(_localctx);
enterOuterAlt(_localctx, 2);
{
setState(22);
match(ROTATE);
setState(23);
expr(0);
}
break;
case 3:
_localctx = new IfContext(_localctx);
enterOuterAlt(_localctx, 3);
{
setState(24);
match(IF);
setState(25);
expr(0);
setState(26);
match(NEWLINE);
setState(27);
block();
setState(28);
match(ELSE);
setState(29);
block();
setState(30);
match(END);
}
break;
case 4:
_localctx = new FunctionDefineContext(_localctx);
enterOuterAlt(_localctx, 4);
{
setState(32);
match(TO);
setState(33);
match(IDENTIFIER);
setState(37);
_errHandler.sync(this);
_la = _input.LA(1);
while (_la==IDENTIFIER) {
{
{
setState(34);
match(IDENTIFIER);
}
}
setState(39);
_errHandler.sync(this);
_la = _input.LA(1);
}
setState(40);
match(NEWLINE);
setState(41);
block();
setState(42);
match(END);
}
break;
case 5:
_localctx = new FunctionCallContext(_localctx);
enterOuterAlt(_localctx, 5);
{
setState(44);
match(IDENTIFIER);
setState(48);
_errHandler.sync(this);
_la = _input.LA(1);
while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LEFT_PARENTHESIS) | (1L << NEGATIVE) | (1L << IDENTIFIER) | (1L << NUMBER))) != 0)) {
{
{
setState(45);
expr(0);
}
}
setState(50);
_errHandler.sync(this);
_la = _input.LA(1);
}
}
break;
case 6:
_localctx = new RepeatContext(_localctx);
enterOuterAlt(_localctx, 6);
{
setState(51);
match(REPEAT);
setState(52);
expr(0);
setState(53);
match(NEWLINE);
setState(54);
block();
setState(55);
match(END);
}
break;
case 7:
_localctx = new AssignmentContext(_localctx);
enterOuterAlt(_localctx, 7);
{
setState(57);
match(IDENTIFIER);
setState(58);
match(ASSIGNMENT);
setState(59);
expr(0);
}
break;
}
}
catch (RecognitionException re) {
_localctx.exception = re;
_errHandler.reportError(this, re);
_errHandler.recover(this, re);
}
finally {
exitRule();
}
return _localctx;
}
public static class ExprContext extends ParserRuleContext {
public ExprContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
}
@Override public int getRuleIndex() { return RULE_expr; }
public ExprContext() { }
public void copyFrom(ExprContext ctx) {
super.copyFrom(ctx);
}
}
public static class AddContext extends ExprContext {
public List<ExprContext> expr() {
return getRuleContexts(ExprContext.class);
}
public ExprContext expr(int i) {
return getRuleContext(ExprContext.class,i);
}
public TerminalNode ADDITIVE_OPERATOR() { return getToken(LogoParser.ADDITIVE_OPERATOR, 0); }
public AddContext(ExprContext 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 ExprContext {
public TerminalNode IDENTIFIER() { return getToken(LogoParser.IDENTIFIER, 0); }
public IdentifierContext(ExprContext 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 LiteralContext extends ExprContext {
public TerminalNode NUMBER() { return getToken(LogoParser.NUMBER, 0); }
public LiteralContext(ExprContext 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 MultiplyContext extends ExprContext {
public List<ExprContext> expr() {
return getRuleContexts(ExprContext.class);
}
public ExprContext expr(int i) {
return getRuleContext(ExprContext.class,i);
}
public TerminalNode MULTIPLICATIVE_OPERATOR() { return getToken(LogoParser.MULTIPLICATIVE_OPERATOR, 0); }
public MultiplyContext(ExprContext 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 static class NegateContext extends ExprContext {
public TerminalNode NEGATIVE() { return getToken(LogoParser.NEGATIVE, 0); }
public ExprContext expr() {
return getRuleContext(ExprContext.class,0);
}
public NegateContext(ExprContext ctx) { copyFrom(ctx); }
@Override
public void enterRule(ParseTreeListener listener) {
if ( listener instanceof LogoListener ) ((LogoListener)listener).enterNegate(this);
}
@Override
public void exitRule(ParseTreeListener listener) {
if ( listener instanceof LogoListener ) ((LogoListener)listener).exitNegate(this);
}
}
public static class GroupedContext extends ExprContext {
public TerminalNode LEFT_PARENTHESIS() { return getToken(LogoParser.LEFT_PARENTHESIS, 0); }
public ExprContext expr() {
return getRuleContext(ExprContext.class,0);
}
public TerminalNode RIGHT_PARENTHESIS() { return getToken(LogoParser.RIGHT_PARENTHESIS, 0); }
public GroupedContext(ExprContext 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 PowerContext extends ExprContext {
public List<ExprContext> expr() {
return getRuleContexts(ExprContext.class);
}
public ExprContext expr(int i) {
return getRuleContext(ExprContext.class,i);
}
public TerminalNode POWER() { return getToken(LogoParser.POWER, 0); }
public PowerContext(ExprContext 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 final ExprContext expr() throws RecognitionException {
return expr(0);
}
private ExprContext expr(int _p) throws RecognitionException {
ParserRuleContext _parentctx = _ctx;
int _parentState = getState();
ExprContext _localctx = new ExprContext(_ctx, _parentState);
ExprContext _prevctx = _localctx;
int _startState = 6;
enterRecursionRule(_localctx, 6, RULE_expr, _p);
try {
int _alt;
enterOuterAlt(_localctx, 1);
{
setState(71);
switch (_input.LA(1)) {
case NEGATIVE:
{
_localctx = new NegateContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
setState(63);
match(NEGATIVE);
setState(64);
expr(6);
}
break;
case LEFT_PARENTHESIS:
{
_localctx = new GroupedContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
setState(65);
match(LEFT_PARENTHESIS);
setState(66);
expr(0);
setState(67);
match(RIGHT_PARENTHESIS);
}
break;
case NUMBER:
{
_localctx = new LiteralContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
setState(69);
match(NUMBER);
}
break;
case IDENTIFIER:
{
_localctx = new IdentifierContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
setState(70);
match(IDENTIFIER);
}
break;
default:
throw new NoViableAltException(this);
}
_ctx.stop = _input.LT(-1);
setState(84);
_errHandler.sync(this);
_alt = getInterpreter().adaptivePredict(_input,7,_ctx);
while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
if ( _alt==1 ) {
if ( _parseListeners!=null ) triggerExitRuleEvent();
_prevctx = _localctx;
{
setState(82);
switch ( getInterpreter().adaptivePredict(_input,6,_ctx) ) {
case 1:
{
_localctx = new PowerContext(new ExprContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expr);
setState(73);
if (!(precpred(_ctx, 5))) throw new FailedPredicateException(this, "precpred(_ctx, 5)");
setState(74);
match(POWER);
setState(75);
expr(6);
}
break;
case 2:
{
_localctx = new MultiplyContext(new ExprContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expr);
setState(76);
if (!(precpred(_ctx, 4))) throw new FailedPredicateException(this, "precpred(_ctx, 4)");
setState(77);
match(MULTIPLICATIVE_OPERATOR);
setState(78);
expr(5);
}
break;
case 3:
{
_localctx = new AddContext(new ExprContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expr);
setState(79);
if (!(precpred(_ctx, 3))) throw new FailedPredicateException(this, "precpred(_ctx, 3)");
setState(80);
match(ADDITIVE_OPERATOR);
setState(81);
expr(4);
}
break;
}
}
}
setState(86);
_errHandler.sync(this);
_alt = getInterpreter().adaptivePredict(_input,7,_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 expr_sempred((ExprContext)_localctx, predIndex);
}
return true;
}
private boolean expr_sempred(ExprContext _localctx, int predIndex) {
switch (predIndex) {
case 0:
return precpred(_ctx, 5);
case 1:
return precpred(_ctx, 4);
case 2:
return precpred(_ctx, 3);
}
return true;
}
public static final String _serializedATN =
"\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3\24Z\4\2\t\2\4\3\t"+
"\3\4\4\t\4\4\5\t\5\3\2\3\2\3\2\3\3\5\3\17\n\3\3\3\7\3\22\n\3\f\3\16\3"+
"\25\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\7"+
"\4&\n\4\f\4\16\4)\13\4\3\4\3\4\3\4\3\4\3\4\3\4\7\4\61\n\4\f\4\16\4\64"+
"\13\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\5\4?\n\4\3\5\3\5\3\5\3\5\3\5"+
"\3\5\3\5\3\5\3\5\5\5J\n\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\7\5U\n\5"+
"\f\5\16\5X\13\5\3\5\2\3\b\6\2\4\6\b\2\2e\2\n\3\2\2\2\4\23\3\2\2\2\6>\3"+
"\2\2\2\bI\3\2\2\2\n\13\5\4\3\2\13\f\7\2\2\3\f\3\3\2\2\2\r\17\5\6\4\2\16"+
"\r\3\2\2\2\16\17\3\2\2\2\17\20\3\2\2\2\20\22\7\23\2\2\21\16\3\2\2\2\22"+
"\25\3\2\2\2\23\21\3\2\2\2\23\24\3\2\2\2\24\5\3\2\2\2\25\23\3\2\2\2\26"+
"\27\7\6\2\2\27?\5\b\5\2\30\31\7\7\2\2\31?\5\b\5\2\32\33\7\3\2\2\33\34"+
"\5\b\5\2\34\35\7\23\2\2\35\36\5\4\3\2\36\37\7\4\2\2\37 \5\4\3\2 !\7\t"+
"\2\2!?\3\2\2\2\"#\7\5\2\2#\'\7\21\2\2$&\7\21\2\2%$\3\2\2\2&)\3\2\2\2\'"+
"%\3\2\2\2\'(\3\2\2\2(*\3\2\2\2)\'\3\2\2\2*+\7\23\2\2+,\5\4\3\2,-\7\t\2"+
"\2-?\3\2\2\2.\62\7\21\2\2/\61\5\b\5\2\60/\3\2\2\2\61\64\3\2\2\2\62\60"+
"\3\2\2\2\62\63\3\2\2\2\63?\3\2\2\2\64\62\3\2\2\2\65\66\7\b\2\2\66\67\5"+
"\b\5\2\678\7\23\2\289\5\4\3\29:\7\t\2\2:?\3\2\2\2;<\7\21\2\2<=\7\20\2"+
"\2=?\5\b\5\2>\26\3\2\2\2>\30\3\2\2\2>\32\3\2\2\2>\"\3\2\2\2>.\3\2\2\2"+
">\65\3\2\2\2>;\3\2\2\2?\7\3\2\2\2@A\b\5\1\2AB\7\r\2\2BJ\5\b\5\bCD\7\n"+
"\2\2DE\5\b\5\2EF\7\13\2\2FJ\3\2\2\2GJ\7\22\2\2HJ\7\21\2\2I@\3\2\2\2IC"+
"\3\2\2\2IG\3\2\2\2IH\3\2\2\2JV\3\2\2\2KL\f\7\2\2LM\7\f\2\2MU\5\b\5\bN"+
"O\f\6\2\2OP\7\16\2\2PU\5\b\5\7QR\f\5\2\2RS\7\17\2\2SU\5\b\5\6TK\3\2\2"+
"\2TN\3\2\2\2TQ\3\2\2\2UX\3\2\2\2VT\3\2\2\2VW\3\2\2\2W\t\3\2\2\2XV\3\2"+
"\2\2\n\16\23\'\62>ITV";
public static final ATN _ATN =
new ATNDeserializer().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);
}
}
}
LogoVirtualMachine.java
import java.awt.Dimension;
import javax.swing.JButton;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.BorderLayout;
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;
public class LogoVirtualMachine implements StatementListener {
private JFrame display;
private LogoDisplay panel;
private int delay = 100;
public LogoVirtualMachine(final Block main) {
display = new JFrame("Logo");
panel = new LogoDisplay();
JScrollPane scroller = new JScrollPane(panel);
display.add(scroller);
JButton runButton = new JButton("Run");
runButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Environment env = new Environment();
panel.setEnvironment(env);
env.listener = LogoVirtualMachine.this;
main.execute(env);
}
});
display.add(runButton, BorderLayout.NORTH);
panel.setPreferredSize(new Dimension(3000, 3000));
panel.setSize(panel.getPreferredSize());
display.setSize(1200, 700);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
display.setVisible(true);
}
public void onPostExecute() {
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() {
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 setEnvironment(Environment env) {
this.env = env;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (env == null) {
return;
}
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.heading);
g2.draw(arrowTop);
g2.draw(arrowBottom);
g2.setTransform(xform);
}
}
}
Interpreter.java
import java.util.HashMap;
import java.util.ArrayList;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.File;
import javax.swing.JFileChooser;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ANTLRInputStream;
import java.util.Stack;
public class Interpreter extends LogoBaseListener {
private Stack<Expr> operands;
private Stack<Block> blocks;
public Interpreter() {
operands = new Stack<>();
blocks = new Stack<>();
}
@Override
public void exitProgram(LogoParser.ProgramContext ctx) {
Block main = blocks.pop();
new LogoVirtualMachine(main);
}
@Override
public void enterBlock(LogoParser.BlockContext ctx) {
blocks.push(new Block());
}
@Override
public void exitMove(LogoParser.MoveContext ctx) {
blocks.peek().add(new StatementMove(operands.pop()));
}
@Override
public void exitRepeat(LogoParser.RepeatContext ctx) {
Block body = blocks.pop();
blocks.peek().add(new StatementRepeat(operands.pop(), body));
}
@Override
public void exitIf(LogoParser.IfContext ctx) {
Block elseBlock = blocks.pop();
Block thenBlock = blocks.pop();
blocks.peek().add(new StatementIf(operands.pop(), thenBlock, elseBlock));
}
@Override
public void exitAssignment(LogoParser.AssignmentContext ctx) {
blocks.peek().add(new StatementAssignment(ctx.IDENTIFIER().getText(), operands.pop()));
}
@Override
public void exitRotate(LogoParser.RotateContext ctx) {
blocks.peek().add(new StatementRotate(operands.pop()));
}
@Override
public void exitFunctionDefine(LogoParser.FunctionDefineContext ctx) {
Block body = blocks.pop();
ArrayList<String> formals = new ArrayList<String>();
for (int i = 1; i < ctx.IDENTIFIER().size(); ++i) {
formals.add(ctx.IDENTIFIER(i).getText());
}
blocks.peek().add(new StatementFunctionDefine(ctx.IDENTIFIER(0).getText(), formals, body));
}
@Override
public void exitFunctionCall(LogoParser.FunctionCallContext ctx) {
ArrayList<Expr> actuals = new ArrayList<Expr>();
for (int i = 0; i < ctx.expr().size(); ++i) {
actuals.add(0, operands.pop());
}
blocks.peek().add(new StatementFunctionCall(ctx.IDENTIFIER().getText(), actuals));
}
@Override
public void exitLiteral(LogoParser.LiteralContext ctx) {
String digitsAsString = ctx.NUMBER().getText();
double digits = Double.parseDouble(digitsAsString);
operands.push(new ExprLiteral(digits));
}
@Override
public void exitAdd(LogoParser.AddContext ctx) {
Expr b = operands.pop();
Expr a = operands.pop();
if (ctx.ADDITIVE_OPERATOR().getText().equals("+")) {
operands.push(new ExprAdd(a, b));
} else {
operands.push(new ExprSubtract(a, b));
}
}
@Override
public void exitPower(LogoParser.PowerContext ctx) {
Expr b = operands.pop();
Expr a = operands.pop();
operands.push(new ExprPower(a, b));
}
@Override
public void exitNegate(LogoParser.NegateContext ctx) {
Expr a = operands.pop();
operands.push(new ExprNegate(a));
}
@Override
public void exitMultiply(LogoParser.MultiplyContext ctx) {
Expr b = operands.pop();
Expr a = operands.pop();
if (ctx.MULTIPLICATIVE_OPERATOR().getText().equals("*")) {
operands.push(new ExprMultiply(a, b));
} else if (ctx.MULTIPLICATIVE_OPERATOR().getText().equals("/")) {
operands.push(new ExprDivide(a, b));
} else {
operands.push(new ExprRemainder(a, b));
}
}
@Override
public void exitIdentifier(LogoParser.IdentifierContext ctx) {
operands.push(new ExprIdentifier(ctx.IDENTIFIER().getText()));
}
public static void main(String[] args) throws IOException {
File f = new File(args[0]);
if (!f.exists()) {
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 Interpreter(), tree);
}
}
square2.logo
move 50
rotate 90
move 50
rotate 90
move 50
rotate 90
move 50
square2_with_loop.logo
a = 50
repeat 20
move a
rotate 90
move a
rotate 90
move a
rotate 90
move a
a = a + 10
end
pyramid.logo
to pyramid level
if level
move 20
rotate -90
move 20
rotate 90
pyramid level - 1
else
end
end
pyramid 10
Haiku
on differential geometry
I’m A-to-B-ing
The direct routeĀ costs the most
‘Cuz I think the least
I’m A-to-B-ing
The direct routeĀ costs the most
‘Cuz I think the least