public interface MachineI { MemoryI getMem (); ProcessorI getProc (); ioUnitI getIO (); /** * Tests each component of the machine. For example, attempts to * store a number in a known memory location, and then read that * location, etc. */ void selfTest (); } //------------------------------------------ public interface ioUnitI { /** * The default underlying byte-oriented input stream. */ java.io.InputStream DEFAULT_ISTREAM = System.in; /** * The default underlying byte-oriented output stream. */ java.io.OutputStream DEFAULT_OSTREAM = System.out; java.io.PrintWriter getWriter (); java.io.StreamTokenizer getReader (); /** * A call to readData reads one integer from the input stream. The call * will block until there is something to read. * @exception ioE If the input cannot be parsed as a number. */ Word readData () throws ioE; void writeData (Word w); } //------------------------------------------ public interface ProcessorI { ALUI getALU (); Word fetchPC (); Word fetchACC (); Instruction fetchIR (); void storePC (Word newpc); void storeACC (Word newacc); void storeIR (Instruction newir); }
Machine
,
Processor
, and ioUnit
that implement the
appropriate interfaces. Write any additional classes that you need to
make your code compile and run properly:
The I/O unit communicates with the outside world using streams.
Intuitively streams are unbounded sequences of values. The
java.io
package supports streams extensively.
Underlying any Java stream is a stream of bytes. Such byte streams
called InputStream
and OutputStream
are
low-level and rarely used directly in applications. For our purposes,
we would like to view the input stream as carrying a sequence of
numbers and we would also like to write arbitrary values to the output
stream. We can achieve this with a bit of work.
First, we move from byte streams to character streams using the
classes InputStreamReader
and
OutputStreamWriter
. The read and write operations on
these streams handle only one character at a time (which maycorrespond
to more than one byte on the underlying byte stream). For efficiency,
these streams are usually wrapped using a BufferedReader
and BufferedWriter
.
Next, we can automatically convert a stream of characters to a
stream of "tokens" where tokens represent entities such as strings,
numbers, etc. This is achieved using the rather flexible class
StreamTokenizer
. The behavior of this class can be
parameterized by a number of flags so you will need to consult the API
before using it. Symmetrically, we can write arbitrary Java objects
to a character stream by first wrapping it in a
PrintWriter
stream.
All inputs to our machine are numbers that are converted to
integers and stored in the memory. A call to the method
readData
may throw an exception if the input cannot be
parsed as a number. More importantly, the call will block waiting for
input if there are no characters to read from the input stream. This
is consistent with the intuitive behavior of programs: if a program is
requesting an input value, then it will wait (block) until that value
is supplied.