Design overview

In this document, we will describe how 無PC works and why it was made that way. Examples in this chapgter will be in C because 無PC is written in C, so some knowledge of C syntax and semantics is required.

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.

The value stack

As mentioned the value stack is an array of elements that can hold any value. Each of these elements is a 'struct svalue' which looks like this:
	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)

The different types (draft)

Integers and Floats
Integers and Floats are stored directly in the union.
Strings
For string values, the union contains a pointer to a struct lpc_string, this struct is a part of a shared string table. That means that all equal strings actually point to the same struct. This makes string comparison very fast, but creating new strings somewhat slow.
Arrays
In an array value, the union contains a pointer to a struct array, which in it's turn contains a number of struct svalues.
Mappings
Mappings are structs which contains one pointer to an array of indices and one pointer to an array of values. These two arrays are sorted so that lookup can use a binary search algorithm for speed.
Lists
Lists works just like mappings, except there is no value array.
Objects
Objects are merely structs containing a pointer to the program for this object and any global variables needed this object needs.
Programs
Programs are pointers to a 'struct program'. This struct contains the byte-code and additional information needed by the interpreter.