1
Fork 0
master
Joshua Potter 2015-12-15 07:40:18 -05:00
parent 518ca35a68
commit 72f3b2b497
75 changed files with 5203 additions and 5339 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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();

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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.");
}
}

View File

@ -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;

View File

@ -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;

View File

@ -17,6 +17,7 @@ public class Reporter {
/**
* Redefinitions
*
* @param d1
* @param d2
*/

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}
}
}
}

View File

@ -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());
}
}

View File

@ -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();

View File

@ -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();