(********************************************************************) (* 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 (******************************************************************)