Compare commits

...
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

48 Commits
main ... java11

Author SHA1 Message Date
simonkellet 54d9f06a9e merge 2 years ago
simonkellet d1a97c0d8f added this file 2 years ago
simonkellet 693d933c19 repeatuntil works 2 years ago
simonkellet c9ca3c5bba bardemo works 2 years ago
Sandy Brownlee ce307a11a6
Update ConstantFolder.java 2 years ago
Sandy Brownlee 55fdd944fa Changes for constant folding 2 years ago
Sandy Brownlee 7a8fb2564c Added NOP to opcodes so ordinals match the book 2 years ago
Sandy Brownlee 6a30c4db8b Updated examples 2 years ago
simonkellet e1268aae42 end of practical3 (no bonus) 2 years ago
Sandy Brownlee 461749e44a Added timing to interpreter 2 years ago
simonkellet 4341d02572 end of practical 2 2 years ago
simonkellet 32bd99d78b new lines to check if it is still working 2 years ago
simonkellet fab24be627 added success test for multi-line 2 years ago
simonkellet 6b7fdd3bb0 added multi-line comment support 2 years ago
simonkellet f69942533f works with error code 2 years ago
Sandy Brownlee 0c1b2530fa Amended comments in Encoder 2 years ago
Sandy Brownlee f5951671b9 Added increment demo program 2 years ago
Sandy Brownlee 1da8cabdf7 minor fix to repeatuntil 2 years ago
simonkellet a647259dc2 added readme 2 years ago
simonkellet befe8f93a2 eclipse and gradle changes 2 years ago
simonkellet 7c64cb7eff added new tri files 2 years ago
simonkellet a4c304f58d changes to tam 2 years ago
simonkellet 36f3fac111 added build folder ignore 2 years ago
simonkellet cd280e3c4b added test case for new comment 2 years ago
simonkellet d28b3c7403 added new comment 2 years ago
simonkellet 3f58bdfad9 added bash file to compile and run files quicker 2 years ago
simonkellet 6377dd8250 added ignore to .tam files 2 years ago
simonkellet 955517af29 added build dir 2 years ago
Sandy Brownlee 3dade998ba possible fix for windows 2 years ago
Sandy Brownlee 048cbac0b4 Added bardemo 2 years ago
Sandy Brownlee 77846e5800 Merge branch 'java11' of github.com:sandybrownlee/Triangle-Tools into java11 2 years ago
Sandy Brownlee f4e1a08f61 minor fix to tests 2 years ago
Sandy Brownlee c3c2076d9e repeat until 2 years ago
Sandy Brownlee 64c25f1486 Added pounddemo 2 years ago
Sandy Brownlee c469297712 Amended comment 2 type 2 years ago
Sandy Brownlee a2cac87f81 Changed master project to Java 11 2 years ago
Sandy Brownlee b3375e2050 Added single jar build to root project 2 years ago
Sandy Brownlee 11be265081 Added object filename option to Compiler 2 years ago
Sandy Brownlee 6820b55cf1 Streamlined unit tests 2 years ago
Sandy Brownlee f709234c4e Added unit tests for bad syntax in hi-newcomment.tri 2 years ago
Sandy Brownlee 07b0d85bdf added test 2 years ago
Sandy Brownlee e8780a5b11 Merge branch 'java11' of github.com:sandybrownlee/Triangle-Tools into java11 2 years ago
Sandy Brownlee 90977fb64f added comment tests 2 years ago
Sandy Brownlee 3150ae8fa9
Merge branch 'deryckb:main' into java11 2 years ago
Sandy Brownlee a026ec3840 add while example 2 years ago
Sandy Brownlee 3de9d5e0cc Merge branch 'main' into java11 2 years ago
Sandy Brownlee ee57c9f711 added assignments example 2 years ago
Sandy Brownlee 01f468f07d Java 11 compatibility 2 years ago
  1. 6
      .classpath
  2. 6
      .gitignore
  3. 6
      .project
  4. 2
      README.md
  5. 2
      Triangle.AbstractMachine.Disassembler/build.gradle
  6. 2
      Triangle.AbstractMachine.Interpreter/build.gradle
  7. 4
      Triangle.AbstractMachine.Interpreter/src/main/java/triangle/abstractMachine/Interpreter.java
  8. 2
      Triangle.AbstractMachine/build.gradle
  9. 2
      Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/OpCode.java
  10. 7
      Triangle.Compiler/.project
  11. 13
      Triangle.Compiler/build.gradle
  12. 39
      Triangle.Compiler/src/main/java/triangle/Compiler.java
  13. 35
      Triangle.Compiler/src/main/java/triangle/ErrorReporter.java
  14. 3
      Triangle.Compiler/src/main/java/triangle/StdEnvironment.java
  15. 2
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ConstActualParameter.java
  16. 2
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleArrayAggregate.java
  17. 2
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleRecordAggregate.java
  18. 2
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleArrayAggregate.java
  19. 2
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleRecordAggregate.java
  20. 2
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/AssignCommand.java
  21. 2
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/IfCommand.java
  22. 22
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/RepeatCommand.java
  23. 2
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/WhileCommand.java
  24. 2
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstDeclaration.java
  25. 2
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FuncDeclaration.java
  26. 3
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/BinaryExpression.java
  27. 4
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IfExpression.java
  28. 2
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/LetExpression.java
  29. 2
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/UnaryExpression.java
  30. 4
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ConstFormalParameter.java
  31. 4
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/VarFormalParameter.java
  32. 6
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/CommandVisitor.java
  33. 2
      Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SubscriptVname.java
  34. 21
      Triangle.Compiler/src/main/java/triangle/codeGenerator/Encoder.java
  35. 27
      Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/BarPrimitiveRoutine.java
  36. 73
      Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/Checker.java
  37. 601
      Triangle.Compiler/src/main/java/triangle/optimiser/ConstantFolder.java
  38. 14
      Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Parser.java
  39. 35
      Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Scanner.java
  40. 20
      Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourceFile.java
  41. 12
      Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Token.java
  42. 7
      Triangle.Compiler/src/main/java/triangle/treeDrawer/Drawer.java
  43. 9
      Triangle.Compiler/src/main/java/triangle/treeDrawer/LayoutVisitor.java
  44. 3
      Triangle.Compiler/src/main/java/triangle/treeDrawer/Polyline.java
  45. 90
      Triangle.Compiler/src/test/java/triangle/syntacticAnalyser/TestScanner.java
  46. 11
      build.gradle
  47. BIN
      build/libs/Triangle-Tools.jar
  48. 46
      programs/add.tri
  49. 12
      programs/adddeep.tri
  50. 27
      programs/bardemo.tri
  51. 30
      programs/errorsfix.tri
  52. 7
      programs/hi-newcomment.tri
  53. 14
      programs/hi-newcomment2.tri
  54. 14
      programs/increment.tri
  55. 14
      programs/repeatuntil.tri
  56. 22
      programs/while-longloop.tri
  57. 11
      programs/while.tri
  58. 29
      tam

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

6
.gitignore vendored

@ -60,3 +60,9 @@ local.properties
# Typically, this file would be tracked if it contains build/dependency configurations:
#.project
/.gradle/
# tam files
*.tam
# Build folder
/build/

@ -5,6 +5,11 @@
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
@ -12,6 +17,7 @@
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

@ -0,0 +1,2 @@
# A5 Triangle Compiler

@ -1,7 +1,7 @@
apply plugin: 'java'
apply plugin: 'application'
sourceCompatibility = 17
sourceCompatibility = 11
dependencies {
implementation project(':Triangle.AbstractMachine')

@ -1,7 +1,7 @@
apply plugin: 'java'
apply plugin: 'application'
sourceCompatibility = 17
sourceCompatibility = 11
dependencies {
implementation project(':Triangle.AbstractMachine')

@ -21,6 +21,8 @@ import java.io.IOException;
public class Interpreter {
static long startTimeNanos = 0;
static String objectName;
// DATA STORE
@ -183,6 +185,7 @@ public class Interpreter {
break;
case halted:
System.out.println("Program has halted normally.");
System.out.println("Total execution time (ns): " + (System.nanoTime() - startTimeNanos));
break;
case failedDataStoreFull:
System.out.println("Program has failed due to exhaustion of Data Store.");
@ -634,6 +637,7 @@ public class Interpreter {
loadObjectProgram(objectName);
if (CT != CB) {
startTimeNanos = System.nanoTime();
interpretProgram();
showStatus();
}

@ -1,4 +1,4 @@
apply plugin: 'java-library'
apply plugin: 'eclipse'
sourceCompatibility = 17
sourceCompatibility = 11

@ -1,5 +1,5 @@
package triangle.abstractMachine;
public enum OpCode {
LOAD, LOADA, LOADI, LOADL, STORE, STOREI, CALL, CALLI, RETURN, PUSH, POP, JUMP, JUMPI, JUMPIF, HALT
LOAD, LOADA, LOADI, LOADL, STORE, STOREI, CALL, CALLI, RETURN, NOP, PUSH, POP, JUMP, JUMPI, JUMPIF, HALT
}

@ -20,4 +20,11 @@
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
<linkedResources>
<link>
<name>programs</name>
<type>2</type>
<location>/home/simon/Documents/Uni/CS/CSCU9A5/Triangle-Tools/programs</location>
</link>
</linkedResources>
</projectDescription>

@ -1,12 +1,21 @@
apply plugin: 'java'
apply plugin: 'application'
sourceCompatibility = 17
sourceCompatibility = 11
repositories {
mavenCentral()
}
dependencies {
implementation project(':Triangle.AbstractMachine')
testImplementation group: 'junit', name: 'junit', version: '4.13.2'
}
application {
mainClass = 'Triangle.Compiler'
}
}
// allow access to programs for unit tests
sourceSets.test.resources.srcDir file("$rootDir/programs")

@ -18,6 +18,7 @@ import triangle.abstractSyntaxTrees.Program;
import triangle.codeGenerator.Emitter;
import triangle.codeGenerator.Encoder;
import triangle.contextualAnalyzer.Checker;
import triangle.optimiser.ConstantFolder;
import triangle.syntacticAnalyzer.Parser;
import triangle.syntacticAnalyzer.Scanner;
import triangle.syntacticAnalyzer.SourceFile;
@ -33,6 +34,9 @@ public class Compiler {
/** The filename for the object program, normally obj.tam. */
static String objectName = "obj.tam";
static boolean showTree = false;
static boolean folding = false;
private static Scanner scanner;
private static Parser parser;
@ -71,7 +75,7 @@ public class Compiler {
}
scanner = new Scanner(source);
reporter = new ErrorReporter();
reporter = new ErrorReporter(false);
parser = new Parser(scanner, reporter);
checker = new Checker(reporter);
emitter = new Emitter(reporter);
@ -80,7 +84,7 @@ public class Compiler {
// scanner.enableDebugging();
theAST = parser.parseProgram(); // 1st pass
if (reporter.numErrors == 0) {
if (reporter.getNumErrors() == 0) {
// if (showingAST) {
// drawer.draw(theAST);
// }
@ -89,13 +93,17 @@ public class Compiler {
if (showingAST) {
drawer.draw(theAST);
}
if (reporter.numErrors == 0) {
if (folding) {
theAST.visit(new ConstantFolder());
}
if (reporter.getNumErrors() == 0) {
System.out.println("Code Generation ...");
encoder.encodeRun(theAST, showingTable); // 3rd pass
}
}
boolean successful = (reporter.numErrors == 0);
boolean successful = (reporter.getNumErrors() == 0);
if (successful) {
emitter.saveObjectProgram(objectName);
System.out.println("Compilation was successful.");
@ -114,16 +122,31 @@ public class Compiler {
public static void main(String[] args) {
if (args.length < 1) {
System.out.println("Usage: tc filename [tree]");
System.out.println("Usage: tc filename [-o=outputfilename] [tree] [folding]");
System.exit(1);
}
parseArgs(args);
String sourceName = args[0];
boolean tree = (args.length > 1 && args[1].equalsIgnoreCase("tree"));
var compiledOK = compileProgram(sourceName, objectName, tree, false);
var compiledOK = compileProgram(sourceName, objectName, showTree, false);
if (!tree) {
if (!showTree) {
System.exit(compiledOK ? 0 : 1);
}
}
private static void parseArgs(String[] args) {
for (String s : args) {
var sl = s.toLowerCase();
if (sl.equals("tree")) {
showTree = true;
} else if (sl.startsWith("-o=")) {
objectName = s.substring(3);
} else if (sl.equals("folding")) {
folding = true;
}
}
}
}

@ -18,25 +18,44 @@ import triangle.syntacticAnalyzer.SourcePosition;
public class ErrorReporter {
int numErrors;
ErrorReporter() {
private int numErrors;
private boolean throwExceptions;
/**
* @param throwExceptions if true, throw exceptions (good for unit tests) otherwise write to stdout
*/
public ErrorReporter(boolean throwExceptions) {
numErrors = 0;
this.throwExceptions = throwExceptions;
}
public void reportError(String message, String tokenName, SourcePosition pos) {
System.out.print("ERROR: ");
numErrors++;
String s = ("ERROR: ");
for (int p = 0; p < message.length(); p++)
if (message.charAt(p) == '%')
System.out.print(tokenName);
s += tokenName;
else
System.out.print(message.charAt(p));
System.out.println(" " + pos.start + ".." + pos.finish);
numErrors++;
s += message.charAt(p);
s += (" " + pos.start + ".." + pos.finish);
if (throwExceptions) {
throw new RuntimeException(s);
} else {
System.out.println(s);
}
}
public void reportRestriction(String message) {
System.out.println("RESTRICTION: " + message);
}
public int getNumErrors() {
return numErrors;
}
}

@ -42,5 +42,8 @@ public final class StdEnvironment {
public static ProcDeclaration getDecl, putDecl, getintDecl, putintDecl, geteolDecl, puteolDecl;
public static FuncDeclaration chrDecl, ordDecl, eolDecl, eofDecl;
//keep the bar separate for practical 3 (week 3) work!
public static UnaryOperatorDeclaration barDecl;
}

@ -29,5 +29,5 @@ public class ConstActualParameter extends ActualParameter {
return v.visitConstActualParameter(this, arg);
}
public final Expression E;
public Expression E;
}

@ -30,6 +30,6 @@ public class MultipleArrayAggregate extends ArrayAggregate {
return v.visitMultipleArrayAggregate(this, arg);
}
public final Expression E;
public Expression E;
public final ArrayAggregate AA;
}

@ -33,6 +33,6 @@ public class MultipleRecordAggregate extends RecordAggregate {
}
public final Identifier I;
public final Expression E;
public Expression E;
public final RecordAggregate RA;
}

@ -29,5 +29,5 @@ public class SingleArrayAggregate extends ArrayAggregate {
return v.visitSingleArrayAggregate(this, arg);
}
public final Expression E;
public Expression E;
}

@ -32,5 +32,5 @@ public class SingleRecordAggregate extends RecordAggregate {
}
public final Identifier I;
public final Expression E;
public Expression E;
}

@ -32,5 +32,5 @@ public class AssignCommand extends Command {
}
public final Vname V;
public final Expression E;
public Expression E;
}

@ -31,6 +31,6 @@ public class IfCommand extends Command {
return v.visitIfCommand(this, arg);
}
public final Expression E;
public Expression E;
public final Command C1, C2;
}

@ -0,0 +1,22 @@
package triangle.abstractSyntaxTrees.commands;
import triangle.abstractSyntaxTrees.expressions.Expression;
import triangle.abstractSyntaxTrees.visitors.CommandVisitor;
import triangle.syntacticAnalyzer.SourcePosition;
public class RepeatCommand extends Command {
public RepeatCommand(Expression eAST, Command cAST, SourcePosition position) {
super(position);
E = eAST;
C = cAST;
}
public <TArg, TResult> TResult visit(CommandVisitor<TArg, TResult> v, TArg arg) {
return v.visitRepeatCommand(this, arg);
}
//public final Expression E;
public Expression E;
public final Command C;
}

@ -30,6 +30,6 @@ public class WhileCommand extends Command {
return v.visitWhileCommand(this, arg);
}
public final Expression E;
public Expression E;
public final Command C;
}

@ -38,5 +38,5 @@ public class ConstDeclaration extends Declaration implements ConstantDeclaration
}
public final Identifier I;
public final Expression E;
public Expression E;
}

@ -49,5 +49,5 @@ public class FuncDeclaration extends Declaration implements FunctionDeclaration
public final Identifier I;
public final FormalParameterSequence FPS;
public TypeDenoter T;
public final Expression E;
public Expression E;
}

@ -31,6 +31,7 @@ public class BinaryExpression extends Expression {
return v.visitBinaryExpression(this, arg);
}
public final Expression E1, E2;
public Expression E1;
public Expression E2;
public final Operator O;
}

@ -30,5 +30,7 @@ public class IfExpression extends Expression {
return v.visitIfExpression(this, arg);
}
public final Expression E1, E2, E3;
public Expression E1;
public Expression E2;
public Expression E3;
}

@ -31,5 +31,5 @@ public class LetExpression extends Expression {
}
public final Declaration D;
public final Expression E;
public Expression E;
}

@ -30,6 +30,6 @@ public class UnaryExpression extends Expression {
return v.visitUnaryExpression(this, arg);
}
public final Expression E;
public Expression E;
public final Operator O;
}

@ -39,8 +39,8 @@ public class ConstFormalParameter extends FormalParameter implements ConstantDec
@Override
public boolean equals(Object fpAST) {
if (fpAST instanceof ConstFormalParameter cfpAST) {
return T.equals(cfpAST.T);
if (fpAST instanceof ConstFormalParameter) {
return T.equals(((ConstFormalParameter)fpAST).T);
} else {
return false;
}

@ -39,8 +39,8 @@ public class VarFormalParameter extends FormalParameter implements VariableDecla
@Override
public boolean equals(Object fpAST) {
if (fpAST instanceof VarFormalParameter vfpAST) {
return T.equals(vfpAST.T);
if (fpAST instanceof VarFormalParameter) {
return T.equals(((VarFormalParameter)fpAST).T);
} else {
return false;
}

@ -5,11 +5,11 @@ import triangle.abstractSyntaxTrees.commands.CallCommand;
import triangle.abstractSyntaxTrees.commands.EmptyCommand;
import triangle.abstractSyntaxTrees.commands.IfCommand;
import triangle.abstractSyntaxTrees.commands.LetCommand;
import triangle.abstractSyntaxTrees.commands.RepeatCommand;
import triangle.abstractSyntaxTrees.commands.SequentialCommand;
import triangle.abstractSyntaxTrees.commands.WhileCommand;
public interface CommandVisitor<TArg, TResult> {
TResult visitAssignCommand(AssignCommand ast, TArg arg);
TResult visitCallCommand(CallCommand ast, TArg arg);
@ -23,5 +23,7 @@ public interface CommandVisitor<TArg, TResult> {
TResult visitSequentialCommand(SequentialCommand ast, TArg arg);
TResult visitWhileCommand(WhileCommand ast, TArg arg);
TResult visitRepeatCommand(RepeatCommand ast, TArg arg);
}
}

@ -30,6 +30,6 @@ public class SubscriptVname extends Vname {
return v.visitSubscriptVname(this, arg);
}
public final Expression E;
public Expression E;
public final Vname V;
}

@ -38,6 +38,7 @@ import triangle.abstractSyntaxTrees.commands.CallCommand;
import triangle.abstractSyntaxTrees.commands.EmptyCommand;
import triangle.abstractSyntaxTrees.commands.IfCommand;
import triangle.abstractSyntaxTrees.commands.LetCommand;
import triangle.abstractSyntaxTrees.commands.RepeatCommand;
import triangle.abstractSyntaxTrees.commands.SequentialCommand;
import triangle.abstractSyntaxTrees.commands.WhileCommand;
import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration;
@ -100,6 +101,7 @@ import triangle.abstractSyntaxTrees.vnames.SimpleVname;
import triangle.abstractSyntaxTrees.vnames.SubscriptVname;
import triangle.abstractSyntaxTrees.vnames.Vname;
import triangle.codeGenerator.entities.AddressableEntity;
import triangle.codeGenerator.entities.BarPrimitiveRoutine;
import triangle.codeGenerator.entities.EqualityRoutine;
import triangle.codeGenerator.entities.FetchableEntity;
import triangle.codeGenerator.entities.Field;
@ -180,6 +182,15 @@ public final class Encoder implements ActualParameterVisitor<Frame, Integer>,
emitter.emit(OpCode.JUMPIF, Machine.trueRep, Register.CB, loopAddr);
return null;
}
@Override
public Void visitRepeatCommand(RepeatCommand ast, Frame frame) {
var loopAddr = emitter.getNextInstrAddr();
ast.E.visit(this, frame);
ast.C.visit(this, frame);
emitter.emit(OpCode.JUMPIF, Machine.trueRep, Register.CB, loopAddr);
return null;
}
// Expressions
@Override
@ -734,6 +745,9 @@ public final class Encoder implements ActualParameterVisitor<Frame, Integer>,
elaborateStdPrimRoutine(StdEnvironment.puteolDecl, Primitive.PUTEOL);
elaborateStdEqRoutine(StdEnvironment.equalDecl, Primitive.EQ);
elaborateStdEqRoutine(StdEnvironment.unequalDecl, Primitive.NE);
StdEnvironment.barDecl.entity = new BarPrimitiveRoutine();
}
boolean tableDetailsReqd;
@ -741,10 +755,9 @@ public final class Encoder implements ActualParameterVisitor<Frame, Integer>,
public static void writeTableDetails(AbstractSyntaxTree ast) {
}
// Generates code to fetch the value of a named constant or variable
// and push it on to the stack.
// currentLevel is the routine level where the vname occurs.
// frameSize is the anticipated size of the local stack frame when
// Generates code to pop the top off the stack
// and store the value in a named constant or variable
// frame the local stack frame when
// the constant or variable is fetched at run-time.
// valSize is the size of the constant or variable's value.

@ -0,0 +1,27 @@
package triangle.codeGenerator.entities;
import triangle.abstractMachine.Machine;
import triangle.abstractMachine.OpCode;
import triangle.abstractMachine.Primitive;
import triangle.abstractMachine.Register;
import triangle.codeGenerator.Emitter;
import triangle.codeGenerator.Frame;
public class BarPrimitiveRoutine extends RuntimeEntity implements RoutineEntity {
public BarPrimitiveRoutine() {
super(Machine.closureSize);
}
public void encodeCall(Emitter emitter, Frame frame) {
//push the literal value of 100 onto the stack
emitter.emit(OpCode.LOADL, 0, 100);
emitter.emit(OpCode.CALL, Register.PB, Primitive.MULT);
}
public void encodeFetch(Emitter emitter, Frame frame) {
emitter.emit(OpCode.LOADA, 0, Register.SB, 0);
emitter.emit(OpCode.LOADA, Register.PB, Primitive.MULT);
}
}

@ -34,6 +34,7 @@ import triangle.abstractSyntaxTrees.commands.CallCommand;
import triangle.abstractSyntaxTrees.commands.EmptyCommand;
import triangle.abstractSyntaxTrees.commands.IfCommand;
import triangle.abstractSyntaxTrees.commands.LetCommand;
import triangle.abstractSyntaxTrees.commands.RepeatCommand;
import triangle.abstractSyntaxTrees.commands.SequentialCommand;
import triangle.abstractSyntaxTrees.commands.WhileCommand;
import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration;
@ -132,7 +133,8 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
public Void visitCallCommand(CallCommand ast, Void arg) {
var binding = ast.I.visit(this);
if (binding instanceof ProcedureDeclaration procedure) {
if (binding instanceof ProcedureDeclaration) {
ProcedureDeclaration procedure = (ProcedureDeclaration)binding;
ast.APS.visit(this, procedure.getFormals());
} else {
reportUndeclaredOrError(binding, ast.I, "\"%\" is not a procedure identifier");
@ -183,6 +185,15 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
return null;
}
@Override
public Void visitRepeatCommand(RepeatCommand ast, Void arg) {
var eType = ast.E.visit(this);
checkAndReportError(eType.equals(StdEnvironment.booleanType), "Boolean expression expected here", ast.E);
ast.C.visit(this);
return null;
}
// Expressions
@ -203,7 +214,8 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
var e2Type = ast.E2.visit(this);
var binding = ast.O.visit(this);
if (binding instanceof BinaryOperatorDeclaration bbinding) {
if (binding instanceof BinaryOperatorDeclaration) {
BinaryOperatorDeclaration bbinding = (BinaryOperatorDeclaration)binding;
if (bbinding.ARG1 == StdEnvironment.anyType) {
// this operator must be "=" or "\="
checkAndReportError(e1Type.equals(e2Type), "incompatible argument types for \"%\"", ast.O, ast);
@ -222,7 +234,8 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
public TypeDenoter visitCallExpression(CallExpression ast, Void arg) {
var binding = ast.I.visit(this);
if (binding instanceof FunctionDeclaration function) {
if (binding instanceof FunctionDeclaration) {
FunctionDeclaration function = (FunctionDeclaration)binding;
ast.APS.visit(this, function.getFormals());
return ast.type = function.getType();
}
@ -277,7 +290,8 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
var eType = ast.E.visit(this);
var binding = ast.O.visit(this);
if (binding instanceof UnaryOperatorDeclaration ubinding) {
if (binding instanceof UnaryOperatorDeclaration) {
UnaryOperatorDeclaration ubinding = (UnaryOperatorDeclaration)binding;
checkAndReportError(eType.equals(ubinding.ARG), "wrong argument type for \"%\"", ast.O);
return ast.type = ubinding.RES;
}
@ -472,8 +486,9 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override
public Void visitConstActualParameter(ConstActualParameter ast, FormalParameter arg) {
var eType = ast.E.visit(this);
if (arg instanceof ConstFormalParameter param) {
checkAndReportError(eType.equals(param.T), "wrong type for const actual parameter", ast.E);
if (arg instanceof ConstFormalParameter) {
ConstFormalParameter param = (ConstFormalParameter)arg;
checkAndReportError(eType.equals(((ConstFormalParameter)arg).T), "wrong type for const actual parameter", ast.E);
} else {
reportError("const actual parameter not expected here", ast);
}
@ -483,10 +498,12 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override
public Void visitFuncActualParameter(FuncActualParameter ast, FormalParameter arg) {
var binding = ast.I.visit(this);
if (binding instanceof FunctionDeclaration function) {
if (binding instanceof FunctionDeclaration) {
FunctionDeclaration function = (FunctionDeclaration)binding;
var formals = function.getFormals();
var functionType = function.getType();
if (arg instanceof FuncFormalParameter param) {
if (arg instanceof FuncFormalParameter) {
FuncFormalParameter param = (FuncFormalParameter)arg;
if (!formals.equals(param.getFormals())) {
reportError("wrong signature for function \"%\"", ast.I);
} else if (!functionType.equals(param.T)) {
@ -504,9 +521,11 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override
public Void visitProcActualParameter(ProcActualParameter ast, FormalParameter arg) {
var binding = ast.I.visit(this);
if (binding instanceof ProcedureDeclaration procedure) {
if (binding instanceof ProcedureDeclaration) {
ProcedureDeclaration procedure = (ProcedureDeclaration)binding;
var formals = procedure.getFormals();
if (arg instanceof ProcFormalParameter param) {
if (arg instanceof ProcFormalParameter) {
ProcFormalParameter param = (ProcFormalParameter)arg;
checkAndReportError(formals.equals(param.getFormals()), "wrong signature for procedure \"%\"", ast.I);
} else {
reportError("proc actual parameter not expected here", ast);
@ -522,7 +541,8 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
var vType = ast.V.visit(this);
if (!ast.V.variable) {
reportError("actual parameter is not a variable", ast.V);
} else if (arg instanceof VarFormalParameter parameter) {
} else if (arg instanceof VarFormalParameter) {
VarFormalParameter parameter = (VarFormalParameter)arg;
checkAndReportError(vType.equals(parameter.T), "wrong type for var actual parameter", ast.V);
} else {
reportError("var actual parameter not expected here", ast.V);
@ -538,7 +558,8 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override
public Void visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, FormalParameterSequence arg) {
if (arg instanceof MultipleFormalParameterSequence formals) {
if (arg instanceof MultipleFormalParameterSequence) {
MultipleFormalParameterSequence formals = (MultipleFormalParameterSequence)arg;
ast.AP.visit(this, formals.FP);
ast.APS.visit(this, formals.FPS);
} else {
@ -549,7 +570,8 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override
public Void visitSingleActualParameterSequence(SingleActualParameterSequence ast, FormalParameterSequence arg) {
if (arg instanceof SingleFormalParameterSequence formal) {
if (arg instanceof SingleFormalParameterSequence) {
SingleFormalParameterSequence formal = (SingleFormalParameterSequence)arg;
ast.AP.visit(this, formal.FP);
} else {
reportError("incorrect number of actual parameters", ast);
@ -592,7 +614,8 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override
public TypeDenoter visitSimpleTypeDenoter(SimpleTypeDenoter ast, Void arg) {
var binding = ast.I.visit(this);
if (binding instanceof TypeDeclaration decl) {
if (binding instanceof TypeDeclaration) {
TypeDeclaration decl = (TypeDeclaration)binding;
return decl.T;
}
@ -679,7 +702,8 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
ast.type = null;
var vType = ast.V.visit(this);
ast.variable = ast.V.variable;
if (vType instanceof RecordTypeDenoter record) {
if (vType instanceof RecordTypeDenoter) {
RecordTypeDenoter record = (RecordTypeDenoter)vType;
ast.type = checkFieldIdentifier(record.FT, ast.I);
checkAndReportError(ast.type != StdEnvironment.errorType, "no field \"%\" in this record type",
ast.I);
@ -695,10 +719,12 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
ast.type = StdEnvironment.errorType;
var binding = ast.I.visit(this);
if (binding instanceof ConstantDeclaration constant) {
if (binding instanceof ConstantDeclaration) {
ConstantDeclaration constant = (ConstantDeclaration)binding;
ast.variable = false;
return ast.type = constant.getType();
} else if (binding instanceof VariableDeclaration variable) {
} else if (binding instanceof VariableDeclaration) {
VariableDeclaration variable = (VariableDeclaration)binding;
ast.variable = true;
return ast.type = variable.getType();
}
@ -714,7 +740,8 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
var eType = ast.E.visit(this);
if (vType != StdEnvironment.errorType) {
if (vType instanceof ArrayTypeDenoter arrayType) {
if (vType instanceof ArrayTypeDenoter) {
ArrayTypeDenoter arrayType = (ArrayTypeDenoter)vType;
checkAndReportError(eType.equals(StdEnvironment.integerType), "Integer expression expected here",
ast.E);
ast.type = arrayType.T;
@ -799,14 +826,16 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
}
private static TypeDenoter checkFieldIdentifier(FieldTypeDenoter ast, Identifier I) {
if (ast instanceof MultipleFieldTypeDenoter ft) {
if (ast instanceof MultipleFieldTypeDenoter) {
MultipleFieldTypeDenoter ft = (MultipleFieldTypeDenoter)ast;
if (ft.I.spelling.compareTo(I.spelling) == 0) {
I.decl = ast;
return ft.T;
} else {
return checkFieldIdentifier(ft.FT, I);
}
} else if (ast instanceof SingleFieldTypeDenoter ft) {
} else if (ast instanceof SingleFieldTypeDenoter) {
SingleFieldTypeDenoter ft = (SingleFieldTypeDenoter)ast;
if (ft.I.spelling.compareTo(I.spelling) == 0) {
I.decl = ast;
return ft.T;
@ -928,7 +957,11 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
StdEnvironment.booleanType);
StdEnvironment.notlessDecl = declareStdBinaryOp(">=", StdEnvironment.integerType, StdEnvironment.integerType,
StdEnvironment.booleanType);
//add the new bar operator!
StdEnvironment.barDecl = declareStdUnaryOp("|", StdEnvironment.integerType, StdEnvironment.integerType);
StdEnvironment.charDecl = declareStdType("Char", StdEnvironment.charType);
StdEnvironment.chrDecl = declareStdFunc("chr",
new SingleFormalParameterSequence(

@ -0,0 +1,601 @@
package triangle.optimiser;
import triangle.StdEnvironment;
import triangle.abstractSyntaxTrees.AbstractSyntaxTree;
import triangle.abstractSyntaxTrees.Program;
import triangle.abstractSyntaxTrees.actuals.ConstActualParameter;
import triangle.abstractSyntaxTrees.actuals.EmptyActualParameterSequence;
import triangle.abstractSyntaxTrees.actuals.FuncActualParameter;
import triangle.abstractSyntaxTrees.actuals.MultipleActualParameterSequence;
import triangle.abstractSyntaxTrees.actuals.ProcActualParameter;
import triangle.abstractSyntaxTrees.actuals.SingleActualParameterSequence;
import triangle.abstractSyntaxTrees.actuals.VarActualParameter;
import triangle.abstractSyntaxTrees.aggregates.MultipleArrayAggregate;
import triangle.abstractSyntaxTrees.aggregates.MultipleRecordAggregate;
import triangle.abstractSyntaxTrees.aggregates.SingleArrayAggregate;
import triangle.abstractSyntaxTrees.aggregates.SingleRecordAggregate;
import triangle.abstractSyntaxTrees.commands.AssignCommand;
import triangle.abstractSyntaxTrees.commands.CallCommand;
import triangle.abstractSyntaxTrees.commands.EmptyCommand;
import triangle.abstractSyntaxTrees.commands.IfCommand;
import triangle.abstractSyntaxTrees.commands.LetCommand;
import triangle.abstractSyntaxTrees.commands.RepeatCommand;
import triangle.abstractSyntaxTrees.commands.SequentialCommand;
import triangle.abstractSyntaxTrees.commands.WhileCommand;
import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration;
import triangle.abstractSyntaxTrees.declarations.ConstDeclaration;
import triangle.abstractSyntaxTrees.declarations.FuncDeclaration;
import triangle.abstractSyntaxTrees.declarations.ProcDeclaration;
import triangle.abstractSyntaxTrees.declarations.SequentialDeclaration;
import triangle.abstractSyntaxTrees.declarations.UnaryOperatorDeclaration;
import triangle.abstractSyntaxTrees.declarations.VarDeclaration;
import triangle.abstractSyntaxTrees.expressions.ArrayExpression;
import triangle.abstractSyntaxTrees.expressions.BinaryExpression;
import triangle.abstractSyntaxTrees.expressions.CallExpression;
import triangle.abstractSyntaxTrees.expressions.CharacterExpression;
import triangle.abstractSyntaxTrees.expressions.EmptyExpression;
import triangle.abstractSyntaxTrees.expressions.Expression;
import triangle.abstractSyntaxTrees.expressions.IfExpression;
import triangle.abstractSyntaxTrees.expressions.IntegerExpression;
import triangle.abstractSyntaxTrees.expressions.LetExpression;
import triangle.abstractSyntaxTrees.expressions.RecordExpression;
import triangle.abstractSyntaxTrees.expressions.UnaryExpression;
import triangle.abstractSyntaxTrees.expressions.VnameExpression;
import triangle.abstractSyntaxTrees.formals.ConstFormalParameter;
import triangle.abstractSyntaxTrees.formals.EmptyFormalParameterSequence;
import triangle.abstractSyntaxTrees.formals.FuncFormalParameter;
import triangle.abstractSyntaxTrees.formals.MultipleFormalParameterSequence;
import triangle.abstractSyntaxTrees.formals.ProcFormalParameter;
import triangle.abstractSyntaxTrees.formals.SingleFormalParameterSequence;
import triangle.abstractSyntaxTrees.formals.VarFormalParameter;
import triangle.abstractSyntaxTrees.terminals.CharacterLiteral;
import triangle.abstractSyntaxTrees.terminals.Identifier;
import triangle.abstractSyntaxTrees.terminals.IntegerLiteral;
import triangle.abstractSyntaxTrees.terminals.Operator;
import triangle.abstractSyntaxTrees.types.AnyTypeDenoter;
import triangle.abstractSyntaxTrees.types.ArrayTypeDenoter;
import triangle.abstractSyntaxTrees.types.BoolTypeDenoter;
import triangle.abstractSyntaxTrees.types.CharTypeDenoter;
import triangle.abstractSyntaxTrees.types.ErrorTypeDenoter;
import triangle.abstractSyntaxTrees.types.IntTypeDenoter;
import triangle.abstractSyntaxTrees.types.MultipleFieldTypeDenoter;
import triangle.abstractSyntaxTrees.types.RecordTypeDenoter;
import triangle.abstractSyntaxTrees.types.SimpleTypeDenoter;
import triangle.abstractSyntaxTrees.types.SingleFieldTypeDenoter;
import triangle.abstractSyntaxTrees.types.TypeDeclaration;
import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor;
import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor;
import triangle.abstractSyntaxTrees.visitors.ArrayAggregateVisitor;
import triangle.abstractSyntaxTrees.visitors.CommandVisitor;
import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor;
import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor;
import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor;
import triangle.abstractSyntaxTrees.visitors.IdentifierVisitor;
import triangle.abstractSyntaxTrees.visitors.LiteralVisitor;
import triangle.abstractSyntaxTrees.visitors.OperatorVisitor;
import triangle.abstractSyntaxTrees.visitors.ProgramVisitor;
import triangle.abstractSyntaxTrees.visitors.RecordAggregateVisitor;
import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor;
import triangle.abstractSyntaxTrees.visitors.VnameVisitor;
import triangle.abstractSyntaxTrees.vnames.DotVname;
import triangle.abstractSyntaxTrees.vnames.SimpleVname;
import triangle.abstractSyntaxTrees.vnames.SubscriptVname;
import triangle.codeGenerator.entities.RuntimeEntity;
public class ConstantFolder implements ActualParameterVisitor<Void, AbstractSyntaxTree>,
ActualParameterSequenceVisitor<Void, AbstractSyntaxTree>, ArrayAggregateVisitor<Void, AbstractSyntaxTree>,
CommandVisitor<Void, AbstractSyntaxTree>, DeclarationVisitor<Void, AbstractSyntaxTree>,
ExpressionVisitor<Void, AbstractSyntaxTree>, FormalParameterSequenceVisitor<Void, AbstractSyntaxTree>,
IdentifierVisitor<Void, AbstractSyntaxTree>, LiteralVisitor<Void, AbstractSyntaxTree>,
OperatorVisitor<Void, AbstractSyntaxTree>, ProgramVisitor<Void, AbstractSyntaxTree>,
RecordAggregateVisitor<Void, AbstractSyntaxTree>, TypeDenoterVisitor<Void, AbstractSyntaxTree>,
VnameVisitor<Void, RuntimeEntity> {
{
}
@Override
public AbstractSyntaxTree visitConstFormalParameter(ConstFormalParameter ast, Void arg) {
ast.I.visit(this);
ast.T.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitFuncFormalParameter(FuncFormalParameter ast, Void arg) {
ast.I.visit(this);
ast.T.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitProcFormalParameter(ProcFormalParameter ast, Void arg) {
ast.I.visit(this);
ast.FPS.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitVarFormalParameter(VarFormalParameter ast, Void arg) {
ast.I.visit(this);
ast.T.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitMultipleFieldTypeDenoter(MultipleFieldTypeDenoter ast, Void arg) {
ast.FT.visit(this);
ast.I.visit(this);
ast.T.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitSingleFieldTypeDenoter(SingleFieldTypeDenoter ast, Void arg) {
ast.I.visit(this);
ast.T.visit(this);
return null;
}
@Override
public RuntimeEntity visitDotVname(DotVname ast, Void arg) {
ast.I.visit(this);
ast.V.visit(this);
return null;
}
@Override
public RuntimeEntity visitSimpleVname(SimpleVname ast, Void arg) {
ast.I.visit(this);
return null;
}
@Override
public RuntimeEntity visitSubscriptVname(SubscriptVname ast, Void arg) {
AbstractSyntaxTree replacement = ast.E.visit(this);
if (replacement != null) {
ast.E = (Expression) replacement;
}
ast.V.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitAnyTypeDenoter(AnyTypeDenoter ast, Void arg) {
return null;
}
@Override
public AbstractSyntaxTree visitArrayTypeDenoter(ArrayTypeDenoter ast, Void arg) {
ast.IL.visit(this);
ast.T.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitBoolTypeDenoter(BoolTypeDenoter ast, Void arg) {
return null;
}
@Override
public AbstractSyntaxTree visitCharTypeDenoter(CharTypeDenoter ast, Void arg) {
return null;
}
@Override
public AbstractSyntaxTree visitErrorTypeDenoter(ErrorTypeDenoter ast, Void arg) {
return null;
}
@Override
public AbstractSyntaxTree visitSimpleTypeDenoter(SimpleTypeDenoter ast, Void arg) {
ast.I.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitIntTypeDenoter(IntTypeDenoter ast, Void arg) {
return null;
}
@Override
public AbstractSyntaxTree visitRecordTypeDenoter(RecordTypeDenoter ast, Void arg) {
ast.FT.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitMultipleRecordAggregate(MultipleRecordAggregate ast, Void arg) {
AbstractSyntaxTree replacement = ast.E.visit(this);
if (replacement != null) {
ast.E = (Expression) replacement;
}
ast.I.visit(this);
ast.RA.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitSingleRecordAggregate(SingleRecordAggregate ast, Void arg) {
AbstractSyntaxTree replacement = ast.E.visit(this);
if (replacement != null) {
ast.E = (Expression) replacement;
}
ast.I.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitProgram(Program ast, Void arg) {
ast.C.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitOperator(Operator ast, Void arg) {
return null;
}
@Override
public AbstractSyntaxTree visitCharacterLiteral(CharacterLiteral ast, Void arg) {
return null;
}
@Override
public AbstractSyntaxTree visitIntegerLiteral(IntegerLiteral ast, Void arg) {
return ast;
}
@Override
public AbstractSyntaxTree visitIdentifier(Identifier ast, Void arg) {
return null;
}
@Override
public AbstractSyntaxTree visitEmptyFormalParameterSequence(EmptyFormalParameterSequence ast, Void arg) {
return null;
}
@Override
public AbstractSyntaxTree visitMultipleFormalParameterSequence(MultipleFormalParameterSequence ast, Void arg) {
ast.FP.visit(this);
ast.FPS.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitSingleFormalParameterSequence(SingleFormalParameterSequence ast, Void arg) {
ast.FP.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitArrayExpression(ArrayExpression ast, Void arg) {
ast.AA.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitBinaryExpression(BinaryExpression ast, Void arg) {
AbstractSyntaxTree replacement1 = ast.E1.visit(this);
AbstractSyntaxTree replacement2 = ast.E2.visit(this);
ast.O.visit(this);
// if visiting a child node returns something, it's either the original constant
// (IntegerLiteral) or a folded version replacing the expression at that child
// node
// If both child nodes are not null; return a folded version of this
// BinaryExpression
// Otherwise, at least one child node isn't constant (foldable) so just replace
// the
// foldable child nodes with their folded equivalent and return null
if (replacement1 != null && replacement2 != null) {
return foldBinaryExpression(replacement1, replacement2, ast.O);
} else if (replacement1 != null) {
ast.E1 = (Expression) replacement1;
} else if (replacement2 != null) {
ast.E2 = (Expression) replacement2;
}
// if we get here, we can't fold any higher than this level
return null;
}
@Override
public AbstractSyntaxTree visitCallExpression(CallExpression ast, Void arg) {
ast.APS.visit(this);
ast.I.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitCharacterExpression(CharacterExpression ast, Void arg) {
ast.CL.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitEmptyExpression(EmptyExpression ast, Void arg) {
return null;
}
@Override
public AbstractSyntaxTree visitIfExpression(IfExpression ast, Void arg) {
AbstractSyntaxTree replacement1 = ast.E1.visit(this);
if (replacement1 != null) {
ast.E1 = (Expression) replacement1;
}
AbstractSyntaxTree replacement2 = ast.E2.visit(this);
if (replacement2 != null) {
ast.E2 = (Expression) replacement2;
}
AbstractSyntaxTree replacement3 = ast.E3.visit(this);
if (replacement3 != null) {
ast.E3 = (Expression) replacement3;
}
return null;
}
@Override
public AbstractSyntaxTree visitIntegerExpression(IntegerExpression ast, Void arg) {
return ast;
}
@Override
public AbstractSyntaxTree visitLetExpression(LetExpression ast, Void arg) {
ast.D.visit(this);
AbstractSyntaxTree replacement = ast.E.visit(this);
if (replacement != null) {
ast.E = (Expression) replacement;
}
return null;
}
@Override
public AbstractSyntaxTree visitRecordExpression(RecordExpression ast, Void arg) {
ast.RA.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitUnaryExpression(UnaryExpression ast, Void arg) {
AbstractSyntaxTree replacement = ast.E.visit(this);
if (replacement != null) {
ast.E = (Expression) replacement;
}
ast.O.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitVnameExpression(VnameExpression ast, Void arg) {
ast.V.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitBinaryOperatorDeclaration(BinaryOperatorDeclaration ast, Void arg) {
ast.ARG1.visit(this);
ast.ARG2.visit(this);
ast.O.visit(this);
ast.RES.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitConstDeclaration(ConstDeclaration ast, Void arg) {
AbstractSyntaxTree replacement = ast.E.visit(this);
if (replacement != null) {
ast.E = (Expression) replacement;
}
ast.I.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitFuncDeclaration(FuncDeclaration ast, Void arg) {
AbstractSyntaxTree replacement = ast.E.visit(this);
if (replacement != null) {
ast.E = (Expression) replacement;
}
ast.FPS.visit(this);
ast.I.visit(this);
ast.T.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitProcDeclaration(ProcDeclaration ast, Void arg) {
ast.C.visit(this);
ast.FPS.visit(this);
ast.I.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitSequentialDeclaration(SequentialDeclaration ast, Void arg) {
ast.D1.visit(this);
ast.D2.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitTypeDeclaration(TypeDeclaration ast, Void arg) {
ast.I.visit(this);
ast.T.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitUnaryOperatorDeclaration(UnaryOperatorDeclaration ast, Void arg) {
ast.ARG.visit(this);
ast.O.visit(this);
ast.RES.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitVarDeclaration(VarDeclaration ast, Void arg) {
ast.I.visit(this);
ast.T.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitAssignCommand(AssignCommand ast, Void arg) {
AbstractSyntaxTree replacement = ast.E.visit(this);
if (replacement != null) {
ast.E = (Expression) replacement;
}
ast.V.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitCallCommand(CallCommand ast, Void arg) {
return null;
}
@Override
public AbstractSyntaxTree visitEmptyCommand(EmptyCommand ast, Void arg) {
return null;
}
@Override
public AbstractSyntaxTree visitIfCommand(IfCommand ast, Void arg) {
ast.C1.visit(this);
ast.C2.visit(this);
AbstractSyntaxTree replacement = ast.E.visit(this);
if (replacement != null) {
ast.E = (Expression) replacement;
}
return null;
}
@Override
public AbstractSyntaxTree visitLetCommand(LetCommand ast, Void arg) {
ast.C.visit(this);
ast.D.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitSequentialCommand(SequentialCommand ast, Void arg) {
ast.C1.visit(this);
ast.C2.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitWhileCommand(WhileCommand ast, Void arg) {
ast.C.visit(this);
AbstractSyntaxTree replacement = ast.E.visit(this);
if (replacement != null) {
ast.E = (Expression) replacement;
}
return null;
}
// TODO uncomment if you've implemented the repeat command
// @Override
// public AbstractSyntaxTree visitRepeatCommand(RepeatCommand ast, Void arg) {
// ast.C.visit(this);
// AbstractSyntaxTree replacement = ast.E.visit(this);
// if (replacement != null) {
// ast.E = (Expression) replacement;
// }
// return null;
// }
@Override
public AbstractSyntaxTree visitMultipleArrayAggregate(MultipleArrayAggregate ast, Void arg) {
ast.AA.visit(this);
AbstractSyntaxTree replacement = ast.E.visit(this);
if (replacement != null) {
ast.E = (Expression) replacement;
}
return null;
}
@Override
public AbstractSyntaxTree visitSingleArrayAggregate(SingleArrayAggregate ast, Void arg) {
AbstractSyntaxTree replacement = ast.E.visit(this);
if (replacement != null) {
ast.E = (Expression) replacement;
}
return null;
}
@Override
public AbstractSyntaxTree visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, Void arg) {
return null;
}
@Override
public AbstractSyntaxTree visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, Void arg) {
ast.AP.visit(this);
ast.APS.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitSingleActualParameterSequence(SingleActualParameterSequence ast, Void arg) {
ast.AP.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitConstActualParameter(ConstActualParameter ast, Void arg) {
AbstractSyntaxTree replacement = ast.E.visit(this);
if (replacement != null) {
ast.E = (Expression) replacement;
}
return null;
}
@Override
public AbstractSyntaxTree visitFuncActualParameter(FuncActualParameter ast, Void arg) {
ast.I.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitProcActualParameter(ProcActualParameter ast, Void arg) {
ast.I.visit(this);
return null;
}
@Override
public AbstractSyntaxTree visitVarActualParameter(VarActualParameter ast, Void arg) {
ast.V.visit(this);
return null;
}
public AbstractSyntaxTree foldBinaryExpression(AbstractSyntaxTree node1, AbstractSyntaxTree node2, Operator o) {
// the only case we know how to deal with for now is two IntegerExpressions
if ((node1 instanceof IntegerExpression) && (node2 instanceof IntegerExpression)) {
int int1 = (Integer.parseInt(((IntegerExpression) node1).IL.spelling));
int int2 = (Integer.parseInt(((IntegerExpression) node2).IL.spelling));
Object foldedValue = null;
if (o.decl == StdEnvironment.addDecl) {
foldedValue = int1 + int2;
}
if (foldedValue instanceof Integer) {
IntegerLiteral il = new IntegerLiteral(foldedValue.toString(), node1.getPosition());
IntegerExpression ie = new IntegerExpression(il, node1.getPosition());
ie.type = StdEnvironment.integerType;
return ie;
} else if (foldedValue instanceof Boolean) {
/* currently not handled! */
}
}
// any unhandled situation (i.e., not foldable) is ignored
return null;
}
}

@ -37,6 +37,7 @@ import triangle.abstractSyntaxTrees.commands.Command;
import triangle.abstractSyntaxTrees.commands.EmptyCommand;
import triangle.abstractSyntaxTrees.commands.IfCommand;
import triangle.abstractSyntaxTrees.commands.LetCommand;
import triangle.abstractSyntaxTrees.commands.RepeatCommand;
import triangle.abstractSyntaxTrees.commands.SequentialCommand;
import triangle.abstractSyntaxTrees.commands.WhileCommand;
import triangle.abstractSyntaxTrees.declarations.ConstDeclaration;
@ -320,7 +321,7 @@ public class Parser {
}
break;
case Token.WHILE: {
case Token.WHILE: { //while expr. do command
acceptIt();
Expression eAST = parseExpression();
accept(Token.DO);
@ -330,6 +331,16 @@ public class Parser {
}
break;
case Token.REPEAT: { //repeat command until expr.
acceptIt();
Command cAST = parseSingleCommand();
accept(Token.UNTIL); //check that there is a "until"
Expression eAST = parseExpression();
finish(commandPos);
commandAST = new RepeatCommand(eAST, cAST, commandPos);
}
break;
case Token.SEMICOLON:
case Token.END:
case Token.ELSE:
@ -918,3 +929,4 @@ public class Parser {
return fieldAST;
}
}

@ -35,7 +35,7 @@ public final class Scanner {
private boolean isOperator(char c) {
return (c == '+' || c == '-' || c == '*' || c == '/' || c == '=' || c == '<' || c == '>' || c == '\\'
|| c == '&' || c == '@' || c == '%' || c == '^' || c == '?');
|| c == '&' || c == '@' || c == '%' || c == '^' || c == '?' || c == '|');
}
///////////////////////////////////////////////////////////////////////////////
@ -64,7 +64,7 @@ public final class Scanner {
private void scanSeparator() {
switch (currentChar) {
// comment
// ! comment
case '!': {
takeIt();
while ((currentChar != SourceFile.EOL) && (currentChar != SourceFile.EOT))
@ -73,7 +73,29 @@ public final class Scanner {
takeIt();
}
break;
// new type of comment, the # comment, same as before when it comes to code
case '#':{
takeIt();
while((currentChar != SourceFile.EOL) && (currentChar != SourceFile.EOT))
takeIt();
if(currentChar == SourceFile.EOL)
takeIt();
}
break;
// new type of comment, the multi-line $ comment
case '$':{
takeIt();
//check if it is not the comment char or EOT, skipping new lines (no EOL)
while((currentChar != '$') && (currentChar != SourceFile.EOT))
takeIt();
//if we reach another $, takeIt and move on, we've reached the end of the multi-line comment
if(currentChar == '$')
takeIt();
}
break;
// whitespace
case ' ':
case '\n':
@ -177,6 +199,13 @@ public final class Scanner {
while (isOperator(currentChar))
takeIt();
return Token.OPERATOR;
// TODO: Bar operator, week 3
case '|':
takeIt();
while(isOperator(currentChar))
takeIt();
return Token.OPERATOR;
case '\'':
takeIt();
@ -252,7 +281,7 @@ public final class Scanner {
currentlyScanningToken = false;
// skip any whitespace or comments
while (currentChar == '!' || currentChar == ' ' || currentChar == '\n' || currentChar == '\r'
|| currentChar == '\t')
|| currentChar == '\t' || currentChar == '#' || currentChar == '$')
scanSeparator();
currentlyScanningToken = true;

@ -14,26 +14,36 @@
package triangle.syntacticAnalyzer;
import java.net.URL;
public class SourceFile {
public static final char EOL = '\n';
public static final char EOT = '\u0000';
java.io.File sourceFile;
java.io.FileInputStream source;
java.io.InputStream source;
int currentLine;
public static SourceFile ofPath(String pathname) {
try {
return new SourceFile(pathname);
SourceFile sf = new SourceFile();
sf.sourceFile = new java.io.File(pathname);
sf.source = new java.io.FileInputStream(sf.sourceFile);
return sf;
} catch (java.io.IOException s) {
return null;
}
}
public static SourceFile fromResource(String handle) {
SourceFile sf = new SourceFile();
//sf.sourceFile = new java.io.File(pathname);
sf.source = sf.getClass().getResourceAsStream(handle);
return sf;
}
private SourceFile(String pathname) throws java.io.FileNotFoundException {
sourceFile = new java.io.File(pathname);
source = new java.io.FileInputStream(sourceFile);
private SourceFile() {
currentLine = 1;
}

@ -64,20 +64,20 @@ final class Token extends Object {
// reserved words - must be in alphabetical order...
ARRAY = 4, BEGIN = 5, CONST = 6, DO = 7, ELSE = 8, END = 9, FUNC = 10, IF = 11, IN = 12, LET = 13, OF = 14,
PROC = 15, RECORD = 16, THEN = 17, TYPE = 18, VAR = 19, WHILE = 20,
PROC = 15, RECORD = 16, REPEAT = 17, THEN = 18, TYPE = 19, UNTIL = 20, VAR = 21, WHILE = 22,
// punctuation...
DOT = 21, COLON = 22, SEMICOLON = 23, COMMA = 24, BECOMES = 25, IS = 26,
DOT = 23, COLON = 24, SEMICOLON = 25, COMMA = 26, BECOMES = 27, IS = 28,
// brackets...
LPAREN = 27, RPAREN = 28, LBRACKET = 29, RBRACKET = 30, LCURLY = 31, RCURLY = 32,
LPAREN = 29, RPAREN = 30, LBRACKET = 31, RBRACKET = 32, LCURLY = 33, RCURLY = 34,
// special tokens...
EOT = 33, ERROR = 34;
EOT = 35, ERROR = 36;
private static String[] tokenTable = new String[] { "<int>", "<char>", "<identifier>", "<operator>", "array",
"begin", "const", "do", "else", "end", "func", "if", "in", "let", "of", "proc", "record", "then", "type",
"var", "while", ".", ":", ";", ",", ":=", "~", "(", ")", "[", "]", "{", "}", "", "<error>" };
"begin", "const", "do", "else", "end", "func", "if", "in", "let", "of", "proc", "record", "repeat", "then", "type",
"until", "var", "while", ".", ":", ";", ",", ":=", "~", "(", ")", "[", "]", "{", "}", "", "<error>" };
private final static int firstReservedWord = Token.ARRAY, lastReservedWord = Token.WHILE;

@ -42,6 +42,13 @@ public class Drawer {
FontMetrics fontMetrics = frame.getFontMetrics(font);
// another class of visitor is used for drawing the tree: LayoutVisitor
// LayoutVisitor is passed to the AST which, in turn, calls visitProgram
// and then each AST node is visited. This ultimately constructs a
// DrawingTree, which is structurally the same as the AST but is decorated
// with coordinates (and has only DrawingTree objects as nodes)
// Each DrawingTree object knows how to paint itself, so it's passed to a
// DrawerPanel and DrawerFrame for display
LayoutVisitor layout = new LayoutVisitor(fontMetrics);
theDrawing = (DrawingTree) theAST.visit(layout, null);
theDrawing.position(new Point(2048, 10));

@ -33,6 +33,7 @@ import triangle.abstractSyntaxTrees.commands.CallCommand;
import triangle.abstractSyntaxTrees.commands.EmptyCommand;
import triangle.abstractSyntaxTrees.commands.IfCommand;
import triangle.abstractSyntaxTrees.commands.LetCommand;
import triangle.abstractSyntaxTrees.commands.RepeatCommand;
import triangle.abstractSyntaxTrees.commands.SequentialCommand;
import triangle.abstractSyntaxTrees.commands.WhileCommand;
import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration;
@ -158,6 +159,14 @@ public class LayoutVisitor implements ActualParameterVisitor<Void, DrawingTree>,
var d2 = ast.C.visit(this);
return layoutBinary("WhileCom.", d1, d2);
}
@Override
public DrawingTree visitRepeatCommand(RepeatCommand ast, Void obj) {
//very similar to the while cmd, just reverse!
var d1 = ast.C.visit(this);
var d2 = ast.E.visit(this);
return layoutBinary("Repeat.Com.", d1, d2);
}
// Expressions
@Override

@ -14,6 +14,9 @@
package triangle.treeDrawer;
/**
* used to keep track of the position for components in the tree to be drawn
*/
class Polyline {
int dx, dy;
Polyline link;

@ -0,0 +1,90 @@
package triangle.syntacticAnalyser;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThrows;
import org.junit.Test;
import org.junit.function.ThrowingRunnable;
import triangle.ErrorReporter;
import triangle.syntacticAnalyzer.Parser;
import triangle.syntacticAnalyzer.Scanner;
import triangle.syntacticAnalyzer.SourceFile;
public class TestScanner {
@Test
public void testHi() {
compileExpectSuccess("/hi.tri");
}
@Test
public void testHiNewComment() {
compileExpectSuccess("/hi-newcomment.tri");
}
@Test
public void testHiNewComment2() {
compileExpectSuccess("/hi-newcomment2.tri");
}
@Test
public void testBarDemo() {
compileExpectSuccess("/bardemo.tri"); //TODO: Change this to failure
}
@Test
public void testRepeatUntil() {
compileExpectSuccess("/repeatuntil.tri");
}
@Test
public void testAdd() {
//compileExpectFailure("/addd.tri"); //fail here!
compileExpectFailure("/add.tri");
}
private void compileExpectSuccess(String filename) {
// build.gradle has a line sourceSets.test.resources.srcDir file("$rootDir/programs")
// which adds the programs directory to the list of places Java can easily find files
// getResource() below searches for a file, which is in /programs
//SourceFile source = SourceFile.ofPath(this.getClass().getResource(filename).getFile().toString());
SourceFile source = SourceFile.fromResource(filename);
Scanner scanner = new Scanner(source);
ErrorReporter reporter = new ErrorReporter(true);
Parser parser = new Parser(scanner, reporter);
parser.parseProgram();
// we should get to here with no exceptions
assertEquals("Problem compiling " + filename, 0, reporter.getNumErrors());
}
private void compileExpectFailure(String filename) {
//SourceFile source = SourceFile.ofPath(this.getClass().getResource(filename).getFile().toString());
SourceFile source = SourceFile.fromResource(filename);
Scanner scanner = new Scanner(source);
ErrorReporter reporter = new ErrorReporter(true);
Parser parser = new Parser(scanner, reporter);
// we expect an exception here as the program has invalid syntax
assertThrows(RuntimeException.class, new ThrowingRunnable() {
public void run(){
parser.parseProgram();
}
});
// currently this program will fail
assertNotEquals("Problem compiling " + filename, 0, reporter.getNumErrors());
}
}

@ -0,0 +1,11 @@
apply plugin: 'java'
sourceCompatibility = 11
subprojects.each { subproject ->
evaluationDependsOn(subproject.path)
}
jar {
from subprojects.sourceSets.main.output
}

Binary file not shown.

@ -0,0 +1,46 @@
! Program that will: read two ints, print their sum and their product. If they are the same, print "Same"
! Global Consts, Funcs.
let
type String ~ array 6 of Char; ! String type implemented, not used yet
var num1 : Integer;
var num2 : Integer;
func sum(x : Integer, y : Integer) : Integer ~
x + y; ! Return x + y
func product(x : Integer, y : Integer) : Integer ~
x * y; ! Return x * y
func isSame(x : Integer, y : Integer) : Boolean ~
if x = y then true else false
! Main Loop
in
begin
num1 := 0;
num2 := 0; ! Init. values to 0
getint(var num1);
getint(var num2); ! Get user input
! Sum
putint(num1); put('+'); put(' '); putint(num2); put(' '); put('='); put(' ');
putint(sum(num1, num2)); puteol();
puteol();
! Product
putint(num1); put(' '); put('*'); put(' '); putint(num2); put(' '); put('='); put(' ');
putint(product(num1, num2)); puteol();
if isSame(num1, num2) = true then
put('S'); put('a'); put('m'); put('e'); puteol();
else
puteol();
end

@ -0,0 +1,12 @@
let
var a: Integer
in
begin
a := 10 + 20 * 2 / 3;
putint(a);
puteol();
a := 5 + 8;
putint(a)
end

@ -0,0 +1,27 @@
! this won't work until after some work in the practicals
let
var a : Integer;
var b : Integer
in
begin
a := 1;
b := 2;
putint(a);
<<<<<<< HEAD
puteol();
=======
puteol();
>>>>>>> ce307a11a6c71de9c69bd0a4c91205bb6437f6e9
putint(b);
puteol();
putint(|a);
puteol();
putint(|b);
puteol()
<<<<<<< HEAD
=======
>>>>>>> ce307a11a6c71de9c69bd0a4c91205bb6437f6e9
end

@ -0,0 +1,30 @@
! Program with a variety of contextual errors.
let
type String ~ array 4 of Char;
type Name ~ array 3 of String;
type Rec ~ record x: Integer, x: Integer end;
var me: Name;
var silly : maxint;
var silly: Rec;
proc putstr (s: String) ~
let var i: Integer
in
begin
s[4] := ' ';
i := 0;
while i do
begin i := i+true;
put (s[\i])
end
end
in
begin
me[true] := ['T','i','n','y'];
me[2][2] := 0;
put (me[1]); put (4); put ();
putstr (initials (me)); puteol ()
end

@ -0,0 +1,7 @@
! this won't work until after some work in the practicals
# new comment
begin
put('H'); put('i'); put('!')
end

@ -0,0 +1,14 @@
! this won't work until after some work in the practicals
# new comment
$
another new comment
another new comment
another new comment
another new comment
$
begin
put('H'); put('i'); put('!')
end

@ -0,0 +1,14 @@
! this won't compile without implementing the bonus material in Practical 3
let
var a: Integer
in
begin
getint(var a);
a++;
putint(a);
puteol();
a++;
putint(a);
puteol();
end

@ -0,0 +1,14 @@
! this won't work until after some lab work
let
var a : Integer
in
begin
a := 0;
repeat
begin
put('a');
a := a + 1;
end
until a >= 5
end

@ -0,0 +1,22 @@
let
var a : Integer;
var b : Integer;
var c : Integer
in
begin
put('1');
puteol();
a := 0;
while a < 5000 do
begin
b := 0;
while b < 3000 do
begin
c := c + a;
c := c / (1 + b);
b := b + 1;
end;
a := a + 1;
end;
putint(c);
end

@ -0,0 +1,11 @@
let
var a : Integer
in
begin
a := 0;
while a < 5 do
begin
put('a');
a := a + 1;
end
end

29
tam

@ -0,0 +1,29 @@
#!/bin/bash
RED='\033[0;31m' # Red
GRN='\033[0;32m' # Green
NC='\033[0m' # No Color
file=""
if [ -z "$1" ]
then
printf "${RED}Usage: $0 file${NC}"
exit 1 # Exit with code 1, failure
else
file=$1
fi
printf "${GRN}[INFO] Compiling file: $1.tri to $1.tam ...${NC}\n"
# Compile to tam
if java -cp build/libs/Triangle-Tools.jar triangle.Compiler programs/$1.tri -o=$1.tam &> /dev/null #quiet
then
printf "${GRN}[INFO] Running file: $1.tam ...${NC}\n"
java -cp build/libs/Triangle-Tools.jar triangle.abstractMachine.Interpreter $1.tam
else
printf "${RED}[ERROR] Could not complie $1.tri ...${NC}"
err=$(java -cp build/libs/Triangle-Tools.jar triangle.Compiler programs/$1.tri -o=$1.tam)
printf "${RED}\n$err\n${NC}"
exit 1
fi