While machine language consists of instructions for the microprocessor in your computer, p-code consists of instructions for an imaginary processor that is simulated by the run-time interpreter. This imaginary processor is known as a “stack machine,” because it uses a stack for almost all of its operations. In contrast, the microprocessor in your computer uses its registers for most operations, and uses its stack primarily for function calls.
The stack holds the operands used by the instructions. In assembly language, you usually specify a source and a destination for each instruction, indicating where the operands reside and where to place any result. For example:
ADD AX, BX
With a stack machine, you usually don't need to specify a source or a destination. Each instruction pops its operands off the stack and pushes its result back onto the stack. For example, the p-code instruction
AddW
implies the following operations (using C-style pseudocode):
w2 = pop(); // get first operand from stack
w1 = pop(); // get second operand from stack
push(w1 + w2); // place result on stack
Omitting the source and destination saves space and helps make p-code as compact as it is. Some p-code instructions do specify a source and destination if they are modifying the value of variables, which are not stored on the stack. However, most instructions use the stack for at least one of their arguments.
The stack can store items of different data types, including bytes, words, and longs. However, floating-point types (float, double, and long double) are stored on a separate stack, called the “coprocessor stack.”
The stack replaces the need for the general purpose registers AX through DX. However, the DS, SS, CS, IP, SP, and BP registers can still be accessed by the stack machine.
In addition, there are two pseudoregisters, available only in p-code:
The PQ register, used during “quoting” (see “Reducing Duplicate Code with Quoting” on this page)
The temporary register, whose high and low words are accessible as TH and TL, respectively