(********************************************************************)
(* TYPE DECLARATIONS *)
(********************************************************************)
datatype token = INT of int | REG of int | LOC of int |
VPUT | LPUT | WRI | PUT | ADD | MUL | SUB
type state = ( (int * int) * (int * int * int * int) )
(********************************************************************)
(********************************************************************)
(* SIGNATURE DECLARATIONS *)
(********************************************************************)
signature VMPROCESS =
sig
val execute : int -> unit
end
signature VIRTMACH =
sig
val interpret : token list * state * int -> token list * state
end
signature PROGRAM =
sig
val sourceFile : TextIO.instream
val resultFile : TextIO.outstream
end
(********************************************************************)
(********************************************************************)
(* PROGRAM INSTANCE CREATION *)
(********************************************************************)
structure ProgOne : PROGRAM =
struct
val sourceFile = TextIO.openIn("progone.vm")
val resultFile = TextIO.openOut("progone.out")
end
structure ProgTwo : PROGRAM =
struct
val sourceFile = TextIO.openIn("progtwo.vm")
val resultFile = TextIO.openOut("progtwo.out")
end
structure ProgThree : PROGRAM =
struct
val sourceFile = TextIO.openIn("progthree.vm")
val resultFile = TextIO.openOut("progthree.out")
end
(********************************************************************)
(*****************************************************************************)
(* VIRTUAL MACHINE FUNCTOR *)
(*****************************************************************************)
functor makeVirtualMachine(val outfile : TextIO.outstream) : VIRTMACH =
struct
exception Syntax of string
val outf : TextIO.outstream = outfile;
fun syntaxError s = raise (Syntax s)
(*======================FUNCTIONS YOU MUST WRITE=====================*)
fun printState : state -> unit
(* state -> output to file *)
(* Prints an output to the outfile that looks like
Registers: 1 2
Memory: 1 0 0 4
*)
fun regStore : int * int * state -> state
(* reg#, value, oldstate -> newstate *)
(* Puts value in reg# and returns the newstate tuple *)
(* Raises exception Syntax with appropriate message if # is not 1 or 2 *)
fun memStore : int * int * state -> state
(* mem#, value, oldstate -> newstate *)
(* Puts value in mem# and returns the newstate tuple *)
(* Raises exception Syntax with appropriate message if # is not 1 - 4 *)
fun regGet : int * state -> int
(* reg#, state -> value *)
(* Returns the value in reg# obtained from the state *)
(* Raises exception Syntax with appropriate message if # is not 1 or 2 *)
fun memGet : int * state -> int
(* mem#, state -> value *)
(* Returns the value in mem# obtained from the state *)
(* Raises exception Syntax with appropriate message if # is not 1 - 4 *)
fun stmt : token * token * token * state -> state
(* three tokens from the token list, oldstate -> newstate *)
(* This is the heart of the parsing. Given three tokens
that have been successfully removed from the token list by stmts,
match on the particulars and do the processing. Match also
many different incorrect combinations/range violations and
raise exception Syntax with appropriate messages *)
fun stmts : token list * state * int -> token list * state
(* old token list, oldstate, instruction count -> (new token list, newstate) *)
(* If the token list is empty, close the outfile and return the tuple (nil,s)
where s is state. Otherwise try to match three tokens from the list,
using them to call stmt. That result is the newstate. Print it,
and then if the instruction count not zero recurse, decrementing the count.
If it is zero, print to outfile the line "======> CONTEXT SWITCH" and
return the tuple (remaining token list, newstate).
Also raise exception Syntax if there is no successful match. *)
(*===================================================================*)
fun interpret(tokenStream : token list, s : state, numInstr : int ) : token list * state =
stmts(tokenStream,s,numInstr)
handle
Syntax s => (TextIO.output(outf,"Syntax error: "^s^"\n"); (nil,((0,0),(0,0,0,0))) )
end
(*********************************************************************************)
(*********************************************************************)
(* VMPROCESS FUNCTOR *)
(*********************************************************************)
functor makeVMProcess(prog : PROGRAM ) : VMPROCESS
=
struct
(******************************************)
(* Some utilities for the parsing process *)
(******************************************)
exception Invalid_Register of int
exception Invalid_Memory of int
exception Lexical of string
fun regError k = raise (Invalid_Register k)
fun memError k = raise (Invalid_Memory k)
fun lexicalError s = raise (Lexical s)
fun token(s : string) : token =
if Char.isDigit(String.sub(s,0)) orelse (String.sub(s,0) = #"~")
then case Int.fromString(s)
of SOME n => if (String.size(Int.toString(n))=String.size(s))
then INT n
else lexicalError ("Bad numeric token "^s)
| NONE => lexicalError ("Bad numeric token "^s)
else
if String.size(s)=2
then
if (String.sub(s,0) = #"r")
then
if Char.isDigit(String.sub(s,1))
then case Int.fromString(Char.toString(String.sub(s,1)))
of SOME n => if (n<1) orelse (n>2)
then regError(n)
else REG n
| NONE => lexicalError ("Bad register token "^s)
else lexicalError("Bad register token "^s)
else
if (String.sub(s,0) = #"l")
then
if Char.isDigit(String.sub(s,1))
then case (Int.fromString(Char.toString(String.sub(s,1))))
of SOME n => if (n<1) orelse (n>4)
then memError(n)
else LOC n
| NONE => lexicalError ("Bad token "^s)
else lexicalError("Bad memory location token "^s)
else lexicalError("Bad memory location or register token "^s)
else
case s
of "vput" => VPUT
| "put" => PUT
| "add" => ADD
| "mul" => MUL
| "sub" => SUB
| "lput" => LPUT
| "wri" => WRI
| _ => lexicalError ("Bad token "^s)
fun getStrings(infile: TextIO.instream) : string list =
String.tokens Char.isSpace (TextIO.input infile)
(***********************************************)
(* Local state for tracking execution progress *)
(***********************************************)
val sourceFile : TextIO.instream = prog.sourceFile;
val resultFile : TextIO.outstream = prog.resultFile;
structure virtmach : VIRTMACH = makeVirtualMachine(val outfile = resultFile);
(*======================CODE YOU MUST WRITE=====================*)
val tokencoding : token list ref
(* set this equal to a reference to the result of mapping
token over the result of getStrings applied to sourceFile
and handle exceptions here *)
(*****************************************************)
(* Provide int ref's for *)
(* *)
(* reg1, reg2, mem1, mem2, mem3, and mem4 *)
(* *)
(* and initialize them to reference values of zero *)
(*****************************************************)
fun setState : state -> unit
(* newstate -> reference variables for state updated *)
fun getState : unit -> state
(* no arguments -> current state tuple *)
fun execute : int -> unit
(* number of instructions to process -> output of state at each instruction to file *)
(* and update of state and remaining token list *)
(*==============================================================*)
end
(******************************************************************)