Basic stack operators: Op Description Example ------------------------------------------------------------------------------ pop Remove top element 1 2 3 pop --> 1 2 dup Duplicate top element 1 2 dup --> 1 2 2 exch Exchange top two elements 1 2 exch --> 2 1 index Duplicate element 4 5 6 7 2 index --> 4 5 6 7 5 replace Replace element 4 5 6 7 10 2 replace --> 4 10 6 7 insert Insert element 4 5 6 7 2 insert --> 4 7 5 6 extract Extract element 4 5 6 7 2 extract --> 4 6 7 5 mark Push marker [1] 1 2 mark 3 4 --> 1 2 | 3 4 reset Remove up to/including marker 1 2 | 3 4 reset --> 1 2 dist Byte distance to last marker 1 2 | 3 4 dist --> 1 2 | 3 4 16 Memory buffers and strings: Op Description Example/syntax ------------------------------------------------------------------------------ alloca Allocate memory on stack [2] 1 2 16 alloca --> 1 2 ... store Store to memory store load Load from memory load --> src Push ld source pointer src --> dest Push st destination pointer dest --> setsrc Set ld source pointer setsrc setdest Set st destination pointer setdest ldb Load byte from source ldb --> ldw Load word from source ldw --> ldd Load double-word from source ldd --> ldq Load quadword from source ldq --> mv[bwdq] Copy from source to dest mvb st[bwdq] Store to destination 42 stb strcmp Compare n bytes src with dest 6 strcmp --> true/false strlen Push length of string [3] "abcdef" strlen --> 6 search Search src for byte value [4] search rsearch "search" with reversed args rsearch Integer arithmetic, boolean logic, comparisons, and bit shifting: Op Description Example/syntax ------------------------------------------------------------------------------ + Add two integers 1 2 + --> 3 - Subtract two integers 3 2 - --> 1 * Multiply two integers 3 2 * --> 6 / Divide two integers 30 8 / --> 3 % Remainder of division 30 8 % --> 6 qr Quotient and remainder 30 8 qr --> 3 6 rq Remainder and quotient 30 8 rq --> 6 3 & Bitwise/logical AND 0xdeffef 0xe1fffe & --> 0xc0ffee | Bitwise/logical OR 0x402468 0x80db86 & --> 0xc0ffee ^ Bitwise/logical XOR 0xc0ffee 0x110 ^ --> 0xc0fefe ~ Bitwise/logical NOT 0 ~ --> -1 true Pushes -1 (true) true --> -1 false Pushes 0 (false) false --> 0 << Shift left 4 3 << --> 32 >> Shift right 128 4 >> --> 8 >>> Arithmetic shift right [5] 32 neg 2 >>> --> -8 < Less than 1 1 < --> 0 <= Less than or equal 1 1 <= --> -1 == Equal 1 1 == --> -1 != Not equal 1 1 != --> 0 >= Greater than or equal 1 1 >= --> -1 > Greater than 1 1 > --> 0 Procedures and control: Op Description Example/syntax ------------------------------------------------------------------------------ : Define named procedure : mul3add1 { 3 * 1 + } { ... } Create anonymous procedure { 3 * 1 + } --> @ Push named proc reference [6] @mul3add1 --> call Call procedure by address 3 @mul3add1 call --> 10 return Exit procedure immediately : mul3 { 3 * return 1 + } if Call procedure conditionally 2 1 1 == {1 +} if --> 3 ifelse Call 1 of 2 procedures 2 1 2 == {1 +} {2 +} ifelse --> 4 while Repeat until false [7] 1 2 3 4 {3 !=} while --> 1 2 repeat Repeat proc n times 1 2 3 4 {+} 3 repeat --> 10 foreach Pop n, call proc for each [8] 1 2 4 8 {+ exch} 2 foreach --> 9 6 Notes ----- [1] Don't move markers around on the stack -- markers are implemented as frame pointers; rbp points to the last marked location, and the value of a marker value is simply the previous rbp value. This makes it very fast but means that moving them around (e.g. by using insert/extract) will break them. The main reason they were implemented like this isn't because of speed, but because the language has no types (so markers cannot be distinguished by looking at them). [2] Best combined with a marker so it can be easily deallocated using "reset" later; also, allocating an amount that's not a multiple of the machine's native word size may misalign the stack and hurt performance. [3] String should be null-terminated; string literals are. [4] This is a basic wrapper around an intel "repne scasb" instruction; the argument is the maximum distance to search, is the byte value to look for. No result is pushed onto the stack, only the "src" pointer is advanced. [5] Parsing of literal negative integers is not (yet) implemented, so instead of "-123" you have to write "123 neg" or "0 123 -". [6] Primitive operations can _not_ be referenced this way. Wrap them instead, e.g. {exch}. [7] Always runs the procedure at least once (like do-while). After each call, the topmost element on the stack is popped and used as the condition to check. The loop terminates once the condition is false (zero). [8] Detailed explanation: "proc n foreach" first pops n elements from the stack. Then, for each element that was popped, starting from the one that was furthest down the stack, it pushes that element back onto the stack and calls proc. Similar to array "forall" in PostScript, but without the array. This is what happens in the example: Stack Operation ------------------------------ --------------------------------- 1 2 4 8 {+ exch} 2 foreach invoked 1 2 pop n, proc, and n=2 elements 1 2 4 push 4 (first element) 6 1 {+ exch} 6 1 8 push 8 (second element) 9 6 {+ exch}