In which we refactor compiled words again
It’s probably come to your attention that I now have a file called MyForth+Primitives.swift that contains two enormous switch statements. Frankly, I think these need to go away. The easiest way – well, the easiest I’ve thought of – would be make CompiledWord
map to Int
with a raw value and to create WordList
entries for the primitives. That way, I can eliminate all of the switches eventually.
Well, baby steps: first, we’ll create the WordList
and dictionary entries based on the existing token
property. We do this when we initialise the Forth machine. We use one function: createPrimitive
to build both the word lists for the primitives and the initial dictionary.
The code for this is tagged blog-1163-1. Note that, I’m doing this on a branch because it is a big change.
This change, together with some simplifications made possible by it gives us a run time for the fibonacci test as follows:
Time of run: 3.690076811s, words executed: 4778203, mips: 1.2948790078722294
["121393"]
The simplifications are that the compileOnly
and immediate
flags are stored in the WordList
for both defined words and primitive words. I also eliminated branch?
which is just a synonym for 0<>branch?
.
There is one final simplification which is to get rid of the nasty switch that gets the compile word descriptions. The descriptions of compiled words need to come from the WordList
, so I created a new function in MyForth
and get rid of the conformance to CustomStringConvertible
.
func descrition(of compiledWord: CompiledWord) -> String
{
wordLists[compiledWord.token].name
}
The above replaces a 150 line switch
. I’ve also removed the conformances to CustomStringConvertible
for CompiledWord
and for WordList
. This gives me another slight performance bump:
Time of run: 3.517964204s, words executed: 4778203, mips: 1.3582295677048337
["121393"]
The code is tagged blog-1163-2.
Following the changes detailed above, there are four CompiledWord
cases that have associated values:
case parsedLiteral(Int)
case undefined(Word)
case redefined(Word)
case definition(Cell)
We need to eliminate these, because ultimately, we want CompiledWord
to have raw values, which, I hope, will provide us with another performance boost. The .definition
case can be done away with by introducing a new primitive called .jsr
. This will work very much like .pushNext
and then we can pass the cell (which is the word list number to call) as a .parsedLiteral
.
One thought on “My Forth Rethink on Execution Tokens”