And I don’t mean graphical windows.
I’ll admit it, I’m only passingly familiar with the Sierra PMachine’s internal workings. I know much more about the SC script code than the PMachine bytecode it compiles to. Specifically, I know it’s a stack machine with a single accumulator and that literally everything is a 16-bit value but while researching that thing from last time I finally figured out how sends work.
Let’s go through some examples of various things you might do in SCI code.
Let’s say we have a local variable that we want to set to a particular value:
(= aLocal 42). Simple enough, right? That translates to
sal aLocal. Well, technically the disassembler has no notion of what the local variables are named so that’d actually come out as
sal local0 or whatever our local’s place in the list is but the instructions are clear: set the accumulator to a value, then store the accumulator in a local variable. A global variable is much the same but would use
Here’s a slightly more complicated one:
(if aLocal (Printf "lol") )
_: lal aLocal bnt notTrue push1 lofss strLol calle 921 1 2 //Printf, script 921 export 1. notTrue: //rest of the script
See what’s going on there? First we use
lal to load a local var’s value to the accumulator. Branch to another spot if that value is not truthy (non-zero), skipping over the
Printf. Then we first push the amount of arguments given (just the one), and load the offset of our string to the stack. Then we call an external function by number. With one 16-bit argument on the stack taking two bytes, we look back that far plus another two to reach the 1, which is our argument count, so that
Printf can later tell how many arguments it was given. Likewise,
(Printf "lol" 42) would become
_: push2 lofss strLol pushi 42 calle 921 1 4
We pass a frame size, as they’re called, of four, so we look back that many bytes plus two in the stack, passing an argc of two, a pointer to our string, and the number 42 to
How about a little trickery?
(Printf "lol" (+ aLocal 1)) perhaps?
_: push2 lofss strLol lsl aLocal ldi 1 add push calle 921 1 4
So first we load a local to the stack, not the accumulator, then load the immediate value 1 to the accumulator (there is no accumulator version of
push1 after all). The
add command takes the value on top of the stack and adds it to the accumulator, leaving the result in the accumulator. Then
push takes the accumulator and puts it on the stack, thus giving a stack of two arguments, the offset to “lol”, and the value of
aLocal plus one. We look back four bytes, plus another two, and we know what to tell
And that’s how Kawa learned what a frame size actually is.