As mentioned earlier, 無PC is interpreted. To be more precise the 無PC interpreter compiles 無PC source into byte-code. Byte-code can be compared to machine language, which the 無PC interpreter will later execute. For instance, our simple "Hello world" program would roughly compile to the following bytecode:
mark push "Hello world\n" write
For now we don't have to know how these instructions are stored, instead we will concentrate at what these instructions do. But first we have to know about the two stacks that 無PC uses. One is a stack of values each can hold an 無PC value of any type. You could say that it is an mixed * to use 無PC terminology. This stack hold local variables, function arguments and much more. This stack will be refered to as the value stack so not to confuse it with the marker stack. The marker stack can only hold pointers to elements in the first stack and is used to remember the start of an argument list.
What mark does is that it pushes the number of elements on the value stack onto the marker stack. Then push will push the string "Hello world\n" onto the value stack. Then write will take the top value from the marker stack and the differance between this value and the number of values on the value stack will tell write how many arguments it has received. Write will then write the string to stdout and remove all it's arguments from the stack.
All functions in 無PC receives their arguments on the stack like this, builtin and user-defined.
struct svalue { short type; short subtype; union anything; };
The type is a number representing the type, defines like T_ARRAY or T_STRING are made to specify which type has which number. The subtype field is not used by most types and can be ignored for now. The 'union anything' is a union that can contain a float, integer or a pointer to a struct containing additional data.
... (To be continued)