1 Commits
Author SHA1 Message Date
simonkellet c3d038dd35 lets see if this works 2022-09-20 11:58:18 +01:00
36 changed files with 61 additions and 518 deletions
-6
View File
@@ -1,6 +0,0 @@
<?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
View File
@@ -60,9 +60,3 @@ local.properties
# Typically, this file would be tracked if it contains build/dependency configurations: # Typically, this file would be tracked if it contains build/dependency configurations:
#.project #.project
/.gradle/ /.gradle/
# tam files
*.tam
# Build folder
/build/
-6
View File
@@ -5,11 +5,6 @@
<projects> <projects>
</projects> </projects>
<buildSpec> <buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name> <name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments> <arguments>
@@ -17,7 +12,6 @@
</buildCommand> </buildCommand>
</buildSpec> </buildSpec>
<natures> <natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature> <nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures> </natures>
</projectDescription> </projectDescription>
-2
View File
@@ -1,2 +0,0 @@
# A5 Triangle Compiler
@@ -1,7 +1,7 @@
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'application' apply plugin: 'application'
sourceCompatibility = 11 sourceCompatibility = 17
dependencies { dependencies {
implementation project(':Triangle.AbstractMachine') implementation project(':Triangle.AbstractMachine')
@@ -1,7 +1,7 @@
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'application' apply plugin: 'application'
sourceCompatibility = 11 sourceCompatibility = 17
dependencies { dependencies {
implementation project(':Triangle.AbstractMachine') implementation project(':Triangle.AbstractMachine')
+1 -1
View File
@@ -1,4 +1,4 @@
apply plugin: 'java-library' apply plugin: 'java-library'
apply plugin: 'eclipse' apply plugin: 'eclipse'
sourceCompatibility = 11 sourceCompatibility = 17
-7
View File
@@ -20,11 +20,4 @@
<nature>org.eclipse.jdt.core.javanature</nature> <nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature> <nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures> </natures>
<linkedResources>
<link>
<name>programs</name>
<type>2</type>
<location>/home/simon/Documents/Uni/CS/CSCU9A5/Triangle-Tools/programs</location>
</link>
</linkedResources>
</projectDescription> </projectDescription>
+1 -10
View File
@@ -1,21 +1,12 @@
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'application' apply plugin: 'application'
sourceCompatibility = 11 sourceCompatibility = 17
repositories {
mavenCentral()
}
dependencies { dependencies {
implementation project(':Triangle.AbstractMachine') implementation project(':Triangle.AbstractMachine')
testImplementation group: 'junit', name: 'junit', version: '4.13.2'
} }
application { application {
mainClass = 'Triangle.Compiler' mainClass = 'Triangle.Compiler'
} }
// allow access to programs for unit tests
sourceSets.test.resources.srcDir file("$rootDir/programs")
@@ -34,8 +34,6 @@ public class Compiler {
/** The filename for the object program, normally obj.tam. */ /** The filename for the object program, normally obj.tam. */
static String objectName = "obj.tam"; static String objectName = "obj.tam";
static boolean showTree = false;
private static Scanner scanner; private static Scanner scanner;
private static Parser parser; private static Parser parser;
private static Checker checker; private static Checker checker;
@@ -73,7 +71,7 @@ public class Compiler {
} }
scanner = new Scanner(source); scanner = new Scanner(source);
reporter = new ErrorReporter(false); reporter = new ErrorReporter();
parser = new Parser(scanner, reporter); parser = new Parser(scanner, reporter);
checker = new Checker(reporter); checker = new Checker(reporter);
emitter = new Emitter(reporter); emitter = new Emitter(reporter);
@@ -82,7 +80,7 @@ public class Compiler {
// scanner.enableDebugging(); // scanner.enableDebugging();
theAST = parser.parseProgram(); // 1st pass theAST = parser.parseProgram(); // 1st pass
if (reporter.getNumErrors() == 0) { if (reporter.numErrors == 0) {
// if (showingAST) { // if (showingAST) {
// drawer.draw(theAST); // drawer.draw(theAST);
// } // }
@@ -91,13 +89,13 @@ public class Compiler {
if (showingAST) { if (showingAST) {
drawer.draw(theAST); drawer.draw(theAST);
} }
if (reporter.getNumErrors() == 0) { if (reporter.numErrors == 0) {
System.out.println("Code Generation ..."); System.out.println("Code Generation ...");
encoder.encodeRun(theAST, showingTable); // 3rd pass encoder.encodeRun(theAST, showingTable); // 3rd pass
} }
} }
boolean successful = (reporter.getNumErrors() == 0); boolean successful = (reporter.numErrors == 0);
if (successful) { if (successful) {
emitter.saveObjectProgram(objectName); emitter.saveObjectProgram(objectName);
System.out.println("Compilation was successful."); System.out.println("Compilation was successful.");
@@ -116,29 +114,16 @@ public class Compiler {
public static void main(String[] args) { public static void main(String[] args) {
if (args.length < 1) { if (args.length < 1) {
System.out.println("Usage: tc filename [-o=outputfilename] [tree]"); System.out.println("Usage: tc filename [tree]");
System.exit(1); System.exit(1);
} }
parseArgs(args);
String sourceName = args[0]; 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); 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);
}
}
}
} }
@@ -18,44 +18,25 @@ import triangle.syntacticAnalyzer.SourcePosition;
public class ErrorReporter { public class ErrorReporter {
private int numErrors; int numErrors;
private boolean throwExceptions; ErrorReporter() {
/**
* @param throwExceptions if true, throw exceptions (good for unit tests) otherwise write to stdout
*/
public ErrorReporter(boolean throwExceptions) {
numErrors = 0; numErrors = 0;
this.throwExceptions = throwExceptions;
} }
public void reportError(String message, String tokenName, SourcePosition pos) { 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++) for (int p = 0; p < message.length(); p++)
if (message.charAt(p) == '%') if (message.charAt(p) == '%')
s += tokenName; System.out.print(tokenName);
else else
s += message.charAt(p); System.out.print(message.charAt(p));
s += (" " + pos.start + ".." + pos.finish); System.out.println(" " + pos.start + ".." + pos.finish);
numErrors++;
if (throwExceptions) {
throw new RuntimeException(s);
} else {
System.out.println(s);
}
} }
public void reportRestriction(String message) { public void reportRestriction(String message) {
System.out.println("RESTRICTION: " + message); System.out.println("RESTRICTION: " + message);
} }
public int getNumErrors() {
return numErrors;
}
} }
@@ -1,21 +0,0 @@
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 final Command C;
}
@@ -39,8 +39,8 @@ public class ConstFormalParameter extends FormalParameter implements ConstantDec
@Override @Override
public boolean equals(Object fpAST) { public boolean equals(Object fpAST) {
if (fpAST instanceof ConstFormalParameter) { if (fpAST instanceof ConstFormalParameter cfpAST) {
return T.equals(((ConstFormalParameter)fpAST).T); return T.equals(cfpAST.T);
} else { } else {
return false; return false;
} }
@@ -39,8 +39,8 @@ public class VarFormalParameter extends FormalParameter implements VariableDecla
@Override @Override
public boolean equals(Object fpAST) { public boolean equals(Object fpAST) {
if (fpAST instanceof VarFormalParameter) { if (fpAST instanceof VarFormalParameter vfpAST) {
return T.equals(((VarFormalParameter)fpAST).T); return T.equals(vfpAST.T);
} else { } else {
return false; return false;
} }
@@ -5,11 +5,11 @@ import triangle.abstractSyntaxTrees.commands.CallCommand;
import triangle.abstractSyntaxTrees.commands.EmptyCommand; import triangle.abstractSyntaxTrees.commands.EmptyCommand;
import triangle.abstractSyntaxTrees.commands.IfCommand; import triangle.abstractSyntaxTrees.commands.IfCommand;
import triangle.abstractSyntaxTrees.commands.LetCommand; import triangle.abstractSyntaxTrees.commands.LetCommand;
import triangle.abstractSyntaxTrees.commands.RepeatCommand;
import triangle.abstractSyntaxTrees.commands.SequentialCommand; import triangle.abstractSyntaxTrees.commands.SequentialCommand;
import triangle.abstractSyntaxTrees.commands.WhileCommand; import triangle.abstractSyntaxTrees.commands.WhileCommand;
public interface CommandVisitor<TArg, TResult> { public interface CommandVisitor<TArg, TResult> {
TResult visitAssignCommand(AssignCommand ast, TArg arg); TResult visitAssignCommand(AssignCommand ast, TArg arg);
TResult visitCallCommand(CallCommand ast, TArg arg); TResult visitCallCommand(CallCommand ast, TArg arg);
@@ -24,6 +24,4 @@ public interface CommandVisitor<TArg, TResult> {
TResult visitWhileCommand(WhileCommand ast, TArg arg); TResult visitWhileCommand(WhileCommand ast, TArg arg);
TResult visitRepeatCommand(RepeatCommand ast, TArg arg);
} }
@@ -38,7 +38,6 @@ import triangle.abstractSyntaxTrees.commands.CallCommand;
import triangle.abstractSyntaxTrees.commands.EmptyCommand; import triangle.abstractSyntaxTrees.commands.EmptyCommand;
import triangle.abstractSyntaxTrees.commands.IfCommand; import triangle.abstractSyntaxTrees.commands.IfCommand;
import triangle.abstractSyntaxTrees.commands.LetCommand; import triangle.abstractSyntaxTrees.commands.LetCommand;
import triangle.abstractSyntaxTrees.commands.RepeatCommand;
import triangle.abstractSyntaxTrees.commands.SequentialCommand; import triangle.abstractSyntaxTrees.commands.SequentialCommand;
import triangle.abstractSyntaxTrees.commands.WhileCommand; import triangle.abstractSyntaxTrees.commands.WhileCommand;
import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration;
@@ -182,11 +181,6 @@ public final class Encoder implements ActualParameterVisitor<Frame, Integer>,
return null; return null;
} }
@Override
public Void visitRepeatCommand(RepeatCommand ast, Frame frame) {
return null;
}
// Expressions // Expressions
@Override @Override
public Integer visitArrayExpression(ArrayExpression ast, Frame frame) { public Integer visitArrayExpression(ArrayExpression ast, Frame frame) {
@@ -34,7 +34,6 @@ import triangle.abstractSyntaxTrees.commands.CallCommand;
import triangle.abstractSyntaxTrees.commands.EmptyCommand; import triangle.abstractSyntaxTrees.commands.EmptyCommand;
import triangle.abstractSyntaxTrees.commands.IfCommand; import triangle.abstractSyntaxTrees.commands.IfCommand;
import triangle.abstractSyntaxTrees.commands.LetCommand; import triangle.abstractSyntaxTrees.commands.LetCommand;
import triangle.abstractSyntaxTrees.commands.RepeatCommand;
import triangle.abstractSyntaxTrees.commands.SequentialCommand; import triangle.abstractSyntaxTrees.commands.SequentialCommand;
import triangle.abstractSyntaxTrees.commands.WhileCommand; import triangle.abstractSyntaxTrees.commands.WhileCommand;
import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration;
@@ -133,8 +132,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
public Void visitCallCommand(CallCommand ast, Void arg) { public Void visitCallCommand(CallCommand ast, Void arg) {
var binding = ast.I.visit(this); var binding = ast.I.visit(this);
if (binding instanceof ProcedureDeclaration) { if (binding instanceof ProcedureDeclaration procedure) {
ProcedureDeclaration procedure = (ProcedureDeclaration)binding;
ast.APS.visit(this, procedure.getFormals()); ast.APS.visit(this, procedure.getFormals());
} else { } else {
reportUndeclaredOrError(binding, ast.I, "\"%\" is not a procedure identifier"); reportUndeclaredOrError(binding, ast.I, "\"%\" is not a procedure identifier");
@@ -186,11 +184,6 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
return null; return null;
} }
@Override
public Void visitRepeatCommand(RepeatCommand ast, Void arg) {
return null;
}
// Expressions // Expressions
// Returns the TypeDenoter denoting the type of the expression. Does // Returns the TypeDenoter denoting the type of the expression. Does
@@ -210,8 +203,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
var e2Type = ast.E2.visit(this); var e2Type = ast.E2.visit(this);
var binding = ast.O.visit(this); var binding = ast.O.visit(this);
if (binding instanceof BinaryOperatorDeclaration) { if (binding instanceof BinaryOperatorDeclaration bbinding) {
BinaryOperatorDeclaration bbinding = (BinaryOperatorDeclaration)binding;
if (bbinding.ARG1 == StdEnvironment.anyType) { if (bbinding.ARG1 == StdEnvironment.anyType) {
// this operator must be "=" or "\=" // this operator must be "=" or "\="
checkAndReportError(e1Type.equals(e2Type), "incompatible argument types for \"%\"", ast.O, ast); checkAndReportError(e1Type.equals(e2Type), "incompatible argument types for \"%\"", ast.O, ast);
@@ -230,8 +222,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
public TypeDenoter visitCallExpression(CallExpression ast, Void arg) { public TypeDenoter visitCallExpression(CallExpression ast, Void arg) {
var binding = ast.I.visit(this); var binding = ast.I.visit(this);
if (binding instanceof FunctionDeclaration) { if (binding instanceof FunctionDeclaration function) {
FunctionDeclaration function = (FunctionDeclaration)binding;
ast.APS.visit(this, function.getFormals()); ast.APS.visit(this, function.getFormals());
return ast.type = function.getType(); return ast.type = function.getType();
} }
@@ -286,8 +277,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
var eType = ast.E.visit(this); var eType = ast.E.visit(this);
var binding = ast.O.visit(this); var binding = ast.O.visit(this);
if (binding instanceof UnaryOperatorDeclaration) { if (binding instanceof UnaryOperatorDeclaration ubinding) {
UnaryOperatorDeclaration ubinding = (UnaryOperatorDeclaration)binding;
checkAndReportError(eType.equals(ubinding.ARG), "wrong argument type for \"%\"", ast.O); checkAndReportError(eType.equals(ubinding.ARG), "wrong argument type for \"%\"", ast.O);
return ast.type = ubinding.RES; return ast.type = ubinding.RES;
} }
@@ -482,9 +472,8 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public Void visitConstActualParameter(ConstActualParameter ast, FormalParameter arg) { public Void visitConstActualParameter(ConstActualParameter ast, FormalParameter arg) {
var eType = ast.E.visit(this); var eType = ast.E.visit(this);
if (arg instanceof ConstFormalParameter) { if (arg instanceof ConstFormalParameter param) {
ConstFormalParameter param = (ConstFormalParameter)arg; checkAndReportError(eType.equals(param.T), "wrong type for const actual parameter", ast.E);
checkAndReportError(eType.equals(((ConstFormalParameter)arg).T), "wrong type for const actual parameter", ast.E);
} else { } else {
reportError("const actual parameter not expected here", ast); reportError("const actual parameter not expected here", ast);
} }
@@ -494,12 +483,10 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public Void visitFuncActualParameter(FuncActualParameter ast, FormalParameter arg) { public Void visitFuncActualParameter(FuncActualParameter ast, FormalParameter arg) {
var binding = ast.I.visit(this); var binding = ast.I.visit(this);
if (binding instanceof FunctionDeclaration) { if (binding instanceof FunctionDeclaration function) {
FunctionDeclaration function = (FunctionDeclaration)binding;
var formals = function.getFormals(); var formals = function.getFormals();
var functionType = function.getType(); var functionType = function.getType();
if (arg instanceof FuncFormalParameter) { if (arg instanceof FuncFormalParameter param) {
FuncFormalParameter param = (FuncFormalParameter)arg;
if (!formals.equals(param.getFormals())) { if (!formals.equals(param.getFormals())) {
reportError("wrong signature for function \"%\"", ast.I); reportError("wrong signature for function \"%\"", ast.I);
} else if (!functionType.equals(param.T)) { } else if (!functionType.equals(param.T)) {
@@ -517,11 +504,9 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public Void visitProcActualParameter(ProcActualParameter ast, FormalParameter arg) { public Void visitProcActualParameter(ProcActualParameter ast, FormalParameter arg) {
var binding = ast.I.visit(this); var binding = ast.I.visit(this);
if (binding instanceof ProcedureDeclaration) { if (binding instanceof ProcedureDeclaration procedure) {
ProcedureDeclaration procedure = (ProcedureDeclaration)binding;
var formals = procedure.getFormals(); var formals = procedure.getFormals();
if (arg instanceof ProcFormalParameter) { if (arg instanceof ProcFormalParameter param) {
ProcFormalParameter param = (ProcFormalParameter)arg;
checkAndReportError(formals.equals(param.getFormals()), "wrong signature for procedure \"%\"", ast.I); checkAndReportError(formals.equals(param.getFormals()), "wrong signature for procedure \"%\"", ast.I);
} else { } else {
reportError("proc actual parameter not expected here", ast); reportError("proc actual parameter not expected here", ast);
@@ -537,8 +522,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
var vType = ast.V.visit(this); var vType = ast.V.visit(this);
if (!ast.V.variable) { if (!ast.V.variable) {
reportError("actual parameter is not a variable", ast.V); reportError("actual parameter is not a variable", ast.V);
} else if (arg instanceof VarFormalParameter) { } else if (arg instanceof VarFormalParameter parameter) {
VarFormalParameter parameter = (VarFormalParameter)arg;
checkAndReportError(vType.equals(parameter.T), "wrong type for var actual parameter", ast.V); checkAndReportError(vType.equals(parameter.T), "wrong type for var actual parameter", ast.V);
} else { } else {
reportError("var actual parameter not expected here", ast.V); reportError("var actual parameter not expected here", ast.V);
@@ -554,8 +538,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public Void visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, FormalParameterSequence arg) { public Void visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, FormalParameterSequence arg) {
if (arg instanceof MultipleFormalParameterSequence) { if (arg instanceof MultipleFormalParameterSequence formals) {
MultipleFormalParameterSequence formals = (MultipleFormalParameterSequence)arg;
ast.AP.visit(this, formals.FP); ast.AP.visit(this, formals.FP);
ast.APS.visit(this, formals.FPS); ast.APS.visit(this, formals.FPS);
} else { } else {
@@ -566,8 +549,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public Void visitSingleActualParameterSequence(SingleActualParameterSequence ast, FormalParameterSequence arg) { public Void visitSingleActualParameterSequence(SingleActualParameterSequence ast, FormalParameterSequence arg) {
if (arg instanceof SingleFormalParameterSequence) { if (arg instanceof SingleFormalParameterSequence formal) {
SingleFormalParameterSequence formal = (SingleFormalParameterSequence)arg;
ast.AP.visit(this, formal.FP); ast.AP.visit(this, formal.FP);
} else { } else {
reportError("incorrect number of actual parameters", ast); reportError("incorrect number of actual parameters", ast);
@@ -610,8 +592,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
@Override @Override
public TypeDenoter visitSimpleTypeDenoter(SimpleTypeDenoter ast, Void arg) { public TypeDenoter visitSimpleTypeDenoter(SimpleTypeDenoter ast, Void arg) {
var binding = ast.I.visit(this); var binding = ast.I.visit(this);
if (binding instanceof TypeDeclaration) { if (binding instanceof TypeDeclaration decl) {
TypeDeclaration decl = (TypeDeclaration)binding;
return decl.T; return decl.T;
} }
@@ -698,8 +679,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
ast.type = null; ast.type = null;
var vType = ast.V.visit(this); var vType = ast.V.visit(this);
ast.variable = ast.V.variable; ast.variable = ast.V.variable;
if (vType instanceof RecordTypeDenoter) { if (vType instanceof RecordTypeDenoter record) {
RecordTypeDenoter record = (RecordTypeDenoter)vType;
ast.type = checkFieldIdentifier(record.FT, ast.I); ast.type = checkFieldIdentifier(record.FT, ast.I);
checkAndReportError(ast.type != StdEnvironment.errorType, "no field \"%\" in this record type", checkAndReportError(ast.type != StdEnvironment.errorType, "no field \"%\" in this record type",
ast.I); ast.I);
@@ -715,12 +695,10 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
ast.type = StdEnvironment.errorType; ast.type = StdEnvironment.errorType;
var binding = ast.I.visit(this); var binding = ast.I.visit(this);
if (binding instanceof ConstantDeclaration) { if (binding instanceof ConstantDeclaration constant) {
ConstantDeclaration constant = (ConstantDeclaration)binding;
ast.variable = false; ast.variable = false;
return ast.type = constant.getType(); return ast.type = constant.getType();
} else if (binding instanceof VariableDeclaration) { } else if (binding instanceof VariableDeclaration variable) {
VariableDeclaration variable = (VariableDeclaration)binding;
ast.variable = true; ast.variable = true;
return ast.type = variable.getType(); return ast.type = variable.getType();
} }
@@ -736,8 +714,7 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
var eType = ast.E.visit(this); var eType = ast.E.visit(this);
if (vType != StdEnvironment.errorType) { if (vType != StdEnvironment.errorType) {
if (vType instanceof ArrayTypeDenoter) { if (vType instanceof ArrayTypeDenoter arrayType) {
ArrayTypeDenoter arrayType = (ArrayTypeDenoter)vType;
checkAndReportError(eType.equals(StdEnvironment.integerType), "Integer expression expected here", checkAndReportError(eType.equals(StdEnvironment.integerType), "Integer expression expected here",
ast.E); ast.E);
ast.type = arrayType.T; ast.type = arrayType.T;
@@ -822,16 +799,14 @@ public final class Checker implements ActualParameterVisitor<FormalParameter, Vo
} }
private static TypeDenoter checkFieldIdentifier(FieldTypeDenoter ast, Identifier I) { private static TypeDenoter checkFieldIdentifier(FieldTypeDenoter ast, Identifier I) {
if (ast instanceof MultipleFieldTypeDenoter) { if (ast instanceof MultipleFieldTypeDenoter ft) {
MultipleFieldTypeDenoter ft = (MultipleFieldTypeDenoter)ast;
if (ft.I.spelling.compareTo(I.spelling) == 0) { if (ft.I.spelling.compareTo(I.spelling) == 0) {
I.decl = ast; I.decl = ast;
return ft.T; return ft.T;
} else { } else {
return checkFieldIdentifier(ft.FT, I); return checkFieldIdentifier(ft.FT, I);
} }
} else if (ast instanceof SingleFieldTypeDenoter) { } else if (ast instanceof SingleFieldTypeDenoter ft) {
SingleFieldTypeDenoter ft = (SingleFieldTypeDenoter)ast;
if (ft.I.spelling.compareTo(I.spelling) == 0) { if (ft.I.spelling.compareTo(I.spelling) == 0) {
I.decl = ast; I.decl = ast;
return ft.T; return ft.T;
@@ -37,7 +37,6 @@ import triangle.abstractSyntaxTrees.commands.Command;
import triangle.abstractSyntaxTrees.commands.EmptyCommand; import triangle.abstractSyntaxTrees.commands.EmptyCommand;
import triangle.abstractSyntaxTrees.commands.IfCommand; import triangle.abstractSyntaxTrees.commands.IfCommand;
import triangle.abstractSyntaxTrees.commands.LetCommand; import triangle.abstractSyntaxTrees.commands.LetCommand;
import triangle.abstractSyntaxTrees.commands.RepeatCommand;
import triangle.abstractSyntaxTrees.commands.SequentialCommand; import triangle.abstractSyntaxTrees.commands.SequentialCommand;
import triangle.abstractSyntaxTrees.commands.WhileCommand; import triangle.abstractSyntaxTrees.commands.WhileCommand;
import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; import triangle.abstractSyntaxTrees.declarations.ConstDeclaration;
@@ -321,7 +320,7 @@ public class Parser {
} }
break; break;
case Token.WHILE: { //while expr. do command case Token.WHILE: {
acceptIt(); acceptIt();
Expression eAST = parseExpression(); Expression eAST = parseExpression();
accept(Token.DO); accept(Token.DO);
@@ -331,16 +330,6 @@ public class Parser {
} }
break; 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.SEMICOLON:
case Token.END: case Token.END:
case Token.ELSE: case Token.ELSE:
@@ -35,7 +35,7 @@ public final class Scanner {
private boolean isOperator(char c) { private boolean isOperator(char c) {
return (c == '+' || c == '-' || c == '*' || c == '/' || c == '=' || c == '<' || c == '>' || 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() { private void scanSeparator() {
switch (currentChar) { switch (currentChar) {
// ! comment // comment
case '!': { case '!': {
takeIt(); takeIt();
while ((currentChar != SourceFile.EOL) && (currentChar != SourceFile.EOT)) while ((currentChar != SourceFile.EOL) && (currentChar != SourceFile.EOT))
@@ -74,28 +74,6 @@ public final class Scanner {
} }
break; 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 // whitespace
case ' ': case ' ':
case '\n': case '\n':
@@ -200,13 +178,6 @@ public final class Scanner {
takeIt(); takeIt();
return Token.OPERATOR; return Token.OPERATOR;
// TODO: Bar operator, week 3
case '|':
takeIt();
while(isOperator(currentChar))
takeIt();
return Token.OPERATOR;
case '\'': case '\'':
takeIt(); takeIt();
takeIt(); // the quoted character takeIt(); // the quoted character
@@ -281,7 +252,7 @@ public final class Scanner {
currentlyScanningToken = false; currentlyScanningToken = false;
// skip any whitespace or comments // skip any whitespace or comments
while (currentChar == '!' || currentChar == ' ' || currentChar == '\n' || currentChar == '\r' while (currentChar == '!' || currentChar == ' ' || currentChar == '\n' || currentChar == '\r'
|| currentChar == '\t' || currentChar == '#' || currentChar == '$') || currentChar == '\t')
scanSeparator(); scanSeparator();
currentlyScanningToken = true; currentlyScanningToken = true;
@@ -14,36 +14,26 @@
package triangle.syntacticAnalyzer; package triangle.syntacticAnalyzer;
import java.net.URL;
public class SourceFile { public class SourceFile {
public static final char EOL = '\n'; public static final char EOL = '\n';
public static final char EOT = '\u0000'; public static final char EOT = '\u0000';
java.io.File sourceFile; java.io.File sourceFile;
java.io.InputStream source; java.io.FileInputStream source;
int currentLine; int currentLine;
public static SourceFile ofPath(String pathname) { public static SourceFile ofPath(String pathname) {
try { try {
SourceFile sf = new SourceFile(); return new SourceFile(pathname);
sf.sourceFile = new java.io.File(pathname);
sf.source = new java.io.FileInputStream(sf.sourceFile);
return sf;
} catch (java.io.IOException s) { } catch (java.io.IOException s) {
return null; return null;
} }
} }
public static SourceFile fromResource(String handle) { private SourceFile(String pathname) throws java.io.FileNotFoundException {
SourceFile sf = new SourceFile(); sourceFile = new java.io.File(pathname);
//sf.sourceFile = new java.io.File(pathname); source = new java.io.FileInputStream(sourceFile);
sf.source = sf.getClass().getResourceAsStream(handle);
return sf;
}
private SourceFile() {
currentLine = 1; currentLine = 1;
} }
@@ -64,20 +64,20 @@ final class Token extends Object {
// reserved words - must be in alphabetical order... // 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, 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, REPEAT = 17, THEN = 18, TYPE = 19, UNTIL = 20, VAR = 21, WHILE = 22, PROC = 15, RECORD = 16, THEN = 17, TYPE = 18, VAR = 19, WHILE = 20,
// punctuation... // punctuation...
DOT = 23, COLON = 24, SEMICOLON = 25, COMMA = 26, BECOMES = 27, IS = 28, DOT = 21, COLON = 22, SEMICOLON = 23, COMMA = 24, BECOMES = 25, IS = 26,
// brackets... // brackets...
LPAREN = 29, RPAREN = 30, LBRACKET = 31, RBRACKET = 32, LCURLY = 33, RCURLY = 34, LPAREN = 27, RPAREN = 28, LBRACKET = 29, RBRACKET = 30, LCURLY = 31, RCURLY = 32,
// special tokens... // special tokens...
EOT = 35, ERROR = 36; EOT = 33, ERROR = 34;
private static String[] tokenTable = new String[] { "<int>", "<char>", "<identifier>", "<operator>", "array", private static String[] tokenTable = new String[] { "<int>", "<char>", "<identifier>", "<operator>", "array",
"begin", "const", "do", "else", "end", "func", "if", "in", "let", "of", "proc", "record", "repeat", "then", "type", "begin", "const", "do", "else", "end", "func", "if", "in", "let", "of", "proc", "record", "then", "type",
"until", "var", "while", ".", ":", ";", ",", ":=", "~", "(", ")", "[", "]", "{", "}", "", "<error>" }; "var", "while", ".", ":", ";", ",", ":=", "~", "(", ")", "[", "]", "{", "}", "", "<error>" };
private final static int firstReservedWord = Token.ARRAY, lastReservedWord = Token.WHILE; private final static int firstReservedWord = Token.ARRAY, lastReservedWord = Token.WHILE;
@@ -42,13 +42,6 @@ public class Drawer {
FontMetrics fontMetrics = frame.getFontMetrics(font); 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); LayoutVisitor layout = new LayoutVisitor(fontMetrics);
theDrawing = (DrawingTree) theAST.visit(layout, null); theDrawing = (DrawingTree) theAST.visit(layout, null);
theDrawing.position(new Point(2048, 10)); theDrawing.position(new Point(2048, 10));
@@ -33,7 +33,6 @@ import triangle.abstractSyntaxTrees.commands.CallCommand;
import triangle.abstractSyntaxTrees.commands.EmptyCommand; import triangle.abstractSyntaxTrees.commands.EmptyCommand;
import triangle.abstractSyntaxTrees.commands.IfCommand; import triangle.abstractSyntaxTrees.commands.IfCommand;
import triangle.abstractSyntaxTrees.commands.LetCommand; import triangle.abstractSyntaxTrees.commands.LetCommand;
import triangle.abstractSyntaxTrees.commands.RepeatCommand;
import triangle.abstractSyntaxTrees.commands.SequentialCommand; import triangle.abstractSyntaxTrees.commands.SequentialCommand;
import triangle.abstractSyntaxTrees.commands.WhileCommand; import triangle.abstractSyntaxTrees.commands.WhileCommand;
import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration;
@@ -160,11 +159,6 @@ public class LayoutVisitor implements ActualParameterVisitor<Void, DrawingTree>,
return layoutBinary("WhileCom.", d1, d2); return layoutBinary("WhileCom.", d1, d2);
} }
@Override
public DrawingTree visitRepeatCommand(RepeatCommand ast, Void obj) {
return null;
}
// Expressions // Expressions
@Override @Override
public DrawingTree visitArrayExpression(ArrayExpression ast, Void obj) { public DrawingTree visitArrayExpression(ArrayExpression ast, Void obj) {
@@ -14,9 +14,6 @@
package triangle.treeDrawer; package triangle.treeDrawer;
/**
* used to keep track of the position for components in the tree to be drawn
*/
class Polyline { class Polyline {
int dx, dy; int dx, dy;
Polyline link; Polyline link;
@@ -1,90 +0,0 @@
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());
}
}
-11
View File
@@ -1,11 +0,0 @@
apply plugin: 'java'
sourceCompatibility = 11
subprojects.each { subproject ->
evaluationDependsOn(subproject.path)
}
jar {
from subprojects.sourceSets.main.output
}
Binary file not shown.
-46
View File
@@ -1,46 +0,0 @@
! 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
-15
View File
@@ -1,15 +0,0 @@
! 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);
putint(b);
putint(|a);
putint(|b)
end
-30
View File
@@ -1,30 +0,0 @@
! 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
-7
View File
@@ -1,7 +0,0 @@
! this won't work until after some work in the practicals
# new comment
begin
put('H'); put('i'); put('!')
end
-14
View File
@@ -1,14 +0,0 @@
! 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
-14
View File
@@ -1,14 +0,0 @@
! 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
-11
View File
@@ -1,11 +0,0 @@
let
var a : Integer
in
begin
a := 0;
while a < 5 do
begin
put('a');
a := a + 1;
end
end
-29
View File
@@ -1,29 +0,0 @@
#!/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
View File