// © Copyright 1997, 1999, Joseph Bergin. All rights reserved.import java.util.Vector;import java.util.Hashtable;import java.util.Stack;import java.util.Enumeration;import java.io.Reader;import java.io.BufferedReader;import java.io.PrintWriter;import java.io.IOException;import java.util.NoSuchElementException;import java.util.StringTokenizer;class CPUProcess implements Cloneable{		public CPUProcess(int serialNumber , Reader in, PrintWriter out, boolean trace)	{	_serialNumber = serialNumber;		_input = new BufferedReader(in);		_output = out;		this.trace = trace;	}			public Object clone ()	{	CPUProcess result = new CPUProcess(_serialNumber, _input, _output, trace);		result._instructionCount = _instructionCount;		result._state = _state;		result.PC = PC;		result._programLength = _programLength;		result._variables = (Vector)_variables.clone();		result._stack = (Stack)_stack.clone();		result.simulator = simulator;		result._memory = (Hashtable)_memory; // not cloned-- shared		result.program = new Vector();		for(int i = 0; i < _programLength; ++i)		{	Instruction inst = (Instruction)program.elementAt(i);			result.program.addElement(inst.makeCopyIn(result));		}		return result;	}			public void setSerialNumber(int serialNumber)	{	_serialNumber = serialNumber;	}		public void setSimulator(Simulator s) 	{	simulator = s;	}		public void setRestart(int pc)	{	if(pc < _programLength){ PC = pc; } else { PC = _programLength-1;}	}		public void setMemory(Hashtable m) // Simulator calls this when process is inserted.	{	_memory = m;		Enumeration e = _variables.elements(); // Load P's variables into the (shared) memory		while(e.hasMoreElements())		{	_memory.put(e.nextElement(), new Integer(0));		}	}		public void setRunnable() { _state = 1; }		public int getRestart(){ return PC; }		public Instruction fetch(int pc){ return (Instruction)program.elementAt(pc); }			public void reset() // Set _pc to zero and clear _stack.	// The memory is a collection of labeled cells.  The labels are integers, as are	// the contents. Instruction pushv(v), pushes the contents of the cell with label v	// Instruction pushi(x) pushes the literal value x.  Instruction pop(v) pops the 	// stack and stores the result in location with label v.  Arithmetic operations get	// operands from stack by popping and return results to stack.	{	_programLength = 0;		_stack.removeAllElements();	}			 void declare(int c)	// declare a variable // initialized to zero	{	Integer C = new Integer(c);		Enumeration e = _variables.elements();		while(e.hasMoreElements())			if(C.equals(e.nextElement())) return; // already defined		_variables.addElement(C); // define it. 	}		// The next 19 instructions simply enter an equiv statement into the next		// available slot in the program.  They do not execute the program.  		// Instructions inserted are implicitly numbered starting with 0. 				public void pushv(int c)		// push the current value of a variable	{	program.addElement(new Pushv(c));		_programLength++;	}	public void pushi(int i)		// push a literal	{	program.addElement(new Pushi(i));		_programLength++;	}	public void pop(int c)		// pop a value to a declared variable	{	program.addElement(new Pop(c));		_programLength++;	}	public void add()		// add two top values(popping) and push the result	{	program.addElement(new Add());		_programLength++;	}	public void sub()		// top value is RIGHT operand	{	program.addElement(new Sub());		_programLength++;	}	public void mult()	{	program.addElement(new Mult());		_programLength++;	}	public void div()		// integer division (top value is RIGHT operand)	{	program.addElement(new Div());		_programLength++;	}	public void negate()	// negate the top of the stack (in place)	{	program.addElement(new Negate());		_programLength++;	}	public void output()	// copy top of run time stack to output	{	program.addElement(new Output());		_programLength++;	}	public void input()		// push a value from the input	{	program.addElement(new Input());		_programLength++;	}	public void toss()		// discard top of run time stack	{	program.addElement(new Toss());		_programLength++;	}	public void swap()		// swap two top values on run time stack	{	program.addElement(new Swap());		_programLength++;	}	public void dup()		// duplicate top of run time stack	{	program.addElement(new Dup());		_programLength++;	}	public void outputAscii()	// Interpret top of stack as ascii char and output it	{	program.addElement(new OutputAscii());		_programLength++;	}	public void inputAscii()  	// Read in an ascii char and push it.  	{	program.addElement(new InputAscii());		_programLength++;	}	public void JMP(int lab)	{	Integer dest = (Integer) _symbols.get(new Integer(lab));		program.addElement(new JMP(dest));		if (dest == null)			enterForward(lab, _programLength);		_programLength++;	}		public void JGZ(int lab)	{	Integer dest =  (Integer)_symbols.get(new Integer(lab));		program.addElement(new JGZ(dest));		if (dest == null)			enterForward(lab, _programLength);		_programLength++;	}		public void JEZ(int lab)	{	Integer dest =  (Integer)_symbols.get(new Integer(lab));		program.addElement(new JEZ(dest));		if (dest == null)			enterForward(lab, _programLength);		_programLength++;	}		public void halt()		// Halts your program (with a message).	{	program.addElement(new Halt());		_programLength++;	}	public void label(int lab)	{	_symbols.put(new Integer(lab), new Integer(_programLength));		for(int i = 0; i < _forwards.size(); ++i)			if( ((Integer) ((Pair) _forwards.elementAt(i)).first).intValue() == lab)			{	int loc = ((Integer)((Pair) _forwards.elementAt(i)).second).intValue();				JMP j = (JMP)program.elementAt(loc);				j.setDestination(new Integer(_programLength));			} 	}		public boolean isHalted(){return _state == 0;}		public void userERROR(String s)	{	System.out.println(s);	}		public String toString()	{	String result = "Process " + _serialNumber +"" +(_state==0?" halted":" runnable")+ ":\n";		for(int i = 0; i < _programLength; ++i)		{	result = result + program.elementAt(i).toString() + "\n";		}		return result;	}		public int serialNumber(){ return _serialNumber; }				private void enterForward(int labelName, int fixLoc)	{	_forwards.addElement(new Pair(new Integer(labelName), new Integer(fixLoc)));	}			private Hashtable _symbols = new Hashtable();	private Vector _forwards = new Vector();			private  int _forwardCount;	Vector program = new Vector(); // Contains Instructions. 	private int _programLength = 0; // logical length. 	private int _serialNumber; // for reporting	private Vector _variables = new Vector(); // The variable "names".  (Integers)// Execution environment	private int _instructionCount = 0; //number of instructions executed(reporting only)	private int _state = 0;  //1 = active, 0 = halted.			private Stack _stack = new Stack(); // Run time stack of this process	private Hashtable _memory = null; // Set when entered into simulator (shared).	private int PC = 0; // only valid when not executing.	private BufferedReader  _input;	private PrintWriter  _output;	private boolean trace = false;	private Simulator simulator = null; // The simulator that will execute this. 	private StringTokenizer fetcher = null; // Used to parse input. 	private String inBuffer = null;	abstract class Instruction	{	public abstract boolean  execute(); // return true to halt the process		public  Instruction makeCopyIn(CPUProcess c) {return new Halt();}		// The makeCopyIn methods enable the containing process to be cloned while attaching the		// inner objects (these Instructions) to have copies attached to the new clone process.		// There seems to be a bug in the java compiler that won't let these be both polymorphic		// and private. 	}		class Halt extends Instruction	{	public boolean execute()		{	if(trace)System.out.println(_serialNumber + ": halt");			_state = 0; //halted			return true; 		}				public String toString()		{	return "halt ";		}				public Instruction makeCopyIn(CPUProcess c)		{	return c.new Halt(); // All Halt objects are identical.		}	}			class Add extends Instruction	{	public boolean execute() 		{	if(trace) System.out.println(_serialNumber + ": add");			Integer right = (Integer)_stack.pop();			Integer left  = (Integer)_stack.pop();			_stack.push(new Integer(left.intValue() + right.intValue()));			return false;		}				public String toString()		{	return "add ";		}				public Instruction makeCopyIn(CPUProcess c)		{	return c.new Add(); // All such objects are identical.		}	}		class Sub extends Instruction	{	public boolean execute() 		{	if(trace) System.out.println(_serialNumber + ": sub");			Integer right = (Integer)_stack.pop();			Integer left  = (Integer)_stack.pop();			_stack.push(new Integer(left.intValue() - right.intValue()));			return false;		}				public String toString()		{	return "sub ";		}		public Instruction makeCopyIn(CPUProcess c)		{	return c.new Sub(); // All such objects are identical.		}	}		class Mult extends Instruction	{	public boolean execute() 		{	if(trace) System.out.println(_serialNumber +  ": mult");			Integer right = (Integer)_stack.pop();			Integer left  = (Integer)_stack.pop();			_stack.push(new Integer(left.intValue() * right.intValue()));			return false;		}				public String toString()		{	return "mult ";		}		public Instruction makeCopyIn(CPUProcess c)		{	return c.new Mult(); // All such objects are identical.		}	}		class Div extends Instruction	{	public boolean execute() 		{	if(trace) System.out.println(_serialNumber +  ": div");			Integer right = (Integer)_stack.pop();			Integer left  = (Integer)_stack.pop();			if(right.intValue() == 0){ userERROR("Zero Divide"); return true; }			_stack.push(new Integer(left.intValue() / right.intValue()));			return false;		}				public String toString()		{	return "div ";		}		public Instruction makeCopyIn(CPUProcess c)		{	return c.new Div(); // All such objects are identical.		}	}		class JMP extends Instruction	{	public JMP(Integer dest)		{	destination = dest;		}				public void setDestination(Integer dest)		{	destination = dest;		}				public boolean execute()		{	if(trace)System.out.println(_serialNumber +  ": JMP " +destination);			simulator.setPC(destination.intValue());			return false;		}						public String toString()		{	return "jmp " + destination;		}		private Integer destination;		public Instruction makeCopyIn(CPUProcess c)		{	return c.new JMP(destination); 		}	}		class JGZ extends JMP	{	public JGZ(Integer dest)		{	super(dest);		}				public boolean execute()		{	if(trace)System.out.println(_serialNumber +  ": JGZ " + destination);			Integer right = (Integer)_stack.peek();			if(right.intValue() > 0) simulator.setPC(destination.intValue());			return false;		}				public String toString()		{	return "jgz " + destination;		}		public Instruction makeCopyIn(CPUProcess c)		{	return c.new JGZ(destination); 		}	}		class JEZ extends JMP	{	public JEZ(Integer dest)		{	super(dest);		}				public boolean execute()		{	if(trace)System.out.println(_serialNumber + ": JEZ " +destination);			Integer right = (Integer)_stack.peek();			if(right.intValue() == 0) simulator.setPC(destination.intValue());			return false;		}				public String toString()		{	return "jez " + destination;		}		public Instruction makeCopyIn(CPUProcess c)		{	return c.new JEZ(destination); 		}	}		class Dup extends Instruction	{	public boolean execute()		{	if(trace)System.out.println(_serialNumber +  ": dup");				_stack.push(_stack.peek());					return false;		}				public String toString()		{	return "dup ";		}		public Instruction makeCopyIn(CPUProcess c)		{	return c.new Dup(); // All such objects are identical.		}	}		class Input extends Instruction	{	public boolean execute()		{	if(trace)System.out.println(_serialNumber +  ": input");			{	int x = 0;				try				{	if( inBuffer == null || ! fetcher.hasMoreElements() )					{	inBuffer = _input.readLine();						fetcher = new StringTokenizer(inBuffer);					}					x = Integer.parseInt(fetcher.nextToken());				}				catch(NoSuchElementException e){ x = 0; userERROR("No element");}				catch(IOException e)				{	x = 0; 					userERROR("InputError");					_state = 0; //halted					return true;				}				_stack.push(new Integer( x ));					if(trace)System.out.println("read: " + x);								}			return false;		}				public String toString()		{	return "input ";		}		public Instruction makeCopyIn(CPUProcess c)		{	return c.new Input(); // All such objects are identical.		}	}		class Output extends Instruction	{	public boolean execute()		{	if(trace)System.out.println(_serialNumber + ": output");			_output.println (_stack.peek());			if(trace)System.out.println ("write: " + _stack.peek());			return false;		}				public String toString()		{	return "output ";		}		public Instruction makeCopyIn(CPUProcess c)		{	return c.new Output(); // All such objects are identical.		}	}		class InputAscii extends Instruction // not implemented	{	public boolean execute()		{			return false;		}				public String toString()		{	return "inputAscii not implemented ";		}		public Instruction makeCopyIn(CPUProcess c)		{	return c.new InputAscii(); // All such objects are identical.		}	}		class OutputAscii extends Instruction // not implemented	{	public boolean execute()		{			return false;		}				public String toString()		{	return "outputAscii not implemented ";		}		public Instruction makeCopyIn(CPUProcess c)		{	return c.new OutputAscii(); // All such objects are identical.		}	}		class Pushi extends Instruction	{	public Pushi(int i)		{	value = new Integer(i);		}				public boolean execute()		{	if(trace)System.out.println(_serialNumber +  ": pushi " + value);				_stack.push(value);			return false;		}				public String toString()		{	return "pushi " + value;		}				Integer value = null;		public Instruction makeCopyIn(CPUProcess c)		{	return c.new Pushi(value.intValue());		}	}		class Pushv extends Instruction	{	public Pushv(int c) { variable = c; }		public boolean execute() 		{	if(trace) System.out.println(_serialNumber + ": pushv " + variable);				Object temp;			Integer v = new Integer(variable);			if(!_memory.containsKey(v)) 			{	userERROR("ILLEGAL Memory Location");				return true;			}			else 				temp = _memory.get(v);			_stack.push(temp);			return false;		}				public String toString()		{	return "pushv " + variable;		}				private int variable;		public Instruction makeCopyIn(CPUProcess c)		{	return c.new Pushv(variable); 		}	}		class Pop extends Instruction	{	public Pop(int c)		{	where = new Integer(c);		}				public boolean execute()		{	if(trace)System.out.println(_serialNumber +  ": pop " + where);			Integer right = (Integer)_stack.pop();			if(!_memory.containsKey(where))			{	userERROR("ILLEGAL Memory Location");				return true;			}			_memory.put(where, right);			return false;		}				public String toString()		{	return "pop " + where;		}				Integer where = null;		public Instruction makeCopyIn(CPUProcess c)		{	return c.new Pop(where.intValue()); 		}	}		class Toss extends Instruction	{	public boolean execute()		{	if(trace)System.out.println(_serialNumber + ": toss");				_stack.pop(); // discard			return false;		}				public String toString()		{	return "toss ";		}		public Instruction makeCopyIn(CPUProcess c)		{	return c.new Toss(); // All such objects are identical.		}	}		class Swap extends Instruction	{	public boolean execute()		{	System.out.println(_serialNumber +  ": swap");			Integer right = (Integer)_stack.pop();			Integer left = (Integer)_stack.pop();			_stack.push(right);			_stack.push(left);			return false;		}				public String toString()		{	return "swap ";		}		public Instruction makeCopyIn(CPUProcess c)		{	return c.new Swap(); // All such objects are identical.		}	}		class Negate extends Instruction	{	public boolean execute()		{	if(trace)System.out.println(_serialNumber + ": negate");			Integer right = (Integer)_stack.pop();			_stack.push(new Integer(- right.intValue()));			return false;		}				public String toString()		{	return "negate ";		}		public Instruction makeCopyIn(CPUProcess c)		{	return c.new Negate(); // All such objects are identical.		}	}	}