Version 13 of A different FORTH

Updated 2002-12-11 21:40:06

I wrote this about a year ago and am prompted to post it now by JCW's Trying FORTH in Tcl -- JBR 12/11/2002

Here FORTH is not nearly as faithfully reproduced as JCW's. Missing are the ability to get at the input stream with token (word in FORTH?) and I have no return stack. But code is eval'ed as a list and it makes the inner interpreter very fast. unknown is used there to push values onto the stack.

After RS made his comment (below) about the code's brevity I actually looked at it in the light of what I have learned from RS and the rest of the active Wiki authors and I've given it the once over.

Now I'd say its brief. I'm still stumped about a way to make pop a one liner. - RS: Easy if you have the famous K combinator ;-):

 proc K {x y} {set x}
 proc pop {} {K [lindex $::S end] [set ::S [lrange $::S 0 end-1]]}

11dec02 jcw - Pesky types like me would say that this is still a two-liner. How about...

 proc pop {} {lindex [list $::S [set ::S [lrange $::S 0 end-1]]] end}

Untested code ... (cool stuff, btw!)


I knew that K would be the answer but I couldn't see that I should put the value I wanted to keep first. Code updated just so I can say that I've used the K (I'd never used end-1 eighter) Thanks -- JBR.

After jcw's comment (above), I deleted a little more code in the ":" proc and used a definition of pop similar to his, although now I might have to admit that I'm reaching for brevity at the expence of simplicity here.


 # Stack Primitives
 #
 proc T  { } { lindex $::S end   }                                    ;# Top value
 proc S  { } { lindex $::S end-1 }                                    ;# Second value

 # Stack Ops
 #
 proc psh { x } { lappend ::S $x }                                    ;# Push value stack
 proc pop { } { lindex [list [T] [set ::S [lrange $::S 0 end-1]]] 0 } ;# Pop  value stack

 proc ! { } { set ::[pop] [pop] }               ;# Set named reference top to value
 proc @ { } { psh [set ::[pop]] }               ;# Get named reference top

 proc .    { } { puts [pop] }                   ;# Print top
 proc drop { } { pop }                          ;# Drop  top

 proc unknown { args } { psh $args }            ;# Push anything thats not a proc (values)


 # Construct a set of useful binary operators
 #
 proc stkops { args } {
     foreach op $args {
         proc $op { }  "set ::S \[lreplace \$::S end-1 end \[expr \[T] $op \[S]]]"
     }
 }
 stkops  + - * / % | & ^ || == <= >=

 proc : { name list } { proc $name { } [join $list "\n"] }

 : Two    2
 : setX { X ! }
 : dotX { X @ . }

 : Test {
     Two 4 *
     45 +
     setX dotX
 }

 Test   ;# --> 53

RS: I really like this code for its brevity - and the unknown redirection ;-) My own attempts in that direction, also a little old, are at RPN in Tcl.