format
parent
518ca35a68
commit
72f3b2b497
|
@ -13,9 +13,8 @@ import java.util.SortedSet;
|
|||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Disassemble the mJAM object code
|
||||
* from input file xxx.mJAM
|
||||
* into output file xxx.asm
|
||||
* Disassemble the mJAM object code from input file xxx.mJAM into output file
|
||||
* xxx.asm
|
||||
*
|
||||
* @author prins
|
||||
* @version COMP 520 v2.2
|
||||
|
@ -33,11 +32,15 @@ public class Disassembler {
|
|||
}
|
||||
|
||||
/**
|
||||
* Writes the r-field of an instruction in the form "l<I>reg</I>r", 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.
|
||||
* Writes the r-field of an instruction in the form "l<I>reg</I>r", 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 void writeR(char leftbracket, int r, char rightbracket) {
|
||||
asmWrite(Character.toString(leftbracket));
|
||||
|
@ -55,15 +58,19 @@ public class Disassembler {
|
|||
// Writes the n-field of an instruction.
|
||||
/**
|
||||
* Writes the n-field of an instruction in the form "(n)".
|
||||
* @param n the integer to write.
|
||||
*
|
||||
* @param n
|
||||
* the integer to write.
|
||||
*/
|
||||
private void writeN(int n) {
|
||||
asmWrite(String.format("%-6s","(" + n + ")"));
|
||||
asmWrite(String.format("%-6s", "(" + n + ")"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the d-field of an instruction.
|
||||
* @param d the integer to write.
|
||||
*
|
||||
* @param d
|
||||
* the integer to write.
|
||||
*/
|
||||
private void writeD(int d) {
|
||||
asmWrite(Integer.toString(d));
|
||||
|
@ -71,16 +78,20 @@ public class Disassembler {
|
|||
|
||||
/**
|
||||
* Writes the name of primitive routine with relative address d.
|
||||
* @param d the displacment of the primitive routine.
|
||||
*
|
||||
* @param d
|
||||
* the displacment of the primitive routine.
|
||||
*/
|
||||
private void writePrimitive(int d) {
|
||||
Machine.Prim prim = Machine.intToPrim[d];
|
||||
asmWrite(String.format("%-8s",prim.toString()));
|
||||
asmWrite(String.format("%-8s", prim.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given instruction in assembly-code format.
|
||||
* @param instr the instruction to display.
|
||||
*
|
||||
* @param instr
|
||||
* the instruction to display.
|
||||
*/
|
||||
private void writeInstruction(Instruction instr) {
|
||||
|
||||
|
@ -90,7 +101,7 @@ public class Disassembler {
|
|||
targetLabel = addrToLabel.get(instr.d);
|
||||
|
||||
Machine.Op instruction = Machine.intToOp[instr.op];
|
||||
asmWrite(String.format("%-7s",instruction.toString()));
|
||||
asmWrite(String.format("%-7s", instruction.toString()));
|
||||
switch (instruction) {
|
||||
case LOAD:
|
||||
blankN();
|
||||
|
@ -190,8 +201,7 @@ public class Disassembler {
|
|||
try {
|
||||
asmOut = new FileWriter(asmFileName);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Disassembler: can not create asm output file "
|
||||
+ asmName);
|
||||
System.out.println("Disassembler: can not create asm output file " + asmName);
|
||||
error = true;
|
||||
return;
|
||||
}
|
||||
|
@ -204,13 +214,15 @@ public class Disassembler {
|
|||
switch (op) {
|
||||
case CALL:
|
||||
case CALLI:
|
||||
// only consider calls (branches) within code memory (i.e. not primitives)
|
||||
// only consider calls (branches) within code memory (i.e. not
|
||||
// primitives)
|
||||
if (inst.r == Machine.Reg.CB.ordinal())
|
||||
targets.add(inst.d);
|
||||
break;
|
||||
case JUMP:
|
||||
// address following an unconditional branch is an implicit target
|
||||
targets.add(addr+1);
|
||||
// address following an unconditional branch is an implicit
|
||||
// target
|
||||
targets.add(addr + 1);
|
||||
targets.add(inst.d);
|
||||
break;
|
||||
case JUMPIF:
|
||||
|
@ -226,7 +238,7 @@ public class Disassembler {
|
|||
addrToLabel = new HashMap<Integer, String>();
|
||||
int labelCounter = 10;
|
||||
for (Integer addr : targets) {
|
||||
String label = "L" + labelCounter++ ;
|
||||
String label = "L" + labelCounter++;
|
||||
addrToLabel.put(addr, label);
|
||||
}
|
||||
|
||||
|
@ -276,6 +288,7 @@ public class Disassembler {
|
|||
|
||||
/**
|
||||
* Disassemble object file
|
||||
*
|
||||
* @return true if error encountered else false
|
||||
*/
|
||||
public boolean disassemble() {
|
||||
|
@ -283,15 +296,13 @@ public class Disassembler {
|
|||
|
||||
// read object file into code store
|
||||
if (objectFile.read()) {
|
||||
System.out.println("Disassembler: unable to read object file"
|
||||
+ objectFileName);
|
||||
System.out.println("Disassembler: unable to read object file" + objectFileName);
|
||||
return true;
|
||||
}
|
||||
|
||||
// assembler-code output file name
|
||||
if (objectFileName.endsWith(".mJAM"))
|
||||
asmName = objectFileName.substring(0, objectFileName.length() - 5)
|
||||
+ ".asm";
|
||||
asmName = objectFileName.substring(0, objectFileName.length() - 5) + ".asm";
|
||||
else
|
||||
asmName = objectFileName + ".asm";
|
||||
|
||||
|
@ -299,8 +310,7 @@ public class Disassembler {
|
|||
disassembleProgram(asmName);
|
||||
|
||||
if (error) {
|
||||
System.out.println("Disassembler: unable to write asm file"
|
||||
+ asmName);
|
||||
System.out.println("Disassembler: unable to write asm file" + asmName);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,17 +22,15 @@ public class Interpreter {
|
|||
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
|
||||
|
||||
final static int CB = 0, SB = 0, HB = 1024; // = upper bound of data array +
|
||||
// 1
|
||||
|
||||
static int CT, CP, ST, HT, LB, OB, status, temp;
|
||||
|
||||
// machine status values
|
||||
final static int running = 0, halted = 1, failedDataStoreFull = 2,
|
||||
failedInvalidCodeAddress = 3, failedInvalidInstruction = 4,
|
||||
failedOverflow = 5, failedZeroDivide = 6, failedIOError = 7,
|
||||
failedArrayIndex = 8, failedNullRef = 9, failedHeapRef =10,
|
||||
failedMethodIndex = 11;
|
||||
final static int running = 0, halted = 1, failedDataStoreFull = 2, failedInvalidCodeAddress = 3,
|
||||
failedInvalidInstruction = 4, failedOverflow = 5, failedZeroDivide = 6, failedIOError = 7,
|
||||
failedArrayIndex = 8, failedNullRef = 9, failedHeapRef = 10, failedMethodIndex = 11;
|
||||
|
||||
static long accumulator;
|
||||
|
||||
|
@ -82,8 +80,7 @@ public class Interpreter {
|
|||
// Writes a summary of the machine state.
|
||||
int addr, dynamicLink;
|
||||
System.out.println("");
|
||||
System.out.println("At instruction " + CP
|
||||
+ ", state of mJAM data store and registers is:");
|
||||
System.out.println("At instruction " + CP + ", state of mJAM data store and registers is:");
|
||||
System.out.println("");
|
||||
if (HT == HB)
|
||||
System.out.println(" |--------| (heap is empty)");
|
||||
|
@ -98,8 +95,7 @@ public class Interpreter {
|
|||
System.out.print("HT--> ");
|
||||
else
|
||||
System.out.print(" ");
|
||||
System.out.println("|" + leftPad(8, String.valueOf(data[addr]))
|
||||
+ "|");
|
||||
System.out.println("|" + leftPad(8, String.valueOf(data[addr])) + "|");
|
||||
}
|
||||
System.out.println(" |--------|");
|
||||
}
|
||||
|
@ -120,17 +116,13 @@ public class Interpreter {
|
|||
else
|
||||
System.out.print(" ");
|
||||
if ((addr == dynamicLink) && (dynamicLink != SB))
|
||||
System.out.print("|OB="
|
||||
+ leftPad(5, String.valueOf(data[addr])) + "|");
|
||||
System.out.print("|OB=" + leftPad(5, String.valueOf(data[addr])) + "|");
|
||||
else if ((addr == dynamicLink + 1) && (dynamicLink != SB))
|
||||
System.out.print("|DL="
|
||||
+ leftPad(5, String.valueOf(data[addr])) + "|");
|
||||
System.out.print("|DL=" + leftPad(5, String.valueOf(data[addr])) + "|");
|
||||
else if ((addr == dynamicLink + 2) && (dynamicLink != SB))
|
||||
System.out.print("|RA="
|
||||
+ leftPad(5, String.valueOf(data[addr])) + "|");
|
||||
System.out.print("|RA=" + leftPad(5, String.valueOf(data[addr])) + "|");
|
||||
else
|
||||
System.out.print("|"
|
||||
+ leftPad(8, String.valueOf(data[addr])) + "|");
|
||||
System.out.print("|" + leftPad(8, String.valueOf(data[addr])) + "|");
|
||||
System.out.println("");
|
||||
if (addr == dynamicLink) {
|
||||
System.out.println(" |--------|");
|
||||
|
@ -423,7 +415,8 @@ public class Interpreter {
|
|||
HT = HT - size; // reserve space
|
||||
data[HT] = data[ST - 2]; // set class object addr
|
||||
data[HT + 1] = size - 2; // set size of object
|
||||
data[ST - 2] = HT + 2; // addr of new object instance, returned on stack
|
||||
data[ST - 2] = HT + 2; // addr of new object instance, returned on
|
||||
// stack
|
||||
ST = ST - 1; // net effect of pop 2 args, push 1 result
|
||||
for (int i = 2; i < size; i++) {
|
||||
data[HT + i] = 0; // zero all fields of new object
|
||||
|
@ -451,7 +444,8 @@ public class Interpreter {
|
|||
status = failedArrayIndex;
|
||||
break;
|
||||
}
|
||||
data[ST - 2] = data[addr + index]; // result element, returned on stack
|
||||
data[ST - 2] = data[addr + index]; // result element, returned on
|
||||
// stack
|
||||
ST = ST - 1; // pop two args, return one result
|
||||
break;
|
||||
case arrayupd:
|
||||
|
@ -565,8 +559,10 @@ public class Interpreter {
|
|||
// static method in code segment, no instance addr on stack
|
||||
checkSpace(3);
|
||||
data[ST] = OB; // save caller OB in callee frame
|
||||
data[ST + 1] = LB; // save caller LB in callee frame (dynamic link)
|
||||
data[ST + 2] = CP + 1; // save caller return address in callee frame
|
||||
data[ST + 1] = LB; // save caller LB in callee frame (dynamic
|
||||
// link)
|
||||
data[ST + 2] = CP + 1; // save caller return address in callee
|
||||
// frame
|
||||
OB = Machine.nullRep; // set callee OB (null since no instance)
|
||||
LB = ST; // set LB = start of callee frame
|
||||
ST = ST + 3; // set ST = end of callee frame
|
||||
|
@ -596,7 +592,8 @@ public class Interpreter {
|
|||
break;
|
||||
|
||||
case RETURN:
|
||||
// d = number of method args (does not include instance addr for CALLI)
|
||||
// d = number of method args (does not include instance addr for
|
||||
// CALLI)
|
||||
// n = size of result (0 or 1)
|
||||
if (n < 0 || n > 1) {
|
||||
status = failedInvalidInstruction;
|
||||
|
@ -708,27 +705,15 @@ public class Interpreter {
|
|||
}
|
||||
|
||||
static void printHelp() {
|
||||
String[] help = {
|
||||
"p or print:",
|
||||
" print entire machine state",
|
||||
"l or list [offset] [size]:",
|
||||
String[] help = { "p or print:", " print entire machine state", "l or list [offset] [size]:",
|
||||
" print the instructions around CP + offset, with size lines on either side",
|
||||
" offset = 0 and size = 2 by default",
|
||||
"b or break [address]:",
|
||||
" set a breakpoint at address",
|
||||
" address = CP by default",
|
||||
"del:",
|
||||
" delete one or more breakpoints",
|
||||
"n or next:",
|
||||
" execute one instruction",
|
||||
"c or continue:",
|
||||
" offset = 0 and size = 2 by default", "b or break [address]:", " set a breakpoint at address",
|
||||
" address = CP by default", "del:", " delete one or more breakpoints", "n or next:",
|
||||
" execute one instruction", "c or continue:",
|
||||
" continue running the program from current position, until next breakpoint or completion",
|
||||
"r or run:",
|
||||
" run the program from start, until next breakpoint or completion",
|
||||
"i or info:", " list the current breakpoints",
|
||||
"q, quit or <EOF>:", " quit the debugger",
|
||||
"Simply press enter to repeat the last command", "? or help:",
|
||||
" print this help" };
|
||||
"r or run:", " run the program from start, until next breakpoint or completion", "i or info:",
|
||||
" list the current breakpoints", "q, quit or <EOF>:", " quit the debugger",
|
||||
"Simply press enter to repeat the last command", "? or help:", " print this help" };
|
||||
|
||||
for (String line : help) {
|
||||
System.out.println(" " + line);
|
||||
|
@ -738,8 +723,7 @@ public class Interpreter {
|
|||
static void debugProgram() {
|
||||
initMachine();
|
||||
|
||||
BufferedReader inputReader = new BufferedReader(new InputStreamReader(
|
||||
System.in));
|
||||
BufferedReader inputReader = new BufferedReader(new InputStreamReader(System.in));
|
||||
|
||||
String lastCommand = "";
|
||||
|
||||
|
@ -762,11 +746,9 @@ public class Interpreter {
|
|||
|
||||
if (command.equals("?") || command.equals("help")) {
|
||||
printHelp();
|
||||
} else if (command.equalsIgnoreCase("p")
|
||||
|| command.equalsIgnoreCase("print")) {
|
||||
} else if (command.equalsIgnoreCase("p") || command.equalsIgnoreCase("print")) {
|
||||
dump();
|
||||
} else if (command.equalsIgnoreCase("l")
|
||||
|| command.equalsIgnoreCase("list")) {
|
||||
} else if (command.equalsIgnoreCase("l") || command.equalsIgnoreCase("list")) {
|
||||
int offset = 0, size = 2;
|
||||
if (scanner.hasNextInt())
|
||||
offset = scanner.nextInt();
|
||||
|
@ -775,52 +757,42 @@ public class Interpreter {
|
|||
|
||||
for (int i = CP + offset - size; i <= CP + offset + size; ++i) {
|
||||
if (i >= 0 && i < sourceLines.size())
|
||||
System.out.println((i == CP ? " >" : " ")
|
||||
+ sourceLines.get(i));
|
||||
System.out.println((i == CP ? " >" : " ") + sourceLines.get(i));
|
||||
}
|
||||
} else if (command.equalsIgnoreCase("b")
|
||||
|| command.equalsIgnoreCase("break")) {
|
||||
} else if (command.equalsIgnoreCase("b") || command.equalsIgnoreCase("break")) {
|
||||
int addr = scanner.hasNextInt() ? scanner.nextInt() : CP;
|
||||
if (!breakpoints.contains(addr))
|
||||
breakpoints.add(addr);
|
||||
System.out.println("Added breakpoint at "
|
||||
+ sourceLines.get(addr));
|
||||
System.out.println("Added breakpoint at " + sourceLines.get(addr));
|
||||
} else if (command.equalsIgnoreCase("del")) {
|
||||
while (scanner.hasNextInt()) {
|
||||
int addr = scanner.nextInt(), idx = breakpoints
|
||||
.indexOf(addr);
|
||||
int addr = scanner.nextInt(), idx = breakpoints.indexOf(addr);
|
||||
if (idx != -1) {
|
||||
breakpoints.remove(idx);
|
||||
} else {
|
||||
System.out.println("No breakpoint at " + addr);
|
||||
}
|
||||
}
|
||||
} else if (command.equalsIgnoreCase("n")
|
||||
|| command.equalsIgnoreCase("next")) {
|
||||
} else if (command.equalsIgnoreCase("n") || command.equalsIgnoreCase("next")) {
|
||||
if (status == running) {
|
||||
interpretOneOperation();
|
||||
} else {
|
||||
System.out.println("Program is not running");
|
||||
}
|
||||
} else if (command.equalsIgnoreCase("c")
|
||||
|| command.equalsIgnoreCase("continue")) {
|
||||
} else if (command.equalsIgnoreCase("c") || command.equalsIgnoreCase("continue")) {
|
||||
continueProgram();
|
||||
} else if (command.equalsIgnoreCase("r")
|
||||
|| command.equalsIgnoreCase("run")) {
|
||||
} else if (command.equalsIgnoreCase("r") || command.equalsIgnoreCase("run")) {
|
||||
runProgramFromStart();
|
||||
} else if (command.equalsIgnoreCase("i")
|
||||
|| command.equalsIgnoreCase("info")) {
|
||||
} else if (command.equalsIgnoreCase("i") || command.equalsIgnoreCase("info")) {
|
||||
System.out.println("Breakpoints:");
|
||||
for (int b : breakpoints) {
|
||||
System.out.println("\t" + sourceLines.get(b));
|
||||
}
|
||||
} else if (command.equalsIgnoreCase("q")
|
||||
|| command.equalsIgnoreCase("quit")) {
|
||||
} else if (command.equalsIgnoreCase("q") || command.equalsIgnoreCase("quit")) {
|
||||
scanner.close();
|
||||
return;
|
||||
} else {
|
||||
System.out.println("Unknown command '" + command
|
||||
+ "'. Type 'help' for a list of commands");
|
||||
System.out.println("Unknown command '" + command + "'. Type 'help' for a list of commands");
|
||||
}
|
||||
scanner.close();
|
||||
}
|
||||
|
@ -829,8 +801,7 @@ public class Interpreter {
|
|||
// RUNNING
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out
|
||||
.println("********** mJAM Interpreter (Version 1.2) **********");
|
||||
System.out.println("********** mJAM Interpreter (Version 1.2) **********");
|
||||
|
||||
String objectFileName;
|
||||
if (args.length >= 1)
|
||||
|
@ -867,8 +838,7 @@ public class Interpreter {
|
|||
|
||||
sourceLines = new ArrayList<String>();
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new FileReader(new File(
|
||||
sourceFileName)));
|
||||
BufferedReader reader = new BufferedReader(new FileReader(new File(sourceFileName)));
|
||||
String line = reader.readLine();
|
||||
while (line != null) {
|
||||
sourceLines.add(line);
|
||||
|
|
|
@ -2,6 +2,7 @@ package mJAM;
|
|||
|
||||
/**
|
||||
* Defines names and sizes of mJAM instructions and primitives
|
||||
*
|
||||
* @author prins
|
||||
* @version COMP 520 V2.2
|
||||
*/
|
||||
|
@ -11,25 +12,14 @@ public final class Machine {
|
|||
* mJAM instructions
|
||||
*/
|
||||
public enum Op {
|
||||
LOAD,
|
||||
LOADA,
|
||||
LOADI,
|
||||
LOADL,
|
||||
STORE,
|
||||
STOREI,
|
||||
CALL, // direct call of instance method
|
||||
LOAD, LOADA, LOADI, LOADL, STORE, STOREI, CALL, // direct call of
|
||||
// instance method
|
||||
CALLI, // indirect call of instance method
|
||||
CALLD, // dynamic call of instance method
|
||||
RETURN,
|
||||
PUSH,
|
||||
POP,
|
||||
JUMP,
|
||||
JUMPI,
|
||||
JUMPIF,
|
||||
HALT;
|
||||
RETURN, PUSH, POP, JUMP, JUMPI, JUMPIF, HALT;
|
||||
}
|
||||
public static Op [] intToOp = Op.values();
|
||||
|
||||
public static Op[] intToOp = Op.values();
|
||||
|
||||
/**
|
||||
* mJAM registers
|
||||
|
@ -48,62 +38,28 @@ public final class Machine {
|
|||
HT, // heap top
|
||||
OB; // object base
|
||||
}
|
||||
public static Reg [] intToReg = Reg.values();
|
||||
|
||||
public static Reg[] intToReg = Reg.values();
|
||||
|
||||
/**
|
||||
* mJAM primitives
|
||||
*/
|
||||
public enum Prim {
|
||||
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,
|
||||
putintnl,
|
||||
alloc,
|
||||
dispose,
|
||||
newobj,
|
||||
newarr,
|
||||
arrayref,
|
||||
arrayupd,
|
||||
fieldref,
|
||||
fieldupd;
|
||||
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, putintnl, alloc, dispose, newobj, newarr, arrayref, arrayupd, fieldref, fieldupd;
|
||||
}
|
||||
public static Prim [] intToPrim = Prim.values();
|
||||
|
||||
public static Prim[] intToPrim = Prim.values();
|
||||
|
||||
|
||||
// range for int constants
|
||||
public final static long
|
||||
minintRep = -2147483648,
|
||||
maxintRep = 2147483647;
|
||||
|
||||
// range for int constants
|
||||
public final static long minintRep = -2147483648, maxintRep = 2147483647;
|
||||
|
||||
// CODE STORE REGISTERS
|
||||
public final static int CB = 0; // start of code space
|
||||
public final static int PB = 1024; // size of code space reserved for instructions
|
||||
public final static int PT = PB + Prim.values().length; // code space reserved for primitives
|
||||
public final static int PB = 1024; // size of code space reserved for
|
||||
// instructions
|
||||
public final static int PT = PB + Prim.values().length; // code space
|
||||
// reserved for
|
||||
// primitives
|
||||
|
||||
// CODE STORE
|
||||
public static Instruction[] code = new Instruction[PB];
|
||||
|
@ -114,23 +70,29 @@ public final class Machine {
|
|||
}
|
||||
|
||||
/**
|
||||
* Places an instruction, with the given fields, into the next position in the code store
|
||||
* @param op - operation
|
||||
* @param n - length
|
||||
* @param r - register
|
||||
* @param d - displacement
|
||||
* Places an instruction, with the given fields, into the next position in
|
||||
* the code store
|
||||
*
|
||||
* @param op
|
||||
* - operation
|
||||
* @param n
|
||||
* - length
|
||||
* @param r
|
||||
* - register
|
||||
* @param d
|
||||
* - displacement
|
||||
*/
|
||||
public static void emit(Op op, int n, Reg r, Prim d) {
|
||||
public static void emit(Op op, int n, Reg r, Prim d) {
|
||||
emit(op.ordinal(), n, r.ordinal(), d.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* emit operation with single literal argument d (n,r not used). These are
|
||||
* operations like LOADL 44, PUSH 3, and CALLD 1
|
||||
*/
|
||||
public static void emit(Op op, int d) {
|
||||
public static void emit(Op op, int d) {
|
||||
emit(op.ordinal(), 0, 0, d);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* emit "call primitive operation" (operation built-in to mJAM). This
|
||||
|
@ -141,8 +103,8 @@ public static void emit(Op op, int d) {
|
|||
}
|
||||
|
||||
/**
|
||||
* emit operations without arguments. These are operations like
|
||||
* LOADI and STOREI
|
||||
* emit operations without arguments. These are operations like LOADI and
|
||||
* STOREI
|
||||
*/
|
||||
public static void emit(Op op) {
|
||||
emit(op, 0, 0, 0);
|
||||
|
@ -157,20 +119,19 @@ public static void emit(Op op, int d) {
|
|||
}
|
||||
|
||||
/**
|
||||
* emit operation with n field, and register r and integer displacement. These are
|
||||
* operations like JUMPIF (1) 25[CB]. In the assembly code the value of n is shown
|
||||
* in parens.
|
||||
* emit operation with n field, and register r and integer displacement.
|
||||
* These are operations like JUMPIF (1) 25[CB]. In the assembly code the
|
||||
* value of n is shown in parens.
|
||||
*/
|
||||
public static void emit(Op op, int n, Reg r, int d) {
|
||||
emit(op.ordinal(), n, r.ordinal(), d);
|
||||
}
|
||||
|
||||
/**
|
||||
* emit operation with integer n, r, d. These are operations
|
||||
* like RETURN (1) 3 and HALT (4) 0. For RETURN the value
|
||||
* of d is the number of caller args to pop off the callers
|
||||
* stack and n is the number of values to return at caller stack
|
||||
* top. n must be 0 or 1.
|
||||
* emit operation with integer n, r, d. These are operations like RETURN (1)
|
||||
* 3 and HALT (4) 0. For RETURN the value of d is the number of caller args
|
||||
* to pop off the callers stack and n is the number of values to return at
|
||||
* caller stack top. n must be 0 or 1.
|
||||
*/
|
||||
public static void emit(Op op, int n, int r, int d) {
|
||||
emit(op.ordinal(), n, r, d);
|
||||
|
@ -179,7 +140,7 @@ public static void emit(Op op, int d) {
|
|||
/**
|
||||
* helper operation for emit using integer values
|
||||
*/
|
||||
private static void emit (int op, int n, int r, int d) {
|
||||
private static void emit(int op, int n, int r, int d) {
|
||||
if (n > 255) {
|
||||
System.out.println("length of operand can't exceed 255 words");
|
||||
n = 255; // to allow code generation to continue
|
||||
|
@ -192,19 +153,21 @@ private static void emit (int op, int n, int r, int d) {
|
|||
CT = CT + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @return address (relative to CB) of next instruction to be generated
|
||||
*/
|
||||
public static int nextInstrAddr() {
|
||||
public static int nextInstrAddr() {
|
||||
return CT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the displacement component of the (JUMP or CALL) instruction at addr
|
||||
/**
|
||||
* Update the displacement component of the (JUMP or CALL) instruction at
|
||||
* addr
|
||||
*
|
||||
* @param addr
|
||||
* @param displacement
|
||||
*/
|
||||
public static void patch(int addr, int displacement) {
|
||||
public static void patch(int addr, int displacement) {
|
||||
if (addr < 0 || addr >= CT) {
|
||||
System.out.println("patch: address of instruction to be patched is out of range");
|
||||
return;
|
||||
|
@ -215,18 +178,12 @@ public static void patch(int addr, int displacement) {
|
|||
}
|
||||
Machine.code[addr].d = displacement;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// DATA REPRESENTATION
|
||||
// DATA REPRESENTATION
|
||||
|
||||
public final static int
|
||||
booleanSize = 1,
|
||||
characterSize = 1,
|
||||
integerSize = 1,
|
||||
addressSize = 1,
|
||||
public final static int booleanSize = 1, characterSize = 1, integerSize = 1, addressSize = 1,
|
||||
linkDataSize = 3 * addressSize, // caller's OB, LB, CP
|
||||
falseRep = 0,
|
||||
trueRep = 1,
|
||||
nullRep = 0;
|
||||
falseRep = 0, trueRep = 1, nullRep = 0;
|
||||
|
||||
}
|
||||
|
|
|
@ -21,15 +21,17 @@ public class ObjectFile {
|
|||
|
||||
/**
|
||||
* Write code store as object file
|
||||
* @param output object file
|
||||
*
|
||||
* @param output
|
||||
* object file
|
||||
* @return true if write fails
|
||||
*/
|
||||
public boolean write(){
|
||||
public boolean write() {
|
||||
boolean failed = false;
|
||||
try {
|
||||
FileOutputStream objectFile = new FileOutputStream(objectFileName);
|
||||
DataOutputStream is = new DataOutputStream(objectFile);
|
||||
for (int i = Machine.CB; i < Machine.CT; i++ ){
|
||||
for (int i = Machine.CB; i < Machine.CT; i++) {
|
||||
Instruction inst = Machine.code[i];
|
||||
is.writeInt(inst.op);
|
||||
is.writeInt(inst.n);
|
||||
|
@ -37,13 +39,15 @@ public class ObjectFile {
|
|||
is.writeInt(inst.d);
|
||||
}
|
||||
objectFile.close();
|
||||
} catch (Exception e) {
|
||||
failed = true;
|
||||
}
|
||||
catch (Exception e) {failed = true;}
|
||||
return failed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read object file into code store, setting CT
|
||||
*
|
||||
* @return true if object code read fails
|
||||
*/
|
||||
public boolean read() {
|
||||
|
@ -53,7 +57,7 @@ public class ObjectFile {
|
|||
DataInputStream is = new DataInputStream(objectFile);
|
||||
|
||||
Machine.CT = Machine.CB;
|
||||
while (is.available() > 0 && Machine.CT < Machine.PB){
|
||||
while (is.available() > 0 && Machine.CT < Machine.PB) {
|
||||
Instruction inst = new Instruction();
|
||||
inst.op = is.readInt();
|
||||
inst.n = is.readInt();
|
||||
|
|
|
@ -4,127 +4,122 @@
|
|||
* @version COMP 520 V2.2
|
||||
*/
|
||||
package mJAM;
|
||||
|
||||
import mJAM.Machine.Op;
|
||||
import mJAM.Machine.Reg;
|
||||
import mJAM.Machine.Prim;
|
||||
|
||||
// test class to construct and run an mJAM program
|
||||
public class Test
|
||||
{
|
||||
public static void main(String[] args){
|
||||
public class Test {
|
||||
public static void main(String[] args) {
|
||||
|
||||
Machine.initCodeGen();
|
||||
System.out.println("Generating test program object code");
|
||||
|
||||
/* class A {
|
||||
* int x;
|
||||
* int p(){return x;}
|
||||
* }
|
||||
/*
|
||||
* class A { int x; int p(){return x;} }
|
||||
*/
|
||||
Machine.emit(Op.LOADL,11); // hello
|
||||
Machine.emit(Op.LOADL, 11); // hello
|
||||
Machine.emit(Prim.putintnl);
|
||||
int patchme_coA = Machine.nextInstrAddr();
|
||||
Machine.emit(Op.JUMP,Reg.CB,0); // jump around methods of class A (branch to /*coA*/)
|
||||
Machine.emit(Op.JUMP, Reg.CB, 0); // jump around methods of class A
|
||||
// (branch to /*coA*/)
|
||||
|
||||
// code for p() in A
|
||||
int label_pA = Machine.nextInstrAddr();
|
||||
/*pA*/ Machine.emit(Op.LOAD,Reg.OB,0); // x at offset 0 in current instance of A
|
||||
Machine.emit(Op.HALT,4,0,0);
|
||||
Machine.emit(Op.RETURN,1,0,0); // return one value, pop zero args
|
||||
/* pA */ Machine.emit(Op.LOAD, Reg.OB, 0); // x at offset 0 in current
|
||||
// instance of A
|
||||
Machine.emit(Op.HALT, 4, 0, 0);
|
||||
Machine.emit(Op.RETURN, 1, 0, 0); // return one value, pop zero args
|
||||
|
||||
// build class object for A at 0[SB]
|
||||
int label_coA = Machine.nextInstrAddr();
|
||||
Machine.patch(patchme_coA, label_coA);
|
||||
/*coA*/ Machine.emit(Op.LOADL,-1); // no superclass object
|
||||
Machine.emit(Op.LOADL,1); // number of methods
|
||||
Machine.emit(Op.LOADA,Reg.CB,label_pA); // code addr of p_A
|
||||
/* coA */ Machine.emit(Op.LOADL, -1); // no superclass object
|
||||
Machine.emit(Op.LOADL, 1); // number of methods
|
||||
Machine.emit(Op.LOADA, Reg.CB, label_pA); // code addr of p_A
|
||||
|
||||
|
||||
/* class B extends A {
|
||||
* int y;
|
||||
* int p(){return x + 22;}
|
||||
* }
|
||||
/*
|
||||
* class B extends A { int y; int p(){return x + 22;} }
|
||||
*/
|
||||
int patchme_coB = Machine.nextInstrAddr();
|
||||
Machine.emit(Op.JUMP,Reg.CB,0); // branch around methods in class B
|
||||
Machine.emit(Op.JUMP, Reg.CB, 0); // branch around methods in class B
|
||||
|
||||
// code for p() in B
|
||||
int label_pB = Machine.nextInstrAddr();
|
||||
/*pB*/ Machine.emit(Op.LOAD,Reg.OB,0); // x at offset 0 in current instance
|
||||
Machine.emit(Op.LOADL,22);
|
||||
Machine.emit(Op.HALT,4,0,0);
|
||||
/* pB */ Machine.emit(Op.LOAD, Reg.OB, 0); // x at offset 0 in current
|
||||
// instance
|
||||
Machine.emit(Op.LOADL, 22);
|
||||
Machine.emit(Op.HALT, 4, 0, 0);
|
||||
Machine.emit(Prim.add);
|
||||
Machine.emit(Op.RETURN,1,0,0); // return one value, pop zero args
|
||||
Machine.emit(Op.RETURN, 1, 0, 0); // return one value, pop zero args
|
||||
|
||||
// build class object for B at 3[SB]
|
||||
int label_coB = Machine.nextInstrAddr();
|
||||
Machine.patch(patchme_coB, label_coB);
|
||||
/*coB*/ Machine.emit(Op.LOADA,Reg.SB,0); // addr of superclass object
|
||||
Machine.emit(Op.LOADL,1); // number of methods
|
||||
Machine.emit(Op.LOADA,Reg.CB,label_pB); // code addr of p_B
|
||||
/* coB */ Machine.emit(Op.LOADA, Reg.SB, 0); // addr of superclass
|
||||
// object
|
||||
Machine.emit(Op.LOADL, 1); // number of methods
|
||||
Machine.emit(Op.LOADA, Reg.CB, label_pB); // code addr of p_B
|
||||
|
||||
|
||||
/* class C {
|
||||
* public static void main(String [] args) {
|
||||
* A a = new A();
|
||||
* a.x = 33;
|
||||
* System.out.println(a.p());
|
||||
* ...
|
||||
/*
|
||||
* class C { public static void main(String [] args) { A a = new A();
|
||||
* a.x = 33; System.out.println(a.p()); ...
|
||||
*/
|
||||
int patchme_coC = Machine.nextInstrAddr();
|
||||
Machine.emit(Op.JUMP,Reg.CB,0); // branch around methods of class C
|
||||
Machine.emit(Op.JUMP, Reg.CB, 0); // branch around methods of class C
|
||||
|
||||
// code for main() in C
|
||||
int label_mainC = Machine.nextInstrAddr();
|
||||
/*mainC*/ Machine.emit(Op.HALT,4,0,0);
|
||||
/* mainC */ Machine.emit(Op.HALT, 4, 0, 0);
|
||||
// local var "a" will be at 3[LB] after init
|
||||
Machine.emit(Op.LOADA,Reg.SB,0); // class descriptor for A
|
||||
Machine.emit(Op.LOADL,1); // size of A
|
||||
Machine.emit(Op.LOADA, Reg.SB, 0); // class descriptor for A
|
||||
Machine.emit(Op.LOADL, 1); // size of A
|
||||
Machine.emit(Prim.newobj); // result addr becomes value of "a"
|
||||
Machine.emit(Op.LOAD,Reg.LB,3); // value of "a" (heap addr)
|
||||
Machine.emit(Op.LOADL,0); // "x" is field 0 in A
|
||||
Machine.emit(Op.LOADL,33); // new value 33
|
||||
Machine.emit(Op.HALT,4,0,0);
|
||||
Machine.emit(Op.LOAD, Reg.LB, 3); // value of "a" (heap addr)
|
||||
Machine.emit(Op.LOADL, 0); // "x" is field 0 in A
|
||||
Machine.emit(Op.LOADL, 33); // new value 33
|
||||
Machine.emit(Op.HALT, 4, 0, 0);
|
||||
Machine.emit(Prim.fieldupd); // a.x = 33
|
||||
Machine.emit(Op.LOAD,Reg.LB,3); // addr of instance "a" on heap
|
||||
Machine.emit(Op.CALLI,Reg.CB,label_pA); // call to known instance method p_A
|
||||
Machine.emit(Op.LOAD, Reg.LB, 3); // addr of instance "a" on heap
|
||||
Machine.emit(Op.CALLI, Reg.CB, label_pA); // call to known instance
|
||||
// method p_A
|
||||
Machine.emit(Prim.putintnl); // print result
|
||||
|
||||
/* ...
|
||||
* A b = new B();
|
||||
* b.x = 44;
|
||||
* System.out.println(b.p());
|
||||
* } // end main
|
||||
/*
|
||||
* ... A b = new B(); b.x = 44; System.out.println(b.p()); } // end main
|
||||
* } // end class C
|
||||
*/
|
||||
// local var "b" will be at 4[LB] after init
|
||||
Machine.emit(Op.LOADA,Reg.SB,3); // class descriptor for B
|
||||
Machine.emit(Op.LOADL,2); // size of B
|
||||
Machine.emit(Op.LOADA, Reg.SB, 3); // class descriptor for B
|
||||
Machine.emit(Op.LOADL, 2); // size of B
|
||||
Machine.emit(Prim.newobj); // result addr becomes value of "b"
|
||||
Machine.emit(Op.LOAD,Reg.LB,4); // fetch b
|
||||
Machine.emit(Op.LOADL,0); // field 0
|
||||
Machine.emit(Op.LOADL,44); // b.x = 44
|
||||
Machine.emit(Op.LOAD, Reg.LB, 4); // fetch b
|
||||
Machine.emit(Op.LOADL, 0); // field 0
|
||||
Machine.emit(Op.LOADL, 44); // b.x = 44
|
||||
Machine.emit(Prim.fieldupd);
|
||||
Machine.emit(Op.HALT,4,0,0);
|
||||
Machine.emit(Op.LOAD,Reg.LB,4); // addr of instance "b"
|
||||
Machine.emit(Op.CALLD,0); // dynamic call, method index 0 (= method p)
|
||||
Machine.emit(Op.HALT, 4, 0, 0);
|
||||
Machine.emit(Op.LOAD, Reg.LB, 4); // addr of instance "b"
|
||||
Machine.emit(Op.CALLD, 0); // dynamic call, method index 0 (= method p)
|
||||
Machine.emit(Prim.putintnl); // print result
|
||||
Machine.emit(Op.RETURN,0,0,1); // return no value (void), pop 1 arg (= String [] args)
|
||||
Machine.emit(Op.RETURN, 0, 0, 1); // return no value (void), pop 1 arg
|
||||
// (= String [] args)
|
||||
|
||||
// build class descriptor for C at 6[SB]
|
||||
int label_coC = Machine.nextInstrAddr();
|
||||
Machine.patch(patchme_coC, label_coC);
|
||||
/*coC*/ Machine.emit(Op.LOADL,-1); // no superclass object
|
||||
Machine.emit(Op.LOADL,0); // number of methods = 0
|
||||
/* coC */ Machine.emit(Op.LOADL, -1); // no superclass object
|
||||
Machine.emit(Op.LOADL, 0); // number of methods = 0
|
||||
|
||||
/*
|
||||
* End of class declarations - call main
|
||||
*/
|
||||
Machine.emit(Op.LOADL,Machine.nullRep); // put null on stack as value of main's arg
|
||||
Machine.emit(Op.CALL,Reg.CB,label_mainC); // call known static main()
|
||||
Machine.emit(Op.LOADL,88); // goodbye
|
||||
Machine.emit(Op.LOADL, Machine.nullRep); // put null on stack as value
|
||||
// of main's arg
|
||||
Machine.emit(Op.CALL, Reg.CB, label_mainC); // call known static main()
|
||||
Machine.emit(Op.LOADL, 88); // goodbye
|
||||
Machine.emit(Prim.putintnl);
|
||||
Machine.emit(Machine.Op.HALT,0,0,0); // halt
|
||||
Machine.emit(Machine.Op.HALT, 0, 0, 0); // halt
|
||||
|
||||
/* write code as an object file */
|
||||
String objectCodeFileName = "test.mJAM";
|
||||
|
@ -133,8 +128,7 @@ public class Test
|
|||
if (objF.write()) {
|
||||
System.out.println("FAILED!");
|
||||
return;
|
||||
}
|
||||
else
|
||||
} else
|
||||
System.out.println("SUCCEEDED");
|
||||
|
||||
/* create asm file using disassembler */
|
||||
|
@ -144,8 +138,7 @@ public class Test
|
|||
if (d.disassemble()) {
|
||||
System.out.println("FAILED!");
|
||||
return;
|
||||
}
|
||||
else
|
||||
} else
|
||||
System.out.println("SUCCEEDED");
|
||||
|
||||
/* run code */
|
||||
|
|
|
@ -116,16 +116,14 @@ public class ASTDisplay implements Visitor<String, Object> {
|
|||
}
|
||||
|
||||
public Object visitFieldDecl(FieldDecl f, String arg) {
|
||||
show(arg, "(" + (f.isPrivate ? "private" : "public")
|
||||
+ (f.isStatic ? " static) " : ") ") + f.toString());
|
||||
show(arg, "(" + (f.isPrivate ? "private" : "public") + (f.isStatic ? " static) " : ") ") + f.toString());
|
||||
f.type.visit(this, indent(arg));
|
||||
show(indent(arg), quote(f.name) + " fieldname");
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object visitMethodDecl(MethodDecl m, String arg) {
|
||||
show(arg, "(" + (m.isPrivate ? "private" : "public")
|
||||
+ (m.isStatic ? " static) " : ") ") + m.toString());
|
||||
show(arg, "(" + (m.isPrivate ? "private" : "public") + (m.isStatic ? " static) " : ") ") + m.toString());
|
||||
m.type.visit(this, indent(arg));
|
||||
show(indent(arg), quote(m.name) + " methodname");
|
||||
ParameterDeclList pdl = m.parameterDeclList;
|
||||
|
|
|
@ -8,8 +8,7 @@ package miniJava.AbstractSyntaxTrees;
|
|||
import miniJava.SyntacticAnalyzer.SourcePosition;
|
||||
|
||||
public class BinaryExpr extends Expression {
|
||||
public BinaryExpr(Operator o, Expression e1, Expression e2,
|
||||
SourcePosition posn) {
|
||||
public BinaryExpr(Operator o, Expression e1, Expression e2, SourcePosition posn) {
|
||||
super(posn);
|
||||
operator = o;
|
||||
left = e1;
|
||||
|
|
|
@ -9,8 +9,7 @@ import miniJava.SyntacticAnalyzer.SourcePosition;
|
|||
|
||||
public class ClassDecl extends Declaration {
|
||||
|
||||
public ClassDecl(String cn, FieldDeclList fdl, MethodDeclList mdl,
|
||||
SourcePosition posn) {
|
||||
public ClassDecl(String cn, FieldDeclList fdl, MethodDeclList mdl, SourcePosition posn) {
|
||||
super(cn, null, posn);
|
||||
fieldDeclList = fdl;
|
||||
methodDeclList = mdl;
|
||||
|
|
|
@ -8,8 +8,7 @@ import miniJava.SyntacticAnalyzer.SourcePosition;
|
|||
*/
|
||||
public class Declarators {
|
||||
|
||||
public Declarators(boolean isPrivate, boolean isStatic, Type mt,
|
||||
SourcePosition posn) {
|
||||
public Declarators(boolean isPrivate, boolean isStatic, Type mt, SourcePosition posn) {
|
||||
this.isPrivate = isPrivate;
|
||||
this.isStatic = isStatic;
|
||||
this.mt = mt;
|
||||
|
|
|
@ -9,8 +9,7 @@ import miniJava.SyntacticAnalyzer.SourcePosition;
|
|||
|
||||
public class FieldDecl extends MemberDecl {
|
||||
|
||||
public FieldDecl(boolean isPrivate, boolean isStatic, Type t, String name,
|
||||
SourcePosition posn) {
|
||||
public FieldDecl(boolean isPrivate, boolean isStatic, Type t, String name, SourcePosition posn) {
|
||||
super(isPrivate, isStatic, t, name, posn);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,7 @@ import miniJava.SyntacticAnalyzer.SourcePosition;
|
|||
|
||||
abstract public class MemberDecl extends Declaration {
|
||||
|
||||
public MemberDecl(boolean isPrivate, boolean isStatic, Type mt,
|
||||
String name, SourcePosition posn) {
|
||||
public MemberDecl(boolean isPrivate, boolean isStatic, Type mt, String name, SourcePosition posn) {
|
||||
super(name, mt, posn);
|
||||
this.isPrivate = isPrivate;
|
||||
this.isStatic = isStatic;
|
||||
|
|
|
@ -9,8 +9,7 @@ import miniJava.SyntacticAnalyzer.SourcePosition;
|
|||
|
||||
public class MethodDecl extends MemberDecl {
|
||||
|
||||
public MethodDecl(MemberDecl md, ParameterDeclList pl, StatementList sl,
|
||||
Expression e, SourcePosition posn) {
|
||||
public MethodDecl(MemberDecl md, ParameterDeclList pl, StatementList sl, Expression e, SourcePosition posn) {
|
||||
super(md, posn);
|
||||
parameterDeclList = pl;
|
||||
statementList = sl;
|
||||
|
|
|
@ -9,8 +9,9 @@ public class Code {
|
|||
public Declaration decl;
|
||||
|
||||
/**
|
||||
* If addr true, returns the address of the declaration.
|
||||
* Otherwise, uses the size of the declaration in its place.
|
||||
* If addr true, returns the address of the declaration. Otherwise, uses the
|
||||
* size of the declaration in its place.
|
||||
*
|
||||
* @param op
|
||||
* @param decl
|
||||
* @param addr
|
||||
|
@ -27,7 +28,7 @@ public class Code {
|
|||
public void modify(int instr) {
|
||||
|
||||
// Setup size
|
||||
switch(decl.type.typeKind) {
|
||||
switch (decl.type.typeKind) {
|
||||
case ARRAY:
|
||||
case CLASS:
|
||||
Machine.code[instr].n = Machine.addressSize;
|
||||
|
@ -42,7 +43,7 @@ public class Code {
|
|||
}
|
||||
|
||||
// Setup displacement
|
||||
if(addr) {
|
||||
if (addr) {
|
||||
Machine.code[instr].d += decl.entity.addr;
|
||||
} else {
|
||||
Machine.code[instr].d += decl.entity.size;
|
||||
|
|
|
@ -16,7 +16,6 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
// Maintains data to correct once completed traversal
|
||||
private HashMap<Integer, Code> patches = new HashMap<>();
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PACKAGE
|
||||
|
@ -30,10 +29,10 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
|
||||
// Initialize all static fields
|
||||
int staticFieldsSize = 0;
|
||||
for(ClassDecl cd : prog.classDeclList) {
|
||||
for(int i = 0; i < cd.fieldDeclList.size(); i++) {
|
||||
for (ClassDecl cd : prog.classDeclList) {
|
||||
for (int i = 0; i < cd.fieldDeclList.size(); i++) {
|
||||
FieldDecl fd = cd.fieldDeclList.get(i);
|
||||
if(fd.isStatic) {
|
||||
if (fd.isStatic) {
|
||||
int size = getSize(fd.type);
|
||||
fd.entity = new RuntimeEntity(size, staticFieldsSize, Reg.SB);
|
||||
staticFieldsSize += size;
|
||||
|
@ -41,12 +40,12 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
}
|
||||
}
|
||||
|
||||
if(staticFieldsSize > 0) {
|
||||
if (staticFieldsSize > 0) {
|
||||
Machine.emit(Op.PUSH, staticFieldsSize);
|
||||
}
|
||||
|
||||
// Build Classes
|
||||
for(ClassDecl cd : prog.classDeclList) {
|
||||
for (ClassDecl cd : prog.classDeclList) {
|
||||
int cdPatch = Machine.nextInstrAddr();
|
||||
Machine.emit(Op.JUMP, Reg.CB, 0);
|
||||
cd.visit(this, cdPatch);
|
||||
|
@ -64,11 +63,11 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
|
||||
Machine.emit(Op.LOADL, Machine.nullRep);
|
||||
Machine.emit(Op.CALL, Reg.CB, main.addr);
|
||||
Machine.emit(Machine.Op.HALT, 0 ,0, 0);
|
||||
Machine.emit(Machine.Op.HALT, 0, 0, 0);
|
||||
Machine.patch(mainPatch, mainLabel);
|
||||
|
||||
// Patch up
|
||||
for(Integer instr : patches.keySet()) {
|
||||
for (Integer instr : patches.keySet()) {
|
||||
Code c = patches.get(instr);
|
||||
c.modify(instr);
|
||||
}
|
||||
|
@ -76,7 +75,6 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DECLARATIONS
|
||||
|
@ -88,16 +86,16 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
|
||||
// Get size of class
|
||||
int size = 0;
|
||||
for(FieldDecl fd : cd.fieldDeclList) {
|
||||
if(!fd.isStatic) {
|
||||
for (FieldDecl fd : cd.fieldDeclList) {
|
||||
if (!fd.isStatic) {
|
||||
fd.visit(this, size);
|
||||
size += fd.entity.size;
|
||||
}
|
||||
}
|
||||
|
||||
// Build Instance Methods
|
||||
for(MethodDecl md : cd.methodDeclList) {
|
||||
if(md != Analyzer.main) {
|
||||
for (MethodDecl md : cd.methodDeclList) {
|
||||
if (md != Analyzer.main) {
|
||||
md.visit(this, null);
|
||||
}
|
||||
}
|
||||
|
@ -139,18 +137,18 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
|
||||
// Setup parameters
|
||||
int parameterSize = 0;
|
||||
for(ParameterDecl pd : md.parameterDeclList) {
|
||||
for (ParameterDecl pd : md.parameterDeclList) {
|
||||
parameterSize += getSize(pd.type);
|
||||
pd.visit(this, -parameterSize);
|
||||
}
|
||||
|
||||
// Build Body
|
||||
for(Statement s : md.statementList) {
|
||||
for (Statement s : md.statementList) {
|
||||
s.visit(this, null);
|
||||
}
|
||||
|
||||
// Setup Return
|
||||
if(md.returnExp != null) {
|
||||
if (md.returnExp != null) {
|
||||
md.returnExp.visit(this, null);
|
||||
}
|
||||
|
||||
|
@ -183,7 +181,6 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TYPES
|
||||
|
@ -208,7 +205,6 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// STATEMENTS
|
||||
|
@ -220,16 +216,16 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
|
||||
// Execute statements
|
||||
int size = 0;
|
||||
for(Statement s : stmt.sl) {
|
||||
for (Statement s : stmt.sl) {
|
||||
s.visit(this, null);
|
||||
if(s instanceof VarDeclStmt) {
|
||||
if (s instanceof VarDeclStmt) {
|
||||
VarDeclStmt vds = (VarDeclStmt) s;
|
||||
size += vds.varDecl.entity.size;
|
||||
}
|
||||
}
|
||||
|
||||
// Pop off variable declarations
|
||||
if(size > 0) {
|
||||
if (size > 0) {
|
||||
Machine.emit(Op.POP, size);
|
||||
methodDataOffset -= size;
|
||||
}
|
||||
|
@ -253,13 +249,13 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
public Object visitAssignStmt(AssignStmt stmt, Integer arg) {
|
||||
|
||||
// Can potentially reach declaration directly
|
||||
if(stmt.ref instanceof QualifiedRef) {
|
||||
if (stmt.ref instanceof QualifiedRef) {
|
||||
|
||||
QualifiedRef ref = (QualifiedRef) stmt.ref;
|
||||
MemberDecl md = (MemberDecl) ref.id.decl;
|
||||
|
||||
// Just access directly
|
||||
if(md.isStatic) {
|
||||
if (md.isStatic) {
|
||||
stmt.val.visit(this, null);
|
||||
patches.put(Machine.nextInstrAddr(), new Code(md, true));
|
||||
Machine.emit(Op.STORE, getSize(md.type), Reg.SB, 0);
|
||||
|
@ -268,7 +264,7 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
}
|
||||
|
||||
// Access member directly
|
||||
else if(ref.ref instanceof ThisRef) {
|
||||
else if (ref.ref instanceof ThisRef) {
|
||||
stmt.val.visit(this, null);
|
||||
|
||||
int addr = Machine.nextInstrAddr();
|
||||
|
@ -284,15 +280,15 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
stmt.ref.visit(this, 1);
|
||||
stmt.val.visit(this, null);
|
||||
|
||||
if(stmt.ref instanceof QualifiedRef) {
|
||||
if (stmt.ref instanceof QualifiedRef) {
|
||||
Machine.emit(Prim.fieldupd);
|
||||
}
|
||||
|
||||
else if(stmt.ref instanceof IndexedRef) {
|
||||
else if (stmt.ref instanceof IndexedRef) {
|
||||
Machine.emit(Prim.arrayupd);
|
||||
}
|
||||
|
||||
else if(stmt.ref instanceof IdRef) {
|
||||
else if (stmt.ref instanceof IdRef) {
|
||||
int addr = Machine.nextInstrAddr();
|
||||
int size = getSize(stmt.ref.decl.type);
|
||||
patches.put(addr, new Code(stmt.ref.decl, true));
|
||||
|
@ -308,26 +304,26 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
MethodDecl md = (MethodDecl) stmt.methodRef.decl;
|
||||
|
||||
// Request to print out
|
||||
if(md == Analyzer.println) {
|
||||
if (md == Analyzer.println) {
|
||||
stmt.argList.get(0).visit(this, null);
|
||||
Machine.emit(Prim.putintnl);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Push parameters on (must iterate in reverse order)
|
||||
for(int i = stmt.argList.size() - 1; i >= 0; i--) {
|
||||
for (int i = stmt.argList.size() - 1; i >= 0; i--) {
|
||||
stmt.argList.get(i).visit(this, null);
|
||||
}
|
||||
|
||||
// Call method directly
|
||||
if(md.isStatic) {
|
||||
if (md.isStatic) {
|
||||
patches.put(Machine.nextInstrAddr(), new Code(md, true));
|
||||
Machine.emit(Op.CALL, Reg.CB, 0);
|
||||
}
|
||||
|
||||
// Get address of qualified object
|
||||
else {
|
||||
if(stmt.methodRef instanceof QualifiedRef) {
|
||||
if (stmt.methodRef instanceof QualifiedRef) {
|
||||
QualifiedRef ref = (QualifiedRef) stmt.methodRef;
|
||||
ref.ref.visit(this, null);
|
||||
} else {
|
||||
|
@ -340,7 +336,7 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
|
||||
// Clear off stack if necessary
|
||||
int returnSize = getSize(md.type);
|
||||
if(returnSize > 0) {
|
||||
if (returnSize > 0) {
|
||||
Machine.emit(Op.POP, returnSize);
|
||||
}
|
||||
|
||||
|
@ -353,7 +349,7 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
stmt.cond.visit(this, null);
|
||||
|
||||
// Do not have to build as many jump instructions in this case
|
||||
if(stmt.elseStmt == null) {
|
||||
if (stmt.elseStmt == null) {
|
||||
int ifPatch = Machine.nextInstrAddr();
|
||||
Machine.emit(Op.JUMPIF, Machine.falseRep, Reg.CB, 0);
|
||||
|
||||
|
@ -398,7 +394,6 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// EXPRESSIONS
|
||||
|
@ -409,7 +404,7 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
public Object visitUnaryExpr(UnaryExpr expr, Integer arg) {
|
||||
|
||||
expr.expr.visit(this, null);
|
||||
switch(expr.operator.spelling) {
|
||||
switch (expr.operator.spelling) {
|
||||
case "!":
|
||||
Machine.emit(Prim.not);
|
||||
break;
|
||||
|
@ -426,7 +421,7 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
|
||||
String op = expr.operator.spelling;
|
||||
|
||||
if(op.equals("&&") || op.equals("||")) {
|
||||
if (op.equals("&&") || op.equals("||")) {
|
||||
int rep = (op.equals("&&")) ? Machine.falseRep : Machine.trueRep;
|
||||
|
||||
expr.left.visit(this, null);
|
||||
|
@ -462,17 +457,17 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
MethodDecl md = (MethodDecl) expr.functionRef.decl;
|
||||
|
||||
// Push parameters on (must iterate in reverse order)
|
||||
for(int i = expr.argList.size() - 1; i >= 0; i--) {
|
||||
for (int i = expr.argList.size() - 1; i >= 0; i--) {
|
||||
expr.argList.get(i).visit(this, null);
|
||||
}
|
||||
|
||||
// Call Method
|
||||
if(md.isStatic) {
|
||||
if (md.isStatic) {
|
||||
patches.put(Machine.nextInstrAddr(), new Code(md, true));
|
||||
Machine.emit(Op.CALL, Reg.CB, 0);
|
||||
} else {
|
||||
|
||||
if(expr.functionRef instanceof QualifiedRef) {
|
||||
if (expr.functionRef instanceof QualifiedRef) {
|
||||
QualifiedRef ref = (QualifiedRef) expr.functionRef;
|
||||
ref.ref.visit(this, null);
|
||||
} else {
|
||||
|
@ -519,7 +514,6 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// REFERENCES
|
||||
|
@ -530,12 +524,12 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
public Object visitQualifiedRef(QualifiedRef ref, Integer arg) {
|
||||
|
||||
// Array type always returns value
|
||||
if(ref.ref.decl.type.typeKind == TypeKind.ARRAY) {
|
||||
if (ref.ref.decl.type.typeKind == TypeKind.ARRAY) {
|
||||
|
||||
// Get address of object
|
||||
if(ref.ref instanceof QualifiedRef) {
|
||||
if (ref.ref instanceof QualifiedRef) {
|
||||
ref.ref.visit(this, null);
|
||||
} else if(ref.ref instanceof ThisRef) {
|
||||
} else if (ref.ref instanceof ThisRef) {
|
||||
patches.put(Machine.nextInstrAddr(), new Code(ref.id.decl, true));
|
||||
Machine.emit(Op.STORE, getSize(ref.id.decl.type), Reg.OB, 0);
|
||||
} else {
|
||||
|
@ -553,14 +547,14 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
MemberDecl md = (MemberDecl) ref.id.decl;
|
||||
|
||||
// Assigning
|
||||
if(arg != null) {
|
||||
if (arg != null) {
|
||||
ref.ref.visit(this, null);
|
||||
patches.put(Machine.nextInstrAddr(), new Code(ref.id.decl, true));
|
||||
Machine.emit(Op.LOADL, 0);
|
||||
}
|
||||
|
||||
// Retrieving
|
||||
else if(md.isStatic) {
|
||||
else if (md.isStatic) {
|
||||
patches.put(Machine.nextInstrAddr(), new Code(md, true));
|
||||
Machine.emit(Op.LOAD, getSize(md.type), Reg.SB, 0);
|
||||
} else {
|
||||
|
@ -582,7 +576,7 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
ref.indexExpr.visit(this, null);
|
||||
|
||||
// Retrieving
|
||||
if(arg == null) {
|
||||
if (arg == null) {
|
||||
Machine.emit(Prim.arrayref);
|
||||
}
|
||||
|
||||
|
@ -595,7 +589,7 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
ref.entity = ref.decl.entity;
|
||||
|
||||
// Retrieving
|
||||
if(arg == null) {
|
||||
if (arg == null) {
|
||||
int size = getSize(ref.decl.type);
|
||||
int addr = Machine.nextInstrAddr();
|
||||
patches.put(addr, new Code(ref.decl, true));
|
||||
|
@ -614,7 +608,6 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TERMINALS
|
||||
|
@ -630,7 +623,7 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
@Override
|
||||
public Object visitOperator(Operator op, Integer arg) {
|
||||
|
||||
switch(op.spelling) {
|
||||
switch (op.spelling) {
|
||||
case "+":
|
||||
Machine.emit(Prim.add);
|
||||
break;
|
||||
|
@ -684,7 +677,7 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
@Override
|
||||
public Object visitBooleanLiteral(BooleanLiteral bool, Integer arg) {
|
||||
|
||||
if(bool.spelling.equals("true")) {
|
||||
if (bool.spelling.equals("true")) {
|
||||
Machine.emit(Op.LOADL, Machine.trueRep);
|
||||
} else {
|
||||
Machine.emit(Op.LOADL, Machine.falseRep);
|
||||
|
@ -693,7 +686,6 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Convenience Methods
|
||||
|
@ -702,11 +694,12 @@ public class Encoder implements Visitor<Integer, Object> {
|
|||
|
||||
/**
|
||||
* Get size of type for declaration purposes.
|
||||
*
|
||||
* @param t
|
||||
* @return
|
||||
*/
|
||||
private int getSize(Type t) {
|
||||
switch(t.typeKind) {
|
||||
switch (t.typeKind) {
|
||||
case ARRAY:
|
||||
case CLASS:
|
||||
return Machine.addressSize;
|
||||
|
|
|
@ -45,7 +45,7 @@ public class Compiler {
|
|||
analyzer.visitPackage(p, table);
|
||||
|
||||
// Compilation
|
||||
if(Reporter.error) {
|
||||
if (Reporter.error) {
|
||||
System.exit(rc);
|
||||
} else {
|
||||
|
||||
|
@ -57,7 +57,7 @@ public class Compiler {
|
|||
int pos = args[0].lastIndexOf(".java");
|
||||
String objectFileName = args[0].substring(0, pos) + ".mJAM";
|
||||
ObjectFile objF = new ObjectFile(objectFileName);
|
||||
if(objF.write()) {
|
||||
if (objF.write()) {
|
||||
Reporter.emit("Object File Failed.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
// Predefined
|
||||
private static ArrayList<String> predefined;
|
||||
static
|
||||
{
|
||||
|
||||
static {
|
||||
predefined = new ArrayList<String>();
|
||||
predefined.add("class String { }");
|
||||
predefined.add("class _PrintStream { public void println(int n){} }");
|
||||
|
@ -33,7 +33,6 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
private ClassDecl currentClassDecl = null;
|
||||
private MethodDecl currentMethodDecl = null;
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PACKAGE
|
||||
|
@ -47,7 +46,7 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
// Begin predefinitions
|
||||
try {
|
||||
for(String pd : predefined) {
|
||||
for (String pd : predefined) {
|
||||
Scanner scanner = new Scanner(pd, true);
|
||||
Parser parser = new Parser(scanner);
|
||||
ClassDecl cd = parser.parseClassDeclaration();
|
||||
|
@ -55,30 +54,29 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
addDeclarations(cd, table);
|
||||
cd.visit(this, table);
|
||||
}
|
||||
} catch(IOException e) {
|
||||
} catch (IOException e) {
|
||||
Reporter.emit("System Predefinitions Error!");
|
||||
System.exit(Compiler.rc);
|
||||
}
|
||||
|
||||
// Add all second level declarations
|
||||
for(ClassDecl cd : prog.classDeclList) {
|
||||
for (ClassDecl cd : prog.classDeclList) {
|
||||
addDeclarations(cd, table);
|
||||
}
|
||||
|
||||
// Begin traversal
|
||||
for(ClassDecl cd : prog.classDeclList) {
|
||||
for (ClassDecl cd : prog.classDeclList) {
|
||||
cd.visit(this, table);
|
||||
}
|
||||
|
||||
// Check a main exists
|
||||
if(main == null) {
|
||||
if (main == null) {
|
||||
Reporter.emit("Main method undeclared.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DECLARATIONS
|
||||
|
@ -90,11 +88,11 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
currentClassDecl = cd;
|
||||
|
||||
for(FieldDecl fd : cd.fieldDeclList) {
|
||||
for (FieldDecl fd : cd.fieldDeclList) {
|
||||
fd.visit(this, cd.table);
|
||||
}
|
||||
|
||||
for(MethodDecl md : cd.methodDeclList) {
|
||||
for (MethodDecl md : cd.methodDeclList) {
|
||||
md.visit(this, cd.table);
|
||||
}
|
||||
|
||||
|
@ -105,7 +103,7 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
public Type visitFieldDecl(FieldDecl fd, IdTable table) {
|
||||
|
||||
fd.type.visit(this, table);
|
||||
if(fd.type.typeKind == TypeKind.VOID) {
|
||||
if (fd.type.typeKind == TypeKind.VOID) {
|
||||
Reporter.emit("Field " + fd.name + " at " + fd.posn + " cannot have type 'void'");
|
||||
}
|
||||
|
||||
|
@ -118,13 +116,13 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
currentMethodDecl = md;
|
||||
|
||||
// Save println method
|
||||
if(println == null && md.name.equals("println")) {
|
||||
if (println == null && md.name.equals("println")) {
|
||||
println = md;
|
||||
}
|
||||
|
||||
// Save main method
|
||||
if(isMain(md)) {
|
||||
if(main != null) {
|
||||
if (isMain(md)) {
|
||||
if (main != null) {
|
||||
Reporter.emit("Main at " + md.posn + " previously defined at " + main.posn);
|
||||
} else {
|
||||
main = md;
|
||||
|
@ -134,24 +132,24 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
// Continue Traversal
|
||||
md.type.visit(this, table);
|
||||
|
||||
for(ParameterDecl pd : md.parameterDeclList) {
|
||||
for (ParameterDecl pd : md.parameterDeclList) {
|
||||
pd.visit(this, md.table);
|
||||
}
|
||||
|
||||
for(Statement s : md.statementList) {
|
||||
for (Statement s : md.statementList) {
|
||||
s.visit(this, md.table);
|
||||
}
|
||||
|
||||
// Check return status
|
||||
if(md.type.typeKind != TypeKind.VOID && md.returnExp == null) {
|
||||
if (md.type.typeKind != TypeKind.VOID && md.returnExp == null) {
|
||||
Reporter.emit("Method " + md.name + " at " + md.posn + " must have a return expression");
|
||||
} else if(md.type.typeKind == TypeKind.VOID && md.returnExp != null) {
|
||||
} else if (md.type.typeKind == TypeKind.VOID && md.returnExp != null) {
|
||||
Reporter.emit("Method " + md.name + " at " + md.posn + " cannot have a return expression");
|
||||
}
|
||||
|
||||
if(md.returnExp != null) {
|
||||
if (md.returnExp != null) {
|
||||
Type returnType = md.returnExp.visit(this, md.table);
|
||||
if(!match(returnType, md.type)) {
|
||||
if (!match(returnType, md.type)) {
|
||||
Reporter.emit("Expected " + md.type + " but got " + returnType + " at " + md.returnExp.posn);
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +162,7 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
table.add(pd);
|
||||
pd.type.visit(this, table);
|
||||
if(pd.type.typeKind == TypeKind.VOID) {
|
||||
if (pd.type.typeKind == TypeKind.VOID) {
|
||||
Reporter.emit("Parameter " + pd.name + " at " + pd.posn + " cannot have type 'void'");
|
||||
}
|
||||
|
||||
|
@ -176,14 +174,13 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
table.add(decl);
|
||||
decl.type.visit(this, table);
|
||||
if(decl.type.typeKind == TypeKind.VOID) {
|
||||
if (decl.type.typeKind == TypeKind.VOID) {
|
||||
Reporter.emit("Variable " + decl.name + " at " + decl.posn + " cannot have type 'void'");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TYPES
|
||||
|
@ -203,7 +200,7 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
// Must check that the type is valid
|
||||
String cn = type.className.spelling;
|
||||
if(top.getDeclarationAtScope(cn) == null) {
|
||||
if (top.getDeclarationAtScope(cn) == null) {
|
||||
Reporter.emit("Class '" + cn + "' undeclared at " + type.posn);
|
||||
}
|
||||
|
||||
|
@ -218,7 +215,6 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
return type;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// STATEMENTS
|
||||
|
@ -230,7 +226,7 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
table.push();
|
||||
|
||||
for(Statement s : stmt.sl) {
|
||||
for (Statement s : stmt.sl) {
|
||||
s.visit(this, table);
|
||||
}
|
||||
|
||||
|
@ -249,7 +245,7 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
currentVarDecl = null;
|
||||
|
||||
// Types must match
|
||||
if(!match(stmt.varDecl.type, exprType)) {
|
||||
if (!match(stmt.varDecl.type, exprType)) {
|
||||
Reporter.emit("Expected " + stmt.varDecl.type + " but got " + exprType + " at " + stmt.initExp.posn);
|
||||
}
|
||||
|
||||
|
@ -262,24 +258,24 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
Type refType = stmt.ref.visit(this, table);
|
||||
Type valType = stmt.val.visit(this, table);
|
||||
|
||||
if(!match(refType, valType)) {
|
||||
if (!match(refType, valType)) {
|
||||
Reporter.emit("Expected " + refType + " but got " + valType + " at " + stmt.posn);
|
||||
}
|
||||
|
||||
// Should never assign 'this' to anything
|
||||
if(stmt.ref instanceof ThisRef) {
|
||||
if (stmt.ref instanceof ThisRef) {
|
||||
Reporter.emit("Cannot assign 'this' to a value at " + stmt.posn);
|
||||
}
|
||||
|
||||
// Should never assign a method a value
|
||||
if(stmt.ref.decl instanceof MethodDecl) {
|
||||
if (stmt.ref.decl instanceof MethodDecl) {
|
||||
Reporter.emit("Cannot assign a method a value at " + stmt.posn);
|
||||
}
|
||||
|
||||
// Cannot assign array length field
|
||||
if(stmt.ref instanceof QualifiedRef) {
|
||||
if (stmt.ref instanceof QualifiedRef) {
|
||||
QualifiedRef ref = (QualifiedRef) stmt.ref;
|
||||
if(ref.ref.decl.type.typeKind == TypeKind.ARRAY && ref.id.spelling.equals("length")) {
|
||||
if (ref.ref.decl.type.typeKind == TypeKind.ARRAY && ref.id.spelling.equals("length")) {
|
||||
Reporter.emit("'length' field cannot be changed at " + stmt.posn);
|
||||
}
|
||||
}
|
||||
|
@ -294,7 +290,7 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
// Check valid parameter count
|
||||
MethodDecl md = (MethodDecl) stmt.methodRef.decl;
|
||||
if(md.parameterDeclList.size() != stmt.argList.size()) {
|
||||
if (md.parameterDeclList.size() != stmt.argList.size()) {
|
||||
Reporter.emit("Expected " + md.parameterDeclList.size() + " parameters at " + stmt.posn);
|
||||
return null;
|
||||
}
|
||||
|
@ -305,8 +301,9 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
Type exprType = e.visit(this, table);
|
||||
ParameterDecl pd = md.parameterDeclList.get(i);
|
||||
|
||||
if(!match(pd.type, exprType)) {
|
||||
Reporter.emit("Parameter " + pd.name + " is of type " + pd.type + " but got " + exprType + " at " + e.posn);
|
||||
if (!match(pd.type, exprType)) {
|
||||
Reporter.emit(
|
||||
"Parameter " + pd.name + " is of type " + pd.type + " but got " + exprType + " at " + e.posn);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,12 +315,12 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
// Conditional statement must have type boolean
|
||||
Type condType = stmt.cond.visit(this, table);
|
||||
if(condType.typeKind != TypeKind.BOOLEAN) {
|
||||
if (condType.typeKind != TypeKind.BOOLEAN) {
|
||||
Reporter.emit("Expected boolean but got " + condType + " at " + condType.posn);
|
||||
}
|
||||
|
||||
// A single variable declaration not allowed after conditional statement
|
||||
if(stmt.thenStmt instanceof VarDeclStmt) {
|
||||
if (stmt.thenStmt instanceof VarDeclStmt) {
|
||||
Reporter.emit("Variable declaration not allowed solely in 'then' clause at " + stmt.thenStmt.posn);
|
||||
return null;
|
||||
}
|
||||
|
@ -348,11 +345,11 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
// Conditional statement must have type boolean
|
||||
Type condType = stmt.cond.visit(this, table);
|
||||
if(condType.typeKind != TypeKind.BOOLEAN) {
|
||||
if (condType.typeKind != TypeKind.BOOLEAN) {
|
||||
Reporter.emit("Expected boolean but got " + condType + " at " + condType.posn);
|
||||
}
|
||||
|
||||
if(stmt.body instanceof VarDeclStmt) {
|
||||
if (stmt.body instanceof VarDeclStmt) {
|
||||
Reporter.emit("Variable declaration not allowed solely in 'while' clause at " + stmt.body.posn);
|
||||
return null;
|
||||
}
|
||||
|
@ -362,7 +359,6 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// EXPRESSIONS
|
||||
|
@ -374,7 +370,7 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
Type exprType = expr.expr.visit(this, table);
|
||||
Type opType = expr.operator.visit(this, table);
|
||||
if(!match(exprType, opType)) {
|
||||
if (!match(exprType, opType)) {
|
||||
String op = expr.operator.spelling;
|
||||
Reporter.emit("Operator " + op + " applies to " + opType + " but got " + exprType + " at " + expr.posn);
|
||||
}
|
||||
|
@ -390,12 +386,12 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
BaseType type = null;
|
||||
String op = expr.operator.spelling;
|
||||
switch(op) {
|
||||
switch (op) {
|
||||
|
||||
// Equality Operators
|
||||
case "==":
|
||||
case "!=":
|
||||
if(!match(lType, rType)) {
|
||||
if (!match(lType, rType)) {
|
||||
Reporter.emit("Left hand side must be of right hand side's type " + rType + " at " + expr.posn);
|
||||
}
|
||||
return new BaseType(TypeKind.BOOLEAN, expr.posn);
|
||||
|
@ -423,11 +419,11 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
}
|
||||
|
||||
// Make sure types match
|
||||
if(!match(lType, type)) {
|
||||
if (!match(lType, type)) {
|
||||
Reporter.emit("Expected " + type + " but got " + lType + " at " + expr.posn);
|
||||
}
|
||||
|
||||
if(!match(rType, type)) {
|
||||
if (!match(rType, type)) {
|
||||
Reporter.emit("Expected " + type + " but got " + lType + " at " + expr.posn);
|
||||
}
|
||||
|
||||
|
@ -442,19 +438,19 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
Declaration decl = table.getDeclaration(expr.ref.spelling);
|
||||
|
||||
// Should never reference a class name
|
||||
if(decl instanceof ClassDecl) {
|
||||
if (decl instanceof ClassDecl) {
|
||||
Reporter.emit("Class declaration referenced at " + expr.posn);
|
||||
}
|
||||
|
||||
// Should never reference a method name
|
||||
else if(decl instanceof MethodDecl) {
|
||||
else if (decl instanceof MethodDecl) {
|
||||
Reporter.emit("Method declaration referenced at " + expr.posn);
|
||||
}
|
||||
|
||||
// Cannot access instance members in static context
|
||||
if(!(expr.ref instanceof QualifiedRef) && decl instanceof FieldDecl) {
|
||||
if (!(expr.ref instanceof QualifiedRef) && decl instanceof FieldDecl) {
|
||||
FieldDecl fd = (FieldDecl) decl;
|
||||
if(currentMethodDecl.isStatic && !fd.isStatic) {
|
||||
if (currentMethodDecl.isStatic && !fd.isStatic) {
|
||||
Reporter.emit("Cannot access instance member in static context at " + expr.posn);
|
||||
}
|
||||
}
|
||||
|
@ -469,7 +465,7 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
// Check parameter count matches
|
||||
MethodDecl md = (MethodDecl) expr.functionRef.decl;
|
||||
if(md.parameterDeclList.size() != expr.argList.size()) {
|
||||
if (md.parameterDeclList.size() != expr.argList.size()) {
|
||||
Reporter.emit("Expected " + md.parameterDeclList.size() + " parameters at " + expr.posn);
|
||||
return refType;
|
||||
}
|
||||
|
@ -480,8 +476,9 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
Type exprType = e.visit(this, table);
|
||||
ParameterDecl pd = md.parameterDeclList.get(i);
|
||||
|
||||
if(!match(pd.type, exprType)) {
|
||||
Reporter.emit("Parameter " + pd.name + " is of type " + pd.type + " but got " + exprType + " at " + e.posn);
|
||||
if (!match(pd.type, exprType)) {
|
||||
Reporter.emit(
|
||||
"Parameter " + pd.name + " is of type " + pd.type + " but got " + exprType + " at " + e.posn);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -505,7 +502,7 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
// Arrays only of classes and integers
|
||||
Type eltType = expr.eltType.visit(this, table);
|
||||
if(eltType.typeKind != TypeKind.INT && eltType.typeKind != TypeKind.CLASS) {
|
||||
if (eltType.typeKind != TypeKind.INT && eltType.typeKind != TypeKind.CLASS) {
|
||||
Reporter.emit("Cannot create array of type " + eltType + " at " + expr.posn);
|
||||
}
|
||||
|
||||
|
@ -519,7 +516,6 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
return new ArrayType(eltType, expr.posn);
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// REFERENCES
|
||||
|
@ -532,14 +528,14 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
Type refType = ref.ref.visit(this, table);
|
||||
|
||||
// Should not try and access a method in qualified manner
|
||||
if(ref.ref.decl instanceof MethodDecl) {
|
||||
if (ref.ref.decl instanceof MethodDecl) {
|
||||
Reporter.emit("Cannot use method " + ref.ref.decl.name + " in qualified manner at " + ref.ref.posn);
|
||||
return new BaseType(TypeKind.ERROR, ref.ref.posn);
|
||||
}
|
||||
|
||||
// Array types can have a length field
|
||||
if(refType.typeKind == TypeKind.ARRAY) {
|
||||
if(!ref.id.spelling.equals("length")) {
|
||||
if (refType.typeKind == TypeKind.ARRAY) {
|
||||
if (!ref.id.spelling.equals("length")) {
|
||||
Reporter.emit(ref.id.spelling + " attribute not available with arrays at " + ref.id.posn);
|
||||
return new BaseType(TypeKind.ERROR, ref.id.posn);
|
||||
}
|
||||
|
@ -548,7 +544,7 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
}
|
||||
|
||||
// Otherwise, should have a class type
|
||||
if(refType.typeKind != TypeKind.CLASS) {
|
||||
if (refType.typeKind != TypeKind.CLASS) {
|
||||
Reporter.emit("Qualified reference not of type class or array at " + ref.posn);
|
||||
return new BaseType(TypeKind.ERROR, ref.posn);
|
||||
}
|
||||
|
@ -556,25 +552,25 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
// Get member in question
|
||||
ClassType ct = (ClassType) refType;
|
||||
ClassDecl cd = (ClassDecl) top.getDeclarationAtScope(ct.className.spelling);
|
||||
if(cd == null) {
|
||||
if (cd == null) {
|
||||
Reporter.emit("Accessing non-existant class at " + ct.posn);
|
||||
return new BaseType(TypeKind.ERROR, ref.posn);
|
||||
}
|
||||
|
||||
MemberDecl md = (MemberDecl) cd.table.getDeclarationAtScope(ref.id.spelling);
|
||||
if(md == null) {
|
||||
if (md == null) {
|
||||
Reporter.emit("Accessing non-existant field at " + ref.id.posn);
|
||||
return new BaseType(TypeKind.ERROR, ref.posn);
|
||||
}
|
||||
|
||||
// Check if static member
|
||||
Declaration decl = table.getDeclaration(ref.ref.spelling);
|
||||
if(decl instanceof ClassDecl && !md.isStatic) {
|
||||
if (decl instanceof ClassDecl && !md.isStatic) {
|
||||
Reporter.emit("Cannot access non-static member at " + ref.id.posn);
|
||||
}
|
||||
|
||||
// Check Visibility Status
|
||||
if(md.isPrivate && cd != currentClassDecl) {
|
||||
if (md.isPrivate && cd != currentClassDecl) {
|
||||
Reporter.emit("Cannot access private member at " + ref.id.posn);
|
||||
}
|
||||
|
||||
|
@ -592,21 +588,21 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
ref.spelling = ref.ref.spelling;
|
||||
|
||||
// Must be an array type
|
||||
if(refType.typeKind != TypeKind.ARRAY) {
|
||||
if (refType.typeKind != TypeKind.ARRAY) {
|
||||
Reporter.emit("Trying to index " + refType + " at " + ref.ref.posn);
|
||||
return refType;
|
||||
}
|
||||
|
||||
// Index must be an integer value
|
||||
Type indexType = ref.indexExpr.visit(this, table);
|
||||
if(indexType.typeKind != TypeKind.INT) {
|
||||
if (indexType.typeKind != TypeKind.INT) {
|
||||
BaseType type = new BaseType(TypeKind.INT, ref.indexExpr.posn);
|
||||
Reporter.emit("Expected " + type + " but got " + indexType + " at " + type.posn);
|
||||
}
|
||||
|
||||
// Array types can be of either classes or ints
|
||||
ArrayType at = (ArrayType) refType;
|
||||
if(at.eltType.typeKind == TypeKind.CLASS) {
|
||||
if (at.eltType.typeKind == TypeKind.CLASS) {
|
||||
ClassType ct = (ClassType) at.eltType;
|
||||
ref.decl = table.getDeclaration(ct.className.spelling);
|
||||
return ref.decl.type;
|
||||
|
@ -631,14 +627,13 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
ref.spelling = "this";
|
||||
ref.decl = currentClassDecl;
|
||||
if(currentMethodDecl.isStatic) {
|
||||
if (currentMethodDecl.isStatic) {
|
||||
Reporter.emit("'this' cannot be referenced in a static context at " + ref.posn);
|
||||
}
|
||||
|
||||
return ref.decl.type;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TERMINALS
|
||||
|
@ -649,21 +644,21 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
public Type visitIdentifier(Identifier id, IdTable table) {
|
||||
|
||||
// An variable cannot be used in its declaration
|
||||
if(currentVarDecl != null && currentVarDecl.name.equals(id.spelling)) {
|
||||
if (currentVarDecl != null && currentVarDecl.name.equals(id.spelling)) {
|
||||
Reporter.emit("Cannot use variable in declaration at " + id.posn);
|
||||
}
|
||||
|
||||
// Try to find declaration (and abort if not found)
|
||||
id.decl = table.getDeclaration(id.spelling);
|
||||
if(id.decl == null) {
|
||||
if (id.decl == null) {
|
||||
Reporter.emit(id.spelling + " undefined at " + id.posn);
|
||||
System.exit(Compiler.rc);
|
||||
}
|
||||
|
||||
// Cannot access instance method from static context
|
||||
if(id.decl instanceof MemberDecl) {
|
||||
if (id.decl instanceof MemberDecl) {
|
||||
MemberDecl md = (MemberDecl) id.decl;
|
||||
if(currentMethodDecl.isStatic && !md.isStatic) {
|
||||
if (currentMethodDecl.isStatic && !md.isStatic) {
|
||||
Reporter.emit("Cannot access instance member " + md.name + " in a static context at " + id.posn);
|
||||
}
|
||||
}
|
||||
|
@ -674,7 +669,7 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
|
||||
@Override
|
||||
public Type visitOperator(Operator op, IdTable table) {
|
||||
switch(op.spelling) {
|
||||
switch (op.spelling) {
|
||||
case "!":
|
||||
case "&&":
|
||||
case "||":
|
||||
|
@ -709,7 +704,6 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
return new BaseType(TypeKind.BOOLEAN, bool.posn);
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Convenience Functions
|
||||
|
@ -726,11 +720,11 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
table.add(cd);
|
||||
cd.table = new IdTable(table);
|
||||
|
||||
for(FieldDecl fd : cd.fieldDeclList) {
|
||||
for (FieldDecl fd : cd.fieldDeclList) {
|
||||
cd.table.add(fd);
|
||||
}
|
||||
|
||||
for(MethodDecl md : cd.methodDeclList) {
|
||||
for (MethodDecl md : cd.methodDeclList) {
|
||||
cd.table.add(md);
|
||||
md.table = new IdTable(cd.table);
|
||||
}
|
||||
|
@ -744,15 +738,15 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
private boolean isMain(MethodDecl md) {
|
||||
|
||||
// Correct Signature
|
||||
if(!md.isPrivate && md.isStatic) {
|
||||
if(md.type.typeKind == TypeKind.VOID) {
|
||||
if(md.name.equals("main") && md.parameterDeclList.size() == 1) {
|
||||
if (!md.isPrivate && md.isStatic) {
|
||||
if (md.type.typeKind == TypeKind.VOID) {
|
||||
if (md.name.equals("main") && md.parameterDeclList.size() == 1) {
|
||||
|
||||
// Check parameter declaration
|
||||
ParameterDecl pd = md.parameterDeclList.get(0);
|
||||
if(pd.type.typeKind == TypeKind.ARRAY) {
|
||||
if (pd.type.typeKind == TypeKind.ARRAY) {
|
||||
ArrayType at = (ArrayType) pd.type;
|
||||
if(at.eltType.typeKind == TypeKind.CLASS) {
|
||||
if (at.eltType.typeKind == TypeKind.CLASS) {
|
||||
ClassType ct = (ClassType) at.eltType;
|
||||
|
||||
return ct.className.spelling.equals("String");
|
||||
|
@ -773,12 +767,12 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
*/
|
||||
private boolean match(Type t1, Type t2) {
|
||||
|
||||
if(t1.typeKind != t2.typeKind) {
|
||||
if (t1.typeKind != t2.typeKind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check Class Types match
|
||||
else if(t1.typeKind == TypeKind.CLASS) {
|
||||
else if (t1.typeKind == TypeKind.CLASS) {
|
||||
ClassType c1 = (ClassType) t1;
|
||||
ClassType c2 = (ClassType) t2;
|
||||
|
||||
|
@ -786,7 +780,7 @@ public class Analyzer implements Visitor<IdTable, Type> {
|
|||
}
|
||||
|
||||
// Check Array Types match
|
||||
else if(t1.typeKind == TypeKind.ARRAY) {
|
||||
else if (t1.typeKind == TypeKind.ARRAY) {
|
||||
ArrayType a1 = (ArrayType) t1;
|
||||
ArrayType a2 = (ArrayType) t2;
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ public class IdTable {
|
|||
private IdTable parent;
|
||||
private ArrayList<HashMap<String, Declaration>> scope;
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CONSTRUCTORS
|
||||
|
@ -38,7 +37,6 @@ public class IdTable {
|
|||
push();
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ACTIVE SCOPE
|
||||
|
@ -65,21 +63,21 @@ public class IdTable {
|
|||
*
|
||||
*/
|
||||
public void add(Declaration decl) {
|
||||
for(int i = 0; i < scope.size(); i++) {
|
||||
for (int i = 0; i < scope.size(); i++) {
|
||||
HashMap<String, Declaration> nest = scope.get(i);
|
||||
if(nest.containsKey(decl.name)) {
|
||||
if (nest.containsKey(decl.name)) {
|
||||
|
||||
Declaration prev = nest.get(decl.name);
|
||||
|
||||
if(decl instanceof ClassDecl) {
|
||||
if (decl instanceof ClassDecl) {
|
||||
Reporter.report(decl, prev, "Class");
|
||||
} else if(decl instanceof FieldDecl) {
|
||||
} else if (decl instanceof FieldDecl) {
|
||||
Reporter.report(decl, prev, "Field");
|
||||
} else if(decl instanceof MethodDecl) {
|
||||
} else if (decl instanceof MethodDecl) {
|
||||
Reporter.report(decl, prev, "Method");
|
||||
} else if(decl instanceof ParameterDecl) {
|
||||
} else if (decl instanceof ParameterDecl) {
|
||||
Reporter.report(decl, prev, "Parameter");
|
||||
} else if(decl instanceof VarDecl) {
|
||||
} else if (decl instanceof VarDecl) {
|
||||
Reporter.report(decl, prev, "Variable");
|
||||
}
|
||||
|
||||
|
@ -87,10 +85,9 @@ public class IdTable {
|
|||
}
|
||||
}
|
||||
|
||||
scope.get(scope.size()-1).put(decl.name, decl);
|
||||
scope.get(scope.size() - 1).put(decl.name, decl);
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// GETTERS
|
||||
|
@ -105,8 +102,10 @@ public class IdTable {
|
|||
IdTable current = this;
|
||||
while (current != null) {
|
||||
Declaration decl = current.getDeclarationAtScope(name);
|
||||
if (decl == null) current = current.parent;
|
||||
else return decl;
|
||||
if (decl == null)
|
||||
current = current.parent;
|
||||
else
|
||||
return decl;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -119,7 +118,8 @@ public class IdTable {
|
|||
public Declaration getDeclarationAtScope(String name) {
|
||||
for (int i = scope.size() - 1; i >= 0; i--) {
|
||||
HashMap<String, Declaration> nest = scope.get(i);
|
||||
if (nest.containsKey(name)) return nest.get(name);
|
||||
if (nest.containsKey(name))
|
||||
return nest.get(name);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -17,6 +17,7 @@ public class Reporter {
|
|||
|
||||
/**
|
||||
* Redefinitions
|
||||
*
|
||||
* @param d1
|
||||
* @param d2
|
||||
*/
|
||||
|
|
|
@ -11,15 +11,9 @@ import miniJava.AbstractSyntaxTrees.Package;
|
|||
*
|
||||
* Program ::= (ClassDeclaration)* eot
|
||||
*
|
||||
* ClassDeclaration ::=
|
||||
* class id {
|
||||
* (Declarators id (; | MethodDeclaration))*
|
||||
* }
|
||||
* ClassDeclaration ::= class id { (Declarators id (; | MethodDeclaration))* }
|
||||
*
|
||||
* MethodDeclaration ::=
|
||||
* (ParameterList?) {
|
||||
* Statement* (return Expression ;)?
|
||||
* }
|
||||
* MethodDeclaration ::= (ParameterList?) { Statement* (return Expression ;)? }
|
||||
*
|
||||
* Declarators ::= (public | private)? static? Type
|
||||
*
|
||||
|
@ -33,20 +27,13 @@ import miniJava.AbstractSyntaxTrees.Package;
|
|||
*
|
||||
* BaseRef ::= this | id ([ Expression])?
|
||||
*
|
||||
* Statement ::=
|
||||
* {Statement*}
|
||||
* | Type id = Expression;
|
||||
* | Reference = Expression;
|
||||
* | Reference ( ArgumentList? );
|
||||
* | if (Expression) Statement (else Statement)?
|
||||
* Statement ::= {Statement*} | Type id = Expression; | Reference = Expression;
|
||||
* | Reference ( ArgumentList? ); | if (Expression) Statement (else Statement)?
|
||||
* | while (Expression) Statement
|
||||
*
|
||||
* Expression ::=
|
||||
* num | true | false
|
||||
* | ( Expression )
|
||||
* | new (id() | int [ Expression ] | id [ Expression ] )
|
||||
* | Reference ((ArgumentList?))?
|
||||
* | DExpression
|
||||
* Expression ::= num | true | false | ( Expression ) | new (id() | int [
|
||||
* Expression ] | id [ Expression ] ) | Reference ((ArgumentList?))? |
|
||||
* DExpression
|
||||
*
|
||||
* DExpression ::= CExpression (|| CExpression)*
|
||||
*
|
||||
|
@ -60,7 +47,7 @@ import miniJava.AbstractSyntaxTrees.Package;
|
|||
*
|
||||
* MExpression ::= Expression ((*|/) Expression)*
|
||||
*
|
||||
*/
|
||||
*/
|
||||
public class Parser {
|
||||
|
||||
private Scanner scanner;
|
||||
|
@ -75,7 +62,6 @@ public class Parser {
|
|||
this.stream = new LinkedList<Token>();
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Package
|
||||
|
@ -98,7 +84,6 @@ public class Parser {
|
|||
return new Package(decls, new SourcePosition(0, 0));
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DECLARATIONS
|
||||
|
@ -129,7 +114,7 @@ public class Parser {
|
|||
|
||||
// Field Declaration
|
||||
FieldDecl fd = new FieldDecl(d, memberName);
|
||||
if(peek(1).type == Token.TYPE.SEMICOLON) {
|
||||
if (peek(1).type == Token.TYPE.SEMICOLON) {
|
||||
accept(Token.TYPE.SEMICOLON);
|
||||
fdl.add(fd);
|
||||
}
|
||||
|
@ -219,7 +204,6 @@ public class Parser {
|
|||
return new MethodDecl(f, pdl, stl, returnExpr, f.posn);
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TYPES
|
||||
|
@ -233,7 +217,7 @@ public class Parser {
|
|||
*/
|
||||
private Type parseType() throws IOException {
|
||||
|
||||
switch(peek(1).type) {
|
||||
switch (peek(1).type) {
|
||||
|
||||
case VOID: {
|
||||
Token next = accept(Token.TYPE.VOID);
|
||||
|
@ -279,7 +263,6 @@ public class Parser {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Arguments
|
||||
|
@ -301,7 +284,7 @@ public class Parser {
|
|||
decls.add(new ParameterDecl(fpt, next.spelling, fpt.posn));
|
||||
|
||||
// Remainder of List
|
||||
while(peek(1).type == Token.TYPE.COMMA) {
|
||||
while (peek(1).type == Token.TYPE.COMMA) {
|
||||
accept(Token.TYPE.COMMA);
|
||||
Type type = parseType();
|
||||
Token id = accept(Token.TYPE.ID);
|
||||
|
@ -322,7 +305,7 @@ public class Parser {
|
|||
el.add(parseExpression());
|
||||
|
||||
// Rest of argument list
|
||||
while(peek(1).type == Token.TYPE.COMMA) {
|
||||
while (peek(1).type == Token.TYPE.COMMA) {
|
||||
accept(Token.TYPE.COMMA);
|
||||
el.add(parseExpression());
|
||||
}
|
||||
|
@ -330,7 +313,6 @@ public class Parser {
|
|||
return el;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// REFERENCES
|
||||
|
@ -371,7 +353,7 @@ public class Parser {
|
|||
*/
|
||||
private Reference parseBaseRef() throws IOException {
|
||||
|
||||
if(peek(1).type == Token.TYPE.THIS) {
|
||||
if (peek(1).type == Token.TYPE.THIS) {
|
||||
Token next = accept(Token.TYPE.THIS);
|
||||
return new ThisRef(next.posn);
|
||||
}
|
||||
|
@ -391,7 +373,6 @@ public class Parser {
|
|||
return ref;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// STATEMENTS
|
||||
|
@ -408,7 +389,7 @@ public class Parser {
|
|||
StatementList stl = new StatementList();
|
||||
Token left = accept(Token.TYPE.LBRACKET);
|
||||
|
||||
while(peek(1).type != Token.TYPE.RBRACKET) {
|
||||
while (peek(1).type != Token.TYPE.RBRACKET) {
|
||||
stl.add(parseStatement());
|
||||
}
|
||||
|
||||
|
@ -496,7 +477,7 @@ public class Parser {
|
|||
if (peek(1).type == Token.TYPE.LPAREN) {
|
||||
ExprList el = new ExprList();
|
||||
accept(Token.TYPE.LPAREN);
|
||||
if(peek(1).type != Token.TYPE.RPAREN) {
|
||||
if (peek(1).type != Token.TYPE.RPAREN) {
|
||||
el = parseArgumentList();
|
||||
}
|
||||
accept(Token.TYPE.RPAREN);
|
||||
|
@ -548,9 +529,9 @@ public class Parser {
|
|||
Token.TYPE snd = peek(2).type;
|
||||
Token.TYPE thd = peek(3).type;
|
||||
|
||||
if(fst != Token.TYPE.ID || snd == Token.TYPE.ID) {
|
||||
if (fst != Token.TYPE.ID || snd == Token.TYPE.ID) {
|
||||
return parseVarDeclStatement();
|
||||
} else if(snd == Token.TYPE.LSQUARE && thd == Token.TYPE.RSQUARE) {
|
||||
} else if (snd == Token.TYPE.LSQUARE && thd == Token.TYPE.RSQUARE) {
|
||||
return parseVarDeclStatement();
|
||||
}
|
||||
|
||||
|
@ -563,7 +544,6 @@ public class Parser {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// EXPRESSIONS
|
||||
|
@ -661,12 +641,14 @@ public class Parser {
|
|||
}
|
||||
}
|
||||
|
||||
default: throw new ParsingException(peek(1).posn);
|
||||
default:
|
||||
throw new ParsingException(peek(1).posn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disjunctive
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
|
@ -685,6 +667,7 @@ public class Parser {
|
|||
|
||||
/**
|
||||
* Conjunctive
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
|
@ -703,6 +686,7 @@ public class Parser {
|
|||
|
||||
/**
|
||||
* Equality
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
|
@ -721,6 +705,7 @@ public class Parser {
|
|||
|
||||
/**
|
||||
* Relational
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
|
@ -728,8 +713,8 @@ public class Parser {
|
|||
|
||||
Expression expr = parseAExpression();
|
||||
|
||||
while(peek(1).spelling.equals("<") || peek(1).spelling.equals("<=")
|
||||
|| peek(1).spelling.equals(">") || peek(1).spelling.equals(">=")) {
|
||||
while (peek(1).spelling.equals("<") || peek(1).spelling.equals("<=") || peek(1).spelling.equals(">")
|
||||
|| peek(1).spelling.equals(">=")) {
|
||||
Token next = accept(Token.TYPE.BINOP);
|
||||
Operator o = new Operator(next, next.posn);
|
||||
expr = new BinaryExpr(o, expr, parseAExpression(), expr.posn);
|
||||
|
@ -740,6 +725,7 @@ public class Parser {
|
|||
|
||||
/**
|
||||
* Additive
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
|
@ -758,6 +744,7 @@ public class Parser {
|
|||
|
||||
/**
|
||||
* Multiplicative
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
|
@ -774,7 +761,6 @@ public class Parser {
|
|||
return expr;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Convenience Methods
|
||||
|
@ -807,8 +793,10 @@ public class Parser {
|
|||
private Token accept(Token.TYPE type) throws IOException {
|
||||
|
||||
Token next = peek(1);
|
||||
if(next.type == type) stream.poll();
|
||||
else throw new ParsingException(next.posn);
|
||||
if (next.type == type)
|
||||
stream.poll();
|
||||
else
|
||||
throw new ParsingException(next.posn);
|
||||
|
||||
return next;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ public class Scanner {
|
|||
this.predefined = predefined;
|
||||
}
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Scanning
|
||||
|
@ -57,29 +56,30 @@ public class Scanner {
|
|||
int c = read();
|
||||
SourcePosition posn = new SourcePosition(col, line);
|
||||
|
||||
if(c == -1) {
|
||||
if (c == -1) {
|
||||
token = new Token("", Token.TYPE.EOT, posn);
|
||||
} else {
|
||||
spelling += (char) c;
|
||||
|
||||
switch(c) {
|
||||
switch (c) {
|
||||
|
||||
// Operators
|
||||
case '*':
|
||||
case '+':
|
||||
case '-': {
|
||||
if(peek(c)) throw new ScanningException(posn);
|
||||
if (peek(c))
|
||||
throw new ScanningException(posn);
|
||||
token = new Token(spelling, Token.TYPE.BINOP, posn);
|
||||
break;
|
||||
}
|
||||
|
||||
// Comment
|
||||
case '/': {
|
||||
if(peek('*')) {
|
||||
if (peek('*')) {
|
||||
read();
|
||||
readMultiLineComment();
|
||||
spelling = "";
|
||||
} else if(peek('/')) {
|
||||
} else if (peek('/')) {
|
||||
readSingleLineComment();
|
||||
spelling = "";
|
||||
} else {
|
||||
|
@ -92,14 +92,15 @@ public class Scanner {
|
|||
// Relational
|
||||
case '>':
|
||||
case '<': {
|
||||
if (peek('=')) spelling += (char) read();
|
||||
if (peek('='))
|
||||
spelling += (char) read();
|
||||
token = new Token(spelling, Token.TYPE.BINOP, posn);
|
||||
break;
|
||||
}
|
||||
|
||||
// Negation
|
||||
case '!': {
|
||||
if(peek('=')) {
|
||||
if (peek('=')) {
|
||||
spelling += (char) read();
|
||||
token = new Token(spelling, Token.TYPE.BINOP, posn);
|
||||
} else {
|
||||
|
@ -112,7 +113,7 @@ public class Scanner {
|
|||
// Logical
|
||||
case '&':
|
||||
case '|': {
|
||||
if(!peek(c)) {
|
||||
if (!peek(c)) {
|
||||
throw new ScanningException(posn);
|
||||
} else {
|
||||
spelling += (char) read();
|
||||
|
@ -124,7 +125,7 @@ public class Scanner {
|
|||
|
||||
// Other Operators
|
||||
case '=': {
|
||||
if(peek('=')) {
|
||||
if (peek('=')) {
|
||||
spelling += (char) read();
|
||||
token = new Token(spelling, Token.TYPE.BINOP, posn);
|
||||
} else {
|
||||
|
@ -151,14 +152,14 @@ public class Scanner {
|
|||
default: {
|
||||
|
||||
// Identifier or keyword
|
||||
if(isAlpha(c)) {
|
||||
if (isAlpha(c)) {
|
||||
int next = peek();
|
||||
while(isAlpha(next) || isDigit(next) || next == '_') {
|
||||
while (isAlpha(next) || isDigit(next) || next == '_') {
|
||||
spelling += (char) read();
|
||||
next = peek();
|
||||
}
|
||||
|
||||
if(Token.keywords.containsKey(spelling)) {
|
||||
if (Token.keywords.containsKey(spelling)) {
|
||||
token = new Token(spelling, Token.keywords.get(spelling), posn);
|
||||
} else {
|
||||
token = new Token(spelling, Token.TYPE.ID, posn);
|
||||
|
@ -166,9 +167,9 @@ public class Scanner {
|
|||
}
|
||||
|
||||
// Number
|
||||
else if(isDigit(c)) {
|
||||
else if (isDigit(c)) {
|
||||
int next = peek();
|
||||
while(isDigit(next)) {
|
||||
while (isDigit(next)) {
|
||||
spelling += (char) read();
|
||||
next = peek();
|
||||
}
|
||||
|
@ -177,7 +178,7 @@ public class Scanner {
|
|||
}
|
||||
|
||||
// Whitespace
|
||||
else if(isWhitespace(c)) {
|
||||
else if (isWhitespace(c)) {
|
||||
spelling = "";
|
||||
}
|
||||
|
||||
|
@ -193,8 +194,6 @@ public class Scanner {
|
|||
return token;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Convenience Methods
|
||||
|
@ -207,9 +206,7 @@ public class Scanner {
|
|||
* @return
|
||||
*/
|
||||
private boolean isAlpha(int c) {
|
||||
return (c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
|| (predefined && c == '_');
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (predefined && c == '_');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -264,7 +261,7 @@ public class Scanner {
|
|||
*/
|
||||
private int read() throws IOException {
|
||||
int next = input.read();
|
||||
if(next == '\n' || next == '\r') {
|
||||
if (next == '\n' || next == '\r') {
|
||||
col = 1;
|
||||
line += 1;
|
||||
} else {
|
||||
|
@ -292,12 +289,12 @@ public class Scanner {
|
|||
int prev = '\0';
|
||||
int current = '\0';
|
||||
|
||||
while(prev != '*' || current != '/') {
|
||||
while (prev != '*' || current != '/') {
|
||||
prev = current;
|
||||
current = read();
|
||||
|
||||
// Unterminated
|
||||
if(current == -1) {
|
||||
if (current == -1) {
|
||||
SourcePosition posn = new SourcePosition(line, col);
|
||||
throw new ScanningException(posn);
|
||||
}
|
||||
|
|
|
@ -10,37 +10,10 @@ public class Token {
|
|||
public enum TYPE {
|
||||
|
||||
// Terminals
|
||||
ID,
|
||||
NUM,
|
||||
UNOP,
|
||||
BINOP,
|
||||
EQUALS,
|
||||
PERIOD,
|
||||
COMMA,
|
||||
LPAREN,
|
||||
RPAREN,
|
||||
LSQUARE,
|
||||
RSQUARE,
|
||||
LBRACKET,
|
||||
RBRACKET,
|
||||
SEMICOLON,
|
||||
ID, NUM, UNOP, BINOP, EQUALS, PERIOD, COMMA, LPAREN, RPAREN, LSQUARE, RSQUARE, LBRACKET, RBRACKET, SEMICOLON,
|
||||
|
||||
// Keywords
|
||||
IF,
|
||||
ELSE,
|
||||
NEW,
|
||||
INT,
|
||||
VOID,
|
||||
THIS,
|
||||
TRUE,
|
||||
FALSE,
|
||||
CLASS,
|
||||
WHILE,
|
||||
RETURN,
|
||||
BOOLEAN,
|
||||
STATIC,
|
||||
PUBLIC,
|
||||
PRIVATE,
|
||||
IF, ELSE, NEW, INT, VOID, THIS, TRUE, FALSE, CLASS, WHILE, RETURN, BOOLEAN, STATIC, PUBLIC, PRIVATE,
|
||||
|
||||
// End of Token Stream
|
||||
EOT
|
||||
|
@ -48,6 +21,7 @@ public class Token {
|
|||
|
||||
// Pair words with enumeration
|
||||
public final static HashMap<String, TYPE> keywords;
|
||||
|
||||
static {
|
||||
keywords = new HashMap<String, TYPE>();
|
||||
keywords.put("class", TYPE.CLASS);
|
||||
|
@ -69,6 +43,7 @@ public class Token {
|
|||
|
||||
// Pair symbols with enumeration
|
||||
public final static HashMap<Integer, TYPE> symbols;
|
||||
|
||||
static {
|
||||
symbols = new HashMap<Integer, TYPE>();
|
||||
symbols.put((int) '.', TYPE.PERIOD);
|
||||
|
|
|
@ -16,8 +16,7 @@ public class Checkpoint1 {
|
|||
static ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
File testDir = new File(System.getProperty("java.class.path")
|
||||
+ "/../tests/pa1_tests");
|
||||
File testDir = new File(System.getProperty("java.class.path") + "/../tests/pa1_tests");
|
||||
int failures = 0;
|
||||
for (File x : testDir.listFiles()) {
|
||||
int returnCode = runTest(x);
|
||||
|
@ -26,8 +25,7 @@ public class Checkpoint1 {
|
|||
System.out.println(x.getName() + " passed successfully!");
|
||||
else {
|
||||
failures++;
|
||||
System.err.println(x.getName()
|
||||
+ " failed but should have passed!");
|
||||
System.err.println(x.getName() + " failed but should have passed!");
|
||||
}
|
||||
} else {
|
||||
if (returnCode == 4)
|
||||
|
@ -42,7 +40,8 @@ public class Checkpoint1 {
|
|||
}
|
||||
|
||||
private static int runTest(File x) throws IOException, InterruptedException {
|
||||
ProcessBuilder pb = new ProcessBuilder("java", "miniJava.Compiler", x.getPath()).directory(new File(System.getProperty("java.class.path")));
|
||||
ProcessBuilder pb = new ProcessBuilder("java", "miniJava.Compiler", x.getPath())
|
||||
.directory(new File(System.getProperty("java.class.path")));
|
||||
Process p = pb.start();
|
||||
threadPool.execute(new ProcessOutputter(p.getInputStream(), false));
|
||||
p.waitFor();
|
||||
|
@ -57,15 +56,15 @@ public class Checkpoint1 {
|
|||
processOutput = new Scanner(_processStream);
|
||||
output = _output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while(processOutput.hasNextLine()) {
|
||||
while (processOutput.hasNextLine()) {
|
||||
String line = processOutput.nextLine();
|
||||
if (output)
|
||||
System.out.println(line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ public class Checkpoint2 {
|
|||
private static class ReturnInfo {
|
||||
int returnCode;
|
||||
String ast;
|
||||
|
||||
public ReturnInfo(int _returnCode, String _ast) {
|
||||
returnCode = _returnCode;
|
||||
ast = _ast;
|
||||
|
@ -24,8 +25,7 @@ public class Checkpoint2 {
|
|||
}
|
||||
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
File testDir = new File(System.getProperty("java.class.path")
|
||||
+ "/../tests/pa2_tests");
|
||||
File testDir = new File(System.getProperty("java.class.path") + "/../tests/pa2_tests");
|
||||
int failures = 0;
|
||||
for (File x : testDir.listFiles()) {
|
||||
if (x.getName().endsWith("out") || x.getName().startsWith("."))
|
||||
|
@ -42,11 +42,9 @@ public class Checkpoint2 {
|
|||
System.err.println(x.getName() + " parsed successfully but has an incorrect AST!");
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
failures++;
|
||||
System.err.println(x.getName()
|
||||
+ " failed to be parsed!");
|
||||
System.err.println(x.getName() + " failed to be parsed!");
|
||||
}
|
||||
} else {
|
||||
if (returnCode == 4)
|
||||
|
@ -61,7 +59,8 @@ public class Checkpoint2 {
|
|||
}
|
||||
|
||||
private static ReturnInfo runTest(File x) throws IOException, InterruptedException {
|
||||
ProcessBuilder pb = new ProcessBuilder("java", "miniJava.Compiler", x.getPath()).directory(new File(System.getProperty("java.class.path")));
|
||||
ProcessBuilder pb = new ProcessBuilder("java", "miniJava.Compiler", x.getPath())
|
||||
.directory(new File(System.getProperty("java.class.path")));
|
||||
pb.redirectErrorStream(true);
|
||||
Process p = pb.start();
|
||||
|
||||
|
@ -71,7 +70,6 @@ public class Checkpoint2 {
|
|||
return new ReturnInfo(exitValue, ast);
|
||||
}
|
||||
|
||||
|
||||
public static String getAST(InputStream stream) {
|
||||
Scanner scan = new Scanner(stream);
|
||||
String ast = null;
|
||||
|
@ -79,7 +77,7 @@ public class Checkpoint2 {
|
|||
String line = scan.nextLine();
|
||||
if (line.equals("======= AST Display =========================")) {
|
||||
line = scan.nextLine();
|
||||
while(scan.hasNext() && !line.equals("=============================================")) {
|
||||
while (scan.hasNext() && !line.equals("=============================================")) {
|
||||
ast += line + "\n";
|
||||
line = scan.nextLine();
|
||||
}
|
||||
|
@ -88,7 +86,7 @@ public class Checkpoint2 {
|
|||
System.out.println(line);
|
||||
if (line.startsWith("ERROR")) {
|
||||
System.out.println(line);
|
||||
while(scan.hasNext())
|
||||
while (scan.hasNext())
|
||||
System.out.println(scan.next());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.util.Scanner;
|
||||
|
||||
|
||||
/* Automated regression tester for Checkpoint 3 tests
|
||||
* Created by Max Beckman-Harned
|
||||
* Put your tests in "tests/pa3_tests" folder in your Eclipse workspace directory
|
||||
|
@ -14,23 +13,20 @@ import java.util.Scanner;
|
|||
|
||||
public class Checkpoint3 {
|
||||
|
||||
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
File testDir = new File(System.getProperty("java.class.path")
|
||||
+ "/../tests/pa3_tests");
|
||||
File testDir = new File(System.getProperty("java.class.path") + "/../tests/pa3_tests");
|
||||
int failures = 0;
|
||||
for (File x : testDir.listFiles()) {
|
||||
if (x.getName().endsWith("out") || x.getName().startsWith(".") || x.getName().endsWith("mJAM") || x.getName().endsWith("asm"))
|
||||
if (x.getName().endsWith("out") || x.getName().startsWith(".") || x.getName().endsWith("mJAM")
|
||||
|| x.getName().endsWith("asm"))
|
||||
continue;
|
||||
int returnCode = runTest(x);
|
||||
if (x.getName().indexOf("pass") != -1) {
|
||||
if (returnCode == 0) {
|
||||
System.out.println(x.getName() + " processed successfully!");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
failures++;
|
||||
System.err.println(x.getName()
|
||||
+ " failed to be processed!");
|
||||
System.err.println(x.getName() + " failed to be processed!");
|
||||
}
|
||||
} else {
|
||||
if (returnCode == 4)
|
||||
|
@ -45,7 +41,8 @@ public class Checkpoint3 {
|
|||
}
|
||||
|
||||
private static int runTest(File x) throws IOException, InterruptedException {
|
||||
ProcessBuilder pb = new ProcessBuilder("java", "miniJava.Compiler", x.getPath()).directory(new File(System.getProperty("java.class.path")));
|
||||
ProcessBuilder pb = new ProcessBuilder("java", "miniJava.Compiler", x.getPath())
|
||||
.directory(new File(System.getProperty("java.class.path")));
|
||||
pb.redirectErrorStream(true);
|
||||
Process p = pb.start();
|
||||
|
||||
|
@ -55,7 +52,6 @@ public class Checkpoint3 {
|
|||
return exitValue;
|
||||
}
|
||||
|
||||
|
||||
public static void processStream(InputStream stream) {
|
||||
Scanner scan = new Scanner(stream);
|
||||
while (scan.hasNextLine()) {
|
||||
|
@ -64,8 +60,8 @@ public class Checkpoint3 {
|
|||
System.out.println(line);
|
||||
if (line.startsWith("ERROR")) {
|
||||
System.out.println(line);
|
||||
//while(scan.hasNext())
|
||||
//System.out.println(scan.next());
|
||||
// while(scan.hasNext())
|
||||
// System.out.println(scan.next());
|
||||
}
|
||||
}
|
||||
scan.close();
|
||||
|
|
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.util.Scanner;
|
||||
|
||||
|
||||
/* Automated regression tester for Checkpoint 4 tests
|
||||
* Created by Max Beckman-Harned
|
||||
* Put your tests in "tests/pa4_tests" folder in your Eclipse workspace directory
|
||||
|
@ -14,10 +13,8 @@ import java.util.Scanner;
|
|||
|
||||
public class Checkpoint4 {
|
||||
|
||||
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
File testDir = new File(System.getProperty("java.class.path")
|
||||
+ "/../tests/pa4_tests");
|
||||
File testDir = new File(System.getProperty("java.class.path") + "/../tests/pa4_tests");
|
||||
int failures = 0;
|
||||
for (File x : testDir.listFiles()) {
|
||||
if (x.getName().startsWith(".") || x.getName().endsWith("mJAM") || x.getName().endsWith("asm"))
|
||||
|
@ -27,23 +24,21 @@ public class Checkpoint4 {
|
|||
if (returnCode == 0) {
|
||||
try {
|
||||
int val = executeTest(x);
|
||||
int expected = Integer.parseInt(x.getName().substring(5,7));
|
||||
int expected = Integer.parseInt(x.getName().substring(5, 7));
|
||||
if (val == expected)
|
||||
System.out.println(x.getName() + " ran successfully!");
|
||||
else {
|
||||
failures++;
|
||||
System.err.println(x.getName() + " compiled but did not run successfully--got output " + val);
|
||||
System.err
|
||||
.println(x.getName() + " compiled but did not run successfully--got output " + val);
|
||||
}
|
||||
}
|
||||
catch(Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
failures++;
|
||||
System.err.println(x.getName() + " did not output correctly.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
failures++;
|
||||
System.err.println(x.getName()
|
||||
+ " failed to be processed!");
|
||||
System.err.println(x.getName() + " failed to be processed!");
|
||||
}
|
||||
} else {
|
||||
if (returnCode == 4)
|
||||
|
@ -58,7 +53,8 @@ public class Checkpoint4 {
|
|||
}
|
||||
|
||||
private static int runTest(File x) throws IOException, InterruptedException {
|
||||
ProcessBuilder pb = new ProcessBuilder("java", "miniJava.Compiler", x.getPath()).directory(new File(System.getProperty("java.class.path")));
|
||||
ProcessBuilder pb = new ProcessBuilder("java", "miniJava.Compiler", x.getPath())
|
||||
.directory(new File(System.getProperty("java.class.path")));
|
||||
pb.redirectErrorStream(true);
|
||||
Process p = pb.start();
|
||||
|
||||
|
@ -69,7 +65,8 @@ public class Checkpoint4 {
|
|||
}
|
||||
|
||||
private static int executeTest(File x) throws IOException, InterruptedException {
|
||||
ProcessBuilder pb = new ProcessBuilder("java", "mJAM.Interpreter", x.getPath().replace(".java", ".mJAM")).directory(new File(System.getProperty("java.class.path")));
|
||||
ProcessBuilder pb = new ProcessBuilder("java", "mJAM.Interpreter", x.getPath().replace(".java", ".mJAM"))
|
||||
.directory(new File(System.getProperty("java.class.path")));
|
||||
Process process = pb.start();
|
||||
|
||||
Scanner scan = new Scanner(process.getInputStream());
|
||||
|
@ -94,7 +91,6 @@ public class Checkpoint4 {
|
|||
return num;
|
||||
}
|
||||
|
||||
|
||||
public static void processStream(InputStream stream) {
|
||||
Scanner scan = new Scanner(stream);
|
||||
while (scan.hasNextLine()) {
|
||||
|
@ -103,8 +99,8 @@ public class Checkpoint4 {
|
|||
System.out.println(line);
|
||||
if (line.startsWith("ERROR")) {
|
||||
System.out.println(line);
|
||||
//while(scan.hasNext())
|
||||
//System.out.println(scan.next());
|
||||
// while(scan.hasNext())
|
||||
// System.out.println(scan.next());
|
||||
}
|
||||
}
|
||||
scan.close();
|
||||
|
|
Loading…
Reference in New Issue