Article 1ABV1 Hades

Hades

by
ericlippert
from Fabulous adventures in coding on (#1ABV1)

You have entered the Land of the Living Dead. Thousands of lost souls can be heard weeping and moaning. In a corner are the remains of previous adventurers less fortunate than yourself. A passage exits to the north.
Lying in one corner is a beautifully carved crystal skull. It appears to be grinning at you rather nastily.

> blow out the candles then drop the bell and the book

The flame is extinguished.
brass bell: Dropped.
black book: Dropped.

> take the skull

Taken.

> go north
> go up
> go west

Code for this episode can be found in https://github.com/ericlippert/flathead/tree/blog12.

A stack frame is just a thin wrapper around a local store and an evaluation stack. A frame is created when a routine is called, so we'll also need to know what instruction the return must branch to when the current call returns. Also, since a call instruction may have a store, it will be convenient to record here what is going to happen with the returned value; we will make a copy of the store from the call and keep it in the frame.

Note that the store is optional. In version 3 every call has a store, but that is not true in later versions.

type t ={ stack : Evaluation_stack.t; local_store : Local_store.t; resume_at : instruction_address; store : variable_location option}let resume_at frame = frame.resume_atlet store frame = frame.storelet peek_stack frame = Evaluation_stack.peek frame.stacklet pop_stack frame = { frame with stack = Evaluation_stack.pop frame.stack }let push_stack frame value = { frame with stack = Evaluation_stack.push frame.stack value }let write_local frame local value = { frame with local_store = Local_store.write_local frame.local_store local value }let read_local frame local = Local_store.read_local frame.local_store locallet display frame = let (Instruction resume_at) = frame.resume_at in let locals = Local_store.display frame.local_store in let stack = Evaluation_stack.display frame.stack in Printf.sprintf "Locals %s\nStack %s\nResume at:%04x\n" locals stack resume_at

A set of frames is logically a stack. When I first wrote this I just made it a list, but then I realized that it ought to be impossible for the bottom-most frame on the frame set to ever be popped off, because the main routine never returns in the Z-machine. I therefore made it the initial frame, for the main routine, followed by a list of subsequent frames. This reduced the set of weird failure cases I had to handle to one: trying to remove the initial frame.

Notice how all the setters create a new frame, and then create a new frameset with the new frame on top. Again, this is a purely functional data structure; everything is immutable.

type t ={ initial_frame : Frame.t; frames : Frame.t list}let make initial_frame = { initial_frame ; frames = []}let current_frame frameset = match frameset.frames with | [] -> frameset.initial_frame | h :: _ -> hlet set_current_frame frameset frame = match frameset.frames with | [] -> { frameset with initial_frame = frame } | _ :: t -> { frameset with frames = frame :: t }let add_frame frameset frame = { frameset with frames = frame :: frameset.frames }let remove_frame frameset = match frameset.frames with | [] -> failwith "Attempting to remove initial frame" | _ :: t -> { frameset with frames = t }let peek_stack frameset = Frame.peek_stack (current_frame frameset)let pop_stack frameset = set_current_frame frameset (Frame.pop_stack (current_frame frameset))let push_stack frameset value = set_current_frame frameset (Frame.push_stack (current_frame frameset) value)let read_local frameset local = Frame.read_local (current_frame frameset) locallet write_local frameset local value = set_current_frame frameset (Frame.write_local (current_frame frameset) local value)let display frameset = (accumulate_strings Frame.display frameset.frames) ^ (Frame.display frameset.initial_frame) 

Taking inventory: today we can read and write story memory, decode the dictionary, decode the object tree topology, decode any instruction, decode routines, fill in local variable default values, and we have data structures for all the interpreter state.

Next time on FAIC: At long last, let's finally start on an interpreter!


4205 b.gif?host=ericlippert.com&blog=67759120
External Content
Source RSS or Atom Feed
Feed Location http://ericlippert.com/feed
Feed Title Fabulous adventures in coding
Feed Link https://ericlippert.com/
Reply 0 comments