Article 19T7G Windy cave

Windy cave

by
ericlippert
from Fabulous adventures in coding on (#19T7G)

This is a tiny cave with entrances west and north, and a dark, forbidding staircase leading down.

> wait

Time passes"
A gust of wind blows out your candles!

> go down

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

Last time we saw how to find the default values for locals in a routine activation. Now let's actually create the local variable store.

The operations we need to perform on a local store (so far) are (1) initialize all the locals to their default values, (2) read a local, and (3) write a local. Of course the first and third operations return a new local store; a local store is immutable, like all the data structures in this purely functional interpreter will be.

The store maps integer local numbers - from 1 to 15 - onto unsigned word values. Our old friend the integer map seems like a good candidate.

For reasons which will become clear later, we also need to keep track of two numbers. First, how many locals are there? And second, a routine call causes the arguments of the call to be copied to the locals of the newly-activated routine; we will later need to know how many arguments were provided vs how many locals there were.

type t ={ locals : int IntMap.t; count : int; arguments_supplied : int;}

I like to have an empty object for cases where it makes sense.

let empty = { locals = IntMap.empty; count = 0; arguments_supplied = 0 }

Reading is straightforward. When writing we ensure that we have an unsigned value. (In an earlier version of my interpreter I was accidentally writing negative numbers as local values and things got very messed up!)

let read_local local_store (Local local) = IntMap.find local local_store.localslet write_local local_store (Local local) value = let value = unsigned_word value in let locals = IntMap.add local value local_store.locals in { local_store with locals }

Here's where we deal with creating a new local store given a routine.

let add local_store (Local n) default_value = let locals = IntMap.add n default_value local_store.locals in let count = max local_store.count n in { local_store with locals; count }let create_default_locals story routine_address = let count = Routine.locals_count story routine_address in let rec aux acc i = if i > count then acc else let default_value = Routine.local_default_value story routine_address i in let new_store = add acc (Local i) default_value in aux new_store (i + 1) inaux empty 1

And finally I like to have a helper method for displaying my work:

let display local_store = let to_string local value = Printf.sprintf "local%01x=%04x " (local - 1) value in let folder local value acc = acc ^ (to_string local value) in let locals = local_store.locals in IntMap.fold folder locals ""

Note the use of IntMap.fold, which is the logical equivalent of List.fold_left.

Now we can pick a routine address and create a local store with the default values:

let () = let story = Story.load "minizork.z3" in let locals = Local_store.create_default_locals story (Routine 0x3b36) in let text = Local_store.display locals in Printf.printf "%s\n" text

which outputs

local0=0000 local1=0000 local2=0000

All right, maybe not very interesting there, and now we see why in version 5 they simply initialized every local to zero. The majority of the time that's how it goes.

We said that interpreter state is a stack of frames, each frame consists of a local store and an evaluation stack. We've got the store. Next time on FAIC: we'll implement the evaluation stack. It'll be pretty straightforward.


4187 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