diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f4c2b81 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 deryckb + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Triangle.AbstractMachine.Disassembler/.gitignore b/Triangle.AbstractMachine.Disassembler/.gitignore new file mode 100644 index 0000000..8c107fe --- /dev/null +++ b/Triangle.AbstractMachine.Disassembler/.gitignore @@ -0,0 +1,3 @@ +/target/ +/.classpath +/build/ diff --git a/Triangle.AbstractMachine.Disassembler/.project b/Triangle.AbstractMachine.Disassembler/.project new file mode 100644 index 0000000..7024cd7 --- /dev/null +++ b/Triangle.AbstractMachine.Disassembler/.project @@ -0,0 +1,23 @@ + + + Triangle.AbstractMachine.Disassembler + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/Triangle.AbstractMachine.Disassembler/build.gradle b/Triangle.AbstractMachine.Disassembler/build.gradle new file mode 100644 index 0000000..90e01e7 --- /dev/null +++ b/Triangle.AbstractMachine.Disassembler/build.gradle @@ -0,0 +1,12 @@ +apply plugin: 'java' +apply plugin: 'application' + +sourceCompatibility = 11 + +dependencies { + implementation project(':Triangle.AbstractMachine') +} + +application { + mainClass = 'Triangle.AbstractMachine.Disassembler' +} \ No newline at end of file diff --git a/Triangle.AbstractMachine.Disassembler/pom.xml b/Triangle.AbstractMachine.Disassembler/pom.xml new file mode 100644 index 0000000..847d0fc --- /dev/null +++ b/Triangle.AbstractMachine.Disassembler/pom.xml @@ -0,0 +1,18 @@ + + 4.0.0 + triangle-disassembler + + triangle.tools + triangle-tools + 2.1 + ../ + + + + triangle.tools + triangle-abstractmachine + 2.1 + + + diff --git a/Triangle.AbstractMachine.Disassembler/src/main/java/triangle/abstractMachine/Disassembler.java b/Triangle.AbstractMachine.Disassembler/src/main/java/triangle/abstractMachine/Disassembler.java new file mode 100644 index 0000000..ca94c79 --- /dev/null +++ b/Triangle.AbstractMachine.Disassembler/src/main/java/triangle/abstractMachine/Disassembler.java @@ -0,0 +1,351 @@ +/* + * @(#)Disassembler.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractMachine; + +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +/** + * Disassembles the TAM code in the given file, and displays the instructions on + * standard output. + * + * For example: + * + *
+ *   java TAM.Disassembler obj.tam
+ * 
+ * + *

+ * Copyright 1991 David A. Watt, University of Glasgow
+ * Copyright 1998 Deryck F. Brown, The Robert Gordon University
+ *

+ * + */ + +public class Disassembler { + + static String objectName; + + static int CT; + + /** + * Writes the r-field of an instruction in the form "lregr", where l and + * r are the bracket characters to use. + * + * @param leftbracket the character to print before the register. + * @param r the number of the register. + * @param rightbracket the character to print after the register. + */ + private static void writeR(char leftbracket, Register r, char rightbracket) { + + System.out.print(leftbracket); + System.out.print(r.toString()); + System.out.print(rightbracket); + } + + private static void writeR(char leftBracket, int r, char rightBracket) { + var register = Register.values()[r]; + writeR(leftBracket, register, rightBracket); + } + + /** + * Writes a void n-field of an instruction. + */ + private static void blankN() { + System.out.print(" "); + } + + // Writes the n-field of an instruction. + /** + * Writes the n-field of an instruction in the form "(n)". + * + * @param n the integer to write. + */ + private static void writeN(int n) { + System.out.print("(" + n + ") "); + if (n < 10) { + System.out.print(" "); + } else if (n < 100) { + System.out.print(" "); + } + } + + /** + * Writes the d-field of an instruction. + * + * @param d the integer to write. + */ + private static void writeD(int d) { + System.out.print(d); + } + + /** + * Writes the name of primitive routine with relative address d. + * + * @param d the displacement of the primitive routine. + */ + private static void writePrimitive(int d) { + var primitive = Primitive.values()[d]; + switch (primitive) { + case ID: + System.out.print("id "); + break; + case NOT: + System.out.print("not "); + break; + case AND: + System.out.print("and "); + break; + case OR: + System.out.print("or "); + break; + case SUCC: + System.out.print("succ "); + break; + case PRED: + System.out.print("pred "); + break; + case NEG: + System.out.print("neg "); + break; + case ADD: + System.out.print("add "); + break; + case SUB: + System.out.print("sub "); + break; + case MULT: + System.out.print("mult "); + break; + case DIV: + System.out.print("div "); + break; + case MOD: + System.out.print("mod "); + break; + case LT: + System.out.print("lt "); + break; + case LE: + System.out.print("le "); + break; + case GE: + System.out.print("ge "); + break; + case GT: + System.out.print("gt "); + break; + case EQ: + System.out.print("eq "); + break; + case NE: + System.out.print("ne "); + break; + case EOL: + System.out.print("eol "); + break; + case EOF: + System.out.print("eof "); + break; + case GET: + System.out.print("get "); + break; + case PUT: + System.out.print("put "); + break; + case GETEOL: + System.out.print("geteol "); + break; + case PUTEOL: + System.out.print("puteol "); + break; + case GETINT: + System.out.print("getint "); + break; + case PUTINT: + System.out.print("putint "); + break; + case NEW: + System.out.print("new "); + break; + case DISPOSE: + System.out.print("dispose "); + break; + } + } + + /** + * Writes the given instruction in assembly-code format. + * + * @param instr the instruction to display. + */ + private static void writeInstruction(Instruction instr) { + + switch (instr.opCode) { + case LOAD: + System.out.print("LOAD "); + writeN(instr.length); + writeD(instr.operand); + writeR('[', instr.register, ']'); + break; + + case LOADA: + System.out.print("LOADA "); + blankN(); + writeD(instr.operand); + writeR('[', instr.register, ']'); + break; + + case LOADI: + System.out.print("LOADI "); + writeN(instr.length); + break; + + case LOADL: + System.out.print("LOADL "); + blankN(); + writeD(instr.operand); + break; + + case STORE: + System.out.print("STORE "); + writeN(instr.length); + writeD(instr.operand); + writeR('[', instr.register, ']'); + break; + + case STOREI: + System.out.print("STOREI"); + writeN(instr.length); + break; + + case CALL: + System.out.print("CALL "); + if (instr.register == Register.PB) { + blankN(); + writePrimitive(instr.operand); + } else { + writeR('(', instr.length, ')'); + System.out.print(" "); + writeD(instr.operand); + writeR('[', instr.register, ']'); + } + break; + + case CALLI: + System.out.print("CALLI "); + break; + + case RETURN: + System.out.print("RETURN"); + writeN(instr.length); + writeD(instr.operand); + break; + + case PUSH: + System.out.print("PUSH "); + blankN(); + writeD(instr.operand); + break; + + case POP: + System.out.print("POP "); + writeN(instr.length); + writeD(instr.operand); + break; + + case JUMP: + System.out.print("JUMP "); + blankN(); + writeD(instr.operand); + writeR('[', instr.register, ']'); + break; + + case JUMPI: + System.out.print("JUMPI "); + break; + + case JUMPIF: + System.out.print("JUMPIF"); + writeN(instr.length); + writeD(instr.operand); + writeR('[', instr.register, ']'); + break; + + case HALT: + System.out.print("HALT "); + } + } + + /** + * Writes all instructions of the program in code store. + */ + private static void disassembleProgram() { + for (int addr = Machine.CB; addr < CT; addr++) { + System.out.print(addr + ": "); + writeInstruction(Machine.code[addr]); + System.out.println(); + } + } + + // LOADING + + /** + * Loads the TAM object program into code store from the named file. + * + * @param objectName the name of the file containing the program. + */ + static void loadObjectProgram(String objectName) { + + var finished = false; + + try (var objectFile = new FileInputStream(objectName)) { + var objectStream = new DataInputStream(objectFile); + var addr = Machine.CB; + while (!finished) { + Machine.code[addr] = Instruction.read(objectStream); + if (Machine.code[addr] == null) { + finished = true; + } else { + addr = addr + 1; + } + } + CT = addr; + } catch (FileNotFoundException s) { + CT = Machine.CB; + System.err.println("Error opening object file: " + s); + } catch (IOException s) { + CT = Machine.CB; + System.err.println("Error reading object file: " + s); + } + } + + // DISASSEMBLE + + public static void main(String[] args) { + System.out.println("********** TAM Disassembler (Sun Version 2.1) **********"); + + if (args.length == 1) { + objectName = args[0]; + } else { + objectName = "obj.tam"; + } + + loadObjectProgram(objectName); + disassembleProgram(); + } +} diff --git a/Triangle.AbstractMachine.Interpreter/.gitignore b/Triangle.AbstractMachine.Interpreter/.gitignore new file mode 100644 index 0000000..8c107fe --- /dev/null +++ b/Triangle.AbstractMachine.Interpreter/.gitignore @@ -0,0 +1,3 @@ +/target/ +/.classpath +/build/ diff --git a/Triangle.AbstractMachine.Interpreter/.project b/Triangle.AbstractMachine.Interpreter/.project new file mode 100644 index 0000000..a22beaa --- /dev/null +++ b/Triangle.AbstractMachine.Interpreter/.project @@ -0,0 +1,23 @@ + + + Triangle.AbstractMachine.Interpreter + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/Triangle.AbstractMachine.Interpreter/build.gradle b/Triangle.AbstractMachine.Interpreter/build.gradle new file mode 100644 index 0000000..38c7835 --- /dev/null +++ b/Triangle.AbstractMachine.Interpreter/build.gradle @@ -0,0 +1,12 @@ +apply plugin: 'java' +apply plugin: 'application' + +sourceCompatibility = 11 + +dependencies { + implementation project(':Triangle.AbstractMachine') +} + +application { + mainClass = 'Triangle.AbstractMachine.Interpreter' +} \ No newline at end of file diff --git a/Triangle.AbstractMachine.Interpreter/pom.xml b/Triangle.AbstractMachine.Interpreter/pom.xml new file mode 100644 index 0000000..551e835 --- /dev/null +++ b/Triangle.AbstractMachine.Interpreter/pom.xml @@ -0,0 +1,18 @@ + + 4.0.0 + triangle-interpreter + + triangle.tools + triangle-tools + 2.1 + ../ + + + + triangle.tools + triangle-abstractmachine + 2.1 + + + diff --git a/Triangle.AbstractMachine.Interpreter/src/main/java/triangle/abstractMachine/Interpreter.java b/Triangle.AbstractMachine.Interpreter/src/main/java/triangle/abstractMachine/Interpreter.java new file mode 100644 index 0000000..96b10c5 --- /dev/null +++ b/Triangle.AbstractMachine.Interpreter/src/main/java/triangle/abstractMachine/Interpreter.java @@ -0,0 +1,645 @@ +/* + * @(#)Interpreter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractMachine; + +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +public class Interpreter { + + static long startTimeNanos = 0; + + static String objectName; + + // DATA STORE + + static int[] data = new int[1024]; + + // DATA STORE REGISTERS AND OTHER REGISTERS + + final static int CB = 0, SB = 0, HB = 1024; // = upper bound of data array + 1 + + static int CT, CP, ST, HT, LB, status; + + // status values + final static int running = 0, halted = 1, failedDataStoreFull = 2, failedInvalidCodeAddress = 3, + failedInvalidInstruction = 4, failedOverflow = 5, failedZeroDivide = 6, failedIOError = 7; + + static long accumulator; + + static int content(int r) { + var register = Register.values()[r]; + return content(register); + } + + static int content(Register r) { + // Returns the current content of register r, + // even if r is one of the pseudo-registers L1..L6. + + switch (r) { + case CB: + return CB; + case CT: + return CT; + case PB: + return Machine.PB; + case PT: + return Machine.PT; + case SB: + return SB; + case ST: + return ST; + case HB: + return HB; + case HT: + return HT; + case LB: + return LB; + case L1: + return data[LB]; + case L2: + return data[data[LB]]; + case L3: + return data[data[data[LB]]]; + case L4: + return data[data[data[data[LB]]]]; + case L5: + return data[data[data[data[data[LB]]]]]; + case L6: + return data[data[data[data[data[data[LB]]]]]]; + case CP: + return CP; + default: + return 0; + } + } + + // PROGRAM STATUS + + static void dump() { + // Writes a summary of the machine state. + + System.out.println(""); + System.out.println("State of data store and registers:"); + System.out.println(""); + if (HT == HB) { + System.out.println(" |--------| (heap is empty)"); + } else { + System.out.println(" HB-->"); + System.out.println(" |--------|"); + for (var addr = HB - 1; addr >= HT; addr--) { + System.out.print(addr + ":"); + if (addr == HT) { + System.out.print(" HT-->"); + } else { + System.out.print(" "); + } + System.out.println("|" + data[addr] + "|"); + } + System.out.println(" |--------|"); + } + System.out.println(" |////////|"); + System.out.println(" |////////|"); + if (ST == SB) { + System.out.println(" |--------| (stack is empty)"); + } else { + var dynamicLink = LB; + var staticLink = LB; + var localRegNum = Register.LB; + System.out.println(" ST--> |////////|"); + System.out.println(" |--------|"); + for (var addr = ST - 1; addr >= SB; addr--) { + System.out.print(addr + ":"); + if (addr == SB) { + System.out.print(" SB-->"); + } else if (addr == staticLink) { + switch (localRegNum) { + case LB: + System.out.print(" LB-->"); + break; + case L1: + System.out.print(" L1-->"); + break; + case L2: + System.out.print(" L2-->"); + break; + case L3: + System.out.print(" L3-->"); + break; + case L4: + System.out.print(" L4-->"); + break; + case L5: + System.out.print(" L5-->"); + break; + case L6: + System.out.print(" L6-->"); + break; + default: + break; + } + staticLink = data[addr]; + localRegNum = Register.values()[localRegNum.ordinal() + 1]; + } else { + System.out.print(" "); + } + if (addr == dynamicLink && dynamicLink != SB) { + System.out.print("|SL=" + data[addr] + "|"); + } else if (addr == dynamicLink + 1 && dynamicLink != SB) { + System.out.print("|DL=" + data[addr] + "|"); + } else if (addr == dynamicLink + 2 && dynamicLink != SB) { + System.out.print("|RA=" + data[addr] + "|"); + } else { + System.out.print("|" + data[addr] + "|"); + } + System.out.println(""); + if (addr == dynamicLink) { + System.out.println(" |--------|"); + dynamicLink = data[addr + 1]; + } + } + } + System.out.println(""); + } + + static void showStatus() { + // Writes an indication of whether and why the program has terminated. + System.out.println(""); + switch (status) { + case running: + System.out.println("Program is running."); + 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."); + break; + case failedInvalidCodeAddress: + System.out.println("Program has failed due to an invalid code address."); + break; + case failedInvalidInstruction: + System.out.println("Program has failed due to an invalid instruction."); + break; + case failedOverflow: + System.out.println("Program has failed due to overflow."); + break; + case failedZeroDivide: + System.out.println("Program has failed due to division by zero."); + break; + case failedIOError: + System.out.println("Program has failed due to an IO error."); + break; + } + if (status != halted) { + dump(); + } + } + + // INTERPRETATION + + static void checkSpace(int spaceNeeded) { + // Signals failure if there is not enough space to expand the stack or + // heap by spaceNeeded. + + if (HT - ST < spaceNeeded) { + status = failedDataStoreFull; + } + } + + static boolean isTrue(int datum) { + // Tests whether the given datum represents true. + return (datum == Machine.trueRep); + } + + static boolean equal(int size, int addr1, int addr2) { + // Tests whether two multi-word objects are equal, given their common + // size and their base addresses. + + boolean eq; + int index; + + eq = true; + index = 0; + while (eq && (index < size)) { + if (data[addr1 + index] == data[addr2 + index]) { + index = index + 1; + } else { + eq = false; + } + } + + return eq; + } + + static int overflowChecked(long datum) { + // Signals failure if the datum is too large to fit into a single word, + // otherwise returns the datum as a single word. + + if ((-Machine.maxintRep <= datum) && (datum <= Machine.maxintRep)) { + return (int) datum; + } else { + status = failedOverflow; + return 0; + } + } + + static int toInt(boolean b) { + return b ? Machine.trueRep : Machine.falseRep; + } + + static int currentChar; + + static int readInt() throws java.io.IOException { + int temp = 0; + int sign = 1; + + do { + currentChar = System.in.read(); + } while (Character.isWhitespace((char) currentChar)); + + if ((currentChar == '-') || (currentChar == '+')) { + do { + sign = (currentChar == '-') ? -1 : 1; + currentChar = System.in.read(); + } while ((currentChar == '-') || currentChar == '+'); + } + + if (Character.isDigit((char) currentChar)) { + do { + temp = temp * 10 + (currentChar - '0'); + currentChar = System.in.read(); + } while (Character.isDigit((char) currentChar)); + } + + return sign * temp; + } + + static void callPrimitive(int primitiveDisplacement) { + // Invokes the given primitive routine. + + int addr, size; + char ch; + + var primitive = Primitive.values()[primitiveDisplacement]; + switch (primitive) { + case ID: + break; // nothing to be done + case NOT: + data[ST - 1] = toInt(!isTrue(data[ST - 1])); + break; + case AND: + ST = ST - 1; + data[ST - 1] = toInt(isTrue(data[ST - 1]) & isTrue(data[ST])); + break; + case OR: + ST = ST - 1; + data[ST - 1] = toInt(isTrue(data[ST - 1]) | isTrue(data[ST])); + break; + case SUCC: + data[ST - 1] = overflowChecked(data[ST - 1] + 1); + break; + case PRED: + data[ST - 1] = overflowChecked(data[ST - 1] - 1); + break; + case NEG: + data[ST - 1] = -data[ST - 1]; + break; + case ADD: + ST = ST - 1; + accumulator = data[ST - 1]; + data[ST - 1] = overflowChecked(accumulator + data[ST]); + break; + case SUB: + ST = ST - 1; + accumulator = data[ST - 1]; + data[ST - 1] = overflowChecked(accumulator - data[ST]); + break; + case MULT: + ST = ST - 1; + accumulator = data[ST - 1]; + data[ST - 1] = overflowChecked(accumulator * data[ST]); + break; + case DIV: + ST = ST - 1; + accumulator = data[ST - 1]; + if (data[ST] != 0) { + data[ST - 1] = (int) (accumulator / data[ST]); + } else { + status = failedZeroDivide; + } + break; + case MOD: + ST = ST - 1; + accumulator = data[ST - 1]; + if (data[ST] != 0) { + data[ST - 1] = (int) (accumulator % data[ST]); + } else { + status = failedZeroDivide; + } + break; + case LT: + ST = ST - 1; + data[ST - 1] = toInt(data[ST - 1] < data[ST]); + break; + case LE: + ST = ST - 1; + data[ST - 1] = toInt(data[ST - 1] <= data[ST]); + break; + case GE: + ST = ST - 1; + data[ST - 1] = toInt(data[ST - 1] >= data[ST]); + break; + case GT: + ST = ST - 1; + data[ST - 1] = toInt(data[ST - 1] > data[ST]); + break; + case EQ: + size = data[ST - 1]; // size of each comparand + ST = ST - 2 * size; + data[ST - 1] = toInt(equal(size, ST - 1, ST - 1 + size)); + break; + case NE: + size = data[ST - 1]; // size of each comparand + ST = ST - 2 * size; + data[ST - 1] = toInt(!equal(size, ST - 1, ST - 1 + size)); + break; + case EOL: + data[ST] = toInt(currentChar == '\n'); + ST = ST + 1; + break; + case EOF: + data[ST] = toInt(currentChar == -1); + ST = ST + 1; + break; + case GET: + ST = ST - 1; + addr = data[ST]; + try { + currentChar = System.in.read(); + } catch (java.io.IOException s) { + status = failedIOError; + } + data[addr] = currentChar; + break; + case PUT: + ST = ST - 1; + ch = (char) data[ST]; + System.out.print(ch); + break; + case GETEOL: + try { + while ((currentChar = System.in.read()) != '\n') + ; + } catch (java.io.IOException s) { + status = failedIOError; + } + break; + case PUTEOL: + System.out.println(""); + break; + case GETINT: + ST = ST - 1; + addr = data[ST]; + try { + accumulator = readInt(); + } catch (java.io.IOException s) { + status = failedIOError; + } + data[addr] = (int) accumulator; + break; + case PUTINT: + ST = ST - 1; + accumulator = data[ST]; + System.out.print(accumulator); + break; + case NEW: + size = data[ST - 1]; + checkSpace(size); + HT = HT - size; + data[ST - 1] = HT; + break; + case DISPOSE: + ST = ST - 1; // no action taken at present + break; + } + } + + static void interpretProgram() { + // Runs the program in code store. + + Instruction currentInstr; + + // Initialize registers ... + ST = SB; + HT = HB; + LB = SB; + CP = CB; + status = running; + do { + // Fetch instruction ... + currentInstr = Machine.code[CP]; + // Decode instruction ... + var op = currentInstr.opCode; + var r = currentInstr.register; + var n = currentInstr.length; + var d = currentInstr.operand; + int addr; + + // Execute instruction ... + switch (op) { + case LOAD: + addr = d + content(r); + checkSpace(n); + for (var index = 0; index < n; index++) { + data[ST + index] = data[addr + index]; + } + ST = ST + n; + CP = CP + 1; + break; + case LOADA: + addr = d + content(r); + checkSpace(1); + data[ST] = addr; + ST = ST + 1; + CP = CP + 1; + break; + case LOADI: + ST = ST - 1; + addr = data[ST]; + checkSpace(n); + for (var index = 0; index < n; index++) { + data[ST + index] = data[addr + index]; + } + ST = ST + n; + CP = CP + 1; + break; + case LOADL: + checkSpace(1); + data[ST] = d; + ST = ST + 1; + CP = CP + 1; + break; + case STORE: + addr = d + content(r); + ST = ST - n; + for (var index = 0; index < n; index++) { + data[addr + index] = data[ST + index]; + } + CP = CP + 1; + break; + case STOREI: + ST = ST - 1; + addr = data[ST]; + ST = ST - n; + for (var index = 0; index < n; index++) { + data[addr + index] = data[ST + index]; + } + CP = CP + 1; + break; + case CALL: + addr = d + content(r); + if (addr >= Machine.PB) { + callPrimitive(addr - Machine.PB); + CP = CP + 1; + } else { + checkSpace(3); + if (0 <= n && n <= 15) { + data[ST] = content(n); // static link + } else { + status = failedInvalidInstruction; + } + data[ST + 1] = LB; // dynamic link + data[ST + 2] = CP + 1; // return address + LB = ST; + ST = ST + 3; + CP = addr; + } + break; + case CALLI: + ST = ST - 2; + addr = data[ST + 1]; + if (addr >= Machine.PB) { + callPrimitive(addr - Machine.PB); + CP = CP + 1; + } else { + // data[ST] = static link already + data[ST + 1] = LB; // dynamic link + data[ST + 2] = CP + 1; // return address + LB = ST; + ST = ST + 3; + CP = addr; + } + break; + case RETURN: + addr = LB - d; + CP = data[LB + 2]; + LB = data[LB + 1]; + ST = ST - n; + for (var index = 0; index < n; index++) { + data[addr + index] = data[ST + index]; + } + ST = addr + n; + break; + case PUSH: + checkSpace(d); + ST = ST + d; + CP = CP + 1; + break; + case POP: + addr = ST - n - d; + ST = ST - n; + for (var index = 0; index < n; index++) { + data[addr + index] = data[ST + index]; + } + ST = addr + n; + CP = CP + 1; + break; + case JUMP: + CP = d + content(r); + break; + case JUMPI: + ST = ST - 1; + CP = data[ST]; + break; + case JUMPIF: + ST = ST - 1; + if (data[ST] == n) { + CP = d + content(r); + } else { + CP = CP + 1; + } + break; + case HALT: + status = halted; + break; + } + if (CP < CB || CP >= CT) { + status = failedInvalidCodeAddress; + } + } while (status == running); + } + + // LOADING + + static void loadObjectProgram(String objectName) { + // Loads the TAM object program into code store from the named file. + + boolean finished = false; + + try (var objectFile = new FileInputStream(objectName)) { + var objectStream = new DataInputStream(objectFile); + + var addr = Machine.CB; + while (!finished) { + Machine.code[addr] = Instruction.read(objectStream); + if (Machine.code[addr] == null) { + finished = true; + } else { + addr = addr + 1; + } + } + CT = addr; + } catch (FileNotFoundException s) { + CT = CB; + System.err.println("Error opening object file: " + s); + } catch (IOException s) { + CT = CB; + System.err.println("Error reading object file: " + s); + } + } + + // RUNNING + + public static void main(String[] args) { + System.out.println("********** TAM Interpreter (Java Version 2.1) **********"); + + if (args.length == 1) { + objectName = args[0]; + } else { + objectName = "obj.tam"; + } + + loadObjectProgram(objectName); + if (CT != CB) { + startTimeNanos = System.nanoTime(); + interpretProgram(); + showStatus(); + } + } +} diff --git a/Triangle.AbstractMachine/.gitignore b/Triangle.AbstractMachine/.gitignore new file mode 100644 index 0000000..8c107fe --- /dev/null +++ b/Triangle.AbstractMachine/.gitignore @@ -0,0 +1,3 @@ +/target/ +/.classpath +/build/ diff --git a/Triangle.AbstractMachine/.project b/Triangle.AbstractMachine/.project new file mode 100644 index 0000000..42358c2 --- /dev/null +++ b/Triangle.AbstractMachine/.project @@ -0,0 +1,23 @@ + + + Triangle.AbstractMachine + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/Triangle.AbstractMachine/build.gradle b/Triangle.AbstractMachine/build.gradle new file mode 100644 index 0000000..80f98eb --- /dev/null +++ b/Triangle.AbstractMachine/build.gradle @@ -0,0 +1,4 @@ +apply plugin: 'java-library' +apply plugin: 'eclipse' + +sourceCompatibility = 11 \ No newline at end of file diff --git a/Triangle.AbstractMachine/pom.xml b/Triangle.AbstractMachine/pom.xml new file mode 100644 index 0000000..c7675fa --- /dev/null +++ b/Triangle.AbstractMachine/pom.xml @@ -0,0 +1,12 @@ + + 4.0.0 + triangle-abstractmachine + jar + + triangle.tools + triangle-tools + 2.1 + ../ + + \ No newline at end of file diff --git a/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Instruction.java b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Instruction.java new file mode 100644 index 0000000..7ca85c9 --- /dev/null +++ b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Instruction.java @@ -0,0 +1,67 @@ +/* + * @(#)Instruction.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractMachine; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; + +public class Instruction { + + // Java has no type synonyms, so the following representations are + // assumed: + // + // type + // OpCode = 0..15; {4 bits unsigned} + // Length = 0..255; {8 bits unsigned} + // Operand = -32767..+32767; {16 bits signed} + + // Represents TAM instructions. + final OpCode opCode; + final Register register; + final int length; + int operand; // Not final to allow for patching jump address + + public Instruction(OpCode opcode, Register register, int length, int operand) { + this.opCode = opcode; + this.register = register; + this.length = length; + this.operand = operand; + } + + public void setOperand(int operand) { + this.operand = operand; + } + + public void write(DataOutputStream output) throws IOException { + output.writeInt(opCode.ordinal()); + output.writeInt(register.ordinal()); + output.writeInt(length); + output.writeInt(operand); + } + + public static Instruction read(DataInputStream input) throws IOException { + try { + var opCode = OpCode.values()[input.readInt()]; + var register = Register.values()[input.readInt()]; + var length = input.readInt(); + var operand = input.readInt(); + return new Instruction(opCode, register, length, operand); + } catch (EOFException s) { + return null; + } + } +} diff --git a/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Machine.java b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Machine.java new file mode 100644 index 0000000..c857fa5 --- /dev/null +++ b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Machine.java @@ -0,0 +1,54 @@ +/* + * @(#)Machine.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractMachine; + +public final class Machine { + + public final static int maxRoutineLevel = 7; + + // WORDS AND ADDRESSES + + // Java has no type synonyms, so the following representations are + // assumed: + // + // type + // Word = -32767..+32767; {16 bits signed} + // DoubleWord = -2147483648..+2147483647; {32 bits signed} + // CodeAddress = 0..+32767; {15 bits unsigned} + // DataAddress = 0..+32767; {15 bits unsigned} + + // INSTRUCTIONS + + // CODE STORE + + public static Instruction[] code = new Instruction[1024]; + + // CODE STORE REGISTERS + + public final static int CB = 0, PB = 1024, // = upper bound of code array + 1 + PT = 1052; // = PB + 28 + + // REGISTER NUMBERS + + // DATA REPRESENTATION + + public final static int booleanSize = 1, characterSize = 1, integerSize = 1, addressSize = 1, + closureSize = 2 * addressSize, + + linkDataSize = 3 * addressSize, + + falseRep = 0, trueRep = 1, maxintRep = 32767; + +} diff --git a/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/OpCode.java b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/OpCode.java new file mode 100644 index 0000000..23ca257 --- /dev/null +++ b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/OpCode.java @@ -0,0 +1,5 @@ +package triangle.abstractMachine; + +public enum OpCode { + LOAD, LOADA, LOADI, LOADL, STORE, STOREI, CALL, CALLI, RETURN, NOP, PUSH, POP, JUMP, JUMPI, JUMPIF, HALT +} diff --git a/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Primitive.java b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Primitive.java new file mode 100644 index 0000000..11bb5bc --- /dev/null +++ b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Primitive.java @@ -0,0 +1,6 @@ +package triangle.abstractMachine; + +public enum Primitive { + ID, NOT, AND, OR, SUCC, PRED, NEG, ADD, SUB, MULT, DIV, MOD, LT, LE, GE, GT, EQ, NE, EOL, EOF, GET, PUT, GETEOL, + PUTEOL, GETINT, PUTINT, NEW, DISPOSE +} diff --git a/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Register.java b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Register.java new file mode 100644 index 0000000..0b36262 --- /dev/null +++ b/Triangle.AbstractMachine/src/main/java/triangle/abstractMachine/Register.java @@ -0,0 +1,5 @@ +package triangle.abstractMachine; + +public enum Register { + CB, CT, PB, PT, SB, ST, HB, HT, LB, L1, L2, L3, L4, L5, L6, CP +} diff --git a/Triangle.Compiler/.gitignore b/Triangle.Compiler/.gitignore new file mode 100644 index 0000000..55f062a --- /dev/null +++ b/Triangle.Compiler/.gitignore @@ -0,0 +1,4 @@ +/target/ +/.classpath +/.editorconfig +/build/ diff --git a/Triangle.Compiler/.project b/Triangle.Compiler/.project new file mode 100644 index 0000000..dca5b8c --- /dev/null +++ b/Triangle.Compiler/.project @@ -0,0 +1,23 @@ + + + Triangle.Compiler + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/Triangle.Compiler/build.gradle b/Triangle.Compiler/build.gradle new file mode 100644 index 0000000..9733b3f --- /dev/null +++ b/Triangle.Compiler/build.gradle @@ -0,0 +1,21 @@ +apply plugin: 'java' +apply plugin: 'application' + +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") \ No newline at end of file diff --git a/Triangle.Compiler/pom.xml b/Triangle.Compiler/pom.xml new file mode 100644 index 0000000..17b97da --- /dev/null +++ b/Triangle.Compiler/pom.xml @@ -0,0 +1,18 @@ + + 4.0.0 + triangle-compiler + + triangle.tools + triangle-tools + 2.1 + ../ + + + + triangle.tools + triangle-abstractmachine + 2.1 + + + diff --git a/Triangle.Compiler/src/main/java/triangle/Compiler.java b/Triangle.Compiler/src/main/java/triangle/Compiler.java new file mode 100644 index 0000000..1a49778 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/Compiler.java @@ -0,0 +1,152 @@ +/* + * @(#)Compiler.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle; + +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; +import triangle.treeDrawer.Drawer; + +/** + * The main driver class for the Triangle compiler. + * + * @version 2.1 7 Oct 2003 + * @author Deryck F. Brown + */ +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; + private static Checker checker; + private static Encoder encoder; + private static Emitter emitter; + private static ErrorReporter reporter; + private static Drawer drawer; + + /** The AST representing the source program. */ + private static Program theAST; + + /** + * Compile the source program to TAM machine code. + * + * @param sourceName the name of the file containing the source program. + * @param objectName the name of the file containing the object program. + * @param showingAST true iff the AST is to be displayed after contextual + * analysis + * @param showingTable true iff the object description details are to be + * displayed during code generation (not currently + * implemented). + * @return true iff the source program is free of compile-time errors, otherwise + * false. + */ + static boolean compileProgram(String sourceName, String objectName, boolean showingAST, boolean showingTable) { + + System.out.println("********** " + "Triangle Compiler (Java Version 2.1)" + " **********"); + + System.out.println("Syntactic Analysis ..."); + SourceFile source = SourceFile.ofPath(sourceName); + + if (source == null) { + System.out.println("Can't access source file " + sourceName); + System.exit(1); + } + + scanner = new Scanner(source); + reporter = new ErrorReporter(false); + parser = new Parser(scanner, reporter); + checker = new Checker(reporter); + emitter = new Emitter(reporter); + encoder = new Encoder(emitter, reporter); + drawer = new Drawer(); + + // scanner.enableDebugging(); + theAST = parser.parseProgram(); // 1st pass + if (reporter.getNumErrors() == 0) { + // if (showingAST) { + // drawer.draw(theAST); + // } + System.out.println("Contextual Analysis ..."); + checker.check(theAST); // 2nd pass + if (showingAST) { + drawer.draw(theAST); + } + if (folding) { + theAST.visit(new ConstantFolder()); + } + + if (reporter.getNumErrors() == 0) { + System.out.println("Code Generation ..."); + encoder.encodeRun(theAST, showingTable); // 3rd pass + } + } + + boolean successful = (reporter.getNumErrors() == 0); + if (successful) { + emitter.saveObjectProgram(objectName); + System.out.println("Compilation was successful."); + } else { + System.out.println("Compilation was unsuccessful."); + } + return successful; + } + + /** + * Triangle compiler main program. + * + * @param args the only command-line argument to the program specifies the + * source filename. + */ + public static void main(String[] args) { + + if (args.length < 1) { + System.out.println("Usage: tc filename [-o=outputfilename] [tree] [folding]"); + System.exit(1); + } + + parseArgs(args); + + String sourceName = args[0]; + + var compiledOK = compileProgram(sourceName, objectName, showTree, false); + + 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; + } + } + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/ErrorReporter.java b/Triangle.Compiler/src/main/java/triangle/ErrorReporter.java new file mode 100644 index 0000000..cfcc753 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/ErrorReporter.java @@ -0,0 +1,61 @@ +/* + * @(#)ErrorReporter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle; + +import triangle.syntacticAnalyzer.SourcePosition; + +public class 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) { + + numErrors++; + + String s = ("ERROR: "); + + for (int p = 0; p < message.length(); p++) + if (message.charAt(p) == '%') + s += tokenName; + else + 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; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/StdEnvironment.java b/Triangle.Compiler/src/main/java/triangle/StdEnvironment.java new file mode 100644 index 0000000..90507d0 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/StdEnvironment.java @@ -0,0 +1,46 @@ +/* + * @(#)StdEnvironment.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle; + +import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; +import triangle.abstractSyntaxTrees.declarations.FuncDeclaration; +import triangle.abstractSyntaxTrees.declarations.ProcDeclaration; +import triangle.abstractSyntaxTrees.declarations.UnaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.types.TypeDeclaration; +import triangle.abstractSyntaxTrees.types.TypeDenoter; + +public final class StdEnvironment { + + // These are small ASTs representing standard types. + + public static TypeDenoter booleanType, charType, integerType, anyType, errorType; + + public static TypeDeclaration booleanDecl, charDecl, integerDecl; + + // These are small ASTs representing "declarations" of standard entities. + + public static ConstDeclaration falseDecl, trueDecl, maxintDecl; + + public static UnaryOperatorDeclaration notDecl; + + public static BinaryOperatorDeclaration andDecl, orDecl, addDecl, subtractDecl, multiplyDecl, divideDecl, + moduloDecl, equalDecl, unequalDecl, lessDecl, notlessDecl, greaterDecl, notgreaterDecl; + + public static ProcDeclaration getDecl, putDecl, getintDecl, putintDecl, geteolDecl, puteolDecl; + + public static FuncDeclaration chrDecl, ordDecl, eolDecl, eofDecl; + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/AbstractSyntaxTree.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/AbstractSyntaxTree.java new file mode 100644 index 0000000..669f768 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/AbstractSyntaxTree.java @@ -0,0 +1,34 @@ +/* + * @(#)AST.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees; + +import triangle.codeGenerator.entities.RuntimeEntity; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class AbstractSyntaxTree { + + private final SourcePosition position; + + public AbstractSyntaxTree(SourcePosition position) { + this.position = position; + entity = null; + } + + public SourcePosition getPosition() { + return position; + } + + public RuntimeEntity entity; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/Program.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/Program.java new file mode 100644 index 0000000..17a0aa8 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/Program.java @@ -0,0 +1,37 @@ +/* + * @(#)Program.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees; + +import triangle.abstractSyntaxTrees.commands.Command; +import triangle.abstractSyntaxTrees.visitors.ProgramVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class Program extends AbstractSyntaxTree { + + public Program(Command cAST, SourcePosition position) { + super(position); + C = cAST; + } + + public Command C; + + public TResult visit(ProgramVisitor visitor, TArg arg) { + return visitor.visitProgram(this, arg); + } + + public TResult visit(ProgramVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameter.java new file mode 100644 index 0000000..73188df --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameter.java @@ -0,0 +1,32 @@ +/* + * @(#)ActualParameter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class ActualParameter extends AbstractSyntaxTree { + + public ActualParameter(SourcePosition position) { + super(position); + } + + public abstract TResult visit(ActualParameterVisitor visitor, TArg arg); + + public TResult visit(ActualParameterVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameterSequence.java new file mode 100644 index 0000000..d5a2c9a --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ActualParameterSequence.java @@ -0,0 +1,32 @@ +/* + * @(#)ActualParameterSequence.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class ActualParameterSequence extends AbstractSyntaxTree { + + public ActualParameterSequence(SourcePosition position) { + super(position); + } + + public abstract TResult visit(ActualParameterSequenceVisitor v, TArg arg); + + public TResult visit(ActualParameterSequenceVisitor v) { + return visit(v, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ConstActualParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ConstActualParameter.java new file mode 100644 index 0000000..ad469dc --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ConstActualParameter.java @@ -0,0 +1,33 @@ +/* + * @(#)ConstActualParameter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ConstActualParameter extends ActualParameter { + + public ConstActualParameter(Expression eAST, SourcePosition position) { + super(position); + E = eAST; + } + + public TResult visit(ActualParameterVisitor v, TArg arg) { + return v.visitConstActualParameter(this, arg); + } + + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/EmptyActualParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/EmptyActualParameterSequence.java new file mode 100644 index 0000000..13fa735 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/EmptyActualParameterSequence.java @@ -0,0 +1,29 @@ +/* + * @(#)EmptyActualParameterSequence.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class EmptyActualParameterSequence extends ActualParameterSequence { + + public EmptyActualParameterSequence(SourcePosition position) { + super(position); + } + + public TResult visit(ActualParameterSequenceVisitor v, TArg arg) { + return v.visitEmptyActualParameterSequence(this, arg); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/FuncActualParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/FuncActualParameter.java new file mode 100644 index 0000000..3aa0430 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/FuncActualParameter.java @@ -0,0 +1,33 @@ +/* + * @(#)FuncActualParameter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class FuncActualParameter extends ActualParameter { + + public FuncActualParameter(Identifier iAST, SourcePosition position) { + super(position); + I = iAST; + } + + public TResult visit(ActualParameterVisitor v, TArg arg) { + return v.visitFuncActualParameter(this, arg); + } + + public final Identifier I; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/MultipleActualParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/MultipleActualParameterSequence.java new file mode 100644 index 0000000..91e53ef --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/MultipleActualParameterSequence.java @@ -0,0 +1,35 @@ +/* + * @(#)MultipleActualParameterSequence.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class MultipleActualParameterSequence extends ActualParameterSequence { + + public MultipleActualParameterSequence(ActualParameter apAST, ActualParameterSequence apsAST, + SourcePosition position) { + super(position); + AP = apAST; + APS = apsAST; + } + + public TResult visit(ActualParameterSequenceVisitor v, TArg arg) { + return v.visitMultipleActualParameterSequence(this, arg); + } + + public final ActualParameter AP; + public final ActualParameterSequence APS; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ProcActualParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ProcActualParameter.java new file mode 100644 index 0000000..83c40c7 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/ProcActualParameter.java @@ -0,0 +1,33 @@ +/* + * @(#)ProcActualParameter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ProcActualParameter extends ActualParameter { + + public ProcActualParameter(Identifier iAST, SourcePosition position) { + super(position); + I = iAST; + } + + public TResult visit(ActualParameterVisitor v, TArg arg) { + return v.visitProcActualParameter(this, arg); + } + + public final Identifier I; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/SingleActualParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/SingleActualParameterSequence.java new file mode 100644 index 0000000..4dd3a89 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/SingleActualParameterSequence.java @@ -0,0 +1,32 @@ +/* + * @(#)SingleActualParameterSequence.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.visitors.ActualParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SingleActualParameterSequence extends ActualParameterSequence { + + public SingleActualParameterSequence(ActualParameter apAST, SourcePosition position) { + super(position); + AP = apAST; + } + + public TResult visit(ActualParameterSequenceVisitor v, TArg arg) { + return v.visitSingleActualParameterSequence(this, arg); + } + + public final ActualParameter AP; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/VarActualParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/VarActualParameter.java new file mode 100644 index 0000000..979dd15 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/actuals/VarActualParameter.java @@ -0,0 +1,33 @@ +/* + * @(#)VarActualParameter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.actuals; + +import triangle.abstractSyntaxTrees.visitors.ActualParameterVisitor; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.syntacticAnalyzer.SourcePosition; + +public class VarActualParameter extends ActualParameter { + + public VarActualParameter(Vname vAST, SourcePosition position) { + super(position); + V = vAST; + } + + public TResult visit(ActualParameterVisitor v, TArg arg) { + return v.visitVarActualParameter(this, arg); + } + + public final Vname V; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/ArrayAggregate.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/ArrayAggregate.java new file mode 100644 index 0000000..e90330b --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/ArrayAggregate.java @@ -0,0 +1,35 @@ +/* + * @(#)ArrayAggregate.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.aggregates; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.ArrayAggregateVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class ArrayAggregate extends AbstractSyntaxTree { + + public ArrayAggregate(SourcePosition position) { + super(position); + elemCount = 0; + } + + public int elemCount; + + public abstract TResult visit(ArrayAggregateVisitor visitor, TArg arg); + + public TResult visit(ArrayAggregateVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleArrayAggregate.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleArrayAggregate.java new file mode 100644 index 0000000..5b616e1 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleArrayAggregate.java @@ -0,0 +1,35 @@ +/* + * @(#)MultipleArrayAggregate.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.aggregates; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.ArrayAggregateVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class MultipleArrayAggregate extends ArrayAggregate { + + public MultipleArrayAggregate(Expression eAST, ArrayAggregate aaAST, SourcePosition position) { + super(position); + E = eAST; + AA = aaAST; + } + + public TResult visit(ArrayAggregateVisitor v, TArg arg) { + return v.visitMultipleArrayAggregate(this, arg); + } + + public Expression E; + public final ArrayAggregate AA; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleRecordAggregate.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleRecordAggregate.java new file mode 100644 index 0000000..1715b2e --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/MultipleRecordAggregate.java @@ -0,0 +1,38 @@ +/* + * @(#)MultipleRecordAggregate.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.aggregates; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.RecordAggregateVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class MultipleRecordAggregate extends RecordAggregate { + + public MultipleRecordAggregate(Identifier iAST, Expression eAST, RecordAggregate raAST, SourcePosition position) { + super(position); + I = iAST; + E = eAST; + RA = raAST; + } + + public TResult visit(RecordAggregateVisitor v, TArg arg) { + return v.visitMultipleRecordAggregate(this, arg); + } + + public final Identifier I; + public Expression E; + public final RecordAggregate RA; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/RecordAggregate.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/RecordAggregate.java new file mode 100644 index 0000000..f79bd9c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/RecordAggregate.java @@ -0,0 +1,36 @@ +/* + * @(#)RecordAggregate.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.aggregates; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.types.FieldTypeDenoter; +import triangle.abstractSyntaxTrees.visitors.RecordAggregateVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class RecordAggregate extends AbstractSyntaxTree { + + public RecordAggregate(SourcePosition position) { + super(position); + type = null; + } + + public FieldTypeDenoter type; + + public abstract TResult visit(RecordAggregateVisitor visitor, TArg arg); + + public TResult visit(RecordAggregateVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleArrayAggregate.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleArrayAggregate.java new file mode 100644 index 0000000..4d5c624 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleArrayAggregate.java @@ -0,0 +1,33 @@ +/* + * @(#)SingleArrayAggregate.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.aggregates; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.ArrayAggregateVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SingleArrayAggregate extends ArrayAggregate { + + public SingleArrayAggregate(Expression eAST, SourcePosition position) { + super(position); + E = eAST; + } + + public TResult visit(ArrayAggregateVisitor v, TArg arg) { + return v.visitSingleArrayAggregate(this, arg); + } + + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleRecordAggregate.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleRecordAggregate.java new file mode 100644 index 0000000..14510c9 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/aggregates/SingleRecordAggregate.java @@ -0,0 +1,36 @@ +/* + * @(#)SingleRecordAggregate.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.aggregates; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.RecordAggregateVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SingleRecordAggregate extends RecordAggregate { + + public SingleRecordAggregate(Identifier iAST, Expression eAST, SourcePosition position) { + super(position); + I = iAST; + E = eAST; + } + + public TResult visit(RecordAggregateVisitor v, TArg arg) { + return v.visitSingleRecordAggregate(this, arg); + } + + public final Identifier I; + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/AssignCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/AssignCommand.java new file mode 100644 index 0000000..66906ae --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/AssignCommand.java @@ -0,0 +1,36 @@ +/* + * @(#)AssignCommand.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.syntacticAnalyzer.SourcePosition; + +public class AssignCommand extends Command { + + public AssignCommand(Vname vAST, Expression eAST, SourcePosition position) { + super(position); + V = vAST; + E = eAST; + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitAssignCommand(this, arg); + } + + public final Vname V; + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/CallCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/CallCommand.java new file mode 100644 index 0000000..40da558 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/CallCommand.java @@ -0,0 +1,36 @@ +/* + * @(#)CallCommand.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.actuals.ActualParameterSequence; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class CallCommand extends Command { + + public CallCommand(Identifier iAST, ActualParameterSequence apsAST, SourcePosition position) { + super(position); + I = iAST; + APS = apsAST; + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitCallCommand(this, arg); + } + + public final Identifier I; + public final ActualParameterSequence APS; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/Command.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/Command.java new file mode 100644 index 0000000..cd9b94d --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/Command.java @@ -0,0 +1,32 @@ +/* + * @(#)Command.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class Command extends AbstractSyntaxTree { + + public Command(SourcePosition position) { + super(position); + } + + public abstract TResult visit(CommandVisitor visitor, TArg arg); + + public TResult visit(CommandVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/EmptyCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/EmptyCommand.java new file mode 100644 index 0000000..df0a2fb --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/EmptyCommand.java @@ -0,0 +1,29 @@ +/* + * @(#)EmptyCommand.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class EmptyCommand extends Command { + + public EmptyCommand(SourcePosition position) { + super(position); + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitEmptyCommand(this, arg); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/IfCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/IfCommand.java new file mode 100644 index 0000000..e57d560 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/IfCommand.java @@ -0,0 +1,36 @@ +/* + * @(#)IfCommand.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class IfCommand extends Command { + + public IfCommand(Expression eAST, Command c1AST, Command c2AST, SourcePosition position) { + super(position); + E = eAST; + C1 = c1AST; + C2 = c2AST; + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitIfCommand(this, arg); + } + + public Expression E; + public final Command C1, C2; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/LetCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/LetCommand.java new file mode 100644 index 0000000..f59cc5c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/LetCommand.java @@ -0,0 +1,35 @@ +/* + * @(#)LetCommand.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class LetCommand extends Command { + + public LetCommand(Declaration dAST, Command cAST, SourcePosition position) { + super(position); + D = dAST; + C = cAST; + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitLetCommand(this, arg); + } + + public final Declaration D; + public final Command C; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/SequentialCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/SequentialCommand.java new file mode 100644 index 0000000..f8f5f21 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/SequentialCommand.java @@ -0,0 +1,33 @@ +/* + * @(#)SequentialCommand.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SequentialCommand extends Command { + + public SequentialCommand(Command c1AST, Command c2AST, SourcePosition position) { + super(position); + C1 = c1AST; + C2 = c2AST; + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitSequentialCommand(this, arg); + } + + public final Command C1, C2; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/WhileCommand.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/WhileCommand.java new file mode 100644 index 0000000..af21fde --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/commands/WhileCommand.java @@ -0,0 +1,35 @@ +/* + * @(#)WhileCommand.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.commands; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.CommandVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class WhileCommand extends Command { + + public WhileCommand(Expression eAST, Command cAST, SourcePosition position) { + super(position); + E = eAST; + C = cAST; + } + + public TResult visit(CommandVisitor v, TArg arg) { + return v.visitWhileCommand(this, arg); + } + + public Expression E; + public final Command C; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/BinaryOperatorDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/BinaryOperatorDeclaration.java new file mode 100644 index 0000000..1a1b524 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/BinaryOperatorDeclaration.java @@ -0,0 +1,39 @@ +/* + * @(#)BinaryOperatorDeclaration.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class BinaryOperatorDeclaration extends Declaration { + + public BinaryOperatorDeclaration(Operator oAST, TypeDenoter arg1AST, TypeDenoter arg2AST, TypeDenoter resultAST, + SourcePosition position) { + super(position); + O = oAST; + ARG1 = arg1AST; + ARG2 = arg2AST; + RES = resultAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitBinaryOperatorDeclaration(this, arg); + } + + public final Operator O; + public final TypeDenoter ARG1, ARG2, RES; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstDeclaration.java new file mode 100644 index 0000000..86bb95a --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstDeclaration.java @@ -0,0 +1,42 @@ +/* + * @(#)ConstDeclaration.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ConstDeclaration extends Declaration implements ConstantDeclaration { + + public ConstDeclaration(Identifier iAST, Expression eAST, SourcePosition position) { + super(position); + I = iAST; + E = eAST; + } + + @Override + public TypeDenoter getType() { + return E.type; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitConstDeclaration(this, arg); + } + + public final Identifier I; + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstantDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstantDeclaration.java new file mode 100644 index 0000000..5241bfc --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ConstantDeclaration.java @@ -0,0 +1,9 @@ +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.types.TypeDenoter; + +public interface ConstantDeclaration { + + TypeDenoter getType(); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/Declaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/Declaration.java new file mode 100644 index 0000000..ba1b97c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/Declaration.java @@ -0,0 +1,35 @@ +/* + * @(#)Declaration.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class Declaration extends AbstractSyntaxTree { + + public Declaration(SourcePosition position) { + super(position); + duplicated = false; + } + + public boolean duplicated; + + public abstract TResult visit(DeclarationVisitor visitor, TArg arg); + + public TResult visit(DeclarationVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FuncDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FuncDeclaration.java new file mode 100644 index 0000000..55272bb --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FuncDeclaration.java @@ -0,0 +1,53 @@ +/* + * @(#)FuncDeclaration.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.formals.FormalParameterSequence; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class FuncDeclaration extends Declaration implements FunctionDeclaration { + + public FuncDeclaration(Identifier iAST, FormalParameterSequence fpsAST, TypeDenoter tAST, Expression eAST, + SourcePosition position) { + super(position); + I = iAST; + FPS = fpsAST; + T = tAST; + E = eAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitFuncDeclaration(this, arg); + } + + @Override + public FormalParameterSequence getFormals() { + return FPS; + } + + @Override + public TypeDenoter getType() { + return T; + } + + public final Identifier I; + public final FormalParameterSequence FPS; + public TypeDenoter T; + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FunctionDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FunctionDeclaration.java new file mode 100644 index 0000000..425fd7c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/FunctionDeclaration.java @@ -0,0 +1,12 @@ +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.formals.FormalParameterSequence; +import triangle.abstractSyntaxTrees.types.TypeDenoter; + +public interface FunctionDeclaration { + + FormalParameterSequence getFormals(); + + TypeDenoter getType(); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcDeclaration.java new file mode 100644 index 0000000..ba925af --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcDeclaration.java @@ -0,0 +1,44 @@ +/* + * @(#)ProcDeclaration.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.commands.Command; +import triangle.abstractSyntaxTrees.formals.FormalParameterSequence; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ProcDeclaration extends Declaration implements ProcedureDeclaration { + + public ProcDeclaration(Identifier iAST, FormalParameterSequence fpsAST, Command cAST, SourcePosition position) { + super(position); + I = iAST; + FPS = fpsAST; + C = cAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitProcDeclaration(this, arg); + } + + @Override + public FormalParameterSequence getFormals() { + return FPS; + } + + public final Identifier I; + public final FormalParameterSequence FPS; + public final Command C; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcedureDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcedureDeclaration.java new file mode 100644 index 0000000..94dee6f --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/ProcedureDeclaration.java @@ -0,0 +1,9 @@ +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.formals.FormalParameterSequence; + +public interface ProcedureDeclaration { + + FormalParameterSequence getFormals(); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/SequentialDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/SequentialDeclaration.java new file mode 100644 index 0000000..44e6746 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/SequentialDeclaration.java @@ -0,0 +1,33 @@ +/* + * @(#)SequentialDeclaration.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SequentialDeclaration extends Declaration { + + public SequentialDeclaration(Declaration d1AST, Declaration d2AST, SourcePosition position) { + super(position); + D1 = d1AST; + D2 = d2AST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitSequentialDeclaration(this, arg); + } + + public final Declaration D1, D2; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/UnaryOperatorDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/UnaryOperatorDeclaration.java new file mode 100644 index 0000000..fd751c6 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/UnaryOperatorDeclaration.java @@ -0,0 +1,37 @@ +/* + * @(#)UnaryOperatorDeclaration.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class UnaryOperatorDeclaration extends Declaration { + + public UnaryOperatorDeclaration(Operator oAST, TypeDenoter argAST, TypeDenoter resultAST, SourcePosition position) { + super(position); + O = oAST; + ARG = argAST; + RES = resultAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitUnaryOperatorDeclaration(this, arg); + } + + public final Operator O; + public final TypeDenoter ARG, RES; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VarDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VarDeclaration.java new file mode 100644 index 0000000..0933c5f --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VarDeclaration.java @@ -0,0 +1,41 @@ +/* + * @(#)VarDeclaration.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class VarDeclaration extends Declaration implements VariableDeclaration { + + public VarDeclaration(Identifier iAST, TypeDenoter tAST, SourcePosition position) { + super(position); + I = iAST; + T = tAST; + } + + @Override + public TypeDenoter getType() { + return T; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitVarDeclaration(this, arg); + } + + public final Identifier I; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VariableDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VariableDeclaration.java new file mode 100644 index 0000000..4c4bfd4 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/declarations/VariableDeclaration.java @@ -0,0 +1,9 @@ +package triangle.abstractSyntaxTrees.declarations; + +import triangle.abstractSyntaxTrees.types.TypeDenoter; + +public interface VariableDeclaration { + + TypeDenoter getType(); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/ArrayExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/ArrayExpression.java new file mode 100644 index 0000000..4fe4325 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/ArrayExpression.java @@ -0,0 +1,33 @@ +/* + * @(#)ArrayExpression.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.aggregates.ArrayAggregate; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ArrayExpression extends Expression { + + public ArrayExpression(ArrayAggregate aaAST, SourcePosition position) { + super(position); + AA = aaAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitArrayExpression(this, arg); + } + + public final ArrayAggregate AA; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/BinaryExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/BinaryExpression.java new file mode 100644 index 0000000..f5a992a --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/BinaryExpression.java @@ -0,0 +1,37 @@ +/* + * @(#)BinaryExpression.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class BinaryExpression extends Expression { + + public BinaryExpression(Expression e1AST, Operator oAST, Expression e2AST, SourcePosition position) { + super(position); + O = oAST; + E1 = e1AST; + E2 = e2AST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitBinaryExpression(this, arg); + } + + public Expression E1; + public Expression E2; + public final Operator O; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CallExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CallExpression.java new file mode 100644 index 0000000..2eeeb66 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CallExpression.java @@ -0,0 +1,36 @@ +/* + * @(#)CallExpression.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.actuals.ActualParameterSequence; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class CallExpression extends Expression { + + public CallExpression(Identifier iAST, ActualParameterSequence apsAST, SourcePosition position) { + super(position); + I = iAST; + APS = apsAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitCallExpression(this, arg); + } + + public final Identifier I; + public final ActualParameterSequence APS; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CharacterExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CharacterExpression.java new file mode 100644 index 0000000..ba2e959 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/CharacterExpression.java @@ -0,0 +1,43 @@ +/* + * @(#)CharacterExpression.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.terminals.CharacterLiteral; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class CharacterExpression extends Expression { + + public CharacterExpression(CharacterLiteral clAST, SourcePosition position) { + super(position); + CL = clAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitCharacterExpression(this, arg); + } + + public final CharacterLiteral CL; + + @Override + public boolean isLiteral() { + return true; + } + + @Override + public int getValue() { + return CL.getValue(); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/EmptyExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/EmptyExpression.java new file mode 100644 index 0000000..e1fb097 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/EmptyExpression.java @@ -0,0 +1,29 @@ +/* + * @(#)EmptyExpression.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class EmptyExpression extends Expression { + + public EmptyExpression(SourcePosition position) { + super(position); + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitEmptyExpression(this, arg); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/Expression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/Expression.java new file mode 100644 index 0000000..70739bd --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/Expression.java @@ -0,0 +1,44 @@ +/* + * @(#)Expression.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class Expression extends AbstractSyntaxTree { + + public Expression(SourcePosition position) { + super(position); + type = null; + } + + public TypeDenoter type; + + public boolean isLiteral() { + return false; + } + + public int getValue() { + throw new UnsupportedOperationException(); + } + + public abstract TResult visit(ExpressionVisitor visitor, TArg arg); + + public TResult visit(ExpressionVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IfExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IfExpression.java new file mode 100644 index 0000000..0bd208d --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IfExpression.java @@ -0,0 +1,36 @@ +/* + * @(#)IfExpression.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class IfExpression extends Expression { + + public IfExpression(Expression e1AST, Expression e2AST, Expression e3AST, SourcePosition position) { + super(position); + E1 = e1AST; + E2 = e2AST; + E3 = e3AST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitIfExpression(this, arg); + } + + public Expression E1; + public Expression E2; + public Expression E3; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IntegerExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IntegerExpression.java new file mode 100644 index 0000000..97de244 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/IntegerExpression.java @@ -0,0 +1,43 @@ +/* + * @(#)IntegerExpression.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.terminals.IntegerLiteral; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class IntegerExpression extends Expression { + + public IntegerExpression(IntegerLiteral ilAST, SourcePosition position) { + super(position); + IL = ilAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitIntegerExpression(this, arg); + } + + public final IntegerLiteral IL; + + @Override + public boolean isLiteral() { + return true; + } + + @Override + public int getValue() { + return IL.getValue(); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/LetExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/LetExpression.java new file mode 100644 index 0000000..1bfef81 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/LetExpression.java @@ -0,0 +1,35 @@ +/* + * @(#)LetExpression.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class LetExpression extends Expression { + + public LetExpression(Declaration dAST, Expression eAST, SourcePosition position) { + super(position); + D = dAST; + E = eAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitLetExpression(this, arg); + } + + public final Declaration D; + public Expression E; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/RecordExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/RecordExpression.java new file mode 100644 index 0000000..ebe59e2 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/RecordExpression.java @@ -0,0 +1,33 @@ +/* + * @(#)RecordExpression.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.aggregates.RecordAggregate; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class RecordExpression extends Expression { + + public RecordExpression(RecordAggregate raAST, SourcePosition position) { + super(position); + RA = raAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitRecordExpression(this, arg); + } + + public final RecordAggregate RA; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/UnaryExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/UnaryExpression.java new file mode 100644 index 0000000..22199b9 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/UnaryExpression.java @@ -0,0 +1,35 @@ +/* + * @(#)UnaryExpression.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.terminals.Operator; +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class UnaryExpression extends Expression { + + public UnaryExpression(Operator oAST, Expression eAST, SourcePosition position) { + super(position); + O = oAST; + E = eAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitUnaryExpression(this, arg); + } + + public Expression E; + public final Operator O; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/VnameExpression.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/VnameExpression.java new file mode 100644 index 0000000..3bf845a --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/expressions/VnameExpression.java @@ -0,0 +1,33 @@ +/* + * @(#)VnameExpression.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.expressions; + +import triangle.abstractSyntaxTrees.visitors.ExpressionVisitor; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.syntacticAnalyzer.SourcePosition; + +public class VnameExpression extends Expression { + + public VnameExpression(Vname vAST, SourcePosition position) { + super(position); + V = vAST; + } + + public TResult visit(ExpressionVisitor v, TArg arg) { + return v.visitVnameExpression(this, arg); + } + + public final Vname V; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ConstFormalParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ConstFormalParameter.java new file mode 100644 index 0000000..c860a53 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ConstFormalParameter.java @@ -0,0 +1,51 @@ +/* + * @(#)ConstFormalParameter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.declarations.ConstantDeclaration; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ConstFormalParameter extends FormalParameter implements ConstantDeclaration { + + public ConstFormalParameter(Identifier iAST, TypeDenoter tAST, SourcePosition position) { + super(position); + I = iAST; + T = tAST; + } + + @Override + public TypeDenoter getType() { + return T; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitConstFormalParameter(this, arg); + } + + @Override + public boolean equals(Object fpAST) { + if (fpAST instanceof ConstFormalParameter) { + return T.equals(((ConstFormalParameter)fpAST).T); + } else { + return false; + } + } + + public final Identifier I; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/EmptyFormalParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/EmptyFormalParameterSequence.java new file mode 100644 index 0000000..c478e7f --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/EmptyFormalParameterSequence.java @@ -0,0 +1,34 @@ +/* + * @(#)EmptyFormalParameterSequence.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class EmptyFormalParameterSequence extends FormalParameterSequence { + + public EmptyFormalParameterSequence(SourcePosition position) { + super(position); + } + + public TResult visit(FormalParameterSequenceVisitor v, TArg arg) { + return v.visitEmptyFormalParameterSequence(this, arg); + } + + @Override + public boolean equals(Object fpsAST) { + return (fpsAST instanceof EmptyFormalParameterSequence); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameter.java new file mode 100644 index 0000000..b6b643b --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameter.java @@ -0,0 +1,35 @@ +/* + * @(#)FormalParameter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class FormalParameter extends Declaration { + + public FormalParameter(SourcePosition position) { + super(position); + } + + @Override + public abstract boolean equals(Object fpAST); + + public abstract TResult visit(DeclarationVisitor visitor, TArg arg); + + public TResult visit(DeclarationVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameterSequence.java new file mode 100644 index 0000000..c9941d9 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FormalParameterSequence.java @@ -0,0 +1,35 @@ +/* + * @(#)FormalParameterSequence.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class FormalParameterSequence extends AbstractSyntaxTree { + + public FormalParameterSequence(SourcePosition position) { + super(position); + } + + @Override + public abstract boolean equals(Object fpsAST); + + public abstract TResult visit(FormalParameterSequenceVisitor visitor, TArg arg); + + public TResult visit(FormalParameterSequenceVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FuncFormalParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FuncFormalParameter.java new file mode 100644 index 0000000..f362f25 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/FuncFormalParameter.java @@ -0,0 +1,59 @@ +/* + * @(#)FuncFormalParameter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.declarations.FunctionDeclaration; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class FuncFormalParameter extends FormalParameter implements FunctionDeclaration { + + public FuncFormalParameter(Identifier iAST, FormalParameterSequence fpsAST, TypeDenoter tAST, + SourcePosition position) { + super(position); + I = iAST; + FPS = fpsAST; + T = tAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitFuncFormalParameter(this, arg); + } + + @Override + public FormalParameterSequence getFormals() { + return FPS; + } + + @Override + public TypeDenoter getType() { + return T; + } + + @Override + public boolean equals(Object fpAST) { + if (fpAST instanceof FuncFormalParameter) { + FuncFormalParameter ffpAST = (FuncFormalParameter) fpAST; + return FPS.equals(ffpAST.FPS) && T.equals(ffpAST.T); + } else + return false; + } + + public final Identifier I; + public final FormalParameterSequence FPS; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/MultipleFormalParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/MultipleFormalParameterSequence.java new file mode 100644 index 0000000..32b76fa --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/MultipleFormalParameterSequence.java @@ -0,0 +1,45 @@ +/* + * @(#)MultipleFormalParameterSequence.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class MultipleFormalParameterSequence extends FormalParameterSequence { + + public MultipleFormalParameterSequence(FormalParameter fpAST, FormalParameterSequence fpsAST, + SourcePosition position) { + super(position); + FP = fpAST; + FPS = fpsAST; + } + + public TResult visit(FormalParameterSequenceVisitor v, TArg arg) { + return v.visitMultipleFormalParameterSequence(this, arg); + } + + @Override + public boolean equals(Object fpsAST) { + if (fpsAST instanceof MultipleFormalParameterSequence) { + MultipleFormalParameterSequence mfpsAST = (MultipleFormalParameterSequence) fpsAST; + return FP.equals(mfpsAST.FP) && FPS.equals(mfpsAST.FPS); + } else { + return false; + } + } + + public final FormalParameter FP; + public final FormalParameterSequence FPS; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ProcFormalParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ProcFormalParameter.java new file mode 100644 index 0000000..e89561c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/ProcFormalParameter.java @@ -0,0 +1,51 @@ +/* + * @(#)ProcFormalParameter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.declarations.ProcedureDeclaration; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ProcFormalParameter extends FormalParameter implements ProcedureDeclaration { + + public ProcFormalParameter(Identifier iAST, FormalParameterSequence fpsAST, SourcePosition position) { + super(position); + I = iAST; + FPS = fpsAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitProcFormalParameter(this, arg); + } + + @Override + public FormalParameterSequence getFormals() { + return FPS; + } + + @Override + public boolean equals(Object fpAST) { + if (fpAST instanceof ProcFormalParameter) { + ProcFormalParameter pfpAST = (ProcFormalParameter) fpAST; + return FPS.equals(pfpAST.FPS); + } else { + return false; + } + } + + public final Identifier I; + public final FormalParameterSequence FPS; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/SingleFormalParameterSequence.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/SingleFormalParameterSequence.java new file mode 100644 index 0000000..d0f1152 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/SingleFormalParameterSequence.java @@ -0,0 +1,42 @@ +/* + * @(#)SingleFormalParameterSequence.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.visitors.FormalParameterSequenceVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SingleFormalParameterSequence extends FormalParameterSequence { + + public SingleFormalParameterSequence(FormalParameter fpAST, SourcePosition position) { + super(position); + FP = fpAST; + } + + public TResult visit(FormalParameterSequenceVisitor v, TArg arg) { + return v.visitSingleFormalParameterSequence(this, arg); + } + + @Override + public boolean equals(Object fpsAST) { + if (fpsAST instanceof SingleFormalParameterSequence) { + SingleFormalParameterSequence sfpsAST = (SingleFormalParameterSequence) fpsAST; + return FP.equals(sfpsAST.FP); + } else { + return false; + } + } + + public final FormalParameter FP; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/VarFormalParameter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/VarFormalParameter.java new file mode 100644 index 0000000..19efd56 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/formals/VarFormalParameter.java @@ -0,0 +1,51 @@ +/* + * @(#)ValFormalParameter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.formals; + +import triangle.abstractSyntaxTrees.declarations.VariableDeclaration; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class VarFormalParameter extends FormalParameter implements VariableDeclaration { + + public VarFormalParameter(Identifier iAST, TypeDenoter tAST, SourcePosition position) { + super(position); + I = iAST; + T = tAST; + } + + @Override + public TypeDenoter getType() { + return T; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitVarFormalParameter(this, arg); + } + + @Override + public boolean equals(Object fpAST) { + if (fpAST instanceof VarFormalParameter) { + return T.equals(((VarFormalParameter)fpAST).T); + } else { + return false; + } + } + + public final Identifier I; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/CharacterLiteral.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/CharacterLiteral.java new file mode 100644 index 0000000..994b8e9 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/CharacterLiteral.java @@ -0,0 +1,37 @@ +/* + * @(#)CharacterLiteral.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.terminals; + +import triangle.abstractSyntaxTrees.visitors.LiteralVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class CharacterLiteral extends Terminal { + + public CharacterLiteral(String spelling, SourcePosition position) { + super(spelling, position); + } + + public TResult visit(LiteralVisitor v, TArg arg) { + return v.visitCharacterLiteral(this, arg); + } + + public TResult visit(LiteralVisitor visitor) { + return visit(visitor, null); + } + + public int getValue() { + return spelling.charAt(1); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Identifier.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Identifier.java new file mode 100644 index 0000000..139b2c6 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Identifier.java @@ -0,0 +1,40 @@ +/* + * @(#)Identifier.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.terminals; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.IdentifierVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class Identifier extends Terminal { + + public Identifier(String spelling, SourcePosition position) { + super(spelling, position); + type = null; + decl = null; + } + + public TypeDenoter type; + public AbstractSyntaxTree decl; // Either a Declaration or a FieldTypeDenoter + + public TResult visit(IdentifierVisitor visitor, TArg arg) { + return visitor.visitIdentifier(this, arg); + } + + public TResult visit(IdentifierVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/IntegerLiteral.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/IntegerLiteral.java new file mode 100644 index 0000000..03be9dc --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/IntegerLiteral.java @@ -0,0 +1,37 @@ +/* + * @(#)IntegerLiteral.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.terminals; + +import triangle.abstractSyntaxTrees.visitors.LiteralVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class IntegerLiteral extends Terminal { + + public IntegerLiteral(String spelling, SourcePosition position) { + super(spelling, position); + } + + public TResult visit(LiteralVisitor v, TArg arg) { + return v.visitIntegerLiteral(this, arg); + } + + public TResult visit(LiteralVisitor visitor) { + return visit(visitor, null); + } + + public int getValue() { + return Integer.parseInt(spelling); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Operator.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Operator.java new file mode 100644 index 0000000..f6353d1 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Operator.java @@ -0,0 +1,37 @@ +/* + * @(#)Operator.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.terminals; + +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.visitors.OperatorVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class Operator extends Terminal { + + public Operator(String spelling, SourcePosition position) { + super(spelling, position); + decl = null; + } + + public Declaration decl; + + public TResult visit(OperatorVisitor v, TArg arg) { + return v.visitOperator(this, arg); + } + + public TResult visit(OperatorVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Terminal.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Terminal.java new file mode 100644 index 0000000..c74ca4b --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/terminals/Terminal.java @@ -0,0 +1,28 @@ +/* + * @(#)Terminal.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.terminals; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class Terminal extends AbstractSyntaxTree { + + public Terminal(String spelling, SourcePosition position) { + super(position); + this.spelling = spelling; + } + + public final String spelling; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/AnyTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/AnyTypeDenoter.java new file mode 100644 index 0000000..171c9ca --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/AnyTypeDenoter.java @@ -0,0 +1,39 @@ +/* + * @(#)AnyTypeDenoter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class AnyTypeDenoter extends TypeDenoter { + + public AnyTypeDenoter(SourcePosition position) { + super(position); + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitAnyTypeDenoter(this, arg); + } + + @Override + public boolean equals(Object obj) { + return false; + } + + @Override + public int getSize() { + return 0; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ArrayTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ArrayTypeDenoter.java new file mode 100644 index 0000000..8d43342 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ArrayTypeDenoter.java @@ -0,0 +1,52 @@ +/* + * @(#)ArrayTypeDenoter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.terminals.IntegerLiteral; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ArrayTypeDenoter extends TypeDenoter { + + public ArrayTypeDenoter(IntegerLiteral ilAST, TypeDenoter tAST, SourcePosition position) { + super(position); + IL = ilAST; + T = tAST; + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitArrayTypeDenoter(this, arg); + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof ErrorTypeDenoter) { + return true; + } else if (obj != null && obj instanceof ArrayTypeDenoter) { + return this.IL.spelling.compareTo(((ArrayTypeDenoter) obj).IL.spelling) == 0 + && this.T.equals(((ArrayTypeDenoter) obj).T); + } else { + return false; + } + } + + @Override + public int getSize() { + return IL.getValue() * T.getSize(); + } + + public final IntegerLiteral IL; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/BoolTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/BoolTypeDenoter.java new file mode 100644 index 0000000..f00e05e --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/BoolTypeDenoter.java @@ -0,0 +1,44 @@ +/* + * @(#)BoolTypeDenoter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractMachine.Machine; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class BoolTypeDenoter extends TypeDenoter { + + public BoolTypeDenoter(SourcePosition position) { + super(position); + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitBoolTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return Machine.booleanSize; + } + + @Override + public boolean equals(Object obj) { + if ((obj != null) && (obj instanceof ErrorTypeDenoter)) { + return true; + } else { + return ((obj != null) && (obj instanceof BoolTypeDenoter)); + } + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/CharTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/CharTypeDenoter.java new file mode 100644 index 0000000..7f474b4 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/CharTypeDenoter.java @@ -0,0 +1,44 @@ +/* + * @(#)CharTypeDenoter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractMachine.Machine; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class CharTypeDenoter extends TypeDenoter { + + public CharTypeDenoter(SourcePosition position) { + super(position); + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitCharTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return Machine.characterSize; + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof ErrorTypeDenoter) { + return true; + } else { + return (obj != null && obj instanceof CharTypeDenoter); + } + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ErrorTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ErrorTypeDenoter.java new file mode 100644 index 0000000..de6ec0a --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/ErrorTypeDenoter.java @@ -0,0 +1,39 @@ +/* + * @(#)ErrorTypeDenoter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class ErrorTypeDenoter extends TypeDenoter { + + public ErrorTypeDenoter(SourcePosition position) { + super(position); + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitErrorTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return 0; + } + + @Override + public boolean equals(Object obj) { + return true; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/FieldTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/FieldTypeDenoter.java new file mode 100644 index 0000000..00a2d71 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/FieldTypeDenoter.java @@ -0,0 +1,24 @@ +/* + * @(#)FieldTypeDenoter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class FieldTypeDenoter extends TypeDenoter { + + public FieldTypeDenoter(SourcePosition position) { + super(position); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/IntTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/IntTypeDenoter.java new file mode 100644 index 0000000..9c5fb7f --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/IntTypeDenoter.java @@ -0,0 +1,44 @@ +/* + * @(#)IntTypeDenoter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractMachine.Machine; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class IntTypeDenoter extends TypeDenoter { + + public IntTypeDenoter(SourcePosition position) { + super(position); + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitIntTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return Machine.integerSize; + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof ErrorTypeDenoter) { + return true; + } else { + return (obj != null && obj instanceof IntTypeDenoter); + } + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/MultipleFieldTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/MultipleFieldTypeDenoter.java new file mode 100644 index 0000000..c9b7658 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/MultipleFieldTypeDenoter.java @@ -0,0 +1,53 @@ +/* + * @(#)MultipleFieldTypeDenoter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class MultipleFieldTypeDenoter extends FieldTypeDenoter { + + public MultipleFieldTypeDenoter(Identifier iAST, TypeDenoter tAST, FieldTypeDenoter ftAST, + SourcePosition position) { + super(position); + I = iAST; + T = tAST; + FT = ftAST; + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitMultipleFieldTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return T.getSize() + FT.getSize(); + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof MultipleFieldTypeDenoter) { + MultipleFieldTypeDenoter ft = (MultipleFieldTypeDenoter) obj; + return (this.I.spelling.compareTo(ft.I.spelling) == 0) && this.T.equals(ft.T) && this.FT.equals(ft.FT); + } else { + return false; + } + } + + public final Identifier I; + public TypeDenoter T; + public FieldTypeDenoter FT; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/RecordTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/RecordTypeDenoter.java new file mode 100644 index 0000000..8ba90d6 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/RecordTypeDenoter.java @@ -0,0 +1,48 @@ +/* + * @(#)RecordTypeDenoter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class RecordTypeDenoter extends TypeDenoter { + + public RecordTypeDenoter(FieldTypeDenoter ftAST, SourcePosition position) { + super(position); + FT = ftAST; + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitRecordTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return FT.getSize(); + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof ErrorTypeDenoter) { + return true; + } else if (obj != null && obj instanceof RecordTypeDenoter) { + return this.FT.equals(((RecordTypeDenoter) obj).FT); + } else { + return false; + } + } + + public FieldTypeDenoter FT; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SimpleTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SimpleTypeDenoter.java new file mode 100644 index 0000000..9d2d2b5 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SimpleTypeDenoter.java @@ -0,0 +1,43 @@ +/* + * @(#)SimpleTypeDenoter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SimpleTypeDenoter extends TypeDenoter { + + public SimpleTypeDenoter(Identifier iAST, SourcePosition position) { + super(position); + I = iAST; + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitSimpleTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return 0; + } + + @Override + public boolean equals(Object obj) { + return false; // should not happen + } + + public final Identifier I; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SingleFieldTypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SingleFieldTypeDenoter.java new file mode 100644 index 0000000..1471bb0 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/SingleFieldTypeDenoter.java @@ -0,0 +1,50 @@ +/* + * @(#)SingleFieldTypeDenoter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SingleFieldTypeDenoter extends FieldTypeDenoter { + + public SingleFieldTypeDenoter(Identifier iAST, TypeDenoter tAST, SourcePosition position) { + super(position); + I = iAST; + T = tAST; + } + + public TResult visit(TypeDenoterVisitor v, TArg arg) { + return v.visitSingleFieldTypeDenoter(this, arg); + } + + @Override + public int getSize() { + return T.getSize(); + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof SingleFieldTypeDenoter) { + SingleFieldTypeDenoter ft = (SingleFieldTypeDenoter) obj; + return (this.I.spelling.compareTo(ft.I.spelling) == 0) && this.T.equals(ft.T); + } else { + return false; + } + } + + public final Identifier I; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDeclaration.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDeclaration.java new file mode 100644 index 0000000..55e2782 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDeclaration.java @@ -0,0 +1,36 @@ +/* + * @(#)TypeDeclaration.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.DeclarationVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class TypeDeclaration extends Declaration { + + public TypeDeclaration(Identifier iAST, TypeDenoter tAST, SourcePosition position) { + super(position); + I = iAST; + T = tAST; + } + + public TResult visit(DeclarationVisitor v, TArg arg) { + return v.visitTypeDeclaration(this, arg); + } + + public final Identifier I; + public TypeDenoter T; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDenoter.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDenoter.java new file mode 100644 index 0000000..b59be4f --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/types/TypeDenoter.java @@ -0,0 +1,37 @@ +/* + * @(#)TypeDenoter.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.types; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.visitors.TypeDenoterVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class TypeDenoter extends AbstractSyntaxTree { + + public TypeDenoter(SourcePosition position) { + super(position); + } + + @Override + public abstract boolean equals(Object obj); + + public abstract TResult visit(TypeDenoterVisitor visitor, TArg arg); + + public TResult visit(TypeDenoterVisitor visitor) { + return visit(visitor, null); + } + + public abstract int getSize(); +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterSequenceVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterSequenceVisitor.java new file mode 100644 index 0000000..66e68a3 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterSequenceVisitor.java @@ -0,0 +1,15 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.actuals.EmptyActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.MultipleActualParameterSequence; +import triangle.abstractSyntaxTrees.actuals.SingleActualParameterSequence; + +public interface ActualParameterSequenceVisitor { + + TResult visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, TArg arg); + + TResult visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, TArg arg); + + TResult visitSingleActualParameterSequence(SingleActualParameterSequence ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterVisitor.java new file mode 100644 index 0000000..9e9630b --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ActualParameterVisitor.java @@ -0,0 +1,18 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.actuals.ConstActualParameter; +import triangle.abstractSyntaxTrees.actuals.FuncActualParameter; +import triangle.abstractSyntaxTrees.actuals.ProcActualParameter; +import triangle.abstractSyntaxTrees.actuals.VarActualParameter; + +public interface ActualParameterVisitor { + + TResult visitConstActualParameter(ConstActualParameter ast, TArg arg); + + TResult visitFuncActualParameter(FuncActualParameter ast, TArg arg); + + TResult visitProcActualParameter(ProcActualParameter ast, TArg arg); + + TResult visitVarActualParameter(VarActualParameter ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ArrayAggregateVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ArrayAggregateVisitor.java new file mode 100644 index 0000000..8d7abec --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ArrayAggregateVisitor.java @@ -0,0 +1,12 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.aggregates.MultipleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleArrayAggregate; + +public interface ArrayAggregateVisitor { + + TResult visitMultipleArrayAggregate(MultipleArrayAggregate ast, TArg arg); + + TResult visitSingleArrayAggregate(SingleArrayAggregate ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/CommandVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/CommandVisitor.java new file mode 100644 index 0000000..336c97d --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/CommandVisitor.java @@ -0,0 +1,27 @@ +package triangle.abstractSyntaxTrees.visitors; + +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.SequentialCommand; +import triangle.abstractSyntaxTrees.commands.WhileCommand; + +public interface CommandVisitor { + + TResult visitAssignCommand(AssignCommand ast, TArg arg); + + TResult visitCallCommand(CallCommand ast, TArg arg); + + TResult visitEmptyCommand(EmptyCommand ast, TArg arg); + + TResult visitIfCommand(IfCommand ast, TArg arg); + + TResult visitLetCommand(LetCommand ast, TArg arg); + + TResult visitSequentialCommand(SequentialCommand ast, TArg arg); + + TResult visitWhileCommand(WhileCommand ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/DeclarationVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/DeclarationVisitor.java new file mode 100644 index 0000000..7ce845d --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/DeclarationVisitor.java @@ -0,0 +1,30 @@ +package triangle.abstractSyntaxTrees.visitors; + +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.types.TypeDeclaration; + +public interface DeclarationVisitor extends FormalParameterVisitor { + + TResult visitBinaryOperatorDeclaration(BinaryOperatorDeclaration ast, TArg arg); + + TResult visitConstDeclaration(ConstDeclaration ast, TArg arg); + + TResult visitFuncDeclaration(FuncDeclaration ast, TArg arg); + + TResult visitProcDeclaration(ProcDeclaration ast, TArg arg); + + TResult visitSequentialDeclaration(SequentialDeclaration ast, TArg arg); + + TResult visitTypeDeclaration(TypeDeclaration ast, TArg arg); + + TResult visitUnaryOperatorDeclaration(UnaryOperatorDeclaration ast, TArg arg); + + TResult visitVarDeclaration(VarDeclaration ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ExpressionVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ExpressionVisitor.java new file mode 100644 index 0000000..ebb76f4 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ExpressionVisitor.java @@ -0,0 +1,39 @@ +package triangle.abstractSyntaxTrees.visitors; + +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.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; + +public interface ExpressionVisitor { + + TResult visitArrayExpression(ArrayExpression ast, TArg arg); + + TResult visitBinaryExpression(BinaryExpression ast, TArg arg); + + TResult visitCallExpression(CallExpression ast, TArg arg); + + TResult visitCharacterExpression(CharacterExpression ast, TArg arg); + + TResult visitEmptyExpression(EmptyExpression ast, TArg arg); + + TResult visitIfExpression(IfExpression ast, TArg arg); + + TResult visitIntegerExpression(IntegerExpression ast, TArg arg); + + TResult visitLetExpression(LetExpression ast, TArg arg); + + TResult visitRecordExpression(RecordExpression ast, TArg arg); + + TResult visitUnaryExpression(UnaryExpression ast, TArg arg); + + TResult visitVnameExpression(VnameExpression ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FieldTypeDenoterVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FieldTypeDenoterVisitor.java new file mode 100644 index 0000000..2bd3f0d --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FieldTypeDenoterVisitor.java @@ -0,0 +1,12 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.types.MultipleFieldTypeDenoter; +import triangle.abstractSyntaxTrees.types.SingleFieldTypeDenoter; + +public interface FieldTypeDenoterVisitor { + + TResult visitMultipleFieldTypeDenoter(MultipleFieldTypeDenoter ast, TArg arg); + + TResult visitSingleFieldTypeDenoter(SingleFieldTypeDenoter ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterSequenceVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterSequenceVisitor.java new file mode 100644 index 0000000..3505451 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterSequenceVisitor.java @@ -0,0 +1,15 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.formals.EmptyFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.MultipleFormalParameterSequence; +import triangle.abstractSyntaxTrees.formals.SingleFormalParameterSequence; + +public interface FormalParameterSequenceVisitor { + + TResult visitEmptyFormalParameterSequence(EmptyFormalParameterSequence ast, TArg arg); + + TResult visitMultipleFormalParameterSequence(MultipleFormalParameterSequence ast, TArg arg); + + TResult visitSingleFormalParameterSequence(SingleFormalParameterSequence ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterVisitor.java new file mode 100644 index 0000000..cddb0e7 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/FormalParameterVisitor.java @@ -0,0 +1,18 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.formals.ConstFormalParameter; +import triangle.abstractSyntaxTrees.formals.FuncFormalParameter; +import triangle.abstractSyntaxTrees.formals.ProcFormalParameter; +import triangle.abstractSyntaxTrees.formals.VarFormalParameter; + +public interface FormalParameterVisitor { + + TResult visitConstFormalParameter(ConstFormalParameter ast, TArg arg); + + TResult visitFuncFormalParameter(FuncFormalParameter ast, TArg arg); + + TResult visitProcFormalParameter(ProcFormalParameter ast, TArg arg); + + TResult visitVarFormalParameter(VarFormalParameter ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/IdentifierVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/IdentifierVisitor.java new file mode 100644 index 0000000..b303b8e --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/IdentifierVisitor.java @@ -0,0 +1,9 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.terminals.Identifier; + +public interface IdentifierVisitor { + + TResult visitIdentifier(Identifier ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/LiteralVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/LiteralVisitor.java new file mode 100644 index 0000000..1ca4fa4 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/LiteralVisitor.java @@ -0,0 +1,12 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.terminals.CharacterLiteral; +import triangle.abstractSyntaxTrees.terminals.IntegerLiteral; + +public interface LiteralVisitor { + + TResult visitCharacterLiteral(CharacterLiteral ast, TArg arg); + + TResult visitIntegerLiteral(IntegerLiteral ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/OperatorVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/OperatorVisitor.java new file mode 100644 index 0000000..989a653 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/OperatorVisitor.java @@ -0,0 +1,9 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.terminals.Operator; + +public interface OperatorVisitor { + + TResult visitOperator(Operator ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ProgramVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ProgramVisitor.java new file mode 100644 index 0000000..aca855c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/ProgramVisitor.java @@ -0,0 +1,9 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.Program; + +public interface ProgramVisitor { + + TResult visitProgram(Program ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/RecordAggregateVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/RecordAggregateVisitor.java new file mode 100644 index 0000000..20ed097 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/RecordAggregateVisitor.java @@ -0,0 +1,12 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.aggregates.MultipleRecordAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleRecordAggregate; + +public interface RecordAggregateVisitor { + + TResult visitMultipleRecordAggregate(MultipleRecordAggregate ast, TArg arg); + + TResult visitSingleRecordAggregate(SingleRecordAggregate ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/TypeDenoterVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/TypeDenoterVisitor.java new file mode 100644 index 0000000..79b47e3 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/TypeDenoterVisitor.java @@ -0,0 +1,30 @@ +package triangle.abstractSyntaxTrees.visitors; + +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.RecordTypeDenoter; +import triangle.abstractSyntaxTrees.types.SimpleTypeDenoter; + +public interface TypeDenoterVisitor extends FieldTypeDenoterVisitor { + + TResult visitAnyTypeDenoter(AnyTypeDenoter ast, TArg arg); + + TResult visitArrayTypeDenoter(ArrayTypeDenoter ast, TArg arg); + + TResult visitBoolTypeDenoter(BoolTypeDenoter ast, TArg arg); + + TResult visitCharTypeDenoter(CharTypeDenoter ast, TArg arg); + + TResult visitErrorTypeDenoter(ErrorTypeDenoter ast, TArg arg); + + TResult visitSimpleTypeDenoter(SimpleTypeDenoter ast, TArg arg); + + TResult visitIntTypeDenoter(IntTypeDenoter ast, TArg arg); + + TResult visitRecordTypeDenoter(RecordTypeDenoter ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/VnameVisitor.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/VnameVisitor.java new file mode 100644 index 0000000..6936a54 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/visitors/VnameVisitor.java @@ -0,0 +1,15 @@ +package triangle.abstractSyntaxTrees.visitors; + +import triangle.abstractSyntaxTrees.vnames.DotVname; +import triangle.abstractSyntaxTrees.vnames.SimpleVname; +import triangle.abstractSyntaxTrees.vnames.SubscriptVname; + +public interface VnameVisitor { + + TResult visitDotVname(DotVname ast, TArg arg); + + TResult visitSimpleVname(SimpleVname ast, TArg arg); + + TResult visitSubscriptVname(SubscriptVname ast, TArg arg); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/DotVname.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/DotVname.java new file mode 100644 index 0000000..81c1d41 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/DotVname.java @@ -0,0 +1,35 @@ +/* + * @(#)DotVname.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.vnames; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.VnameVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class DotVname extends Vname { + + public DotVname(Vname vAST, Identifier iAST, SourcePosition position) { + super(position); + V = vAST; + I = iAST; + } + + public TResult visit(VnameVisitor v, TArg arg) { + return v.visitDotVname(this, arg); + } + + public final Identifier I; + public final Vname V; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SimpleVname.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SimpleVname.java new file mode 100644 index 0000000..c1ca042 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SimpleVname.java @@ -0,0 +1,33 @@ +/* + * @(#)SimpleVname.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.vnames; + +import triangle.abstractSyntaxTrees.terminals.Identifier; +import triangle.abstractSyntaxTrees.visitors.VnameVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SimpleVname extends Vname { + + public SimpleVname(Identifier iAST, SourcePosition position) { + super(position); + I = iAST; + } + + public TResult visit(VnameVisitor v, TArg arg) { + return v.visitSimpleVname(this, arg); + } + + public final Identifier I; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SubscriptVname.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SubscriptVname.java new file mode 100644 index 0000000..a95d1f4 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/SubscriptVname.java @@ -0,0 +1,35 @@ +/* + * @(#)SubscriptVname.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.vnames; + +import triangle.abstractSyntaxTrees.expressions.Expression; +import triangle.abstractSyntaxTrees.visitors.VnameVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public class SubscriptVname extends Vname { + + public SubscriptVname(Vname vAST, Expression eAST, SourcePosition position) { + super(position); + V = vAST; + E = eAST; + } + + public TResult visit(VnameVisitor v, TArg arg) { + return v.visitSubscriptVname(this, arg); + } + + public Expression E; + public final Vname V; +} diff --git a/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/Vname.java b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/Vname.java new file mode 100644 index 0000000..633b1f0 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/abstractSyntaxTrees/vnames/Vname.java @@ -0,0 +1,39 @@ +/* + * @(#)Vname.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.abstractSyntaxTrees.vnames; + +import triangle.abstractSyntaxTrees.AbstractSyntaxTree; +import triangle.abstractSyntaxTrees.types.TypeDenoter; +import triangle.abstractSyntaxTrees.visitors.VnameVisitor; +import triangle.syntacticAnalyzer.SourcePosition; + +public abstract class Vname extends AbstractSyntaxTree { + + public Vname(SourcePosition position) { + super(position); + variable = false; + type = null; + } + + public boolean variable, indexed; + public int offset; + public TypeDenoter type; + + public abstract TResult visit(VnameVisitor visitor, TArg arg); + + public TResult visit(VnameVisitor visitor) { + return visit(visitor, null); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/Emitter.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/Emitter.java new file mode 100644 index 0000000..e0b037a --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/Emitter.java @@ -0,0 +1,120 @@ +package triangle.codeGenerator; + +import java.io.DataOutputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import triangle.ErrorReporter; +import triangle.abstractMachine.Instruction; +import triangle.abstractMachine.Machine; +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; + +public class Emitter { + + // OBJECT CODE + + // Implementation notes: + // Object code is generated directly into the TAM Code Store, starting at + // CB. + // The address of the next instruction is held in nextInstrAddr. + + ErrorReporter errorReporter; + + int nextInstrAddr; + + public Emitter(ErrorReporter errorReporter) { + this.errorReporter = errorReporter; + nextInstrAddr = Machine.CB; + } + + public int getNextInstrAddr() { + return nextInstrAddr; + } + + public int emit(OpCode op) { + return emit(op, 0, Register.CB, 0); + } + + public int emit(OpCode op, int operand) { + return emit(op, 0, Register.CB, operand); + } + + public int emit(OpCode op, int length, int operand) { + return emit(op, length, Register.CB, operand); + } + + public int emit(OpCode op, Register staticRegister, Register register, int operand) { + return emit(op, staticRegister.ordinal(), register, operand); + } + + public int emit(OpCode op, Register register, int operand) { + return emit(op, 0, register, operand); + } + + public int emit(OpCode op, Register register) { + return emit(op, 0, register, 0); + } + + public int emit(OpCode op, int length, Register register) { + return emit(op, length, register, 0); + } + + public int emit(OpCode op, Register register, Primitive primitive) { + return emit(op, 0, register, primitive.ordinal()); + } + + /** + * Appends an instruction, with the given fields, to the object code. + * + * @param op the opcode + * @param length the length field + * @param register the register field + * @param operand the operand field + * @return the code address of the new instruction + **/ + public int emit(OpCode op, int length, Register register, int operand) { + + if (length > 255) { + errorReporter.reportRestriction("length of operand can't exceed 255 words"); + length = 255; // to allow code generation to continue + } + + var nextInstr = new Instruction(op, register, length, operand); + + var currentInstrAddr = nextInstrAddr; + if (nextInstrAddr == Machine.PB) { + errorReporter.reportRestriction("too many instructions for code segment"); + } else { + Machine.code[nextInstrAddr++] = nextInstr; + } + return currentInstrAddr; + + } + + // Patches the d-field of the instruction at address addr with the next + // instruction address. + public void patch(int addr) { + Machine.code[addr].setOperand(nextInstrAddr); + } + + /** + * Saves the object program in the given object file. + * + * @param objectFile the object file + */ + public void saveObjectProgram(String objectFileName) { + try (var objectFile = new FileOutputStream(objectFileName)) { + var objectStream = new DataOutputStream(objectFile); + for (var addr = Machine.CB; addr < nextInstrAddr; addr++) { + Machine.code[addr].write(objectStream); + } + } catch (FileNotFoundException fnfe) { + System.err.println("Error opening object file: " + fnfe); + } catch (IOException ioe) { + System.err.println("Error writing object file: " + ioe); + } + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/Encoder.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/Encoder.java new file mode 100644 index 0000000..2224aa6 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/Encoder.java @@ -0,0 +1,792 @@ +/* + * @(#)Encoder.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator; + +import triangle.ErrorReporter; +import triangle.StdEnvironment; +import triangle.abstractMachine.Machine; +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; +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.SequentialCommand; +import triangle.abstractSyntaxTrees.commands.WhileCommand; +import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; +import triangle.abstractSyntaxTrees.declarations.Declaration; +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.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.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.entities.AddressableEntity; +import triangle.codeGenerator.entities.EqualityRoutine; +import triangle.codeGenerator.entities.FetchableEntity; +import triangle.codeGenerator.entities.Field; +import triangle.codeGenerator.entities.KnownAddress; +import triangle.codeGenerator.entities.KnownRoutine; +import triangle.codeGenerator.entities.KnownValue; +import triangle.codeGenerator.entities.PrimitiveRoutine; +import triangle.codeGenerator.entities.RoutineEntity; +import triangle.codeGenerator.entities.RuntimeEntity; +import triangle.codeGenerator.entities.TypeRepresentation; +import triangle.codeGenerator.entities.UnknownAddress; +import triangle.codeGenerator.entities.UnknownRoutine; +import triangle.codeGenerator.entities.UnknownValue; + +public final class Encoder implements ActualParameterVisitor, + ActualParameterSequenceVisitor, ArrayAggregateVisitor, + CommandVisitor, DeclarationVisitor, ExpressionVisitor, + FormalParameterSequenceVisitor, IdentifierVisitor, LiteralVisitor, + OperatorVisitor, ProgramVisitor, RecordAggregateVisitor, + TypeDenoterVisitor, VnameVisitor { + + // Commands + @Override + public Void visitAssignCommand(AssignCommand ast, Frame frame) { + var valSize = ast.E.visit(this, frame); + encodeStore(ast.V, frame.expand(valSize), valSize); + return null; + } + + @Override + public Void visitCallCommand(CallCommand ast, Frame frame) { + var argsSize = ast.APS.visit(this, frame); + ast.I.visit(this, frame.replace(argsSize)); + return null; + } + + @Override + public Void visitEmptyCommand(EmptyCommand ast, Frame frame) { + return null; + } + + @Override + public Void visitIfCommand(IfCommand ast, Frame frame) { + ast.E.visit(this, frame); + var jumpifAddr = emitter.emit(OpCode.JUMPIF, Machine.falseRep, Register.CB, 0); + ast.C1.visit(this, frame); + var jumpAddr = emitter.emit(OpCode.JUMP, 0, Register.CB, 0); + emitter.patch(jumpifAddr); + ast.C2.visit(this, frame); + emitter.patch(jumpAddr); + return null; + } + + @Override + public Void visitLetCommand(LetCommand ast, Frame frame) { + var extraSize = ast.D.visit(this, frame); + ast.C.visit(this, frame.expand(extraSize)); + if (extraSize > 0) { + emitter.emit(OpCode.POP, extraSize); + } + return null; + } + + @Override + public Void visitSequentialCommand(SequentialCommand ast, Frame frame) { + ast.C1.visit(this, frame); + ast.C2.visit(this, frame); + return null; + } + + @Override + public Void visitWhileCommand(WhileCommand ast, Frame frame) { + var jumpAddr = emitter.emit(OpCode.JUMP, 0, Register.CB, 0); + var loopAddr = emitter.getNextInstrAddr(); + ast.C.visit(this, frame); + emitter.patch(jumpAddr); + ast.E.visit(this, frame); + emitter.emit(OpCode.JUMPIF, Machine.trueRep, Register.CB, loopAddr); + return null; + } + + // Expressions + @Override + public Integer visitArrayExpression(ArrayExpression ast, Frame frame) { + ast.type.visit(this, frame); + return ast.AA.visit(this, frame); + } + + @Override + public Integer visitBinaryExpression(BinaryExpression ast, Frame frame) { + var valSize = ast.type.visit(this); + var valSize1 = ast.E1.visit(this, frame); + var frame1 = frame.expand(valSize1); + var valSize2 = ast.E2.visit(this, frame1); + var frame2 = frame.replace(valSize1 + valSize2); + ast.O.visit(this, frame2); + return valSize; + } + + @Override + public Integer visitCallExpression(CallExpression ast, Frame frame) { + var valSize = ast.type.visit(this); + var argsSize = ast.APS.visit(this, frame); + ast.I.visit(this, frame.replace(argsSize)); + return valSize; + } + + @Override + public Integer visitCharacterExpression(CharacterExpression ast, Frame frame) { + var valSize = ast.type.visit(this); + emitter.emit(OpCode.LOADL, ast.CL.getValue()); + return valSize; + } + + @Override + public Integer visitEmptyExpression(EmptyExpression ast, Frame frame) { + return 0; + } + + @Override + public Integer visitIfExpression(IfExpression ast, Frame frame) { + ast.type.visit(this); + ast.E1.visit(this, frame); + var jumpifAddr = emitter.emit(OpCode.JUMPIF, Machine.falseRep, Register.CB, 0); + var valSize = ast.E2.visit(this, frame); + var jumpAddr = emitter.emit(OpCode.JUMP, 0, Register.CB, 0); + emitter.patch(jumpifAddr); + valSize = ast.E3.visit(this, frame); + emitter.patch(jumpAddr); + return valSize; + } + + @Override + public Integer visitIntegerExpression(IntegerExpression ast, Frame frame) { + var valSize = ast.type.visit(this); + emitter.emit(OpCode.LOADL, ast.IL.getValue()); + return valSize; + } + + @Override + public Integer visitLetExpression(LetExpression ast, Frame frame) { + ast.type.visit(this); + var extraSize = ast.D.visit(this, frame); + var frame1 = frame.expand(extraSize); + var valSize = ast.E.visit(this, frame1); + if (extraSize > 0) { + emitter.emit(OpCode.POP, valSize, extraSize); + } + return valSize; + } + + @Override + public Integer visitRecordExpression(RecordExpression ast, Frame frame) { + ast.type.visit(this); + return ast.RA.visit(this, frame); + } + + @Override + public Integer visitUnaryExpression(UnaryExpression ast, Frame frame) { + var valSize = ast.type.visit(this); + ast.E.visit(this, frame); + ast.O.visit(this, frame.replace(valSize)); + return valSize; + } + + @Override + public Integer visitVnameExpression(VnameExpression ast, Frame frame) { + var valSize = ast.type.visit(this); + encodeFetch(ast.V, frame, valSize); + return valSize; + } + + // Declarations + @Override + public Integer visitBinaryOperatorDeclaration(BinaryOperatorDeclaration ast, Frame frame) { + return 0; + } + + @Override + public Integer visitConstDeclaration(ConstDeclaration ast, Frame frame) { + var extraSize = 0; + if (ast.E.isLiteral()) { + ast.entity = new KnownValue(ast.E.type.getSize(), ast.E.getValue()); + } else { + var valSize = ast.E.visit(this, frame); + ast.entity = new UnknownValue(valSize, frame); + extraSize = valSize; + } + writeTableDetails(ast); + return extraSize; + } + + @Override + public Integer visitFuncDeclaration(FuncDeclaration ast, Frame frame) { + var argsSize = 0; + var valSize = 0; + + var jumpAddr = emitter.emit(OpCode.JUMP, 0, Register.CB, 0); + ast.entity = new KnownRoutine(Machine.closureSize, frame.getLevel(), emitter.getNextInstrAddr()); + writeTableDetails(ast); + if (frame.getLevel() == Machine.maxRoutineLevel) { + reporter.reportRestriction("can't nest routines more than 7 deep"); + } else { + var frame1 = frame.push(0); + argsSize = ast.FPS.visit(this, frame1); + var frame2 = frame.push(Machine.linkDataSize); + valSize = ast.E.visit(this, frame2); + } + emitter.emit(OpCode.RETURN, valSize, argsSize); + emitter.patch(jumpAddr); + return 0; + } + + @Override + public Integer visitProcDeclaration(ProcDeclaration ast, Frame frame) { + var argsSize = 0; + var jumpAddr = emitter.emit(OpCode.JUMP, 0, Register.CB, 0); + ast.entity = new KnownRoutine(Machine.closureSize, frame.getLevel(), emitter.getNextInstrAddr()); + writeTableDetails(ast); + if (frame.getLevel() == Machine.maxRoutineLevel) { + reporter.reportRestriction("can't nest routines so deeply"); + } else { + var frame1 = frame.push(0); + argsSize = ast.FPS.visit(this, frame1); + var frame2 = frame.push(Machine.linkDataSize); + ast.C.visit(this, frame2); + } + emitter.emit(OpCode.RETURN, argsSize); + emitter.patch(jumpAddr); + return 0; + } + + @Override + public Integer visitSequentialDeclaration(SequentialDeclaration ast, Frame frame) { + var extraSize1 = ast.D1.visit(this, frame); + var frame1 = frame.expand(extraSize1); + var extraSize2 = ast.D2.visit(this, frame1); + return extraSize1 + extraSize2; + } + + @Override + public Integer visitTypeDeclaration(TypeDeclaration ast, Frame frame) { + // just to ensure the type's representation is decided + ast.T.visit(this); + return 0; + } + + @Override + public Integer visitUnaryOperatorDeclaration(UnaryOperatorDeclaration ast, Frame frame) { + return 0; + } + + @Override + public Integer visitVarDeclaration(VarDeclaration ast, Frame frame) { + var extraSize = ast.T.visit(this); + emitter.emit(OpCode.PUSH, extraSize); + ast.entity = new KnownAddress(Machine.addressSize, frame); + writeTableDetails(ast); + return extraSize; + } + + // Array Aggregates + @Override + public Integer visitMultipleArrayAggregate(MultipleArrayAggregate ast, Frame frame) { + var elemSize = ast.E.visit(this, frame); + var frame1 = frame.expand(elemSize); + var arraySize = ast.AA.visit(this, frame1); + return elemSize + arraySize; + } + + @Override + public Integer visitSingleArrayAggregate(SingleArrayAggregate ast, Frame frame) { + return ast.E.visit(this, frame); + } + + // Record Aggregates + @Override + public Integer visitMultipleRecordAggregate(MultipleRecordAggregate ast, Frame frame) { + var fieldSize = ast.E.visit(this, frame); + var frame1 = frame.expand(fieldSize); + var recordSize = ast.RA.visit(this, frame1); + return fieldSize + recordSize; + } + + @Override + public Integer visitSingleRecordAggregate(SingleRecordAggregate ast, Frame frame) { + return ast.E.visit(this, frame); + } + + // Formal Parameters + @Override + public Integer visitConstFormalParameter(ConstFormalParameter ast, Frame frame) { + var valSize = ast.T.visit(this); + ast.entity = new UnknownValue(valSize, frame.getLevel(), -frame.getSize() - valSize); + writeTableDetails(ast); + return valSize; + } + + @Override + public Integer visitFuncFormalParameter(FuncFormalParameter ast, Frame frame) { + var argsSize = Machine.closureSize; + ast.entity = new UnknownRoutine(Machine.closureSize, frame.getLevel(), -frame.getSize() - argsSize); + writeTableDetails(ast); + return argsSize; + } + + @Override + public Integer visitProcFormalParameter(ProcFormalParameter ast, Frame frame) { + var argsSize = Machine.closureSize; + ast.entity = new UnknownRoutine(Machine.closureSize, frame.getLevel(), -frame.getSize() - argsSize); + writeTableDetails(ast); + return argsSize; + } + + @Override + public Integer visitVarFormalParameter(VarFormalParameter ast, Frame frame) { + ast.T.visit(this); + ast.entity = new UnknownAddress(Machine.addressSize, frame.getLevel(), -frame.getSize() - Machine.addressSize); + writeTableDetails(ast); + return Machine.addressSize; + } + + @Override + public Integer visitEmptyFormalParameterSequence(EmptyFormalParameterSequence ast, Frame frame) { + return 0; + } + + @Override + public Integer visitMultipleFormalParameterSequence(MultipleFormalParameterSequence ast, Frame frame) { + var argsSize1 = ast.FPS.visit(this, frame); + var frame1 = frame.expand(argsSize1); + var argsSize2 = ast.FP.visit(this, frame1); + return argsSize1 + argsSize2; + } + + @Override + public Integer visitSingleFormalParameterSequence(SingleFormalParameterSequence ast, Frame frame) { + return ast.FP.visit(this, frame); + } + + // Actual Parameters + @Override + public Integer visitConstActualParameter(ConstActualParameter ast, Frame frame) { + return ast.E.visit(this, frame); + } + + @Override + public Integer visitFuncActualParameter(FuncActualParameter ast, Frame frame) { + var routineEntity = (RoutineEntity) ast.I.decl.entity; + routineEntity.encodeFetch(emitter, frame); + return Machine.closureSize; + } + + @Override + public Integer visitProcActualParameter(ProcActualParameter ast, Frame frame) { + var routineEntity = (RoutineEntity) ast.I.decl.entity; + routineEntity.encodeFetch(emitter, frame); + return Machine.closureSize; + } + + @Override + public Integer visitVarActualParameter(VarActualParameter ast, Frame frame) { + encodeFetchAddress(ast.V, frame); + return Machine.addressSize; + } + + @Override + public Integer visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, Frame frame) { + return 0; + } + + @Override + public Integer visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, Frame frame) { + var argsSize1 = ast.AP.visit(this, frame); + var frame1 = frame.expand(argsSize1); + var argsSize2 = ast.APS.visit(this, frame1); + return argsSize1 + argsSize2; + } + + @Override + public Integer visitSingleActualParameterSequence(SingleActualParameterSequence ast, Frame frame) { + return ast.AP.visit(this, frame); + } + + // Type Denoters + @Override + public Integer visitAnyTypeDenoter(AnyTypeDenoter ast, Frame frame) { + return 0; + } + + @Override + public Integer visitArrayTypeDenoter(ArrayTypeDenoter ast, Frame frame) { + int typeSize; + if (ast.entity == null) { + var elemSize = ast.T.visit(this); + typeSize = ast.IL.getValue() * elemSize; + ast.entity = new TypeRepresentation(typeSize); + writeTableDetails(ast); + } else { + typeSize = ast.entity.getSize(); + } + return typeSize; + } + + @Override + public Integer visitBoolTypeDenoter(BoolTypeDenoter ast, Frame frame) { + if (ast.entity == null) { + ast.entity = new TypeRepresentation(Machine.booleanSize); + writeTableDetails(ast); + } + return Machine.booleanSize; + } + + @Override + public Integer visitCharTypeDenoter(CharTypeDenoter ast, Frame frame) { + if (ast.entity == null) { + ast.entity = new TypeRepresentation(Machine.characterSize); + writeTableDetails(ast); + } + return Machine.characterSize; + } + + @Override + public Integer visitErrorTypeDenoter(ErrorTypeDenoter ast, Frame frame) { + return 0; + } + + @Override + public Integer visitSimpleTypeDenoter(SimpleTypeDenoter ast, Frame frame) { + return 0; + } + + @Override + public Integer visitIntTypeDenoter(IntTypeDenoter ast, Frame frame) { + if (ast.entity == null) { + ast.entity = new TypeRepresentation(Machine.integerSize); + writeTableDetails(ast); + } + return Machine.integerSize; + } + + @Override + public Integer visitRecordTypeDenoter(RecordTypeDenoter ast, Frame frame) { + int typeSize; + if (ast.entity == null) { + typeSize = ast.FT.visit(this, frame); + ast.entity = new TypeRepresentation(typeSize); + writeTableDetails(ast); + } else { + typeSize = ast.entity.getSize(); + } + return typeSize; + } + + @Override + public Integer visitMultipleFieldTypeDenoter(MultipleFieldTypeDenoter ast, Frame frame) { + if (frame == null) { // in this case, we're just using the frame to wrap up the size + frame = Frame.Initial; + } + + var offset = frame.getSize(); + int fieldSize; + if (ast.entity == null) { + fieldSize = ast.T.visit(this); + ast.entity = new Field(fieldSize, offset); + writeTableDetails(ast); + } else { + fieldSize = ast.entity.getSize(); + } + + var offset1 = frame.replace(offset + fieldSize); + var recSize = ast.FT.visit(this, offset1); + return fieldSize + recSize; + } + + @Override + public Integer visitSingleFieldTypeDenoter(SingleFieldTypeDenoter ast, Frame frame) { + var offset = frame.getSize(); + int fieldSize; + if (ast.entity == null) { + fieldSize = ast.T.visit(this); + ast.entity = new Field(fieldSize, offset); + writeTableDetails(ast); + } else { + fieldSize = ast.entity.getSize(); + } + + return fieldSize; + } + + // Literals, Identifiers and Operators + @Override + public Void visitCharacterLiteral(CharacterLiteral ast, Void arg) { + return null; + } + + @Override + public Void visitIdentifier(Identifier ast, Frame frame) { + var routineEntity = (RoutineEntity) ast.decl.entity; + routineEntity.encodeCall(emitter, frame); + return null; + } + + @Override + public Void visitIntegerLiteral(IntegerLiteral ast, Void arg) { + return null; + } + + @Override + public Void visitOperator(Operator ast, Frame frame) { + var routineEntity = (RoutineEntity) ast.decl.entity; + routineEntity.encodeCall(emitter, frame); + return null; + } + + // Value-or-variable names + @Override + public RuntimeEntity visitDotVname(DotVname ast, Frame frame) { + var baseObject = ast.V.visit(this, frame); + ast.offset = ast.V.offset + ((Field) ast.I.decl.entity).getFieldOffset(); + // I.decl points to the appropriate record field + ast.indexed = ast.V.indexed; + return baseObject; + } + + @Override + public RuntimeEntity visitSimpleVname(SimpleVname ast, Frame frame) { + ast.offset = 0; + ast.indexed = false; + return ast.I.decl.entity; + } + + @Override + public RuntimeEntity visitSubscriptVname(SubscriptVname ast, Frame frame) { + var baseObject = ast.V.visit(this, frame); + ast.offset = ast.V.offset; + ast.indexed = ast.V.indexed; + var elemSize = ast.type.visit(this); + if (ast.E.isLiteral()) { + ast.offset = ast.offset + ast.E.getValue() * elemSize; + } else { + // v-name is indexed by a proper expression, not a literal + if (ast.indexed) { + frame = frame.expand(Machine.integerSize); + } + ast.E.visit(this, frame); + if (elemSize != 1) { + emitter.emit(OpCode.LOADL, 0, elemSize); + emitter.emit(OpCode.CALL, Register.PB, Primitive.MULT); + } + if (ast.indexed) + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + else { + ast.indexed = true; + } + } + return baseObject; + } + + // Programs + @Override + public Void visitProgram(Program ast, Frame frame) { + return ast.C.visit(this, frame); + } + + public Encoder(Emitter emitter, ErrorReporter reporter) { + this.emitter = emitter; + this.reporter = reporter; + + elaborateStdEnvironment(); + } + + private Emitter emitter; + + private ErrorReporter reporter; + + // Generates code to run a program. + // showingTable is true iff entity description details + // are to be displayed. + public final void encodeRun(Program program, boolean showingTable) { + tableDetailsReqd = showingTable; + // startCodeGeneration(); + program.visit(this, Frame.Initial); + emitter.emit(OpCode.HALT); + } + + // Decides run-time representation of a standard constant. + private final void elaborateStdConst(ConstDeclaration constDeclaration, int value) { + + var typeSize = constDeclaration.E.type.visit(this); + constDeclaration.entity = new KnownValue(typeSize, value); + writeTableDetails(constDeclaration); + } + + // Decides run-time representation of a standard routine. + private final void elaborateStdPrimRoutine(Declaration routineDeclaration, Primitive primitive) { + routineDeclaration.entity = new PrimitiveRoutine(Machine.closureSize, primitive); + writeTableDetails(routineDeclaration); + } + + private final void elaborateStdEqRoutine(Declaration routineDeclaration, Primitive primitive) { + routineDeclaration.entity = new EqualityRoutine(Machine.closureSize, primitive); + writeTableDetails(routineDeclaration); + } + + private final void elaborateStdEnvironment() { + tableDetailsReqd = false; + elaborateStdConst(StdEnvironment.falseDecl, Machine.falseRep); + elaborateStdConst(StdEnvironment.trueDecl, Machine.trueRep); + elaborateStdPrimRoutine(StdEnvironment.notDecl, Primitive.NOT); + elaborateStdPrimRoutine(StdEnvironment.andDecl, Primitive.AND); + elaborateStdPrimRoutine(StdEnvironment.orDecl, Primitive.OR); + elaborateStdConst(StdEnvironment.maxintDecl, Machine.maxintRep); + elaborateStdPrimRoutine(StdEnvironment.addDecl, Primitive.ADD); + elaborateStdPrimRoutine(StdEnvironment.subtractDecl, Primitive.SUB); + elaborateStdPrimRoutine(StdEnvironment.multiplyDecl, Primitive.MULT); + elaborateStdPrimRoutine(StdEnvironment.divideDecl, Primitive.DIV); + elaborateStdPrimRoutine(StdEnvironment.moduloDecl, Primitive.MOD); + elaborateStdPrimRoutine(StdEnvironment.lessDecl, Primitive.LT); + elaborateStdPrimRoutine(StdEnvironment.notgreaterDecl, Primitive.LE); + elaborateStdPrimRoutine(StdEnvironment.greaterDecl, Primitive.GT); + elaborateStdPrimRoutine(StdEnvironment.notlessDecl, Primitive.GE); + elaborateStdPrimRoutine(StdEnvironment.chrDecl, Primitive.ID); + elaborateStdPrimRoutine(StdEnvironment.ordDecl, Primitive.ID); + elaborateStdPrimRoutine(StdEnvironment.eolDecl, Primitive.EOL); + elaborateStdPrimRoutine(StdEnvironment.eofDecl, Primitive.EOF); + elaborateStdPrimRoutine(StdEnvironment.getDecl, Primitive.GET); + elaborateStdPrimRoutine(StdEnvironment.putDecl, Primitive.PUT); + elaborateStdPrimRoutine(StdEnvironment.getintDecl, Primitive.GETINT); + elaborateStdPrimRoutine(StdEnvironment.putintDecl, Primitive.PUTINT); + elaborateStdPrimRoutine(StdEnvironment.geteolDecl, Primitive.GETEOL); + elaborateStdPrimRoutine(StdEnvironment.puteolDecl, Primitive.PUTEOL); + elaborateStdEqRoutine(StdEnvironment.equalDecl, Primitive.EQ); + elaborateStdEqRoutine(StdEnvironment.unequalDecl, Primitive.NE); + } + + boolean tableDetailsReqd; + + public static void writeTableDetails(AbstractSyntaxTree ast) { + } + + // 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. + + private void encodeStore(Vname V, Frame frame, int valSize) { + + var baseObject = (AddressableEntity) V.visit(this, frame); + // If indexed = true, code will have been generated to load an index value. + if (valSize > 255) { + reporter.reportRestriction("can't store values larger than 255 words"); + valSize = 255; // to allow code generation to continue + } + + baseObject.encodeStore(emitter, frame, valSize, V); + } + + // 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 + // the constant or variable is fetched at run-time. + // valSize is the size of the constant or variable's value. + + private void encodeFetch(Vname V, Frame frame, int valSize) { + + var baseObject = (FetchableEntity) V.visit(this, frame); + // If indexed = true, code will have been generated to load an index value. + if (valSize > 255) { + reporter.reportRestriction("can't load values larger than 255 words"); + valSize = 255; // to allow code generation to continue + } + + baseObject.encodeFetch(emitter, frame, valSize, V); + } + + // Generates code to compute and push the address of a named variable. + // vname is the program phrase that names this variable. + // currentLevel is the routine level where the vname occurs. + // frameSize is the anticipated size of the local stack frame when + // the variable is addressed at run-time. + + private void encodeFetchAddress(Vname V, Frame frame) { + + var baseObject = (AddressableEntity) V.visit(this, frame); + baseObject.encodeFetchAddress(emitter, frame, V); + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/Frame.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/Frame.java new file mode 100644 index 0000000..5aba4e4 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/Frame.java @@ -0,0 +1,73 @@ +/* + * @(#)Frame.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator; + +import triangle.abstractMachine.Register; +import triangle.codeGenerator.entities.ObjectAddress; + +public class Frame { + + public static final Frame Initial = new Frame(0, 0); + + private final int level; + + private final int size; + + private Frame(int level, int size) { + this.level = level; + this.size = size; + } + + public final int getLevel() { + return level; + } + + public final int getSize() { + return size; + } + + public Frame expand(int increment) { + return new Frame(level, size + increment); + } + + public Frame replace(int size) { + return new Frame(level, size); + } + + public Frame push(int size) { + return new Frame(level + 1, size); + } + + /** + * Returns the display register appropriate for object code at the current + * static level to access a data object at the static level of the given + * address. + * + * @param address the address of the data object + * @return the display register required for static addressing + */ + public Register getDisplayRegister(ObjectAddress address) { + if (address.getLevel() == 0) { + return Register.SB; + } + + if (level - address.getLevel() <= 6) { + return Register.values()[Register.LB.ordinal() + level - address.getLevel()]; // LB|L1|...|L6 + } + + // _errorReporter.ReportRestriction("can't access data more than 6 levels out"); + return Register.L6; // to allow code generation to continue + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/AddressableEntity.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/AddressableEntity.java new file mode 100644 index 0000000..3896e32 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/AddressableEntity.java @@ -0,0 +1,29 @@ +package triangle.codeGenerator.entities; + +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public abstract class AddressableEntity extends RuntimeEntity implements FetchableEntity { + + protected final ObjectAddress address; + + protected AddressableEntity(int size, int level, int displacement) { + super(size); + address = new ObjectAddress(level, displacement); + } + + protected AddressableEntity(int size, Frame frame) { + this(size, frame.getLevel(), frame.getSize()); + } + + public ObjectAddress getAddress() { + return address; + } + + public abstract void encodeStore(Emitter emitter, Frame frame, int size, Vname vname); + + public abstract void encodeFetchAddress(Emitter emitter, Frame frame, Vname vname); + + public abstract void encodeFetch(Emitter emitter, Frame frame, int size, Vname vname); +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/EqualityRoutine.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/EqualityRoutine.java new file mode 100644 index 0000000..6c86baf --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/EqualityRoutine.java @@ -0,0 +1,46 @@ +/* + * @(#)EqualityRoutine.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class EqualityRoutine extends RuntimeEntity implements RoutineEntity { + + private final Primitive primitive; + + public EqualityRoutine(int size, Primitive primitive) { + super(size); + this.primitive = primitive; + } + + public final Primitive getPrimitive() { + return primitive; + } + + public void encodeCall(Emitter emitter, Frame frame) { + emitter.emit(OpCode.LOADL, frame.getSize() / 2); + emitter.emit(OpCode.CALL, Register.PB, primitive); + } + + public void encodeFetch(Emitter emitter, Frame frame) { + emitter.emit(OpCode.LOADA, 0, Register.SB, 0); + emitter.emit(OpCode.LOADA, Register.PB, primitive); + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/FetchableEntity.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/FetchableEntity.java new file mode 100644 index 0000000..1e4194c --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/FetchableEntity.java @@ -0,0 +1,11 @@ +package triangle.codeGenerator.entities; + +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public interface FetchableEntity { + + void encodeFetch(Emitter emitter, Frame frame, int size, Vname vname); + +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/Field.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/Field.java new file mode 100644 index 0000000..2354136 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/Field.java @@ -0,0 +1,29 @@ +/* + * @(#)Field.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +public class Field extends RuntimeEntity { + + private final int fieldOffset; + + public Field(int size, int fieldOffset) { + super(size); + this.fieldOffset = fieldOffset; + } + + public final int getFieldOffset() { + return fieldOffset; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownAddress.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownAddress.java new file mode 100644 index 0000000..e62879e --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownAddress.java @@ -0,0 +1,62 @@ +/* + * @(#)KnownAddress.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class KnownAddress extends AddressableEntity { + + public KnownAddress(int size, int level, int displacement) { + super(size, level, displacement); + } + + public KnownAddress(int size, Frame frame) { + super(size, frame); + } + + public void encodeStore(Emitter emitter, Frame frame, int size, Vname vname) { + if (vname.indexed) { + emitter.emit(OpCode.LOADA, 0, frame.getDisplayRegister(address), address.getDisplacement() + vname.offset); + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + emitter.emit(OpCode.STOREI, size, 0); + } else { + emitter.emit(OpCode.STORE, size, frame.getDisplayRegister(address), + address.getDisplacement() + vname.offset); + } + } + + public void encodeFetch(Emitter emitter, Frame frame, int size, Vname vname) { + if (vname.indexed) { + emitter.emit(OpCode.LOADA, 0, frame.getDisplayRegister(address), address.getDisplacement() + vname.offset); + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + emitter.emit(OpCode.LOADI, size, 0); + } else { + emitter.emit(OpCode.LOAD, size, frame.getDisplayRegister(address), + address.getDisplacement() + vname.offset); + } + } + + public void encodeFetchAddress(Emitter emitter, Frame frame, Vname vname) { + emitter.emit(OpCode.LOADA, 0, frame.getDisplayRegister(address), address.getDisplacement() + vname.offset); + if (vname.indexed) { + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + } +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownRoutine.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownRoutine.java new file mode 100644 index 0000000..4adca41 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownRoutine.java @@ -0,0 +1,44 @@ +/* + * @(#)KnownRoutine.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Register; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class KnownRoutine extends RuntimeEntity implements RoutineEntity { + + private final ObjectAddress address; + + public KnownRoutine(int size, int level, int displacement) { + super(size); + address = new ObjectAddress(level, displacement); + } + + public final ObjectAddress getAddress() { + return address; + } + + public void encodeCall(Emitter emitter, Frame frame) { + emitter.emit(OpCode.CALL, frame.getDisplayRegister(address), Register.CB, address.getDisplacement()); + } + + public void encodeFetch(Emitter emitter, Frame frame) { + emitter.emit(OpCode.LOADA, frame.getDisplayRegister(address), 0); + emitter.emit(OpCode.LOADA, Register.CB, address.getDisplacement()); + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownValue.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownValue.java new file mode 100644 index 0000000..af24be5 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/KnownValue.java @@ -0,0 +1,39 @@ +/* + * @(#)KnownValue.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.OpCode; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class KnownValue extends RuntimeEntity implements FetchableEntity { + + private final int value; + + public KnownValue(int size, int value) { + super(size); + this.value = value; + } + + public final int getValue() { + return value; + } + + public void encodeFetch(Emitter emitter, Frame frame, int size, Vname vname) { + // presumably offset = 0 and indexed = false + emitter.emit(OpCode.LOADL, 0, value); + } +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/ObjectAddress.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/ObjectAddress.java new file mode 100644 index 0000000..7440c68 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/ObjectAddress.java @@ -0,0 +1,35 @@ +/* + * @(#)ObjectAddress.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +public class ObjectAddress { + + private final int level; + + private final int displacement; + + public ObjectAddress(int level, int displacement) { + this.level = level; + this.displacement = displacement; + } + + public final int getLevel() { + return level; + } + + public int getDisplacement() { + return displacement; + } +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/PrimitiveRoutine.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/PrimitiveRoutine.java new file mode 100644 index 0000000..4cf3237 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/PrimitiveRoutine.java @@ -0,0 +1,47 @@ +/* + * @(#)PrimitiveRoutine.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class PrimitiveRoutine extends RuntimeEntity implements RoutineEntity { + + private final Primitive primitive; + + public PrimitiveRoutine(int size, Primitive primitive) { + super(size); + this.primitive = primitive; + } + + public final Primitive getPrimitive() { + return primitive; + } + + public void encodeCall(Emitter emitter, Frame frame) { + if (primitive != Primitive.ID) { + emitter.emit(OpCode.CALL, Register.PB, primitive); + } + } + + public void encodeFetch(Emitter emitter, Frame frame) { + emitter.emit(OpCode.LOADA, 0, Register.SB, 0); + emitter.emit(OpCode.LOADA, Register.PB, primitive); + } + +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RoutineEntity.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RoutineEntity.java new file mode 100644 index 0000000..386aef5 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RoutineEntity.java @@ -0,0 +1,11 @@ +package triangle.codeGenerator.entities; + +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public interface RoutineEntity { + + void encodeCall(Emitter emitter, Frame frame); + + void encodeFetch(Emitter emitter, Frame frame); +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RuntimeEntity.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RuntimeEntity.java new file mode 100644 index 0000000..14540ee --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/RuntimeEntity.java @@ -0,0 +1,30 @@ +/* + * @(#)RuntimeEntity.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +// Run-time object + +public abstract class RuntimeEntity { + + private final int size; + + protected RuntimeEntity(int size) { + this.size = size; + } + + public final int getSize() { + return size; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/TypeRepresentation.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/TypeRepresentation.java new file mode 100644 index 0000000..1827025 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/TypeRepresentation.java @@ -0,0 +1,23 @@ +/* + * @(#)TypeRepresentation.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +public class TypeRepresentation extends RuntimeEntity { + + public TypeRepresentation(int size) { + super(size); + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownAddress.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownAddress.java new file mode 100644 index 0000000..af45996 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownAddress.java @@ -0,0 +1,74 @@ +/* + * @(#)UnknownAddress.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.Machine; +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class UnknownAddress extends AddressableEntity { + + public UnknownAddress(int size, int level, int displacement) { + super(size, level, displacement); + } + + public void encodeStore(Emitter emitter, Frame frame, int size, Vname vname) { + + emitter.emit(OpCode.LOAD, Machine.addressSize, frame.getDisplayRegister(address), address.getDisplacement()); + if (vname.indexed) { + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + + int offset = vname.offset; + if (offset != 0) { + emitter.emit(OpCode.LOADL, 0, offset); + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + emitter.emit(OpCode.STOREI, size, 0); + } + + public void encodeFetch(Emitter emitter, Frame frame, int size, Vname vname) { + emitter.emit(OpCode.LOAD, Machine.addressSize, frame.getDisplayRegister(address), address.getDisplacement()); + + if (vname.indexed) { + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + + int offset = vname.offset; + if (offset != 0) { + emitter.emit(OpCode.LOADL, offset); + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + emitter.emit(OpCode.LOADI, size); + } + + public void encodeFetchAddress(Emitter emitter, Frame frame, Vname vname) { + + emitter.emit(OpCode.LOAD, Machine.addressSize, frame.getDisplayRegister(address), address.getDisplacement()); + if (vname.indexed) { + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + + int offset = vname.offset; + if (offset != 0) { + emitter.emit(OpCode.LOADL, offset); + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + } + } +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownRoutine.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownRoutine.java new file mode 100644 index 0000000..bb7fe26 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownRoutine.java @@ -0,0 +1,44 @@ +/* + * @(#)UnknownRoutine.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.Machine; +import triangle.abstractMachine.OpCode; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class UnknownRoutine extends RuntimeEntity implements RoutineEntity { + + private final ObjectAddress address; + + public UnknownRoutine(int size, int level, int displacement) { + super(size); + address = new ObjectAddress(level, displacement); + } + + public final ObjectAddress getAddress() { + return address; + } + + public void encodeCall(Emitter emitter, Frame frame) { + emitter.emit(OpCode.LOAD, Machine.closureSize, frame.getDisplayRegister(address), address.getDisplacement()); + emitter.emit(OpCode.CALLI, 0); + } + + public void encodeFetch(Emitter emitter, Frame frame) { + emitter.emit(OpCode.LOAD, Machine.closureSize, frame.getDisplayRegister(address), address.getDisplacement()); + } + +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownValue.java b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownValue.java new file mode 100644 index 0000000..7f4442f --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/codeGenerator/entities/UnknownValue.java @@ -0,0 +1,51 @@ +/* + * @(#)UnknownValue.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.codeGenerator.entities; + +import triangle.abstractMachine.OpCode; +import triangle.abstractMachine.Primitive; +import triangle.abstractMachine.Register; +import triangle.abstractSyntaxTrees.vnames.Vname; +import triangle.codeGenerator.Emitter; +import triangle.codeGenerator.Frame; + +public class UnknownValue extends RuntimeEntity implements FetchableEntity { + + private final ObjectAddress address; + + public UnknownValue(int size, int level, int displacement) { + super(size); + address = new ObjectAddress(level, displacement); + } + + public UnknownValue(int size, Frame frame) { + this(size, frame.getLevel(), frame.getSize()); + } + + public final ObjectAddress getAddress() { + return address; + } + + public void encodeFetch(Emitter emitter, Frame frame, int size, Vname vname) { + if (vname.indexed) { + emitter.emit(OpCode.LOADA, 0, frame.getDisplayRegister(address), address.getDisplacement() + vname.offset); + emitter.emit(OpCode.CALL, Register.PB, Primitive.ADD); + emitter.emit(OpCode.LOADI, size, 0); + } else { + emitter.emit(OpCode.LOAD, size, frame.getDisplayRegister(address), + address.getDisplacement() + vname.offset); + } + } +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/Checker.java b/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/Checker.java new file mode 100644 index 0000000..863b992 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/Checker.java @@ -0,0 +1,980 @@ +/* + * @(#)Checker.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.contextualAnalyzer; + +import triangle.ErrorReporter; +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.SequentialCommand; +import triangle.abstractSyntaxTrees.commands.WhileCommand; +import triangle.abstractSyntaxTrees.declarations.BinaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; +import triangle.abstractSyntaxTrees.declarations.ConstantDeclaration; +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.declarations.FuncDeclaration; +import triangle.abstractSyntaxTrees.declarations.FunctionDeclaration; +import triangle.abstractSyntaxTrees.declarations.ProcDeclaration; +import triangle.abstractSyntaxTrees.declarations.ProcedureDeclaration; +import triangle.abstractSyntaxTrees.declarations.SequentialDeclaration; +import triangle.abstractSyntaxTrees.declarations.UnaryOperatorDeclaration; +import triangle.abstractSyntaxTrees.declarations.VarDeclaration; +import triangle.abstractSyntaxTrees.declarations.VariableDeclaration; +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.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.FormalParameter; +import triangle.abstractSyntaxTrees.formals.FormalParameterSequence; +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.terminals.Terminal; +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.FieldTypeDenoter; +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.types.TypeDenoter; +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.syntacticAnalyzer.SourcePosition; + +public final class Checker implements ActualParameterVisitor, + ActualParameterSequenceVisitor, ArrayAggregateVisitor, + CommandVisitor, DeclarationVisitor, ExpressionVisitor, + FormalParameterSequenceVisitor, IdentifierVisitor, + LiteralVisitor, OperatorVisitor, ProgramVisitor, + RecordAggregateVisitor, TypeDenoterVisitor, + VnameVisitor { + + // Commands + + // Always returns null. Does not use the given object. + + @Override + public Void visitAssignCommand(AssignCommand ast, Void arg) { + var vType = ast.V.visit(this); + var eType = ast.E.visit(this); + + checkAndReportError(ast.V.variable, "LHS of assignment is not a variable", ast.V); + checkAndReportError(eType.equals(vType), "assignment incompatibilty", ast); + + return null; + } + + @Override + public Void visitCallCommand(CallCommand ast, Void arg) { + var binding = ast.I.visit(this); + + if (binding instanceof ProcedureDeclaration) { + ProcedureDeclaration procedure = (ProcedureDeclaration)binding; + ast.APS.visit(this, procedure.getFormals()); + } else { + reportUndeclaredOrError(binding, ast.I, "\"%\" is not a procedure identifier"); + } + + return null; + } + + @Override + public Void visitEmptyCommand(EmptyCommand ast, Void arg) { + return null; + } + + @Override + public Void visitIfCommand(IfCommand ast, Void arg) { + var eType = ast.E.visit(this); + + checkAndReportError(eType.equals(StdEnvironment.booleanType), "Boolean expression expected here", ast.E); + + ast.C1.visit(this); + ast.C2.visit(this); + + return null; + } + + @Override + public Void visitLetCommand(LetCommand ast, Void arg) { + idTable.openScope(); + ast.D.visit(this); + ast.C.visit(this); + idTable.closeScope(); + return null; + } + + @Override + public Void visitSequentialCommand(SequentialCommand ast, Void arg) { + ast.C1.visit(this); + ast.C2.visit(this); + return null; + } + + @Override + public Void visitWhileCommand(WhileCommand 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 + + // Returns the TypeDenoter denoting the type of the expression. Does + // not use the given object. + + @Override + public TypeDenoter visitArrayExpression(ArrayExpression ast, Void arg) { + var elemType = ast.AA.visit(this); + var il = new IntegerLiteral(Integer.toString(ast.AA.elemCount), ast.getPosition()); + ast.type = new ArrayTypeDenoter(il, elemType, ast.getPosition()); + return ast.type; + } + + @Override + public TypeDenoter visitBinaryExpression(BinaryExpression ast, Void arg) { + var e1Type = ast.E1.visit(this); + var e2Type = ast.E2.visit(this); + var binding = ast.O.visit(this); + + 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); + } else { + checkAndReportError(e1Type.equals(bbinding.ARG1), "wrong argument type for \"%\"", ast.O, ast.E1); + checkAndReportError(e2Type.equals(bbinding.ARG2), "wrong argument type for \"%\"", ast.O, ast.E2); + } + return ast.type = bbinding.RES; + } + + reportUndeclaredOrError(binding, ast.O, "\"%\" is not a binary operator"); + return ast.type = StdEnvironment.errorType; + } + + @Override + public TypeDenoter visitCallExpression(CallExpression ast, Void arg) { + var binding = ast.I.visit(this); + + if (binding instanceof FunctionDeclaration) { + FunctionDeclaration function = (FunctionDeclaration)binding; + ast.APS.visit(this, function.getFormals()); + return ast.type = function.getType(); + } + + reportUndeclaredOrError(binding, ast.I, "\"%\" is not a function identifier"); + return ast.type = StdEnvironment.errorType; + } + + @Override + public TypeDenoter visitCharacterExpression(CharacterExpression ast, Void arg) { + return ast.type = StdEnvironment.charType; + } + + @Override + public TypeDenoter visitEmptyExpression(EmptyExpression ast, Void arg) { + return ast.type = null; + } + + @Override + public TypeDenoter visitIfExpression(IfExpression ast, Void arg) { + var e1Type = ast.E1.visit(this); + checkAndReportError(e1Type.equals(StdEnvironment.booleanType), "Boolean expression expected here", ast.E1); + + var e2Type = ast.E2.visit(this); + var e3Type = ast.E3.visit(this); + checkAndReportError(e2Type.equals(e3Type), "incompatible limbs in if-expression", ast); + return ast.type = e2Type; + } + + @Override + public TypeDenoter visitIntegerExpression(IntegerExpression ast, Void arg) { + return ast.type = StdEnvironment.integerType; + } + + @Override + public TypeDenoter visitLetExpression(LetExpression ast, Void arg) { + idTable.openScope(); + ast.D.visit(this); + ast.type = ast.E.visit(this); + idTable.closeScope(); + return ast.type; + } + + @Override + public TypeDenoter visitRecordExpression(RecordExpression ast, Void arg) { + var rType = ast.RA.visit(this); + return ast.type = new RecordTypeDenoter(rType, ast.getPosition()); + } + + @Override + public TypeDenoter visitUnaryExpression(UnaryExpression ast, Void arg) { + var eType = ast.E.visit(this); + var binding = ast.O.visit(this); + + if (binding instanceof UnaryOperatorDeclaration) { + UnaryOperatorDeclaration ubinding = (UnaryOperatorDeclaration)binding; + checkAndReportError(eType.equals(ubinding.ARG), "wrong argument type for \"%\"", ast.O); + return ast.type = ubinding.RES; + } + + reportUndeclaredOrError(binding, ast.O, "\"%\" is not a unary operator"); + return ast.type = StdEnvironment.errorType; + } + + @Override + public TypeDenoter visitVnameExpression(VnameExpression ast, Void arg) { + return ast.type = ast.V.visit(this); + } + + // Declarations + + // Always returns null. Does not use the given object. + @Override + public Void visitBinaryOperatorDeclaration(BinaryOperatorDeclaration ast, Void arg) { + return null; + } + + @Override + public Void visitConstDeclaration(ConstDeclaration ast, Void arg) { + ast.E.visit(this); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast); + return null; + } + + @Override + public Void visitFuncDeclaration(FuncDeclaration ast, Void arg) { + ast.T = ast.T.visit(this); + // permits recursion + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast); + + idTable.openScope(); + ast.FPS.visit(this); + var eType = ast.E.visit(this); + idTable.closeScope(); + + checkAndReportError(ast.T.equals(eType), "body of function \"%\" has wrong type", ast.I, ast.E); + return null; + } + + @Override + public Void visitProcDeclaration(ProcDeclaration ast, Void arg) { + // permits recursion + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast); + + idTable.openScope(); + ast.FPS.visit(this); + ast.C.visit(this); + idTable.closeScope(); + + return null; + } + + @Override + public Void visitSequentialDeclaration(SequentialDeclaration ast, Void arg) { + ast.D1.visit(this); + ast.D2.visit(this); + return null; + } + + @Override + public Void visitTypeDeclaration(TypeDeclaration ast, Void arg) { + ast.T = ast.T.visit(this); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast); + return null; + } + + @Override + public Void visitUnaryOperatorDeclaration(UnaryOperatorDeclaration ast, Void arg) { + return null; + } + + @Override + public Void visitVarDeclaration(VarDeclaration ast, Void arg) { + ast.T = ast.T.visit(this); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "identifier \"%\" already declared", ast.I, ast); + return null; + } + + // Array Aggregates + + // Returns the TypeDenoter for the Array Aggregate. Does not use the + // given object. + + @Override + public TypeDenoter visitMultipleArrayAggregate(MultipleArrayAggregate ast, Void arg) { + var eType = ast.E.visit(this); + var elemType = ast.AA.visit(this); + ast.elemCount = ast.AA.elemCount + 1; + checkAndReportError(eType.equals(elemType), "incompatible array-aggregate element", ast.E); + return elemType; + } + + @Override + public TypeDenoter visitSingleArrayAggregate(SingleArrayAggregate ast, Void arg) { + var elemType = ast.E.visit(this); + ast.elemCount = 1; + return elemType; + } + + // Record Aggregates + + // Returns the TypeDenoter for the Record Aggregate. Does not use the + // given object. + + @Override + public FieldTypeDenoter visitMultipleRecordAggregate(MultipleRecordAggregate ast, Void arg) { + var eType = ast.E.visit(this); + var rType = ast.RA.visit(this); + var fType = checkFieldIdentifier(rType, ast.I); + checkAndReportError(fType.equals(StdEnvironment.errorType), "duplicate field \"%\" in record", ast.I); + return ast.type = new MultipleFieldTypeDenoter(ast.I, eType, rType, ast.getPosition()); + } + + @Override + public FieldTypeDenoter visitSingleRecordAggregate(SingleRecordAggregate ast, Void arg) { + var eType = ast.E.visit(this); + return ast.type = new SingleFieldTypeDenoter(ast.I, eType, ast.getPosition()); + } + + // Formal Parameters + + // Always returns null. Does not use the given object. + + @Override + public Void visitConstFormalParameter(ConstFormalParameter ast, Void arg) { + ast.T = ast.T.visit(this); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "duplicated formal parameter \"%\"", ast.I, ast); + return null; + } + + @Override + public Void visitFuncFormalParameter(FuncFormalParameter ast, Void arg) { + idTable.openScope(); + ast.FPS.visit(this); + idTable.closeScope(); + ast.T = ast.T.visit(this); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "duplicated formal parameter \"%\"", ast.I, ast); + return null; + } + + @Override + public Void visitProcFormalParameter(ProcFormalParameter ast, Void arg) { + idTable.openScope(); + ast.FPS.visit(this); + idTable.closeScope(); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "duplicated formal parameter \"%\"", ast.I, ast); + return null; + } + + @Override + public Void visitVarFormalParameter(VarFormalParameter ast, Void arg) { + ast.T = ast.T.visit(this); + idTable.enter(ast.I.spelling, ast); + checkAndReportError(!ast.duplicated, "duplicated formal parameter \"%\"", ast.I, ast); + return null; + } + + @Override + public Void visitEmptyFormalParameterSequence(EmptyFormalParameterSequence ast, Void arg) { + return null; + } + + @Override + public Void visitMultipleFormalParameterSequence(MultipleFormalParameterSequence ast, Void arg) { + ast.FP.visit(this); + ast.FPS.visit(this); + return null; + } + + @Override + public Void visitSingleFormalParameterSequence(SingleFormalParameterSequence ast, Void arg) { + ast.FP.visit(this); + return null; + } + + // Actual Parameters + + // Always returns null. Uses the given FormalParameter. + + @Override + public Void visitConstActualParameter(ConstActualParameter ast, FormalParameter arg) { + var eType = ast.E.visit(this); + 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); + } + return null; + } + + @Override + public Void visitFuncActualParameter(FuncActualParameter ast, FormalParameter arg) { + var binding = ast.I.visit(this); + if (binding instanceof FunctionDeclaration) { + FunctionDeclaration function = (FunctionDeclaration)binding; + var formals = function.getFormals(); + var functionType = function.getType(); + 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)) { + reportError("wrong type for function \"%\"", ast.I); + } + } else { + reportError("func actual parameter not expected here", ast); + } + } else { + reportUndeclaredOrError(binding, ast.I, "\"%\" is not a function identifier"); + } + return null; + } + + @Override + public Void visitProcActualParameter(ProcActualParameter ast, FormalParameter arg) { + var binding = ast.I.visit(this); + if (binding instanceof ProcedureDeclaration) { + ProcedureDeclaration procedure = (ProcedureDeclaration)binding; + var formals = procedure.getFormals(); + 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); + } + } else { + reportUndeclaredOrError(binding, ast.I, "\"%\" is not a procedure identifier"); + } + return null; + } + + @Override + public Void visitVarActualParameter(VarActualParameter ast, FormalParameter arg) { + var vType = ast.V.visit(this); + if (!ast.V.variable) { + reportError("actual parameter is not a variable", ast.V); + } 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); + } + return null; + } + + @Override + public Void visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, FormalParameterSequence arg) { + checkAndReportError(arg instanceof EmptyFormalParameterSequence, "too few actual parameters", ast); + return null; + } + + @Override + public Void visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, FormalParameterSequence arg) { + if (arg instanceof MultipleFormalParameterSequence) { + MultipleFormalParameterSequence formals = (MultipleFormalParameterSequence)arg; + ast.AP.visit(this, formals.FP); + ast.APS.visit(this, formals.FPS); + } else { + reportError("too many actual parameters", ast); + } + return null; + } + + @Override + public Void visitSingleActualParameterSequence(SingleActualParameterSequence ast, FormalParameterSequence arg) { + if (arg instanceof SingleFormalParameterSequence) { + SingleFormalParameterSequence formal = (SingleFormalParameterSequence)arg; + ast.AP.visit(this, formal.FP); + } else { + reportError("incorrect number of actual parameters", ast); + } + return null; + } + + // Type Denoters + + // Returns the expanded version of the TypeDenoter. Does not + // use the given object. + + @Override + public TypeDenoter visitAnyTypeDenoter(AnyTypeDenoter ast, Void arg) { + return StdEnvironment.anyType; + } + + @Override + public TypeDenoter visitArrayTypeDenoter(ArrayTypeDenoter ast, Void arg) { + ast.T = ast.T.visit(this); + checkAndReportError(ast.IL.getValue() != 0, "arrays must not be empty", ast.IL); + return ast; + } + + @Override + public TypeDenoter visitBoolTypeDenoter(BoolTypeDenoter ast, Void arg) { + return StdEnvironment.booleanType; + } + + @Override + public TypeDenoter visitCharTypeDenoter(CharTypeDenoter ast, Void arg) { + return StdEnvironment.charType; + } + + @Override + public TypeDenoter visitErrorTypeDenoter(ErrorTypeDenoter ast, Void arg) { + return StdEnvironment.errorType; + } + + @Override + public TypeDenoter visitSimpleTypeDenoter(SimpleTypeDenoter ast, Void arg) { + var binding = ast.I.visit(this); + if (binding instanceof TypeDeclaration) { + TypeDeclaration decl = (TypeDeclaration)binding; + return decl.T; + } + + reportUndeclaredOrError(binding, ast.I, "\"%\" is not a type identifier"); + return StdEnvironment.errorType; + } + + @Override + public TypeDenoter visitIntTypeDenoter(IntTypeDenoter ast, Void arg) { + return StdEnvironment.integerType; + } + + @Override + public TypeDenoter visitRecordTypeDenoter(RecordTypeDenoter ast, Void arg) { + ast.FT = (FieldTypeDenoter) ast.FT.visit(this); + return ast; + } + + @Override + public TypeDenoter visitMultipleFieldTypeDenoter(MultipleFieldTypeDenoter ast, Void arg) { + ast.T = ast.T.visit(this); + ast.FT.visit(this); + return ast; + } + + @Override + public TypeDenoter visitSingleFieldTypeDenoter(SingleFieldTypeDenoter ast, Void arg) { + ast.T = ast.T.visit(this); + return ast; + } + + // Literals, Identifiers and Operators + @Override + public TypeDenoter visitCharacterLiteral(CharacterLiteral CL, Void arg) { + return StdEnvironment.charType; + } + + @Override + public Declaration visitIdentifier(Identifier I, Void arg) { + var binding = idTable.retrieve(I.spelling); + if (binding != null) { + I.decl = binding; + } + return binding; + } + + @Override + public TypeDenoter visitIntegerLiteral(IntegerLiteral IL, Void arg) { + return StdEnvironment.integerType; + } + + @Override + public Declaration visitOperator(Operator O, Void arg) { + var binding = idTable.retrieve(O.spelling); + if (binding != null) { + O.decl = binding; + } + return binding; + } + + // Value-or-variable names + + // Determines the address of a named object (constant or variable). + // This consists of a base object, to which 0 or more field-selection + // or array-indexing operations may be applied (if it is a record or + // array). As much as possible of the address computation is done at + // compile-time. Code is generated only when necessary to evaluate + // index expressions at run-time. + // currentLevel is the routine level where the v-name occurs. + // frameSize is the anticipated size of the local stack frame when + // the object is addressed at run-time. + // It returns the description of the base object. + // offset is set to the total of any field offsets (plus any offsets + // due to index expressions that happen to be literals). + // indexed is set to true iff there are any index expressions (other + // than literals). In that case code is generated to compute the + // offset due to these indexing operations at run-time. + + // Returns the TypeDenoter of the Vname. Does not use the + // given object. + + @Override + public TypeDenoter visitDotVname(DotVname ast, Void arg) { + ast.type = null; + var vType = ast.V.visit(this); + ast.variable = ast.V.variable; + 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); + } else { + reportError("record expected here", ast.V); + } + return ast.type; + } + + @Override + public TypeDenoter visitSimpleVname(SimpleVname ast, Void arg) { + ast.variable = false; + ast.type = StdEnvironment.errorType; + + var binding = ast.I.visit(this); + if (binding instanceof ConstantDeclaration) { + ConstantDeclaration constant = (ConstantDeclaration)binding; + ast.variable = false; + return ast.type = constant.getType(); + } else if (binding instanceof VariableDeclaration) { + VariableDeclaration variable = (VariableDeclaration)binding; + ast.variable = true; + return ast.type = variable.getType(); + } + + reportUndeclaredOrError(binding, ast.I, "\"%\" is not a const or var identifier"); + return ast.type = StdEnvironment.errorType; + } + + @Override + public TypeDenoter visitSubscriptVname(SubscriptVname ast, Void arg) { + var vType = ast.V.visit(this); + ast.variable = ast.V.variable; + + var eType = ast.E.visit(this); + if (vType != StdEnvironment.errorType) { + if (vType instanceof ArrayTypeDenoter) { + ArrayTypeDenoter arrayType = (ArrayTypeDenoter)vType; + checkAndReportError(eType.equals(StdEnvironment.integerType), "Integer expression expected here", + ast.E); + ast.type = arrayType.T; + } else { + reportError("array expected here", ast.V); + } + } + + return ast.type; + } + + // Programs + + @Override + public Void visitProgram(Program ast, Void arg) { + ast.C.visit(this); + return null; + } + + // Checks whether the source program, represented by its AST, satisfies the + // language's scope rules and type rules. + // Also decorates the AST as follows: + // (a) Each applied occurrence of an identifier or operator is linked to + // the corresponding declaration of that identifier or operator. + // (b) Each expression and value-or-variable-name is decorated by its type. + // (c) Each type identifier is replaced by the type it denotes. + // Types are represented by small ASTs. + + public void check(Program ast) { + ast.visit(this); + } + + ///////////////////////////////////////////////////////////////////////////// + + public Checker(ErrorReporter reporter) { + this.reporter = reporter; + this.idTable = new IdentificationTable(); + establishStdEnvironment(); + } + + private IdentificationTable idTable; + private static SourcePosition dummyPos = new SourcePosition(); + private ErrorReporter reporter; + + private void reportUndeclaredOrError(Declaration binding, Terminal leaf, String message) { + if (binding == null) { + reportError("\"%\" is not declared", leaf); + } else { + reportError(message, leaf); + } + } + + private void reportError(String message, Terminal ast) { + reportError(message, ast, ast); + } + + private void reportError(String message, Terminal spellingNode, AbstractSyntaxTree positionNode) { + reporter.reportError(message, spellingNode.spelling, positionNode.getPosition()); + } + + private void reportError(String message, AbstractSyntaxTree positionNode) { + reporter.reportError(message, "", positionNode.getPosition()); + } + + private void checkAndReportError(boolean condition, String message, String token, SourcePosition position) { + if (!condition) { + reporter.reportError(message, token, position); + } + } + + private void checkAndReportError(boolean condition, String message, Terminal ast) { + checkAndReportError(condition, message, ast, ast); + } + + private void checkAndReportError(boolean condition, String message, Terminal spellingNode, + AbstractSyntaxTree positionNode) { + checkAndReportError(condition, message, spellingNode.spelling, positionNode.getPosition()); + } + + private void checkAndReportError(boolean condition, String message, AbstractSyntaxTree positionNode) { + checkAndReportError(condition, message, "", positionNode.getPosition()); + } + + private static TypeDenoter checkFieldIdentifier(FieldTypeDenoter ast, Identifier I) { + 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) { + SingleFieldTypeDenoter ft = (SingleFieldTypeDenoter)ast; + if (ft.I.spelling.compareTo(I.spelling) == 0) { + I.decl = ast; + return ft.T; + } + } + return StdEnvironment.errorType; + } + + // Creates a small AST to represent the "declaration" of a standard + // type, and enters it in the identification table. + + private TypeDeclaration declareStdType(String id, TypeDenoter typedenoter) { + + var binding = new TypeDeclaration(new Identifier(id, dummyPos), typedenoter, dummyPos); + idTable.enter(id, binding); + return binding; + } + + // Creates a small AST to represent the "declaration" of a standard + // type, and enters it in the identification table. + + private ConstDeclaration declareStdConst(String id, TypeDenoter constType) { + + // constExpr used only as a placeholder for constType + var constExpr = new IntegerExpression(null, dummyPos); + constExpr.type = constType; + var binding = new ConstDeclaration(new Identifier(id, dummyPos), constExpr, dummyPos); + idTable.enter(id, binding); + return binding; + } + + // Creates a small AST to represent the "declaration" of a standard + // type, and enters it in the identification table. + + private ProcDeclaration declareStdProc(String id, FormalParameterSequence fps) { + + var binding = new ProcDeclaration(new Identifier(id, dummyPos), fps, new EmptyCommand(dummyPos), dummyPos); + idTable.enter(id, binding); + return binding; + } + + // Creates a small AST to represent the "declaration" of a standard + // type, and enters it in the identification table. + + private FuncDeclaration declareStdFunc(String id, FormalParameterSequence fps, TypeDenoter resultType) { + + var binding = new FuncDeclaration(new Identifier(id, dummyPos), fps, resultType, new EmptyExpression(dummyPos), + dummyPos); + idTable.enter(id, binding); + return binding; + } + + // Creates a small AST to represent the "declaration" of a + // unary operator, and enters it in the identification table. + // This "declaration" summarises the operator's type info. + + private UnaryOperatorDeclaration declareStdUnaryOp(String op, TypeDenoter argType, TypeDenoter resultType) { + + var binding = new UnaryOperatorDeclaration(new Operator(op, dummyPos), argType, resultType, dummyPos); + idTable.enter(op, binding); + return binding; + } + + // Creates a small AST to represent the "declaration" of a + // binary operator, and enters it in the identification table. + // This "declaration" summarises the operator's type info. + + private BinaryOperatorDeclaration declareStdBinaryOp(String op, TypeDenoter arg1Type, TypeDenoter arg2type, + TypeDenoter resultType) { + + var binding = new BinaryOperatorDeclaration(new Operator(op, dummyPos), arg1Type, arg2type, resultType, + dummyPos); + idTable.enter(op, binding); + return binding; + } + + // Creates small ASTs to represent the standard types. + // Creates small ASTs to represent "declarations" of standard types, + // constants, procedures, functions, and operators. + // Enters these "declarations" in the identification table. + + private final static Identifier dummyI = new Identifier("", dummyPos); + + private void establishStdEnvironment() { + + // idTable.startIdentification(); + StdEnvironment.booleanType = new BoolTypeDenoter(dummyPos); + StdEnvironment.integerType = new IntTypeDenoter(dummyPos); + StdEnvironment.charType = new CharTypeDenoter(dummyPos); + StdEnvironment.anyType = new AnyTypeDenoter(dummyPos); + StdEnvironment.errorType = new ErrorTypeDenoter(dummyPos); + + StdEnvironment.booleanDecl = declareStdType("Boolean", StdEnvironment.booleanType); + StdEnvironment.falseDecl = declareStdConst("false", StdEnvironment.booleanType); + StdEnvironment.trueDecl = declareStdConst("true", StdEnvironment.booleanType); + StdEnvironment.notDecl = declareStdUnaryOp("\\", StdEnvironment.booleanType, StdEnvironment.booleanType); + StdEnvironment.andDecl = declareStdBinaryOp("/\\", StdEnvironment.booleanType, StdEnvironment.booleanType, + StdEnvironment.booleanType); + StdEnvironment.orDecl = declareStdBinaryOp("\\/", StdEnvironment.booleanType, StdEnvironment.booleanType, + StdEnvironment.booleanType); + + StdEnvironment.integerDecl = declareStdType("Integer", StdEnvironment.integerType); + StdEnvironment.maxintDecl = declareStdConst("maxint", StdEnvironment.integerType); + StdEnvironment.addDecl = declareStdBinaryOp("+", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.integerType); + StdEnvironment.subtractDecl = declareStdBinaryOp("-", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.integerType); + StdEnvironment.multiplyDecl = declareStdBinaryOp("*", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.integerType); + StdEnvironment.divideDecl = declareStdBinaryOp("/", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.integerType); + StdEnvironment.moduloDecl = declareStdBinaryOp("//", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.integerType); + StdEnvironment.lessDecl = declareStdBinaryOp("<", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.booleanType); + StdEnvironment.notgreaterDecl = declareStdBinaryOp("<=", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.booleanType); + StdEnvironment.greaterDecl = declareStdBinaryOp(">", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.booleanType); + StdEnvironment.notlessDecl = declareStdBinaryOp(">=", StdEnvironment.integerType, StdEnvironment.integerType, + StdEnvironment.booleanType); + + StdEnvironment.charDecl = declareStdType("Char", StdEnvironment.charType); + StdEnvironment.chrDecl = declareStdFunc("chr", + new SingleFormalParameterSequence( + new ConstFormalParameter(dummyI, StdEnvironment.integerType, dummyPos), dummyPos), + StdEnvironment.charType); + StdEnvironment.ordDecl = declareStdFunc("ord", + new SingleFormalParameterSequence(new ConstFormalParameter(dummyI, StdEnvironment.charType, dummyPos), + dummyPos), + StdEnvironment.integerType); + StdEnvironment.eofDecl = declareStdFunc("eof", new EmptyFormalParameterSequence(dummyPos), + StdEnvironment.booleanType); + StdEnvironment.eolDecl = declareStdFunc("eol", new EmptyFormalParameterSequence(dummyPos), + StdEnvironment.booleanType); + StdEnvironment.getDecl = declareStdProc("get", new SingleFormalParameterSequence( + new VarFormalParameter(dummyI, StdEnvironment.charType, dummyPos), dummyPos)); + StdEnvironment.putDecl = declareStdProc("put", new SingleFormalParameterSequence( + new ConstFormalParameter(dummyI, StdEnvironment.charType, dummyPos), dummyPos)); + StdEnvironment.getintDecl = declareStdProc("getint", new SingleFormalParameterSequence( + new VarFormalParameter(dummyI, StdEnvironment.integerType, dummyPos), dummyPos)); + StdEnvironment.putintDecl = declareStdProc("putint", new SingleFormalParameterSequence( + new ConstFormalParameter(dummyI, StdEnvironment.integerType, dummyPos), dummyPos)); + StdEnvironment.geteolDecl = declareStdProc("geteol", new EmptyFormalParameterSequence(dummyPos)); + StdEnvironment.puteolDecl = declareStdProc("puteol", new EmptyFormalParameterSequence(dummyPos)); + StdEnvironment.equalDecl = declareStdBinaryOp("=", StdEnvironment.anyType, StdEnvironment.anyType, + StdEnvironment.booleanType); + StdEnvironment.unequalDecl = declareStdBinaryOp("\\=", StdEnvironment.anyType, StdEnvironment.anyType, + StdEnvironment.booleanType); + + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdEntry.java b/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdEntry.java new file mode 100644 index 0000000..7e6a153 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdEntry.java @@ -0,0 +1,33 @@ +/* + * @(#)IdEntry.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.contextualAnalyzer; + +import triangle.abstractSyntaxTrees.declarations.Declaration; + +public class IdEntry { + + protected String id; + protected Declaration attr; + protected int level; + protected IdEntry previous; + + IdEntry(String id, Declaration attr, int level, IdEntry previous) { + this.id = id; + this.attr = attr; + this.level = level; + this.previous = previous; + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdentificationTable.java b/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdentificationTable.java new file mode 100644 index 0000000..33d1157 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/contextualAnalyzer/IdentificationTable.java @@ -0,0 +1,87 @@ +/* + * @(#)IdentificationTable.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.contextualAnalyzer; + +import triangle.abstractSyntaxTrees.declarations.Declaration; + +public final class IdentificationTable { + + private int level; + private IdEntry latest; + + public IdentificationTable() { + level = 0; + latest = null; + } + + // Opens a new level in the identification table, 1 higher than the + // current topmost level. + + public void openScope() { + level++; + } + + // Closes the topmost level in the identification table, discarding + // all entries belonging to that level. + + public void closeScope() { + // Presumably, idTable.level > 0. + var entry = this.latest; + while (entry.level == this.level) { + entry = entry.previous; + } + + this.level--; + this.latest = entry; + } + + // Makes a new entry in the identification table for the given identifier + // and attribute. The new entry belongs to the current level. + // duplicated is set to to true iff there is already an entry for the + // same identifier at the current level. + + public void enter(String id, Declaration attr) { + attr.duplicated = retrieve(id, true) != null; + this.latest = new IdEntry(id, attr, this.level, this.latest); + } + + // Finds an entry for the given identifier in the identification table, + // if any. If there are several entries for that identifier, finds the + // entry at the highest level, in accordance with the scope rules. + // Returns null iff no entry is found. + // otherwise returns the attribute field of the entry found. + + public Declaration retrieve(String id) { + return retrieve(id, false); + } + + // thisLevelOnly limits the search to only the current level + + public Declaration retrieve(String id, boolean thisLevelOnly) { + var entry = this.latest; + while (true) { + if (entry == null || (thisLevelOnly && entry.level < this.level)) { + break; + } else if (entry.id.equals(id)) { + return entry.attr; + } else { + entry = entry.previous; + } + } + + return null; + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/optimiser/ConstantFolder.java b/Triangle.Compiler/src/main/java/triangle/optimiser/ConstantFolder.java new file mode 100644 index 0000000..1ba56ea --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/optimiser/ConstantFolder.java @@ -0,0 +1,599 @@ +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.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; + +public class ConstantFolder implements ActualParameterVisitor, + ActualParameterSequenceVisitor, ArrayAggregateVisitor, + CommandVisitor, DeclarationVisitor, + ExpressionVisitor, FormalParameterSequenceVisitor, + IdentifierVisitor, LiteralVisitor, + OperatorVisitor, ProgramVisitor, + RecordAggregateVisitor, TypeDenoterVisitor, + VnameVisitor { + { + + } + + @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 AbstractSyntaxTree visitDotVname(DotVname ast, Void arg) { + ast.I.visit(this); + ast.V.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree visitSimpleVname(SimpleVname ast, Void arg) { + ast.I.visit(this); + return null; + } + + @Override + public AbstractSyntaxTree 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; + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Parser.java b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Parser.java new file mode 100644 index 0000000..3cccb6b --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Parser.java @@ -0,0 +1,920 @@ +/* + * @(#)Parser.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.syntacticAnalyzer; + +import triangle.ErrorReporter; +import triangle.abstractSyntaxTrees.Program; +import triangle.abstractSyntaxTrees.actuals.ActualParameter; +import triangle.abstractSyntaxTrees.actuals.ActualParameterSequence; +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.ArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.MultipleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.MultipleRecordAggregate; +import triangle.abstractSyntaxTrees.aggregates.RecordAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleArrayAggregate; +import triangle.abstractSyntaxTrees.aggregates.SingleRecordAggregate; +import triangle.abstractSyntaxTrees.commands.AssignCommand; +import triangle.abstractSyntaxTrees.commands.CallCommand; +import triangle.abstractSyntaxTrees.commands.Command; +import triangle.abstractSyntaxTrees.commands.EmptyCommand; +import triangle.abstractSyntaxTrees.commands.IfCommand; +import triangle.abstractSyntaxTrees.commands.LetCommand; +import triangle.abstractSyntaxTrees.commands.SequentialCommand; +import triangle.abstractSyntaxTrees.commands.WhileCommand; +import triangle.abstractSyntaxTrees.declarations.ConstDeclaration; +import triangle.abstractSyntaxTrees.declarations.Declaration; +import triangle.abstractSyntaxTrees.declarations.FuncDeclaration; +import triangle.abstractSyntaxTrees.declarations.ProcDeclaration; +import triangle.abstractSyntaxTrees.declarations.SequentialDeclaration; +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.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.FormalParameter; +import triangle.abstractSyntaxTrees.formals.FormalParameterSequence; +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.ArrayTypeDenoter; +import triangle.abstractSyntaxTrees.types.FieldTypeDenoter; +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.types.TypeDenoter; +import triangle.abstractSyntaxTrees.vnames.DotVname; +import triangle.abstractSyntaxTrees.vnames.SimpleVname; +import triangle.abstractSyntaxTrees.vnames.SubscriptVname; +import triangle.abstractSyntaxTrees.vnames.Vname; + +public class Parser { + + private Scanner lexicalAnalyser; + private ErrorReporter errorReporter; + private Token currentToken; + private SourcePosition previousTokenPosition; + + public Parser(Scanner lexer, ErrorReporter reporter) { + lexicalAnalyser = lexer; + errorReporter = reporter; + previousTokenPosition = new SourcePosition(); + } + + // accept checks whether the current token matches tokenExpected. + // If so, fetches the next token. + // If not, reports a syntactic error. + + void accept(int tokenExpected) throws SyntaxError { + if (currentToken.kind == tokenExpected) { + previousTokenPosition = currentToken.position; + currentToken = lexicalAnalyser.scan(); + } else { + syntacticError("\"%\" expected here", Token.spell(tokenExpected)); + } + } + + void acceptIt() { + previousTokenPosition = currentToken.position; + currentToken = lexicalAnalyser.scan(); + } + + // start records the position of the start of a phrase. + // This is defined to be the position of the first + // character of the first token of the phrase. + + void start(SourcePosition position) { + position.start = currentToken.position.start; + } + + // finish records the position of the end of a phrase. + // This is defined to be the position of the last + // character of the last token of the phrase. + + void finish(SourcePosition position) { + position.finish = previousTokenPosition.finish; + } + + void syntacticError(String messageTemplate, String tokenQuoted) throws SyntaxError { + SourcePosition pos = currentToken.position; + errorReporter.reportError(messageTemplate, tokenQuoted, pos); + throw (new SyntaxError()); + } + + /////////////////////////////////////////////////////////////////////////////// + // + // PROGRAMS + // + /////////////////////////////////////////////////////////////////////////////// + + public Program parseProgram() { + + Program programAST = null; + + previousTokenPosition.start = 0; + previousTokenPosition.finish = 0; + currentToken = lexicalAnalyser.scan(); + + try { + Command cAST = parseCommand(); + programAST = new Program(cAST, previousTokenPosition); + if (currentToken.kind != Token.EOT) { + syntacticError("\"%\" not expected after end of program", currentToken.spelling); + } + } catch (SyntaxError s) { + return null; + } + return programAST; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // LITERALS + // + /////////////////////////////////////////////////////////////////////////////// + + // parseIntegerLiteral parses an integer-literal, and constructs + // a leaf AST to represent it. + + IntegerLiteral parseIntegerLiteral() throws SyntaxError { + IntegerLiteral IL = null; + + if (currentToken.kind == Token.INTLITERAL) { + previousTokenPosition = currentToken.position; + String spelling = currentToken.spelling; + IL = new IntegerLiteral(spelling, previousTokenPosition); + currentToken = lexicalAnalyser.scan(); + } else { + IL = null; + syntacticError("integer literal expected here", ""); + } + return IL; + } + + // parseCharacterLiteral parses a character-literal, and constructs a leaf + // AST to represent it. + + CharacterLiteral parseCharacterLiteral() throws SyntaxError { + CharacterLiteral CL = null; + + if (currentToken.kind == Token.CHARLITERAL) { + previousTokenPosition = currentToken.position; + String spelling = currentToken.spelling; + CL = new CharacterLiteral(spelling, previousTokenPosition); + currentToken = lexicalAnalyser.scan(); + } else { + CL = null; + syntacticError("character literal expected here", ""); + } + return CL; + } + + // parseIdentifier parses an identifier, and constructs a leaf AST to + // represent it. + + Identifier parseIdentifier() throws SyntaxError { + Identifier I = null; + + if (currentToken.kind == Token.IDENTIFIER) { + previousTokenPosition = currentToken.position; + String spelling = currentToken.spelling; + I = new Identifier(spelling, previousTokenPosition); + currentToken = lexicalAnalyser.scan(); + } else { + I = null; + syntacticError("identifier expected here", ""); + } + return I; + } + + // parseOperator parses an operator, and constructs a leaf AST to + // represent it. + + Operator parseOperator() throws SyntaxError { + Operator O = null; + + if (currentToken.kind == Token.OPERATOR) { + previousTokenPosition = currentToken.position; + String spelling = currentToken.spelling; + O = new Operator(spelling, previousTokenPosition); + currentToken = lexicalAnalyser.scan(); + } else { + O = null; + syntacticError("operator expected here", ""); + } + return O; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // COMMANDS + // + /////////////////////////////////////////////////////////////////////////////// + + // parseCommand parses the command, and constructs an AST + // to represent its phrase structure. + + Command parseCommand() throws SyntaxError { + Command commandAST = null; // in case there's a syntactic error + + SourcePosition commandPos = new SourcePosition(); + + start(commandPos); + commandAST = parseSingleCommand(); + while (currentToken.kind == Token.SEMICOLON) { + acceptIt(); + Command c2AST = parseSingleCommand(); + finish(commandPos); + commandAST = new SequentialCommand(commandAST, c2AST, commandPos); + } + return commandAST; + } + + Command parseSingleCommand() throws SyntaxError { + Command commandAST = null; // in case there's a syntactic error + + SourcePosition commandPos = new SourcePosition(); + start(commandPos); + + switch (currentToken.kind) { + + case Token.IDENTIFIER: { + Identifier iAST = parseIdentifier(); + if (currentToken.kind == Token.LPAREN) { + acceptIt(); + ActualParameterSequence apsAST = parseActualParameterSequence(); + accept(Token.RPAREN); + finish(commandPos); + commandAST = new CallCommand(iAST, apsAST, commandPos); + + } else { + + Vname vAST = parseRestOfVname(iAST); + accept(Token.BECOMES); + Expression eAST = parseExpression(); + finish(commandPos); + commandAST = new AssignCommand(vAST, eAST, commandPos); + } + } + break; + + case Token.BEGIN: + acceptIt(); + commandAST = parseCommand(); + accept(Token.END); + break; + + case Token.LET: { + acceptIt(); + Declaration dAST = parseDeclaration(); + accept(Token.IN); + Command cAST = parseSingleCommand(); + finish(commandPos); + commandAST = new LetCommand(dAST, cAST, commandPos); + } + break; + + case Token.IF: { + acceptIt(); + Expression eAST = parseExpression(); + accept(Token.THEN); + Command c1AST = parseSingleCommand(); + accept(Token.ELSE); + Command c2AST = parseSingleCommand(); + finish(commandPos); + commandAST = new IfCommand(eAST, c1AST, c2AST, commandPos); + } + break; + + case Token.WHILE: { + acceptIt(); + Expression eAST = parseExpression(); + accept(Token.DO); + Command cAST = parseSingleCommand(); + finish(commandPos); + commandAST = new WhileCommand(eAST, cAST, commandPos); + } + break; + + case Token.SEMICOLON: + case Token.END: + case Token.ELSE: + case Token.IN: + case Token.EOT: + + finish(commandPos); + commandAST = new EmptyCommand(commandPos); + break; + + default: + syntacticError("\"%\" cannot start a command", currentToken.spelling); + break; + + } + + return commandAST; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // EXPRESSIONS + // + /////////////////////////////////////////////////////////////////////////////// + + Expression parseExpression() throws SyntaxError { + Expression expressionAST = null; // in case there's a syntactic error + + SourcePosition expressionPos = new SourcePosition(); + + start(expressionPos); + + switch (currentToken.kind) { + + case Token.LET: { + acceptIt(); + Declaration dAST = parseDeclaration(); + accept(Token.IN); + Expression eAST = parseExpression(); + finish(expressionPos); + expressionAST = new LetExpression(dAST, eAST, expressionPos); + } + break; + + case Token.IF: { + acceptIt(); + Expression e1AST = parseExpression(); + accept(Token.THEN); + Expression e2AST = parseExpression(); + accept(Token.ELSE); + Expression e3AST = parseExpression(); + finish(expressionPos); + expressionAST = new IfExpression(e1AST, e2AST, e3AST, expressionPos); + } + break; + + default: + expressionAST = parseSecondaryExpression(); + break; + } + return expressionAST; + } + + Expression parseSecondaryExpression() throws SyntaxError { + Expression expressionAST = null; // in case there's a syntactic error + + SourcePosition expressionPos = new SourcePosition(); + start(expressionPos); + + expressionAST = parsePrimaryExpression(); + while (currentToken.kind == Token.OPERATOR) { + Operator opAST = parseOperator(); + Expression e2AST = parsePrimaryExpression(); + expressionAST = new BinaryExpression(expressionAST, opAST, e2AST, expressionPos); + } + return expressionAST; + } + + Expression parsePrimaryExpression() throws SyntaxError { + Expression expressionAST = null; // in case there's a syntactic error + + SourcePosition expressionPos = new SourcePosition(); + start(expressionPos); + + switch (currentToken.kind) { + + case Token.INTLITERAL: { + IntegerLiteral ilAST = parseIntegerLiteral(); + finish(expressionPos); + expressionAST = new IntegerExpression(ilAST, expressionPos); + } + break; + + case Token.CHARLITERAL: { + CharacterLiteral clAST = parseCharacterLiteral(); + finish(expressionPos); + expressionAST = new CharacterExpression(clAST, expressionPos); + } + break; + + case Token.LBRACKET: { + acceptIt(); + ArrayAggregate aaAST = parseArrayAggregate(); + accept(Token.RBRACKET); + finish(expressionPos); + expressionAST = new ArrayExpression(aaAST, expressionPos); + } + break; + + case Token.LCURLY: { + acceptIt(); + RecordAggregate raAST = parseRecordAggregate(); + accept(Token.RCURLY); + finish(expressionPos); + expressionAST = new RecordExpression(raAST, expressionPos); + } + break; + + case Token.IDENTIFIER: { + Identifier iAST = parseIdentifier(); + if (currentToken.kind == Token.LPAREN) { + acceptIt(); + ActualParameterSequence apsAST = parseActualParameterSequence(); + accept(Token.RPAREN); + finish(expressionPos); + expressionAST = new CallExpression(iAST, apsAST, expressionPos); + + } else { + Vname vAST = parseRestOfVname(iAST); + finish(expressionPos); + expressionAST = new VnameExpression(vAST, expressionPos); + } + } + break; + + case Token.OPERATOR: { + Operator opAST = parseOperator(); + Expression eAST = parsePrimaryExpression(); + finish(expressionPos); + expressionAST = new UnaryExpression(opAST, eAST, expressionPos); + } + break; + + case Token.LPAREN: + acceptIt(); + expressionAST = parseExpression(); + accept(Token.RPAREN); + break; + + default: + syntacticError("\"%\" cannot start an expression", currentToken.spelling); + break; + + } + return expressionAST; + } + + RecordAggregate parseRecordAggregate() throws SyntaxError { + RecordAggregate aggregateAST = null; // in case there's a syntactic error + + SourcePosition aggregatePos = new SourcePosition(); + start(aggregatePos); + + Identifier iAST = parseIdentifier(); + accept(Token.IS); + Expression eAST = parseExpression(); + + if (currentToken.kind == Token.COMMA) { + acceptIt(); + RecordAggregate aAST = parseRecordAggregate(); + finish(aggregatePos); + aggregateAST = new MultipleRecordAggregate(iAST, eAST, aAST, aggregatePos); + } else { + finish(aggregatePos); + aggregateAST = new SingleRecordAggregate(iAST, eAST, aggregatePos); + } + return aggregateAST; + } + + ArrayAggregate parseArrayAggregate() throws SyntaxError { + ArrayAggregate aggregateAST = null; // in case there's a syntactic error + + SourcePosition aggregatePos = new SourcePosition(); + start(aggregatePos); + + Expression eAST = parseExpression(); + if (currentToken.kind == Token.COMMA) { + acceptIt(); + ArrayAggregate aAST = parseArrayAggregate(); + finish(aggregatePos); + aggregateAST = new MultipleArrayAggregate(eAST, aAST, aggregatePos); + } else { + finish(aggregatePos); + aggregateAST = new SingleArrayAggregate(eAST, aggregatePos); + } + return aggregateAST; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // VALUE-OR-VARIABLE NAMES + // + /////////////////////////////////////////////////////////////////////////////// + + Vname parseVname() throws SyntaxError { + Vname vnameAST = null; // in case there's a syntactic error + Identifier iAST = parseIdentifier(); + vnameAST = parseRestOfVname(iAST); + return vnameAST; + } + + Vname parseRestOfVname(Identifier identifierAST) throws SyntaxError { + SourcePosition vnamePos = new SourcePosition(); + vnamePos = identifierAST.getPosition(); + Vname vAST = new SimpleVname(identifierAST, vnamePos); + + while (currentToken.kind == Token.DOT || currentToken.kind == Token.LBRACKET) { + + if (currentToken.kind == Token.DOT) { + acceptIt(); + Identifier iAST = parseIdentifier(); + vAST = new DotVname(vAST, iAST, vnamePos); + } else { + acceptIt(); + Expression eAST = parseExpression(); + accept(Token.RBRACKET); + finish(vnamePos); + vAST = new SubscriptVname(vAST, eAST, vnamePos); + } + } + return vAST; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // DECLARATIONS + // + /////////////////////////////////////////////////////////////////////////////// + + Declaration parseDeclaration() throws SyntaxError { + Declaration declarationAST = null; // in case there's a syntactic error + + SourcePosition declarationPos = new SourcePosition(); + start(declarationPos); + declarationAST = parseSingleDeclaration(); + while (currentToken.kind == Token.SEMICOLON) { + acceptIt(); + Declaration d2AST = parseSingleDeclaration(); + finish(declarationPos); + declarationAST = new SequentialDeclaration(declarationAST, d2AST, declarationPos); + } + return declarationAST; + } + + Declaration parseSingleDeclaration() throws SyntaxError { + Declaration declarationAST = null; // in case there's a syntactic error + + SourcePosition declarationPos = new SourcePosition(); + start(declarationPos); + + switch (currentToken.kind) { + + case Token.CONST: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.IS); + Expression eAST = parseExpression(); + finish(declarationPos); + declarationAST = new ConstDeclaration(iAST, eAST, declarationPos); + } + break; + + case Token.VAR: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.COLON); + TypeDenoter tAST = parseTypeDenoter(); + finish(declarationPos); + declarationAST = new VarDeclaration(iAST, tAST, declarationPos); + } + break; + + case Token.PROC: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.LPAREN); + FormalParameterSequence fpsAST = parseFormalParameterSequence(); + accept(Token.RPAREN); + accept(Token.IS); + Command cAST = parseSingleCommand(); + finish(declarationPos); + declarationAST = new ProcDeclaration(iAST, fpsAST, cAST, declarationPos); + } + break; + + case Token.FUNC: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.LPAREN); + FormalParameterSequence fpsAST = parseFormalParameterSequence(); + accept(Token.RPAREN); + accept(Token.COLON); + TypeDenoter tAST = parseTypeDenoter(); + accept(Token.IS); + Expression eAST = parseExpression(); + finish(declarationPos); + declarationAST = new FuncDeclaration(iAST, fpsAST, tAST, eAST, declarationPos); + } + break; + + case Token.TYPE: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.IS); + TypeDenoter tAST = parseTypeDenoter(); + finish(declarationPos); + declarationAST = new TypeDeclaration(iAST, tAST, declarationPos); + } + break; + + default: + syntacticError("\"%\" cannot start a declaration", currentToken.spelling); + break; + + } + return declarationAST; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // PARAMETERS + // + /////////////////////////////////////////////////////////////////////////////// + + FormalParameterSequence parseFormalParameterSequence() throws SyntaxError { + FormalParameterSequence formalsAST; + + SourcePosition formalsPos = new SourcePosition(); + + start(formalsPos); + if (currentToken.kind == Token.RPAREN) { + finish(formalsPos); + formalsAST = new EmptyFormalParameterSequence(formalsPos); + + } else { + formalsAST = parseProperFormalParameterSequence(); + } + return formalsAST; + } + + FormalParameterSequence parseProperFormalParameterSequence() throws SyntaxError { + FormalParameterSequence formalsAST = null; // in case there's a syntactic error; + + SourcePosition formalsPos = new SourcePosition(); + start(formalsPos); + FormalParameter fpAST = parseFormalParameter(); + if (currentToken.kind == Token.COMMA) { + acceptIt(); + FormalParameterSequence fpsAST = parseProperFormalParameterSequence(); + finish(formalsPos); + formalsAST = new MultipleFormalParameterSequence(fpAST, fpsAST, formalsPos); + + } else { + finish(formalsPos); + formalsAST = new SingleFormalParameterSequence(fpAST, formalsPos); + } + return formalsAST; + } + + FormalParameter parseFormalParameter() throws SyntaxError { + FormalParameter formalAST = null; // in case there's a syntactic error; + + SourcePosition formalPos = new SourcePosition(); + start(formalPos); + + switch (currentToken.kind) { + + case Token.IDENTIFIER: { + Identifier iAST = parseIdentifier(); + accept(Token.COLON); + TypeDenoter tAST = parseTypeDenoter(); + finish(formalPos); + formalAST = new ConstFormalParameter(iAST, tAST, formalPos); + } + break; + + case Token.VAR: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.COLON); + TypeDenoter tAST = parseTypeDenoter(); + finish(formalPos); + formalAST = new VarFormalParameter(iAST, tAST, formalPos); + } + break; + + case Token.PROC: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.LPAREN); + FormalParameterSequence fpsAST = parseFormalParameterSequence(); + accept(Token.RPAREN); + finish(formalPos); + formalAST = new ProcFormalParameter(iAST, fpsAST, formalPos); + } + break; + + case Token.FUNC: { + acceptIt(); + Identifier iAST = parseIdentifier(); + accept(Token.LPAREN); + FormalParameterSequence fpsAST = parseFormalParameterSequence(); + accept(Token.RPAREN); + accept(Token.COLON); + TypeDenoter tAST = parseTypeDenoter(); + finish(formalPos); + formalAST = new FuncFormalParameter(iAST, fpsAST, tAST, formalPos); + } + break; + + default: + syntacticError("\"%\" cannot start a formal parameter", currentToken.spelling); + break; + + } + return formalAST; + } + + ActualParameterSequence parseActualParameterSequence() throws SyntaxError { + ActualParameterSequence actualsAST; + + SourcePosition actualsPos = new SourcePosition(); + + start(actualsPos); + if (currentToken.kind == Token.RPAREN) { + finish(actualsPos); + actualsAST = new EmptyActualParameterSequence(actualsPos); + + } else { + actualsAST = parseProperActualParameterSequence(); + } + return actualsAST; + } + + ActualParameterSequence parseProperActualParameterSequence() throws SyntaxError { + ActualParameterSequence actualsAST = null; // in case there's a syntactic error + + SourcePosition actualsPos = new SourcePosition(); + + start(actualsPos); + ActualParameter apAST = parseActualParameter(); + if (currentToken.kind == Token.COMMA) { + acceptIt(); + ActualParameterSequence apsAST = parseProperActualParameterSequence(); + finish(actualsPos); + actualsAST = new MultipleActualParameterSequence(apAST, apsAST, actualsPos); + } else { + finish(actualsPos); + actualsAST = new SingleActualParameterSequence(apAST, actualsPos); + } + return actualsAST; + } + + ActualParameter parseActualParameter() throws SyntaxError { + ActualParameter actualAST = null; // in case there's a syntactic error + + SourcePosition actualPos = new SourcePosition(); + + start(actualPos); + + switch (currentToken.kind) { + + case Token.IDENTIFIER: + case Token.INTLITERAL: + case Token.CHARLITERAL: + case Token.OPERATOR: + case Token.LET: + case Token.IF: + case Token.LPAREN: + case Token.LBRACKET: + case Token.LCURLY: { + Expression eAST = parseExpression(); + finish(actualPos); + actualAST = new ConstActualParameter(eAST, actualPos); + } + break; + + case Token.VAR: { + acceptIt(); + Vname vAST = parseVname(); + finish(actualPos); + actualAST = new VarActualParameter(vAST, actualPos); + } + break; + + case Token.PROC: { + acceptIt(); + Identifier iAST = parseIdentifier(); + finish(actualPos); + actualAST = new ProcActualParameter(iAST, actualPos); + } + break; + + case Token.FUNC: { + acceptIt(); + Identifier iAST = parseIdentifier(); + finish(actualPos); + actualAST = new FuncActualParameter(iAST, actualPos); + } + break; + + default: + syntacticError("\"%\" cannot start an actual parameter", currentToken.spelling); + break; + + } + return actualAST; + } + + /////////////////////////////////////////////////////////////////////////////// + // + // TYPE-DENOTERS + // + /////////////////////////////////////////////////////////////////////////////// + + TypeDenoter parseTypeDenoter() throws SyntaxError { + TypeDenoter typeAST = null; // in case there's a syntactic error + SourcePosition typePos = new SourcePosition(); + + start(typePos); + + switch (currentToken.kind) { + + case Token.IDENTIFIER: { + Identifier iAST = parseIdentifier(); + finish(typePos); + typeAST = new SimpleTypeDenoter(iAST, typePos); + } + break; + + case Token.ARRAY: { + acceptIt(); + IntegerLiteral ilAST = parseIntegerLiteral(); + accept(Token.OF); + TypeDenoter tAST = parseTypeDenoter(); + finish(typePos); + typeAST = new ArrayTypeDenoter(ilAST, tAST, typePos); + } + break; + + case Token.RECORD: { + acceptIt(); + FieldTypeDenoter fAST = parseFieldTypeDenoter(); + accept(Token.END); + finish(typePos); + typeAST = new RecordTypeDenoter(fAST, typePos); + } + break; + + default: + syntacticError("\"%\" cannot start a type denoter", currentToken.spelling); + break; + + } + return typeAST; + } + + FieldTypeDenoter parseFieldTypeDenoter() throws SyntaxError { + FieldTypeDenoter fieldAST = null; // in case there's a syntactic error + + SourcePosition fieldPos = new SourcePosition(); + + start(fieldPos); + Identifier iAST = parseIdentifier(); + accept(Token.COLON); + TypeDenoter tAST = parseTypeDenoter(); + if (currentToken.kind == Token.COMMA) { + acceptIt(); + FieldTypeDenoter fAST = parseFieldTypeDenoter(); + finish(fieldPos); + fieldAST = new MultipleFieldTypeDenoter(iAST, tAST, fAST, fieldPos); + } else { + finish(fieldPos); + fieldAST = new SingleFieldTypeDenoter(iAST, tAST, fieldPos); + } + return fieldAST; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Scanner.java b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Scanner.java new file mode 100644 index 0000000..4da5ed5 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Scanner.java @@ -0,0 +1,272 @@ +/* + * @(#)Scanner.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.syntacticAnalyzer; + +public final class Scanner { + + private SourceFile sourceFile; + private boolean debug; + + private char currentChar; + private StringBuffer currentSpelling; + private boolean currentlyScanningToken; + + private boolean isLetter(char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + + private boolean isDigit(char c) { + return (c >= '0' && c <= '9'); + } + + // isOperator returns true iff the given character is an operator character. + + private boolean isOperator(char c) { + return (c == '+' || c == '-' || c == '*' || c == '/' || c == '=' || c == '<' || c == '>' || c == '\\' + || c == '&' || c == '@' || c == '%' || c == '^' || c == '?'); + } + + /////////////////////////////////////////////////////////////////////////////// + + public Scanner(SourceFile source) { + sourceFile = source; + currentChar = sourceFile.getSource(); + debug = false; + } + + public void enableDebugging() { + debug = true; + } + + // takeIt appends the current character to the current token, and gets + // the next character from the source program. + + private void takeIt() { + if (currentlyScanningToken) + currentSpelling.append(currentChar); + currentChar = sourceFile.getSource(); + } + + // scanSeparator skips a single separator. + + private void scanSeparator() { + switch (currentChar) { + + // comment + case '!': { + takeIt(); + while ((currentChar != SourceFile.EOL) && (currentChar != SourceFile.EOT)) + takeIt(); + if (currentChar == SourceFile.EOL) + takeIt(); + } + break; + + // whitespace + case ' ': + case '\n': + case '\r': + case '\t': + takeIt(); + break; + } + } + + private int scanToken() { + + switch (currentChar) { + + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + takeIt(); + while (isLetter(currentChar) || isDigit(currentChar)) + takeIt(); + return Token.IDENTIFIER; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + takeIt(); + while (isDigit(currentChar)) + takeIt(); + return Token.INTLITERAL; + + case '+': + case '-': + case '*': + case '/': + case '=': + case '<': + case '>': + case '\\': + case '&': + case '@': + case '%': + case '^': + case '?': + takeIt(); + while (isOperator(currentChar)) + takeIt(); + return Token.OPERATOR; + + case '\'': + takeIt(); + takeIt(); // the quoted character + if (currentChar == '\'') { + takeIt(); + return Token.CHARLITERAL; + } else + return Token.ERROR; + + case '.': + takeIt(); + return Token.DOT; + + case ':': + takeIt(); + if (currentChar == '=') { + takeIt(); + return Token.BECOMES; + } else + return Token.COLON; + + case ';': + takeIt(); + return Token.SEMICOLON; + + case ',': + takeIt(); + return Token.COMMA; + + case '~': + takeIt(); + return Token.IS; + + case '(': + takeIt(); + return Token.LPAREN; + + case ')': + takeIt(); + return Token.RPAREN; + + case '[': + takeIt(); + return Token.LBRACKET; + + case ']': + takeIt(); + return Token.RBRACKET; + + case '{': + takeIt(); + return Token.LCURLY; + + case '}': + takeIt(); + return Token.RCURLY; + + case SourceFile.EOT: + return Token.EOT; + + default: + takeIt(); + return Token.ERROR; + } + } + + public Token scan() { + Token tok; + SourcePosition pos; + int kind; + + currentlyScanningToken = false; + // skip any whitespace or comments + while (currentChar == '!' || currentChar == ' ' || currentChar == '\n' || currentChar == '\r' + || currentChar == '\t') + scanSeparator(); + + currentlyScanningToken = true; + currentSpelling = new StringBuffer(""); + pos = new SourcePosition(); + pos.start = sourceFile.getCurrentLine(); + + kind = scanToken(); + + pos.finish = sourceFile.getCurrentLine(); + tok = new Token(kind, currentSpelling.toString(), pos); + if (debug) + System.out.println(tok); + return tok; + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourceFile.java b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourceFile.java new file mode 100644 index 0000000..3651455 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourceFile.java @@ -0,0 +1,68 @@ +/* + * @(#)SourceFile.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +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.InputStream source; + int currentLine; + + public static SourceFile ofPath(String pathname) { + try { + 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() { + currentLine = 1; + } + + char getSource() { + try { + int c = source.read(); + + if (c == -1) { + c = EOT; + } else if (c == EOL) { + currentLine++; + } + return (char) c; + } catch (java.io.IOException s) { + return EOT; + } + } + + int getCurrentLine() { + return currentLine; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourcePosition.java b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourcePosition.java new file mode 100644 index 0000000..fbd5716 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SourcePosition.java @@ -0,0 +1,35 @@ +/* + * @(#)SourcePosition.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.syntacticAnalyzer; + +public class SourcePosition { + + public int start, finish; + + public SourcePosition() { + start = 0; + finish = 0; + } + + public SourcePosition(int s, int f) { + start = s; + finish = f; + } + + @Override + public String toString() { + return "(" + start + ", " + finish + ")"; + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SyntaxError.java b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SyntaxError.java new file mode 100644 index 0000000..1ea031d --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/SyntaxError.java @@ -0,0 +1,29 @@ +/* + * @(#)SyntaxError.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.syntacticAnalyzer; + +class SyntaxError extends Exception { + + private static final long serialVersionUID = -5280306336102766860L; + + SyntaxError() { + super(); + } + + SyntaxError(String s) { + super(s); + } + +} diff --git a/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Token.java b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Token.java new file mode 100644 index 0000000..51f3203 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/syntacticAnalyzer/Token.java @@ -0,0 +1,84 @@ +/* + * @(#)Token.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.syntacticAnalyzer; + +final class Token extends Object { + + protected int kind; + protected String spelling; + protected SourcePosition position; + + public Token(int kind, String spelling, SourcePosition position) { + + if (kind == Token.IDENTIFIER) { + int currentKind = firstReservedWord; + boolean searching = true; + + while (searching) { + int comparison = tokenTable[currentKind].compareTo(spelling); + if (comparison == 0) { + this.kind = currentKind; + searching = false; + } else if (comparison > 0 || currentKind == lastReservedWord) { + this.kind = Token.IDENTIFIER; + searching = false; + } else { + currentKind++; + } + } + } else + this.kind = kind; + + this.spelling = spelling; + this.position = position; + + } + + public static String spell(int kind) { + return tokenTable[kind]; + } + + @Override + public String toString() { + return "Kind=" + kind + ", spelling=" + spelling + ", position=" + position; + } + + // Token classes... + + public static final int + + // literals, identifiers, operators... + INTLITERAL = 0, CHARLITERAL = 1, IDENTIFIER = 2, OPERATOR = 3, + + // 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, + + // punctuation... + DOT = 21, COLON = 22, SEMICOLON = 23, COMMA = 24, BECOMES = 25, IS = 26, + + // brackets... + LPAREN = 27, RPAREN = 28, LBRACKET = 29, RBRACKET = 30, LCURLY = 31, RCURLY = 32, + + // special tokens... + EOT = 33, ERROR = 34; + + private static String[] tokenTable = new String[] { "", "", "", "", "array", + "begin", "const", "do", "else", "end", "func", "if", "in", "let", "of", "proc", "record", "then", "type", + "var", "while", ".", ":", ";", ",", ":=", "~", "(", ")", "[", "]", "{", "}", "", "" }; + + private final static int firstReservedWord = Token.ARRAY, lastReservedWord = Token.WHILE; + +} diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/Drawer.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/Drawer.java new file mode 100644 index 0000000..53fd82f --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/Drawer.java @@ -0,0 +1,68 @@ +/* + * @(#)Drawer.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.treeDrawer; + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Point; + +import triangle.abstractSyntaxTrees.Program; + +public class Drawer { + + private DrawerFrame frame; + private DrawerPanel panel; + + private Program theAST; + private DrawingTree theDrawing; + + // Draw the AST representing a complete program. + + public void draw(Program ast) { + theAST = ast; + panel = new DrawerPanel(this); + frame = new DrawerFrame(panel); + + Font font = new Font("SansSerif", Font.PLAIN, 12); + frame.setFont(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); + theDrawing = (DrawingTree) theAST.visit(layout, null); + theDrawing.position(new Point(2048, 10)); + + frame.setVisible(true); + } + + public void paintAST(Graphics g) { + g.setColor(panel.getBackground()); + Dimension d = panel.getSize(); + g.fillRect(0, 0, d.width, d.height); + + if (theDrawing != null) { + theDrawing.paint(g); + } + } +} diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerFrame.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerFrame.java new file mode 100644 index 0000000..a939c44 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerFrame.java @@ -0,0 +1,74 @@ +/* + * @(#)DrawerFrame.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.treeDrawer; + +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; + +class DrawerFrame extends JFrame { + /** + * + */ + private static final long serialVersionUID = -3650404598416929282L; + + public DrawerFrame(JPanel panel) { + setSize(300, 200); + Toolkit tk = Toolkit.getDefaultToolkit(); + Dimension d = tk.getScreenSize(); + int screenHeight = d.height; + int screenWidth = d.width; + setTitle("Triangle Compiler Abstract Syntax Tree"); + setSize(screenWidth / 2, screenHeight / 2); + setLocation(screenWidth / 4, screenHeight / 4); + // Image img = tk.getImage("icon.gif"); + // setIconImage(img); + + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }); + Container contentPane = getContentPane(); + final JScrollPane jScrollPane = new JScrollPane(panel); + + contentPane.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + super.componentResized(e); + jScrollPane.getHorizontalScrollBar().setValue(jScrollPane.getHorizontalScrollBar().getMaximum()); + jScrollPane.getHorizontalScrollBar().setValue(jScrollPane.getHorizontalScrollBar().getValue() / 2); + } + }); + + contentPane.add(jScrollPane); + + } + +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerPanel.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerPanel.java new file mode 100644 index 0000000..40c3b72 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawerPanel.java @@ -0,0 +1,39 @@ +/* + * @(#)DrawerPanel.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.treeDrawer; + +import java.awt.Dimension; +import java.awt.Graphics; + +import javax.swing.JPanel; + +class DrawerPanel extends JPanel { + /** + * + */ + private static final long serialVersionUID = 565914745506889669L; + private Drawer drawer; + + public DrawerPanel(Drawer drawer) { + setPreferredSize(new Dimension(4096, 4096)); + this.drawer = drawer; + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + drawer.paintAST(g); + } +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawingTree.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawingTree.java new file mode 100644 index 0000000..742eb6f --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/DrawingTree.java @@ -0,0 +1,84 @@ +/* + * @(#)DrawingTree.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.treeDrawer; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Point; + +public class DrawingTree { + + String caption; + int width, height; + Point pos, offset; + Polygon contour; + DrawingTree parent; + DrawingTree[] children; + + public DrawingTree(String caption, int width, int height) { + this.caption = caption; + this.width = width; + this.height = height; + this.parent = null; + this.children = null; + this.pos = new Point(0, 0); + this.offset = new Point(0, 0); + this.contour = new Polygon(); + } + + public void setChildren(DrawingTree[] children) { + this.children = children; + for (int i = 0; i < children.length; i++) + children[i].parent = this; + } + + private final int FIXED_FONT_HEIGHT = 10; + private final Color nodeColor = new Color(250, 220, 100); + + public void paint(Graphics graphics) { + graphics.setColor(nodeColor); + graphics.fillRect(pos.x, pos.y, width, height); + graphics.setColor(Color.black); + graphics.drawRect(pos.x, pos.y, width - 1, height - 1); + graphics.drawString(caption, pos.x + 2, pos.y + (height + FIXED_FONT_HEIGHT) / 2); + + if (children != null) { + for (DrawingTree child : children) { + child.paint(graphics); + } + } + + if (parent != null) { + graphics.drawLine(pos.x + width / 2, pos.y, parent.pos.x + parent.width / 2, parent.pos.y + parent.height); + } + } + + public void position(Point pos) { + + this.pos.x = pos.x + this.offset.x; + this.pos.y = pos.y + this.offset.y; + + Point temp = new Point(this.pos.x, this.pos.y); + + if (children != null) { + for (DrawingTree child : children) { + child.position(temp); + temp.x += child.offset.x; + temp.y = this.pos.y + children[0].offset.y; + } + } + } + +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/LayoutVisitor.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/LayoutVisitor.java new file mode 100644 index 0000000..dfa4b35 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/LayoutVisitor.java @@ -0,0 +1,680 @@ +/* + * @(#)LayoutVisitor.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.treeDrawer; + +import java.awt.FontMetrics; + +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.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.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; + +public class LayoutVisitor implements ActualParameterVisitor, + ActualParameterSequenceVisitor, ArrayAggregateVisitor, + CommandVisitor, DeclarationVisitor, ExpressionVisitor, + FormalParameterSequenceVisitor, IdentifierVisitor, + LiteralVisitor, OperatorVisitor, ProgramVisitor, + RecordAggregateVisitor, TypeDenoterVisitor, + VnameVisitor { + + private final int BORDER = 5; + private final int PARENT_SEP = 30; + + private FontMetrics fontMetrics; + + public LayoutVisitor(FontMetrics fontMetrics) { + this.fontMetrics = fontMetrics; + } + + // Commands + @Override + public DrawingTree visitAssignCommand(AssignCommand ast, Void obj) { + var d1 = ast.V.visit(this); + var d2 = ast.E.visit(this); + return layoutBinary("AssignCom.", d1, d2); + } + + @Override + public DrawingTree visitCallCommand(CallCommand ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.APS.visit(this); + return layoutBinary("CallCom.", d1, d2); + } + + @Override + public DrawingTree visitEmptyCommand(EmptyCommand ast, Void obj) { + return layoutNullary("EmptyCom."); + } + + @Override + public DrawingTree visitIfCommand(IfCommand ast, Void obj) { + var d1 = ast.E.visit(this); + var d2 = ast.C1.visit(this); + var d3 = ast.C2.visit(this); + return layoutTernary("IfCom.", d1, d2, d3); + } + + @Override + public DrawingTree visitLetCommand(LetCommand ast, Void obj) { + var d1 = ast.D.visit(this); + var d2 = ast.C.visit(this); + return layoutBinary("LetCom.", d1, d2); + } + + @Override + public DrawingTree visitSequentialCommand(SequentialCommand ast, Void obj) { + var d1 = ast.C1.visit(this); + var d2 = ast.C2.visit(this); + return layoutBinary("Seq.Com.", d1, d2); + } + + @Override + public DrawingTree visitWhileCommand(WhileCommand ast, Void obj) { + var d1 = ast.E.visit(this); + var d2 = ast.C.visit(this); + return layoutBinary("WhileCom.", d1, d2); + } + + // Expressions + @Override + public DrawingTree visitArrayExpression(ArrayExpression ast, Void obj) { + var d1 = ast.AA.visit(this); + return layoutUnary("ArrayExpr.", d1); + } + + @Override + public DrawingTree visitBinaryExpression(BinaryExpression ast, Void obj) { + var d1 = ast.E1.visit(this); + var d2 = ast.O.visit(this); + var d3 = ast.E2.visit(this); + return layoutTernary("Bin.Expr.", d1, d2, d3); + } + + @Override + public DrawingTree visitCallExpression(CallExpression ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.APS.visit(this); + return layoutBinary("CallExpr.", d1, d2); + } + + @Override + public DrawingTree visitCharacterExpression(CharacterExpression ast, Void obj) { + var d1 = ast.CL.visit(this); + return layoutUnary("Char.Expr.", d1); + } + + @Override + public DrawingTree visitEmptyExpression(EmptyExpression ast, Void obj) { + return layoutNullary("EmptyExpr."); + } + + @Override + public DrawingTree visitIfExpression(IfExpression ast, Void obj) { + var d1 = ast.E1.visit(this); + var d2 = ast.E2.visit(this); + var d3 = ast.E3.visit(this); + return layoutTernary("IfExpr.", d1, d2, d3); + } + + @Override + public DrawingTree visitIntegerExpression(IntegerExpression ast, Void obj) { + var d1 = ast.IL.visit(this); + return layoutUnary("Int.Expr.", d1); + } + + @Override + public DrawingTree visitLetExpression(LetExpression ast, Void obj) { + var d1 = ast.D.visit(this); + var d2 = ast.E.visit(this); + return layoutBinary("LetExpr.", d1, d2); + } + + @Override + public DrawingTree visitRecordExpression(RecordExpression ast, Void obj) { + var d1 = ast.RA.visit(this); + return layoutUnary("Rec.Expr.", d1); + } + + @Override + public DrawingTree visitUnaryExpression(UnaryExpression ast, Void obj) { + var d1 = ast.O.visit(this); + var d2 = ast.E.visit(this); + return layoutBinary("UnaryExpr.", d1, d2); + } + + @Override + public DrawingTree visitVnameExpression(VnameExpression ast, Void obj) { + var d1 = ast.V.visit(this); + return layoutUnary("VnameExpr.", d1); + } + + // Declarations + @Override + public DrawingTree visitBinaryOperatorDeclaration(BinaryOperatorDeclaration ast, Void obj) { + var d1 = ast.O.visit(this); + var d2 = ast.ARG1.visit(this); + var d3 = ast.ARG2.visit(this); + var d4 = ast.RES.visit(this); + return layoutQuaternary("Bin.Op.Decl.", d1, d2, d3, d4); + } + + @Override + public DrawingTree visitConstDeclaration(ConstDeclaration ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.E.visit(this); + return layoutBinary("ConstDecl.", d1, d2); + } + + @Override + public DrawingTree visitFuncDeclaration(FuncDeclaration ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.FPS.visit(this); + var d3 = ast.T.visit(this); + var d4 = ast.E.visit(this); + return layoutQuaternary("FuncDecl.", d1, d2, d3, d4); + } + + @Override + public DrawingTree visitProcDeclaration(ProcDeclaration ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.FPS.visit(this); + var d3 = ast.C.visit(this); + return layoutTernary("ProcDecl.", d1, d2, d3); + } + + @Override + public DrawingTree visitSequentialDeclaration(SequentialDeclaration ast, Void obj) { + var d1 = ast.D1.visit(this); + var d2 = ast.D2.visit(this); + return layoutBinary("Seq.Decl.", d1, d2); + } + + @Override + public DrawingTree visitTypeDeclaration(TypeDeclaration ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.T.visit(this); + return layoutBinary("TypeDecl.", d1, d2); + } + + @Override + public DrawingTree visitUnaryOperatorDeclaration(UnaryOperatorDeclaration ast, Void obj) { + var d1 = ast.O.visit(this); + var d2 = ast.ARG.visit(this); + var d3 = ast.RES.visit(this); + return layoutTernary("UnaryOp.Decl.", d1, d2, d3); + } + + @Override + public DrawingTree visitVarDeclaration(VarDeclaration ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.T.visit(this); + return layoutBinary("VarDecl.", d1, d2); + } + + // Array Aggregates + @Override + public DrawingTree visitMultipleArrayAggregate(MultipleArrayAggregate ast, Void obj) { + var d1 = ast.E.visit(this); + var d2 = ast.AA.visit(this); + return layoutBinary("Mult.ArrayAgg.", d1, d2); + } + + @Override + public DrawingTree visitSingleArrayAggregate(SingleArrayAggregate ast, Void obj) { + var d1 = ast.E.visit(this); + return layoutUnary("Sing.ArrayAgg.", d1); + } + + // Record Aggregates + @Override + public DrawingTree visitMultipleRecordAggregate(MultipleRecordAggregate ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.E.visit(this); + var d3 = ast.RA.visit(this); + return layoutTernary("Mult.Rec.Agg.", d1, d2, d3); + } + + @Override + public DrawingTree visitSingleRecordAggregate(SingleRecordAggregate ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.E.visit(this); + return layoutBinary("Sing.Rec.Agg.", d1, d2); + } + + // Formal Parameters + @Override + public DrawingTree visitConstFormalParameter(ConstFormalParameter ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.T.visit(this); + return layoutBinary("ConstF.P.", d1, d2); + } + + @Override + public DrawingTree visitFuncFormalParameter(FuncFormalParameter ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.FPS.visit(this); + var d3 = ast.T.visit(this); + return layoutTernary("FuncF.P.", d1, d2, d3); + } + + @Override + public DrawingTree visitProcFormalParameter(ProcFormalParameter ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.FPS.visit(this); + return layoutBinary("ProcF.P.", d1, d2); + } + + @Override + public DrawingTree visitVarFormalParameter(VarFormalParameter ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.T.visit(this); + return layoutBinary("VarF.P.", d1, d2); + } + + @Override + public DrawingTree visitEmptyFormalParameterSequence(EmptyFormalParameterSequence ast, Void obj) { + return layoutNullary("EmptyF.P.S."); + } + + @Override + public DrawingTree visitMultipleFormalParameterSequence(MultipleFormalParameterSequence ast, Void obj) { + var d1 = ast.FP.visit(this); + var d2 = ast.FPS.visit(this); + return layoutBinary("Mult.F.P.S.", d1, d2); + } + + @Override + public DrawingTree visitSingleFormalParameterSequence(SingleFormalParameterSequence ast, Void obj) { + var d1 = ast.FP.visit(this); + return layoutUnary("Sing.F.P.S.", d1); + } + + // Actual Parameters + @Override + public DrawingTree visitConstActualParameter(ConstActualParameter ast, Void obj) { + var d1 = ast.E.visit(this); + return layoutUnary("ConstA.P.", d1); + } + + @Override + public DrawingTree visitFuncActualParameter(FuncActualParameter ast, Void obj) { + var d1 = ast.I.visit(this); + return layoutUnary("FuncA.P.", d1); + } + + @Override + public DrawingTree visitProcActualParameter(ProcActualParameter ast, Void obj) { + var d1 = ast.I.visit(this); + return layoutUnary("ProcA.P.", d1); + } + + @Override + public DrawingTree visitVarActualParameter(VarActualParameter ast, Void obj) { + var d1 = ast.V.visit(this); + return layoutUnary("VarA.P.", d1); + } + + @Override + public DrawingTree visitEmptyActualParameterSequence(EmptyActualParameterSequence ast, Void obj) { + return layoutNullary("EmptyA.P.S."); + } + + @Override + public DrawingTree visitMultipleActualParameterSequence(MultipleActualParameterSequence ast, Void obj) { + var d1 = ast.AP.visit(this); + var d2 = ast.APS.visit(this); + return layoutBinary("Mult.A.P.S.", d1, d2); + } + + @Override + public DrawingTree visitSingleActualParameterSequence(SingleActualParameterSequence ast, Void obj) { + var d1 = ast.AP.visit(this); + return layoutUnary("Sing.A.P.S.", d1); + } + + // Type Denoters + @Override + public DrawingTree visitAnyTypeDenoter(AnyTypeDenoter ast, Void obj) { + return layoutNullary("any"); + } + + @Override + public DrawingTree visitArrayTypeDenoter(ArrayTypeDenoter ast, Void obj) { + var d1 = ast.IL.visit(this); + var d2 = ast.T.visit(this); + return layoutBinary("ArrayTypeD.", d1, d2); + } + + @Override + public DrawingTree visitBoolTypeDenoter(BoolTypeDenoter ast, Void obj) { + return layoutNullary("bool"); + } + + @Override + public DrawingTree visitCharTypeDenoter(CharTypeDenoter ast, Void obj) { + return layoutNullary("char"); + } + + @Override + public DrawingTree visitErrorTypeDenoter(ErrorTypeDenoter ast, Void obj) { + return layoutNullary("error"); + } + + @Override + public DrawingTree visitSimpleTypeDenoter(SimpleTypeDenoter ast, Void obj) { + var d1 = ast.I.visit(this); + return layoutUnary("Sim.TypeD.", d1); + } + + @Override + public DrawingTree visitIntTypeDenoter(IntTypeDenoter ast, Void obj) { + return layoutNullary("int"); + } + + @Override + public DrawingTree visitRecordTypeDenoter(RecordTypeDenoter ast, Void obj) { + var d1 = ast.FT.visit(this); + return layoutUnary("Rec.TypeD.", d1); + } + + @Override + public DrawingTree visitMultipleFieldTypeDenoter(MultipleFieldTypeDenoter ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.T.visit(this); + var d3 = ast.FT.visit(this); + return layoutTernary("Mult.F.TypeD.", d1, d2, d3); + } + + @Override + public DrawingTree visitSingleFieldTypeDenoter(SingleFieldTypeDenoter ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.T.visit(this); + return layoutBinary("Sing.F.TypeD.", d1, d2); + } + + // Literals, Identifiers and Operators + @Override + public DrawingTree visitCharacterLiteral(CharacterLiteral ast, Void obj) { + return layoutNullary(ast.spelling); + } + + @Override + public DrawingTree visitIdentifier(Identifier ast, Void obj) { + return layoutNullary(ast.spelling); + } + + @Override + public DrawingTree visitIntegerLiteral(IntegerLiteral ast, Void obj) { + return layoutNullary(ast.spelling); + } + + @Override + public DrawingTree visitOperator(Operator ast, Void obj) { + return layoutNullary(ast.spelling); + } + + // Value-or-variable names + @Override + public DrawingTree visitDotVname(DotVname ast, Void obj) { + var d1 = ast.I.visit(this); + var d2 = ast.V.visit(this); + return layoutBinary("DotVname", d1, d2); + } + + @Override + public DrawingTree visitSimpleVname(SimpleVname ast, Void obj) { + var d1 = ast.I.visit(this); + return layoutUnary("Sim.Vname", d1); + } + + @Override + public DrawingTree visitSubscriptVname(SubscriptVname ast, Void obj) { + var d1 = ast.V.visit(this); + var d2 = ast.E.visit(this); + return layoutBinary("Sub.Vname", d1, d2); + } + + // Programs + @Override + public DrawingTree visitProgram(Program ast, Void obj) { + var d1 = ast.C.visit(this); + return layoutUnary("Program", d1); + } + + private DrawingTree layoutCaption(String name) { + var w = fontMetrics.stringWidth(name) + 4; + var h = fontMetrics.getHeight() + 4; + return new DrawingTree(name, w, h); + } + + private DrawingTree layoutNullary(String name) { + var dt = layoutCaption(name); + dt.contour.upper_tail = new Polyline(0, dt.height + 2 * BORDER, null); + dt.contour.upper_head = dt.contour.upper_tail; + dt.contour.lower_tail = new Polyline(-dt.width - 2 * BORDER, 0, null); + dt.contour.lower_head = new Polyline(0, dt.height + 2 * BORDER, dt.contour.lower_tail); + return dt; + } + + private DrawingTree layoutUnary(String name, DrawingTree d1) { + var dt = layoutCaption(name); + dt.setChildren(new DrawingTree[] { d1 }); + attachParent(dt, join(dt)); + return dt; + } + + private DrawingTree layoutBinary(String name, DrawingTree d1, DrawingTree d2) { + var dt = layoutCaption(name); + dt.setChildren(new DrawingTree[] { d1, d2 }); + attachParent(dt, join(dt)); + return dt; + } + + private DrawingTree layoutTernary(String name, DrawingTree d1, DrawingTree d2, DrawingTree d3) { + var dt = layoutCaption(name); + dt.setChildren(new DrawingTree[] { d1, d2, d3 }); + attachParent(dt, join(dt)); + return dt; + } + + private DrawingTree layoutQuaternary(String name, DrawingTree d1, DrawingTree d2, DrawingTree d3, DrawingTree d4) { + var dt = layoutCaption(name); + dt.setChildren(new DrawingTree[] { d1, d2, d3, d4 }); + attachParent(dt, join(dt)); + return dt; + } + + private void attachParent(DrawingTree dt, int w) { + var y = PARENT_SEP; + var x2 = (w - dt.width) / 2 - BORDER; + var x1 = x2 + dt.width + 2 * BORDER - w; + + dt.children[0].offset.y = y + dt.height; + dt.children[0].offset.x = x1; + dt.contour.upper_head = new Polyline(0, dt.height, new Polyline(x1, y, dt.contour.upper_head)); + dt.contour.lower_head = new Polyline(0, dt.height, new Polyline(x2, y, dt.contour.lower_head)); + } + + private int join(DrawingTree dt) { + + dt.contour = dt.children[0].contour; + var sum = dt.children[0].width + 2 * BORDER; + var w = sum; + + for (var i = 1; i < dt.children.length; i++) { + var d = merge(dt.contour, dt.children[i].contour); + dt.children[i].offset.x = d + w; + dt.children[i].offset.y = 0; + w = dt.children[i].width + 2 * BORDER; + sum += d + w; + } + return sum; + } + + private int merge(Polygon c1, Polygon c2) { + int x = 0, y = 0, total = 0; + var upper = c1.lower_head; + var lower = c2.upper_head; + + while (lower != null && upper != null) { + var d = offset(x, y, lower.dx, lower.dy, upper.dx, upper.dy); + x += d; + total += d; + + if (y + lower.dy <= upper.dy) { + x += lower.dx; + y += lower.dy; + lower = lower.link; + } else { + x -= upper.dx; + y -= upper.dy; + upper = upper.link; + } + } + + if (lower != null) { + var b = bridge(c1.upper_tail, 0, 0, lower, x, y); + c1.upper_tail = (b.link != null) ? c2.upper_tail : b; + c1.lower_tail = c2.lower_tail; + } else { + var b = bridge(c2.lower_tail, x, y, upper, 0, 0); + if (b.link == null) { + c1.lower_tail = b; + } + } + + c1.lower_head = c2.lower_head; + + return total; + } + + private int offset(int p1, int p2, int a1, int a2, int b1, int b2) { + + if (b2 <= p2 || p2 + a2 <= 0) { + return 0; + } + + var t = b2 * a1 - a2 * b1; + if (t > 0) { + if (p2 < 0) { + var s = p2 * a1; + return Math.max(0, s / a2 - p1); + } else if (p2 > 0) { + var s = p2 * b1; + return Math.max(0, s / b2 - p1); + } else { + return Math.max(0, -p1); + } + } else if (b2 < p2 + a2) { + var s = (b2 - p2) * a1; + return Math.max(0, b1 - (p1 + s / a2)); + } else if (b2 > p2 + a2) { + var s = (a2 + p2) * b1; + return Math.max(0, s / b2 - (p1 + a1)); + } else { + return Math.max(0, b1 - (p1 + a1)); + } + } + + private Polyline bridge(Polyline line1, int x1, int y1, Polyline line2, int x2, int y2) { + + int dx; + var dy = y2 + line2.dy - y1; + if (line2.dy == 0) { + dx = line2.dx; + } else { + var s = dy * line2.dx; + dx = s / line2.dy; + } + + var r = new Polyline(dx, dy, line2.link); + line1.link = new Polyline(x2 + line2.dx - dx - x1, 0, r); + + return r; + } + +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/Polygon.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/Polygon.java new file mode 100644 index 0000000..d9bd6d0 --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/Polygon.java @@ -0,0 +1,20 @@ +/* + * @(#)Polygon.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +package triangle.treeDrawer; + +class Polygon { + Polyline lower_head, lower_tail; + Polyline upper_head, upper_tail; +} \ No newline at end of file diff --git a/Triangle.Compiler/src/main/java/triangle/treeDrawer/Polyline.java b/Triangle.Compiler/src/main/java/triangle/treeDrawer/Polyline.java new file mode 100644 index 0000000..546c37f --- /dev/null +++ b/Triangle.Compiler/src/main/java/triangle/treeDrawer/Polyline.java @@ -0,0 +1,29 @@ +/* + * @(#)Polyline.java 2.1 2003/10/07 + * + * Copyright (C) 1999, 2003 D.A. Watt and D.F. Brown + * Dept. of Computing Science, University of Glasgow, Glasgow G12 8QQ Scotland + * and School of Computer and Math Sciences, The Robert Gordon University, + * St. Andrew Street, Aberdeen AB25 1HG, Scotland. + * All rights reserved. + * + * This software is provided free for educational use only. It may + * not be used for commercial purposes without the prior written permission + * of the authors. + */ + +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; + + Polyline(int dx, int dy, Polyline link) { + this.dx = dx; + this.dy = dy; + this.link = link; + } +} diff --git a/Triangle.Compiler/src/test/java/triangle/syntacticAnalyser/TestScanner.java b/Triangle.Compiler/src/test/java/triangle/syntacticAnalyser/TestScanner.java new file mode 100644 index 0000000..ab10811 --- /dev/null +++ b/Triangle.Compiler/src/test/java/triangle/syntacticAnalyser/TestScanner.java @@ -0,0 +1,84 @@ +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() { + compileExpectFailure("/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"); + } + + + + 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()); + } + +} diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..88279c3 --- /dev/null +++ b/build.gradle @@ -0,0 +1,11 @@ +apply plugin: 'java' + +sourceCompatibility = 11 + +subprojects.each { subproject -> + evaluationDependsOn(subproject.path) +} + +jar { + from subprojects.sourceSets.main.output +} \ No newline at end of file diff --git a/build/libs/Triangle-Tools.jar b/build/libs/Triangle-Tools.jar new file mode 100644 index 0000000..3d2dbf7 Binary files /dev/null and b/build/libs/Triangle-Tools.jar differ diff --git a/build/tmp/jar/MANIFEST.MF b/build/tmp/jar/MANIFEST.MF new file mode 100644 index 0000000..59499bc --- /dev/null +++ b/build/tmp/jar/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..7454180 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..e750102 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..1b6c787 --- /dev/null +++ b/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/obj.tam b/obj.tam new file mode 100644 index 0000000..26e8273 Binary files /dev/null and b/obj.tam differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..596a93b --- /dev/null +++ b/pom.xml @@ -0,0 +1,19 @@ + + 4.0.0 + triangle.tools + triangle-tools + 2.1 + pom + + 17 + 17 + UTF-8 + + + Triangle.AbstractMachine + Triangle.Compiler + Triangle.AbstractMachine.Disassembler + Triangle.AbstractMachine.Interpreter + + \ No newline at end of file diff --git a/programs/adddeep.tri b/programs/adddeep.tri new file mode 100644 index 0000000..5f33bc1 --- /dev/null +++ b/programs/adddeep.tri @@ -0,0 +1,12 @@ +let + var a: Integer +in +begin + a := 10 + 20 * 2 / 3; + putint(a); + + puteol(); + + a := 5 + 8; + putint(a) +end diff --git a/programs/arrays.tam b/programs/arrays.tam new file mode 100644 index 0000000..a3d0afe Binary files /dev/null and b/programs/arrays.tam differ diff --git a/programs/arrays.tri b/programs/arrays.tri new file mode 100644 index 0000000..1cfbd28 --- /dev/null +++ b/programs/arrays.tri @@ -0,0 +1,47 @@ +let + type Vector ~ array 3 of Integer; + type Matrix ~ array 3 of Vector; + + proc putvector (v: Vector) ~ + let var i: Integer + in + begin + put ('['); putint (v[0]); + i := 1; + while i < 3 do + begin + put (' '); putint (v[i]); + i := i+1 + end; + put (']') + end; + + proc putmatrix (m: Matrix) ~ + let var i: Integer + in + begin + i := 0; + while i < 3 do + begin + putvector (m[i]); + puteol (); + i := i+1 + end + end; + + func diagonal + (m: Matrix): Vector ~ + [m[0][0], m[1][1], m[2][2]]; + + var me: Matrix + +in + begin + me := [[1,2,3], [4,5,6], [7,8,9]]; + putmatrix (me); puteol (); + putvector (diagonal (me)); + puteol (); puteol (); + me[1] := [10,11,12]; + me[1][1] := 22; + putmatrix (me); puteol () + end diff --git a/programs/assignments.tri b/programs/assignments.tri new file mode 100644 index 0000000..102bb78 --- /dev/null +++ b/programs/assignments.tri @@ -0,0 +1,9 @@ +let + var n : Integer; + var c : Char +in + + begin + c := '&'; + n := n + 1 + end diff --git a/programs/bank.tri b/programs/bank.tri new file mode 100644 index 0000000..e7f3c0f --- /dev/null +++ b/programs/bank.tri @@ -0,0 +1,86 @@ +let + const max ~ 9999; + const invalid ~ 0-1; + type Money ~ Integer; ! 0 .. max + type Trans ~ Char; ! 'd' | 'w' | 'q' + + func sum (m: Money, n: Money): Money ~ + let const s ~ m + n + in + if s <= max then s else invalid; + + func diff (m: Money, n: Money): Money ~ + let const d ~ m - n + in + if 0 <= d then d else invalid; + + proc gettrans (var code: Trans, + var amount: Money) ~ + begin + get(var code); + if code = 'q' then + ! skip + else + begin + getint(var amount); + if (0 > amount) \/ (amount > max) then + begin + amount := invalid; code := '?' + end + else if (code \= 'd') /\ (code \= 'w') then + code := '?' + else + ! ok + end; + geteol() + end; + + proc processtrans (code: Trans, + amount: Money, + var balance: Money) ~ + let + var newbalance: Money + in + begin + if code = 'd' then + begin + put('D'); put('e'); put('p'); put('o'); put('s'); + put('i'); put('t'); put(' '); + putint(amount); puteol(); + newbalance := sum(balance, amount) + end + else if code = 'w' then + begin + put('W'); put('i'); put('t'); put('h'); put('d'); + put('r'); put('a'); put('w'); put(' '); + putint(amount); puteol(); + newbalance := diff(balance, amount) + end + else + ; !skip + if (code = '?') \/ (newbalance = invalid) then + begin + put('I'); put('n'); put('v'); put('a'); put('l'); + put('i'); put('d'); puteol() + end + else + balance := newbalance; + put('B'); put('a'); put('l'); put('a'); put('n'); + put('c'); put('e'); put(' '); + putint(balance); puteol(); + end; + + var balance: Money; + var amount: Money; + var trans: Trans + +in + begin + balance := 0; + gettrans(var trans, var amount); + while trans \= 'q' do + begin + processtrans(trans, amount, var balance); + gettrans(var trans, var amount) + end + end diff --git a/programs/bardemo.tri b/programs/bardemo.tri new file mode 100644 index 0000000..f730f74 --- /dev/null +++ b/programs/bardemo.tri @@ -0,0 +1,19 @@ +! 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); + puteol(); + putint(b); + puteol(); + putint(|a); + puteol(); + putint(|b); + puteol() + end diff --git a/programs/control.tri b/programs/control.tri new file mode 100644 index 0000000..9d76146 --- /dev/null +++ b/programs/control.tri @@ -0,0 +1,26 @@ +! Plot a histogram from a stream of nonzero integers. + +let + const mark ~ '+'; + var n : Integer +in + begin + getint (var n); geteol (); + while n \= 0 do + let + var i : Integer; + var gap : Integer + in + begin + gap := if n > 0 then 20 else 20 + n; + if n < 0 then n := 0 - n else ; + i := 0; + while i < gap do + begin put (' '); i := i + 1 end; + i := 0; + while i < n do + begin put (mark); i := i + 1 end; + puteol (); + getint (var n); geteol () + end + end diff --git a/programs/deepnest.tri b/programs/deepnest.tri new file mode 100644 index 0000000..315b123 --- /dev/null +++ b/programs/deepnest.tri @@ -0,0 +1,16 @@ +let proc p1 () ~ + let var c1: Char; + proc p2 () ~ + let proc p3 () ~ + let proc p4 () ~ + let proc p5 () ~ + let proc p6 () ~ + let proc p7 () ~ + put (c1) + in p7 () + in p6 () + in p5 () + in p4 () + in p3 () + in begin c1 := '+'; p2 () end +in p1 () diff --git a/programs/directories.tri b/programs/directories.tri new file mode 100644 index 0000000..49e6794 --- /dev/null +++ b/programs/directories.tri @@ -0,0 +1,117 @@ +let + type Name ~ array 6 of Char; + type Number ~ Integer; + + proc prompt () ~ + begin + put('N'); put('a'); put('m'); put('e'); + put('?'); put(' ') + end; + + proc getname (var newname: Name) ~ + let var i: Integer + in + begin + i := 0; + while i < 6 do + begin + if eol () then + newname[i] := ' ' + else + get (var newname[i]); + i := i+1 + end + end; + + proc putname (newname: Name) ~ + let var i: Integer + in + begin + i := 0; + while i < 6 do + begin + put (newname[i]); + i := i+1 + end + end; + + type Entry ~ record + number: Number, + name: Name + end; + type Directory ~ record + size: Integer, + entry: array 100 of Entry + end; + + proc initialize (var dir: Directory) ~ + dir.size := 0; + + proc add (var dir: Directory, + newname: Name, + newnumber: Number) ~ + begin + dir.entry[dir.size] := + {number ~ newnumber, name ~ newname}; + dir.size := dir.size + 1 + end; + + proc lookup (var dir: Directory, + oldname: Name, + var oldnumber: Number, + var found: Boolean) ~ + let + var i: Integer; + var searching: Boolean + in + begin + i := 0; searching := true; + while (i < dir.size) /\ searching do + if dir.entry[i].name = oldname then + searching := false + else + i := i+1; + found := \searching; + if found then + oldnumber := dir.entry[i].number + else !skip + end; + + var mydir: Directory + +in + + begin + initialize (var mydir); + add (var mydir, + ['D','a','v','i','d',' '], 6041); + add (var mydir, + ['M','u','f','f','y',' '], 4969); + add (var mydir, + ['K','i','e','r','a','n'], 6042); + add (var mydir, + ['A','l','e','x','a',' '], 5322); + + let + const blank ~ [' ', ' ', ' ', ' ', ' ', ' ']; + var name: Name; + var num: Number; + var ok: Boolean + in + begin + prompt (); + getname (var name); geteol (); + while name \= blank do + begin + putname (name); put (' '); + lookup (var mydir, name, var num, var ok); + if ok then + putint (num) + else + put ('?'); + puteol (); + prompt (); + getname (var name); geteol () + end + end + end diff --git a/programs/errors.tri b/programs/errors.tri new file mode 100644 index 0000000..ed0e097 --- /dev/null +++ b/programs/errors.tri @@ -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 diff --git a/programs/every.tri b/programs/every.tri new file mode 100644 index 0000000..011fd1c --- /dev/null +++ b/programs/every.tri @@ -0,0 +1,148 @@ +! Marry a woman and man. +! Input following data for each person (woman then man): +! surname, forename (each up to 10 non-blank chars), +! sex ('M'|'F'), marital status ('m'|'u'), +! day, month, year of birth. + +let + type Month ~ Integer; + const Jan ~ 1; const Feb ~ 2; const Mar ~ 3; + const Apr ~ 4; const May ~ 5; const Jun ~ 6; + const Jul ~ 7; const Aug ~ 8; const Sep ~ 9; + const Oct ~ 10; const Nov ~ 11; const Dec ~ 12; + + type Date ~ record + y : Integer, + m : Month, + d : Integer + end; + const today ~ {y ~ 1993, m ~ Apr, d ~ 1}; + + proc getdate (var date : Date) ~ + begin + getint (var date.d); getint (var date.m); getint (var date.y) + end; + + proc putdate (date : Date) ~ + begin + putint (date.d); put ('/'); + putint (date.m); put ('/'); + putint (date.y // 100) + end; + + func yearsbefore (yrs : Integer, date : Date) : Date ~ + {y ~ date.y - yrs, m ~ date.m, d ~ date.d}; + + func earlier (date1 : Date, date2 : Date) : Boolean ~ + if date1.y < date2.y then true + else if date1.y > date2.y then false + else if date1.m < date2.m then true + else if date1.m > date2.m then false + else date1.d < date2.d; + + const maxname ~ 10; + type Name ~ array 10 of Char; + + proc getname (var name : Name) ~ + let + var ch : Char; + var length : Integer + in + begin + get (var ch); while ch = ' ' do get (var ch); + length := 0; + while length < maxname do + begin + length := length + 1; name[length] := ch; + if ch \= ' ' then get (var ch) else ! skip + end + end; + + proc putname (name : Name) ~ + let + var pad : Boolean; + var length : Integer + in + begin + pad := false; length := 0; + while (\ pad) /\ (length < maxname) do + begin + length := length + 1; + if name[length] = ' ' then + pad := true + else + put (name[length]) + end + end; + + type Person ~ record + surname : Name, + forename : Name, + male : Boolean, + married : Boolean, + dob : Date + end; + + proc getperson (var person : Person) ~ + let + var fore : Name; + var sur : Name; + var s : Char; + var m : Char; + var birth : Date + in + begin + getname (var sur); getname (var fore); + get (var s); while s = ' ' do get (var s); + get (var m); while m = ' ' do get (var m); + getdate (var birth); + person := {surname ~ sur, forename ~ fore, + male ~ (s = 'M'), married ~ (m = 'm'), + dob ~ birth} + end; + + proc putperson (person : Person) ~ + begin + putname (person.surname); put (' '); + putname (person.forename); put (' '); + put (if person.male then 'M' else 'F'); put (' '); + put (if person.married then 'm' else 'u'); put (' '); + putdate (person.dob) + end; + + func age (person : Person) : Integer ~ + let + const dob ~ person.dob + in + if (today.m > dob.m) \/ + ((today.m = dob.m) /\ (today.d >= dob.d)) + then today.y - dob.y + else today.y - dob.y - 1; + + const latestdob ~ yearsbefore (16, today); + + var bride : Person; + var groom : Person + +in + begin + getperson (var bride); + getperson (var groom); + puteol (); + if \ bride.male /\ groom.male /\ + \ (bride.married \/ groom.married) /\ + \ earlier (latestdob, bride.dob) /\ + \ earlier (latestdob, groom.dob) then + begin + put ('O'); put ('K'); puteol (); + bride.married := true; groom.married := true; + bride.surname := groom.surname + end + else + begin + put ('N'); put ('o'); put ('!'); puteol () + end; + putperson (bride); put (' '); putint (age (bride)); puteol (); + putperson (groom); put (' '); putint (age (groom)); puteol (); + putdate (today); puteol () + end diff --git a/programs/factorials.tri b/programs/factorials.tri new file mode 100644 index 0000000..c1db33c --- /dev/null +++ b/programs/factorials.tri @@ -0,0 +1,15 @@ +let + func factorial (n: Integer): Integer ~ + if n <= 1 + then 1 + else n * factorial (n-1); + + var i: Integer + +in + begin + getint (var i); + putint (i); put ('!'); + put (' '); put ('='); put (' '); + putint (factorial (i)) + end diff --git a/programs/functions.tri b/programs/functions.tri new file mode 100644 index 0000000..d343874 --- /dev/null +++ b/programs/functions.tri @@ -0,0 +1,28 @@ +! Print powers of integers. + +let + func even (n : Integer) : Boolean ~ + (n // 2) = 0; + + func sqr (n : Integer) : Integer ~ + n * n; + + func power (b : Integer, n : Integer) : Integer ~ + ! assume n >= 0 + if n = 0 + then 1 + else + if even (n) + then sqr (power (b, n/2)) + else sqr (power (b, n/2)) * b; + + var x : Integer; + var m : Integer +in + begin + getint (var x); getint (var m); + putint (x); put ('^'); putint (m); + put (' '); put ('='); put (' '); + putint (power (x, m)); + puteol () + end diff --git a/programs/hi-newcomment.tri b/programs/hi-newcomment.tri new file mode 100644 index 0000000..0929f38 --- /dev/null +++ b/programs/hi-newcomment.tri @@ -0,0 +1,7 @@ +! this won't work until after some work in the practicals + +# new comment + +begin + put('H'); put('i'); put('!') +end diff --git a/programs/hi-newcomment2.tri b/programs/hi-newcomment2.tri new file mode 100644 index 0000000..4e764fc --- /dev/null +++ b/programs/hi-newcomment2.tri @@ -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 diff --git a/programs/hi.tam b/programs/hi.tam new file mode 100644 index 0000000..26e8273 Binary files /dev/null and b/programs/hi.tam differ diff --git a/programs/hi.tri b/programs/hi.tri new file mode 100644 index 0000000..aac4ec1 --- /dev/null +++ b/programs/hi.tri @@ -0,0 +1,3 @@ +begin + put('H'); put('i'); put('!') +end diff --git a/programs/hullo.tri b/programs/hullo.tri new file mode 100644 index 0000000..a7a40a0 --- /dev/null +++ b/programs/hullo.tri @@ -0,0 +1,53 @@ +let + const maxlength ~ 15; + type String ~ array 16 of Char; + const null ~ chr(0); +!Strings will be padded with nulls. + + proc getstring (var s: String) ~ + let var l: Integer + in + begin + l := 0; + while l < maxlength do + begin + if eol () then + s[l] := null + else + get (var s[l]); + l := l+1; + end; + s[maxlength] := null + end; + + proc putstring (s: String) ~ + let var i: Integer + in + begin + i := 0; + while s[i] \= null do + begin + put (s[i]); + i := i+1 + end + end; + + var you: String + +in + begin + putstring ( + ['W','h','o',' ', + 'a','r','e',' ', + 'y','o','u','?', + null,null,null,null]); + puteol (); + getstring (var you); geteol (); + putstring ( + ['H','u','l','l', + 'o',',',' ',null, + null,null,null,null, + null,null,null,null]); + putstring (you); put ('!'); + puteol () +end diff --git a/programs/ifdemo.tri b/programs/ifdemo.tri new file mode 100644 index 0000000..ddc4df3 --- /dev/null +++ b/programs/ifdemo.tri @@ -0,0 +1,9 @@ +let + var a : Integer; + var n : Integer +in + begin + if a < 0 + then n := 0 + else n := 1 + end diff --git a/programs/increment.tri b/programs/increment.tri new file mode 100644 index 0000000..11358a5 --- /dev/null +++ b/programs/increment.tri @@ -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 diff --git a/programs/names.tri b/programs/names.tri new file mode 100644 index 0000000..741167a --- /dev/null +++ b/programs/names.tri @@ -0,0 +1,52 @@ +let + type Name ~ array 6 of Char; + type Number ~ Integer; + + proc getname (var newname: Name) ~ + let var i: Integer + in + begin + i := 0; + while i < 6 do + begin + if eol () then + newname[i] := ' ' + else + get (var newname[i]); + i := i+1 + end + end; + + proc putname (newname: Name) ~ + let var i: Integer + in + begin + i := 0; + while i < 6 do + begin + put (newname[i]); + i := i+1 + end + end; + + func samename (name1: Name, name2: Name) : Boolean ~ + let + func same (n: Integer) : Boolean ~ + (name1[n] = name2[n]) /\ + (if n = 0 then true else same (n-1)) + in + same (5); + + var nam: Name + +in + + begin + getname (var nam); geteol (); + putname (nam); put (' '); + if samename (nam, ['D','a','v','i','d',' ']) then + put ('Y') + else + put ('N'); + puteol () + end diff --git a/programs/nesting.tri b/programs/nesting.tri new file mode 100644 index 0000000..90838ca --- /dev/null +++ b/programs/nesting.tri @@ -0,0 +1,31 @@ +let + var g: Integer; + + proc P() ~ + let + var p: Integer; + + proc Q() ~ + let + var q: Integer; + proc R() ~ + let + var r: Integer + in + r := (g+p+q) * 1000 ! should cause overflow + in + begin q := g+p; R() end; + + proc S() ~ + let + var s: Integer + in + begin s := g+p+1; Q() end + + in + begin p := g+1; S() end + +in + begin g := 1000; P() end + + diff --git a/programs/procedural.tri b/programs/procedural.tri new file mode 100644 index 0000000..65263d0 --- /dev/null +++ b/programs/procedural.tri @@ -0,0 +1,56 @@ +! test program proc.Æ +let + const size ~ 6; + type String ~ array 6 of Char; + + proc putstr (s: String) ~ + let var i: Integer + in + begin + i := 0; + while i < size do + begin put (s[i]); i := i+1 end + end; + + proc apply (proc p (var c : Char), var s : String) ~ + let + var i : Integer + in + begin + i := 0; + while i < size do + begin + p (var s[i]); + i := i+1 + end + end; !apply + + proc shift (var l : Char) ~ + let const ordl ~ ord (l) + in + if (ord('a') <= ordl) + /\ (ordl <= ord('z')) then + l := chr (ordl - ord('a') + ord('A')) + else + ; !skip + + proc replaceall (old: Char, new: Char, + var s: String) ~ + let + proc zap (var c: Char) ~ + if c = old then c := new else !skip + in + apply (proc zap, var s); + + var name : String + +in + begin + apply (proc get, var name); + geteol (); + putstr (name); puteol (); + apply (proc shift, var name); + putstr (name); puteol (); + replaceall ('I', 'i', var name); + putstr (name); puteol () + end diff --git a/programs/procedures.tri b/programs/procedures.tri new file mode 100644 index 0000000..a72f68c --- /dev/null +++ b/programs/procedures.tri @@ -0,0 +1,31 @@ +! Plot a histogram from a stream of nonzero integers. + +let + const mid ~ 40; + var n : Integer; + + proc putmany (c : Char, n : Integer) ~ + let + var i : Integer + in + begin + i := 0; + while i < n do + begin put (c); i := i + 1 end + end; + + proc makenonnegative (var n : Integer) ~ + if n < 0 then n := 0 - n else + +in + begin + getint (var n); geteol (); + while n \= 0 do + begin + putmany (' ', if n > 0 then mid else mid + n); + makenonnegative (var n); + putmany ('+', n); + puteol (); + getint (var n); geteol () + end + end diff --git a/programs/records.tri b/programs/records.tri new file mode 100644 index 0000000..5d8f63e --- /dev/null +++ b/programs/records.tri @@ -0,0 +1,24 @@ +! test program record.Æ +let + type Month ~ array 3 of Char; + type Date ~ record d: Integer, m: Month end; + const xmas ~ {d ~ 25, + m ~ ['D','e','c']}; + var eve: Date; + + proc putmonth (mth: Month) ~ + begin + put (mth[0]); put (mth[1]); put (mth[2]) + end; + + proc putdate (date: Date) ~ + begin + putint (date.d); put ('/'); putmonth (date.m) + end + +in + begin + putdate (xmas); puteol (); + eve := {d ~ xmas.d-1, m ~ xmas.m}; + putdate (eve); puteol () + end \ No newline at end of file diff --git a/programs/repeatuntil.tri b/programs/repeatuntil.tri new file mode 100644 index 0000000..c2518de --- /dev/null +++ b/programs/repeatuntil.tri @@ -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 diff --git a/programs/repl.tri b/programs/repl.tri new file mode 100644 index 0000000..f6cf367 --- /dev/null +++ b/programs/repl.tri @@ -0,0 +1,13 @@ +let + type Str ~ array 10 of Char; + + func replicate (c: Char): Str ~ + [c,c,c,c,c,c,c,c,c,c]; + + var s: Str +in + + begin + s := replicate('*'); + put (s[0]); put(s[9]); puteol() + end diff --git a/programs/run b/programs/run new file mode 100755 index 0000000..84ed354 --- /dev/null +++ b/programs/run @@ -0,0 +1,43 @@ +#!/bin/bash + +# Term colours for output +RED='\033[0;31m' # Red +GRN='\033[0;32m' # Green +NC='\033[0m' # No Color + +TRI="" + +# Check if the input in arg 1 ($1) is empty +if [ -z "$1" ] + then # if empty... + printf "${RED}Usage: $0 *.tri file (optional: $0 *.tri tree)${NC}" + exit 1 # Exit with code 1, failure + else + TRI=$1 +fi + +#Remove the extension of the file +FILENAME=$(echo $TRI | cut -f 1 -d '.') + +#TODO: implement tree command +printf "${GRN}[INFO] Compiling file: $FILENAME.tri to $FILENAME.tam ...${NC}\n" + +# Compile to tam +if java -cp ../build/libs/Triangle-Tools.jar triangle.Compiler $FILENAME.tri -o=$FILENAME.tam &> /dev/null #quiet + then if [ -z "$2" ] + then #if empty + printf "${GRN}[INFO] Running file: $FILENAME.tam ...${NC}\n" + java -cp ../build/libs/Triangle-Tools.jar triangle.abstractMachine.Interpreter $FILENAME.tam + exit 0 + else + printf "${GRN}[INFO] Running file: $FILENAME.tam ... and displaying AST${NC}\n" + java -cp ../build/libs/Triangle-Tools.jar triangle.Compiler $FILENAME.tri tree -o=$FILENAME.tam &> /dev/null #quiet + exit 0 + fi + + else + printf "${RED}[ERROR] Could not complie $FILENAME.tri ...${NC}" + err=$(java -cp ../build/libs/Triangle-Tools.jar triangle.Compiler $FILENAME.tri -o=$FILENAME.tam) + printf "${RED}\n$err\n${NC}" + exit 1 +fi diff --git a/programs/simpleadding.tri b/programs/simpleadding.tri new file mode 100644 index 0000000..139847a --- /dev/null +++ b/programs/simpleadding.tri @@ -0,0 +1,10 @@ +let + var a : Integer; + var b : Integer; + var c : Integer + +in + begin + a := 1; b := 2; c := a / b; + end + diff --git a/programs/triangle.tam b/programs/triangle.tam new file mode 100644 index 0000000..87d30f3 Binary files /dev/null and b/programs/triangle.tam differ diff --git a/programs/triangle.tri b/programs/triangle.tri new file mode 100644 index 0000000..555ea81 --- /dev/null +++ b/programs/triangle.tri @@ -0,0 +1,32 @@ +let + + proc putmany (n: Integer, c: Char) ~ + let + var i: Integer + in + begin + i := 0; + while i < n do + begin i := i+1; put (c) end + end; + + var n: Integer; var r: Integer; + const mark ~ '@' + +in + begin + getint (var n); geteol (); + r := 0; + while r < (n-1) do + begin + r := r + 1; + putmany (n-r, ' '); put (mark); + if r >= 2 then + begin + putmany (2*r - 3, ' '); put (mark) + end + else; !skip + puteol () + end; + putmany (2*n - 1, mark) + end diff --git a/programs/while-longloop.tri b/programs/while-longloop.tri new file mode 100644 index 0000000..75b1088 --- /dev/null +++ b/programs/while-longloop.tri @@ -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 diff --git a/programs/while.tri b/programs/while.tri new file mode 100644 index 0000000..9bbb664 --- /dev/null +++ b/programs/while.tri @@ -0,0 +1,11 @@ +let + var a : Integer +in +begin + a := 0; + while a < 5 do + begin + put('a'); + a := a + 1; + end +end diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..5e273cd --- /dev/null +++ b/settings.gradle @@ -0,0 +1,7 @@ +rootProject.name = 'Triangle-Tools' + +include 'Triangle.Compiler' +include 'Triangle.AbstractMachine' +include 'Triangle.AbstractMachine.Disassembler' +include 'Triangle.AbstractMachine.Interpreter' +