Goku was a Forth like language first implemented on the 6502 Mircro processor and then ported to the 8086/88 family of Intel processors.
For source, see Goku source. These are a few small programs written in it:
Everything packaged together here: GokuLinux-132.tgz
+, -, *, / | basic 32bit arithmetik functions |
% | modulo function |
|, & | bit combination |
<<,>> | bit shift |
# | starts a comment to the end of the current line |
: | noop (no operation) used as seperator in 'module:symbol' |
<, <=, <>, =, >, >= | comparison functions |
! | store prefix |
@ | fetch prefix |
[,] | index operators (really: 'noop' and '+') |
and | logical and |
accept | get input from the console * (based on fgets() for 'stdin') |
atoi | translate an ascii number to binary |
atof | translate an ascii number to floating point (not implemented) |
break | break loop, flow directive (only compiled) |
call | call a function at an address |
catch | save execution address and CPU stack ptr |
callLib | call a function in a shared library * |
clear | clear the Goku data stack |
compare | compare strings |
close | close a file handle * (based on close()) |
compile | compile Goku source code |
concat | concat two strings |
continue | continue loop, flow directive (only compiled) |
copy | copy strings |
create | create a Goku word |
date | translates seconds since 1/1/1970 in to a date/time string |
dec | decrement value at address |
depth | get depth of data stack |
disp | display an integer number |
do | do loop flow directive (only compiled) |
drop | drop top of data stack |
dup | double top of data stack |
else | program flow directive (only compiled) |
emit | emit a character |
end | close a program flow (only compiled) |
eval | evaluate/interprete a Goku source string |
exit | exit the Goku interpreter |
fill | fill memory |
find | find a string in another string |
free | free memory |
getb, getc, getw getu, getl | get a char, byte, word long frorm address |
htoi | translate an ascii hex string to binary |
if | flow directive (only compiled) |
inc | increment value at address |
init | reinitialize Goku startup parameters |
itoa | translate a binary integer to ascii |
length | calculate length of string |
local | declare local variables |
loadLib | load a shared library * |
loadFunc | get function pointer froma shared library * |
lookup | lookup a Goku word in a dictionary |
malloc | allocate memory from the heap * (based on calloc(1, n)) |
max | find the maximum of two integers |
memcopy | copy memory |
min | find the minimum of two integers |
not | logical not |
or | logical or |
open | open a file * (based on open()) |
putb, putc, putw, putl | write a byte, char, word, long to an address |
quit | quit Goku |
recurse | reentry the current function (only compiled) |
read | read from a file * (based on read()) |
return | return from the current function (only compiled) |
sourcePtr | get the current source ptr from evaluator/interpreter |
seek | position in a file * (based on seek()) |
stack | get a value from the data stack |
sysvar | get address from system parameters |
system | execute a shell command |
swap | swap to values on the data stack |
then | flow directive (only compiled) |
time | return elapsed time in milli seconds |
token | get token from a string |
throw | jump to saved address restore CPU stack ptr |
type | type a string of one or more chars on the console |
updatePtr | update the Goku source ptr in the evaluator/interpreter |
while | flow directive (only compiled) |
write | write to a file * (based on write()) |
All five are frequently used when writing Goku programs. The source
for these words can be found in init.goku wich is automatically
loaded on startup from /usr/lib/goku/init.goku. This essential
file is also reprinted at the end of this manual.
array | character array memory pointer |
define | compile a Goku word |
module | declares a different name/module space |
record | declares a data structure |
variable | create a word as a variable |
Most of the examples are interactive, so they can be typed in to the Goku console command line and executed. In all examples the '>' sign is the Goku console prompt followed by the user input.
The functions 'disp', 'type' and 'showStack' are frequently used in
the examples to show the top number on the stack, to type the top string
on the stack or to show the whole stack contents. While 'disp' and 'type'
are Goku core words the function 'showStack' is defined in the file INIT.GOKU,
which is loaded by Goku automatically on startup.
Example:
> 3 4 + disp
7
Example:
> 10 3 % showStack
3 1
Example:
> 0x123456 0xFF00FF & disp
1179734
> 3 5 | disp
7
Example:
> 1 10 << disp
1024
> 16 1 >> disp
8
Example:
define double # double a number dup + disp; # duplicate on stack then add and display
Example:
> 10 3 < disp
0
> 10 3 > disp
1
> 3 4 <> disp
1
Example:
> variable x y; # declare variables
> 123 !x # store 123 in x
> @x disp # display contents of x
123
> 234 x putl # store 234 in x
> @x disp # display contents of x
234
> @x !y # store contents of x in y
> @y disp : fetch contents in y and display
123
Example:
> variable x y; # declare variables
> @x disp # display contents of x
0
> 123 !x # store 123 in x
> @x disp # display contents of x
123
> @x !y # store contents of x in y
> y getl disp # get contents of y and display
123
Example:
> array mem 100; # define a memory pointer to 100 bytes
> 123 mem[0] putb # store a byte at the first location
> 123 mem putb # same as previous
> 111 mem[1] putb # store a byte at the second location
> 111 mem 1 + putb # same as previous
> system[4] getl disp # display the size of the data stack in bytes
512
> system 4 + getl disp # same as previous
512
Example:
> 10 0 and disp
0
> 3 4 and disp
1
Example:
> accept
Hello there
> type
Hello there
Example:
> array myVector 10;The variable myVector contains now a memory address pointing to 4 bytes of allocated space. The new array variable can be indexed using [], the index operators. The new allocated memory area can be accessed using getb, gec, getw and getl for reading or putb, putw and pul for writing.
> myVector "HELLO" concat type hello > myVector[1] getb emit # show the value as a character E > myVector[0] getb disp # show ascii value of 'H' 72The first for bytes of 'myVector' will now contain the number 12345 in little endian order (lowest byte contains least significant part).
Note, that variables declared with
Seee also the other declarative compiling words 'define', 'variable'
and 'load'.
Example:
> "1234" atoi disp
1234
Example:
define breakTest # compile a new function 'breakTest' local last; # declare local variable !last # pop parameter into 'last' 10 while dup 0 > do dup disp "\n" type if dup @last = then drop break end # loop until 'last' 1 - end;
> 7 breakTest 10 9 8 7
>
Example:
define timeIt local start; # create local to save start time time !start # pop time into start variable call # call address on data stack time @start - disp; # calaculate time difference and display
> 40 @fibo timeIt # time the function 'fibo'The function timeIt will execute 'fibo' with an argument of 25 and display the time elapsed since it's start. On a Pentium 200Mhz a value of about 30 seconds will be displayed.
Example:
array jumpbuff 8;
define subProc nap jumpbuff throw;
define aProc jumpbuff catch "hello " type subProc;
> aProcThe example will continue to type "hello " in the console window.Select File/reset from the console window menu to stop. 'catch' and 'throw' are useful for error handling or other situations where the program has to jump to a previous higher calling level of execution without going through a chain of functions returns. In this case the routine doing the 'throw' could leave a value on the data stack which can be tested after the 'catch' (e.g. an error value).
Example:
define whichOne compare : compare the two strings on the stack if dup 0 = then "strings are equal" type return end if dup 0 > then "the second is comes first" type return end if dub 0 < then "the first comes first" type return end;
> "aWord" "bWord" whichOne
the first comes first
'compile' finishes when the string finishes (a '0' zero is encountered) or when compile finds a semicolon, which is not part of a 'local' statement. 'compile' automatically allocates space for the new compiled code using 'malloc'.
Example:
"define" 2 create # create a new word 'define' in the dictionary "sourcePtr token # this string conatins the source code drop 2 create # to be compiled for new word 'define' swap compile updatePtr # which is a compiling word by itself swap putl" # (see decription of 'define') compile drop # compile the function body for 'define' swap putl # put the code address into the 'define' word'compile' is mostly used to define other compiling words. The Goku words 'array', 'define' and 'variable' have all been created using 'compile' and another important Goku word in this context, named 'create'.
See the file INIT.GOKU for the source code for all of them. The example shows the creation of 'define' the most used Goku compiling word to compile new Goku user functions.
Example
> array dest 100; # allocate space for destination string > dest "this " concat > "is very " concat > "useful" concat type this is very useful >
Example:
define testContinue 10 while 1 - dup do if dup 5 > then "*\n" type continue end dup disp "\n" type end;
> testContinue
* * * * 5 4 3 2 1
>
Example:
array buff 20; buff "hi there" copy type Hi there >
Each word in a Goku dictionary has a type and a contents field. There
are three types which can be created by the user:
Type No | Description | Contents field |
0 | normal variable | integer/address |
1 | pointer variable | address of memory area |
2 | code | address of code |
Type 0 variables contain a 32bit integer normally reprensenting a number in their contents field. When executing a type 0 word the address of this contents field is put on the stack, (not the contents of it). Words created with 'variable' are of type 0.
Type 1 variables have an address of a memory area in their contents field. When executing a type 1 variable Goku puts the contents of the contents field on to the data stack, which is the address of a memory area. Words created with 'array' are of type 1.
Type 2 variables have an address of a executable piece of code in their contents field. When executing a type 2 variable Goku will execute the code found at that address. Type 2 vraibles are created using 'define'.
There are three other types used internaly: 3 for inline code, -1 for copiled words like 'break', 'if', while etc., and -2 to indicate the start of the core dictionary (used by 'lookup'). See the chapter 'Inside Goku' for a more detailed diskussion od these word types.
Example:
"define" 2 create # create a new word 'define' in the dictionary "sourcePtr token # this string conatins the source code drop 2 create # to be compiled for new word 'define' swap compile updatePtr # which is a compiling word by itself swap putl" # (see decription of 'define') compile drop # compile the function body for 'define' swap putl # put the code address into the 'define' word'create' is almost exclusevely used when creating compiling words such as 'define', 'variable' or 'array'. See the source of INIT.GOKU for more examples on how to use 'create'.
example:
> 0 date type
# executed in California USA, this is 0:00 AM in Greenwich UK 1/1/19970
Wed Dec 31 16:00:00 1969
> 0x7FFFFFFF date type # rollover date in California
USA
Mon Jan 18 19:14:17 2038
variable x; 123 !x x dec @x disp > 122
Example:
> 1 2 3 # push three number on data stack > depth disp # display depth 3 >
Example:
>123 disp 123 > variable myVar; # declare a variable > myVar disp # display the content address of myVar 13191542 > 12345 !myVar > @myVar disp # display contents of myVar 12345 > @type disp # display the address of the type routine
Example:
define doTest
while 1 - dup do dup disp end; > 10 test 987654321 >
Example:
Example:
> 1 dup + : push one duplicate it and add 2 >
Example:
define checkSize if 1000 > then "big" type else "small" type" end;
> 500 checkSize small > 2000 checkSize big >
Example:
> 65 emit A >
Note, that not all values between 0 and 255 are havae a sceen representation
depending on the character set used.
Example:
> "3 4 + disp" eval 7 >In this example 'eval' is actually used in a nested fashion, because the command line itself is already evaluated by eval. For each nesting level of 'eval' the current Goku source pointer is pushed on an internal stack and can be queried by 'sourcePtr' or updated by 'updatePtr' (see 'compile' and 'define' )
Example:
array buff 11; # create memory area > buff 'A' 10 fill # fill with A's > type AAAAAAAAAA >Not that the area in 'buff' is declared one byte longer then used during 'fill'. The last byte in buff, which will contain a 0 (zero) from 'malloc' stops 'type' from running into undefined memory.
>"you" "How are you today" find type you today >
> "X" "ABCDEFG" find disp -1 >
Example:
The variable 'memPtr' gets created to hold the address for the allocated memory. When the memory is not used anymore, it should be freed.> variable memPtr; # alocate variable > 1000 malloc !memPtr # allocate memory and store address in memPtr ...... > @memPtr free # retrieve address and free memory
Example:
The example shows the difference between 'getc' and 'getb'. While 'getb' interpretes the byte read as a signed 8bit integer, 'getc' returns an unsigned integer.> variable x; > 222 !x > x getb disp -34 > x getc disp 222 >
Note, that '!' used in the example works just like 'putl' but executes faster and is faster to write too. Note also, that when using 'getl' with a variable '@' is the better choice as a complement to '!' it executes faster.
Example:
> variable x; > 123 !x > x getl disp # slower 123 > @x disp # faster 123
Example:
> "FF" htoi disp 255 >
andif ... then ..end
The 'then' part pops the top of the data stack and checks it for zero (0). In case of 0, instructions after then are skipped and executuin continues after the 'end' of the 'else' part.if ... then ... else ... end
Example:
> define check if 10 < then "small" type end; > 5 check small > 20 check >
> define checkit if 10 < then "small" type else "big" type end; > 10 chekit big >
Example:
variable x; 123 !x x inc @x disp > 124
Example:
> array number 16; > 1234567 number itoa type 1234567 >
Example:
> "hello" length disp 5 > array aString 20; > aString "Goku" concat length disp 4 >
Example:
define account local balance; if dup "deposit" compare 0 = then drop @balance + !balance return end if "show" compare 0 = then @balance disp return end;
Locals in Goku are static variables which hold there values between invocations of the defined function. During compilation the values of locals are initialized to 0 (zero).> "show" account 0 > 123 "deposit" account > "show" account 123 > 100 "deposit" account > "show" account 223 >
'lookup' is mainly used internally by the Goku compiler when parsing source code and has no obvious usage in normal Goku source code.
See the chapter "Inside Goku" for a description of the format for a
word entry in a dictionary.
Example:
Often it is more paractical to reserve memory using special memory pointer variables using 'array'> variable memPtr; > 100 malloc !memPtr; # allocate 100 bytes and store the addres in memPtr > @memPtr 'Z' 20 fill type # fill the first 20 bytes with 'Z's and type ZZZZZZZZZZZZZZZZZZZZ
'array' creates a pointer variable, which places a memory pointer on the stack when evaluated. Array variables are also easily indexed using '[ ]'. (See array )> array memPtr 100; > memPtr 'Z' 20 fill type ZZZZZZZZZZZZZZZZZZZZ
Example:
> 3 7 max disp 7 >
Example:
> array buff 10; > "hello\0" buff 6 memcopy type
hello
>Note, that a trailing zero is supplied when copying to limit the 'type'.
Example:
> 3 7 min disp 3 >
Example:
> 123 not disp 0 > 0 not disp 1 >
example:
1 0 or disp 1 < 3 4 or disp 1 > 0 0 or disp 0 >
A value gets written to an address. The byte order for 'putw' and 'put' depends on the underlying hardware. If the value given takes up more bytes then they are to be written, the value gets truncated.
Example:
variable x;> 255 x putb > x getb disp -1 > x getc disp 255 > 0x12340000 x putw > x getw disp 0 >
Example:
define fibo dup if 3 < then drop 1 else dup 1 - recurse swap 2 - recurse + end;> 25 fibo disp 75025
The fibonacci algorithm 'fibo' is defined in the file 'std.goku'.
See examples for compile, create
and see definitions of variable, array and define in the file 'init.goku'
Example:
> 1 2 3 4 5 > 1 stack disp 5 > 2 stack disp 4 > 5 stack disp 1 >
Example:
This will show a directory listing on a UNIX system.> "ls -l" system
Note, that locations in the system area might change in different versions
of Goku.
Example:
> 10 20 showStack 10 20 > swap showStack 20 10 >
'showStack' is defined in the file 'std.goku'.
Example:
The system was started 72 minutes ago.> time 1000 / 60 / disp 72 >
description | value | example |
null token | 0 | end of source |
identifier token | 1 | var1, age, x, y10, phone_no |
string token | 2 | "hello world\n", "\41\42\43" |
floating point token | 3 | 1.234, 0.3, -5.95 |
integer token | 4 | 4765, -987 |
hexadecimal token | 5 | 0xFF00, 0x3c2d, 0xffffffff |
character token | 6 | 'a', 'B', 'C' |
Example:
'token' is mostly used in compiling words like define, variable or array to parse source code.> array source 20; > source "hello 123" copy > source token > disp 1 > type hello < type 123
Example:
> "hello" type hello >
while ... do ... end
The part between 'while' and 'do' contains code defining the condition under which the part between 'do' and 'end' should be executed. When Goku excutes 'do' it pops and checks the top of the stack. In case of a logical 'true' (any value not zero) the part between 'do' and 'end' gets executed. In case of a logical 'false' (zero) value, Goku skips the 'do' - 'end' part and continues execution after the 'end' part.
Example:
define loop local x; 10 !x while @x do @x disp "," type x dec end;> loop 10,9,8,7,6,5,4,3,2,1 >