Archived
Compare commits
29
Commits
main
..
befe8f93a2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
befe8f93a2 | ||
|
|
7c64cb7eff | ||
|
|
a4c304f58d | ||
|
|
36f3fac111 | ||
|
|
cd280e3c4b | ||
|
|
d28b3c7403 | ||
|
|
3f58bdfad9 | ||
|
|
6377dd8250 | ||
|
|
955517af29 | ||
|
|
3dade998ba | ||
|
|
048cbac0b4 | ||
|
|
77846e5800 | ||
|
|
f4e1a08f61 | ||
|
|
c3c2076d9e | ||
|
|
64c25f1486 | ||
|
|
c469297712 | ||
|
|
a2cac87f81 | ||
|
|
b3375e2050 | ||
|
|
11be265081 | ||
|
|
6820b55cf1 | ||
|
|
f709234c4e | ||
|
|
07b0d85bdf | ||
|
|
e8780a5b11 | ||
|
|
90977fb64f | ||
|
|
3150ae8fa9 | ||
|
|
a026ec3840 | ||
|
|
3de9d5e0cc | ||
|
|
ee57c9f711 | ||
|
|
01f468f07d |
@@ -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>
|
||||||
@@ -60,3 +60,9 @@ 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/
|
||||||
|
|||||||
@@ -5,6 +5,11 @@
|
|||||||
<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>
|
||||||
@@ -12,6 +17,7 @@
|
|||||||
</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>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
apply plugin: 'java'
|
apply plugin: 'java'
|
||||||
apply plugin: 'application'
|
apply plugin: 'application'
|
||||||
|
|
||||||
sourceCompatibility = 17
|
sourceCompatibility = 11
|
||||||
|
|
||||||
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 = 17
|
sourceCompatibility = 11
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':Triangle.AbstractMachine')
|
implementation project(':Triangle.AbstractMachine')
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
apply plugin: 'java-library'
|
apply plugin: 'java-library'
|
||||||
apply plugin: 'eclipse'
|
apply plugin: 'eclipse'
|
||||||
|
|
||||||
sourceCompatibility = 17
|
sourceCompatibility = 11
|
||||||
@@ -20,4 +20,11 @@
|
|||||||
<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,12 +1,21 @@
|
|||||||
apply plugin: 'java'
|
apply plugin: 'java'
|
||||||
apply plugin: 'application'
|
apply plugin: 'application'
|
||||||
|
|
||||||
sourceCompatibility = 17
|
sourceCompatibility = 11
|
||||||
|
|
||||||
|
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,6 +34,8 @@ 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;
|
||||||
@@ -71,7 +73,7 @@ public class Compiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scanner = new Scanner(source);
|
scanner = new Scanner(source);
|
||||||
reporter = new ErrorReporter();
|
reporter = new ErrorReporter(false);
|
||||||
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);
|
||||||
@@ -80,7 +82,7 @@ public class Compiler {
|
|||||||
|
|
||||||
// scanner.enableDebugging();
|
// scanner.enableDebugging();
|
||||||
theAST = parser.parseProgram(); // 1st pass
|
theAST = parser.parseProgram(); // 1st pass
|
||||||
if (reporter.numErrors == 0) {
|
if (reporter.getNumErrors() == 0) {
|
||||||
// if (showingAST) {
|
// if (showingAST) {
|
||||||
// drawer.draw(theAST);
|
// drawer.draw(theAST);
|
||||||
// }
|
// }
|
||||||
@@ -89,13 +91,13 @@ public class Compiler {
|
|||||||
if (showingAST) {
|
if (showingAST) {
|
||||||
drawer.draw(theAST);
|
drawer.draw(theAST);
|
||||||
}
|
}
|
||||||
if (reporter.numErrors == 0) {
|
if (reporter.getNumErrors() == 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.numErrors == 0);
|
boolean successful = (reporter.getNumErrors() == 0);
|
||||||
if (successful) {
|
if (successful) {
|
||||||
emitter.saveObjectProgram(objectName);
|
emitter.saveObjectProgram(objectName);
|
||||||
System.out.println("Compilation was successful.");
|
System.out.println("Compilation was successful.");
|
||||||
@@ -114,16 +116,29 @@ 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 [tree]");
|
System.out.println("Usage: tc filename [-o=outputfilename] [tree]");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
String sourceName = args[0];
|
parseArgs(args);
|
||||||
boolean tree = (args.length > 1 && args[1].equalsIgnoreCase("tree"));
|
|
||||||
var compiledOK = compileProgram(sourceName, objectName, tree, false);
|
|
||||||
|
|
||||||
if (!tree) {
|
String sourceName = args[0];
|
||||||
|
|
||||||
|
var compiledOK = compileProgram(sourceName, objectName, showTree, false);
|
||||||
|
|
||||||
|
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,25 +18,44 @@ import triangle.syntacticAnalyzer.SourcePosition;
|
|||||||
|
|
||||||
public class ErrorReporter {
|
public class ErrorReporter {
|
||||||
|
|
||||||
int numErrors;
|
private int numErrors;
|
||||||
|
|
||||||
ErrorReporter() {
|
private boolean throwExceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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) == '%')
|
||||||
System.out.print(tokenName);
|
s += tokenName;
|
||||||
else
|
else
|
||||||
System.out.print(message.charAt(p));
|
s += message.charAt(p);
|
||||||
System.out.println(" " + pos.start + ".." + pos.finish);
|
s += (" " + 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -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 cfpAST) {
|
if (fpAST instanceof ConstFormalParameter) {
|
||||||
return T.equals(cfpAST.T);
|
return T.equals(((ConstFormalParameter)fpAST).T);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -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 vfpAST) {
|
if (fpAST instanceof VarFormalParameter) {
|
||||||
return T.equals(vfpAST.T);
|
return T.equals(((VarFormalParameter)fpAST).T);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,7 +132,8 @@ 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 procedure) {
|
if (binding instanceof ProcedureDeclaration) {
|
||||||
|
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");
|
||||||
@@ -203,7 +204,8 @@ 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 bbinding) {
|
if (binding instanceof BinaryOperatorDeclaration) {
|
||||||
|
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);
|
||||||
@@ -222,7 +224,8 @@ 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 function) {
|
if (binding instanceof FunctionDeclaration) {
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
@@ -277,7 +280,8 @@ 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 ubinding) {
|
if (binding instanceof UnaryOperatorDeclaration) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
@@ -472,8 +476,9 @@ 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 param) {
|
if (arg instanceof ConstFormalParameter) {
|
||||||
checkAndReportError(eType.equals(param.T), "wrong type for const actual parameter", ast.E);
|
ConstFormalParameter param = (ConstFormalParameter)arg;
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
@@ -483,10 +488,12 @@ 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 function) {
|
if (binding instanceof FunctionDeclaration) {
|
||||||
|
FunctionDeclaration function = (FunctionDeclaration)binding;
|
||||||
var formals = function.getFormals();
|
var formals = function.getFormals();
|
||||||
var functionType = function.getType();
|
var functionType = function.getType();
|
||||||
if (arg instanceof FuncFormalParameter param) {
|
if (arg instanceof FuncFormalParameter) {
|
||||||
|
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)) {
|
||||||
@@ -504,9 +511,11 @@ 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 procedure) {
|
if (binding instanceof ProcedureDeclaration) {
|
||||||
|
ProcedureDeclaration procedure = (ProcedureDeclaration)binding;
|
||||||
var formals = procedure.getFormals();
|
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);
|
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);
|
||||||
@@ -522,7 +531,8 @@ 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 parameter) {
|
} else if (arg instanceof VarFormalParameter) {
|
||||||
|
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);
|
||||||
@@ -538,7 +548,8 @@ 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 formals) {
|
if (arg instanceof MultipleFormalParameterSequence) {
|
||||||
|
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 {
|
||||||
@@ -549,7 +560,8 @@ 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 formal) {
|
if (arg instanceof SingleFormalParameterSequence) {
|
||||||
|
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);
|
||||||
@@ -592,7 +604,8 @@ 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 decl) {
|
if (binding instanceof TypeDeclaration) {
|
||||||
|
TypeDeclaration decl = (TypeDeclaration)binding;
|
||||||
return decl.T;
|
return decl.T;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,7 +692,8 @@ 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 record) {
|
if (vType instanceof RecordTypeDenoter) {
|
||||||
|
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);
|
||||||
@@ -695,10 +709,12 @@ 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 constant) {
|
if (binding instanceof ConstantDeclaration) {
|
||||||
|
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 variable) {
|
} else if (binding instanceof VariableDeclaration) {
|
||||||
|
VariableDeclaration variable = (VariableDeclaration)binding;
|
||||||
ast.variable = true;
|
ast.variable = true;
|
||||||
return ast.type = variable.getType();
|
return ast.type = variable.getType();
|
||||||
}
|
}
|
||||||
@@ -714,7 +730,8 @@ 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 arrayType) {
|
if (vType instanceof ArrayTypeDenoter) {
|
||||||
|
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;
|
||||||
@@ -799,14 +816,16 @@ 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 ft) {
|
if (ast instanceof MultipleFieldTypeDenoter) {
|
||||||
|
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 ft) {
|
} else if (ast instanceof SingleFieldTypeDenoter) {
|
||||||
|
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;
|
||||||
|
|||||||
@@ -74,6 +74,16 @@ 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;
|
||||||
|
|
||||||
// whitespace
|
// whitespace
|
||||||
case ' ':
|
case ' ':
|
||||||
case '\n':
|
case '\n':
|
||||||
@@ -252,7 +262,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 == '\t' || currentChar == '#')
|
||||||
scanSeparator();
|
scanSeparator();
|
||||||
|
|
||||||
currentlyScanningToken = true;
|
currentlyScanningToken = true;
|
||||||
|
|||||||
@@ -14,26 +14,36 @@
|
|||||||
|
|
||||||
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.FileInputStream source;
|
java.io.InputStream source;
|
||||||
int currentLine;
|
int currentLine;
|
||||||
|
|
||||||
public static SourceFile ofPath(String pathname) {
|
public static SourceFile ofPath(String pathname) {
|
||||||
try {
|
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) {
|
} catch (java.io.IOException s) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SourceFile(String pathname) throws java.io.FileNotFoundException {
|
public static SourceFile fromResource(String handle) {
|
||||||
sourceFile = new java.io.File(pathname);
|
SourceFile sf = new SourceFile();
|
||||||
source = new java.io.FileInputStream(sourceFile);
|
//sf.sourceFile = new java.io.File(pathname);
|
||||||
|
sf.source = sf.getClass().getResourceAsStream(handle);
|
||||||
|
return sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SourceFile() {
|
||||||
currentLine = 1;
|
currentLine = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,13 @@ 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));
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
|
|
||||||
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;
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
compileExpectFailure("/hi-newcomment2.tri");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBarDemo() {
|
||||||
|
compileExpectFailure("/bardemo.tri");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRepeatUntil() {
|
||||||
|
compileExpectFailure("/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,15 @@
|
|||||||
|
! 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
|
||||||
@@ -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,11 @@
|
|||||||
|
! this won't work until after some work in the practicals
|
||||||
|
|
||||||
|
# new comment
|
||||||
|
|
||||||
|
$
|
||||||
|
another new comment
|
||||||
|
$
|
||||||
|
|
||||||
|
begin
|
||||||
|
put('H'); put('i'); put('!')
|
||||||
|
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,11 @@
|
|||||||
|
let
|
||||||
|
var a : Integer
|
||||||
|
in
|
||||||
|
begin
|
||||||
|
a := 0;
|
||||||
|
while a < 5 do
|
||||||
|
begin
|
||||||
|
put('a');
|
||||||
|
a := a + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#!/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}Compiling file: $1.tri to $1.tam ...${NC}\n"
|
||||||
|
# Compile to tam
|
||||||
|
#java -cp build/libs/Triangle-Tools.jar triangle.Compiler programs/$1.tri -o=$1.tam &> /dev/null #Quiet output, not handy!
|
||||||
|
java -cp build/libs/Triangle-Tools.jar triangle.Compiler programs/$1.tri -o=$1.tam
|
||||||
|
|
||||||
|
printf "${GRN}Running file: $1.tam ...${NC}\n"
|
||||||
|
# Run the Program
|
||||||
|
java -cp build/libs/Triangle-Tools.jar triangle.abstractMachine.Interpreter $1.tam
|
||||||
Reference in New Issue
Block a user