package rebelsky.pal; import java.io.BufferedReader; import java.io.PrintWriter; import java.io.InputStreamReader; import java.util.Vector; /** * A simple computer, intended to run PAL programs. The normal * sequence of operations is: *
 * // Create a new computer
 * Computer hal = new Computer(max-bytes);
 * hal.setCode(program);
 * hal.run(false);
 * 
* * @author Samuel A. Rebelsky * @version 1.0 of November 2002 */ public class Computer { // +----------------+---------------------------------------------------- // | Program Design | // +----------------+ /* A computer includes code, memory, program counter, stack pointer, frame pointer and memory. We repeatedly execute the current instruction (given by the program counter) until we reach a Halt instruction. Labels and Temporaries store their corresponding values. At some point, I should add debugging capabilities. */ // +--------+------------------------------------------------------------ // | Fields | // +--------+ /** The instructions for the current program. */ Vector code; /** The number of instructions for the current program. */ int codesize; /** Memory. */ int[] memory; /** The program counter. */ int pc; /** The stack pointer. */ int sp; /** The frame pointer. */ int fp; /** The writer use for output. */ PrintWriter out; /** The reader to use for input. */ BufferedReader in; // +--------------+------------------------------------------------------ // | Constructors | // +--------------+ /** * Build a new computer with a specified space for memory. */ public Computer(int mem) { this.memory = new int[mem]; out = new PrintWriter(System.out, true); in = new BufferedReader(new InputStreamReader(System.in)); } // Computer() // +---------------+----------------------------------------------------- // | Local Helpers | // +---------------+ /** * Flatten a tree of instructions onto the end of the code. */ private void flatten(InstructionSequence seq) { int seqlen = seq.instructions.size(); for (int i = 0; i < seqlen; i++) { Instruction command = (Instruction) seq.instructions.get(i); if (command instanceof InstructionSequence) flatten((InstructionSequence) command); else this.code.add(command); } // for } // flatten(InstructionSequence, int) /** * Print an instruction along with its line number. */ private void printInstruction(int line, Instruction command) { // Print the instruction number with leading 0's. if (line < 10) out.print("000"); else if (line < 100) out.print("00"); else if (line < 1000) out.print("0"); out.print(line); out.print(" "); // Print labels followed by colons. if (command instanceof Label) out.println(command.toString() + ":"); // Print everything else normally. else out.println(command.toString()); } // printInstruction(int,Instruction) /** * Scan the code, setting each label to its line number. */ private void processLabels() { for (int line = 0; line < this.codesize; line++) { Instruction command = (Instruction) code.get(line); if (command instanceof Label) ((Label) command).address = line; } // for(int line) } // processLabels() // +---------+----------------------------------------------------------- // | Methods | // +---------+ /** * Dump the program to the specified PrintWriter. */ public void dump(PrintWriter out) { for (int line = 0; line < this.codesize; line++) { printInstruction(line, (Instruction) code.get(line)); } // for(int i) } // dump(PrintWriter) /** * Run the program starting at instruction 0. If the parameter is * true, prints out a trace of the program. * * @exception Exception * If one of the instructions fails or we run out of instructions * without hitting a stop. */ public void run(boolean trace) throws Exception { Instruction current; // Set the program counter to 0. this.pc = 0; // Set the frame pointer and stack pointer to the end of memory. this.fp = memory.length; this.sp = memory.length; // Repeatedly get the current instruction and execute it. while (this.pc < this.codesize) { current = (Instruction) this.code.get(this.pc); if (trace) { printInstruction(this.pc, current); } this.pc++; if (current instanceof Halt) return; current.execute(this); } // Sanity check: Did we stop because of incorrect pc? throw new Exception("Invalid instruction number: " + this.pc); } // run() /** * Set the code in the computer to a new sequence of instructions. */ public void setCode(InstructionSequence seq) { this.code = new Vector(); flatten(seq); this.codesize = this.code.size(); processLabels(); } // setCode(InstructionSequence seq) } // class Computer