After completing my interpreter construction tutorial, I could not help but wonder how my little toy would fare in the real world. That, and I came up with a more general way to implement words and control structures. MuScript is the result.
Some code examples:
"Hello, world" print cr (self-explanatory) (count from 1 to 10) 0 begin incr dup print cr end 10 times drop (the same with an explicit test) 1 begin dup 10 > then break dup . cr incr end repeat drop (Simple conditional statements) true false both? then begin 'Is too!' . cr end iftrue begin 'Is not!' . cr end iffalse 3 4 dup * swap dup * + sqrt . cr (calculate a hypotenuse) 3 4 begin dup * swap dup * + sqrt end run . cr (the same, with a block of code) 3 4 begin dup * swap dup * + sqrt end word eval . cr (the same, with an anonymous word) : hypot dup * swap dup * + sqrt ; 3 4 hypot . cr (the same, with a colon definition) x: 3 ! x: @ . cr (variables) hello: begin "Hello, world!" print cr end word ! hello: @ eval (runtime word definition and storing/calling) (Defining a select-case control structure. Note how 'case' works; it is effectively a macro.) : select run ; : case swap: @ then: @ iftrue: @ break: @ ; immediate begin false begin 'Case 1' . cr end case true begin 'Case 2' . cr end case 1 2 < begin "Shouldn't happen" . cr end case end select
I accepted a few limitations in order to maintain simplicity.
immediate only works after a word
definition, not inside it. And you can't have words starting with
a number (hence
incr instead of
parseFloat's overly generous behavior. Oh,
and because a new word doesn't exist until after the semicolon,
recursive calls must use the
@ eval idiom.
Also, for now the interpreter works by precompiling the whole script before running. A truly interactive mode is being planned.