Be More Forthright

In which I call for immediacy

Implement a way to compile immediate words.

As far as I can tell, immediate words are words that are executed immediately, even in compile mode. An example of this is the ; that ends a word definition.

There are two things needed:

  1. tell if a compiled word is immediate so we can execute it even when compiling
  2. mark a word definition as immediate when it is defined

The implementation was quite straightforward. I added a boolean property to CompiledWord called isImmediate. For the built in words, this property is hard coded – in any case, it’s false for all of them except .endCompile. For defined words, the value is delegated to the associated WordList which has a mutable property of the same name.

Implementation of immediate then becomes simple. It just sets the property on the last compiled definition.

There was one wrinkle. I found that embedding a defined immediate word within a definition e.g.

: imm 5 . ; immediate
: foo imm 3 ;

didn’t work. The above snippet is meant to print 5, but it didn’t. Instead, things got weird and confused. The reason turned out to be that the when imm was called in the middle of the definition of foo, the Forth machine was still in compile mode. This meant that 5 and . were jut added to the definition of foo. The answer was to amend the code for executing a definition as follows:

case .definition(let words):
	// Flush our cached stack top back to the stack
	if let st = stackTop.pop()
	let savedState = state.state
	guard state.transition(to: .interpreting)
		else { fatalError("Failed to transition: \(savedState) -> \(State.interpreting)") }
	try interpret(words: words, output: &output)
	let returnedState = state.state
	guard state.transition(to: savedState)
		else { throw Error.invalidReturnState("\(returnedState)") }

What does it do? Well, first it flushes the stack top back to the data stack. Then it saves the current machine state and transitions to .interpreting. The first guard is unnecessary, actually, because we can only be in the .compiling or .interpreting state when we hit this piece of code. Then it interprets the words of the definition and on return, it restores the old state.

To make it work, I had to modify my state machine to make it legal to transition from .interpreting directly to .compiling and also to .interpreting.

The code is tagged blog-1045-1

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.