Files
plib/doc/psl/impl_guide.html

464 lines
12 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="keywords" content="PSL, PLIB, OpenGL, portable, script, language, Baker, Steve">
<meta name="description" content="The PLIB Scripting Language (PSL) Library is a lightweight scripting language that is well suited for games or other interactive programs.">
<title>The PLIB Scripting Language: Implementation Guide.</title>
</head>
<body text="#B5A642" bgcolor="#005000" link="#8FFF8F" vlink="#18A515" alink="#20336B" background="../marble.png">
&nbsp;
<table>
<tr>
<td>
<center>
<h1>The PSL Implementation Guide.</h1></center>
<center>By Steve Baker</center>
</td>
</tr>
</table>
<H1>Introduction</H1>
This document describes the virtual machine that the PSL byte code
interpreter implements.
<p>
The machine has 65536 bytes of instruction memory (and hence, 16 bit
code addresses) and 256 variables (and hence 8 bit data addresses).
Each variable can be a 32 bit integer, an IEEE single precision float
or a character string of arbitary length.
<p>
In addition, there is a 256 element stack - each entry of which can
contain any PSL data type.
<p>
The machine has just two registers - the Program Counter (PC) and
the Stack Pointer (SP) - neither of which are accessible to running
programs directly.
<H1>The Instruction Set</H1>
Each instruction consists of a one byte opcode and some number of
bytes of data.
<p>
The hex numbers for these opcodes are listed in plib/src/psl/pslOpcodes.h
<p>
<H3> OPCODE_BAD </H3>
INTRUCTION BYTES: 1<br>
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Produces a 'Suspicious Opcode' error message and halts the program.<br>
Generally, programs
that run amok for some reason (eg an error in the compiler) will
hit a zero byte fairly soon afterwards. Hence instruction 0x00
is reserved to be the BAD instruction. Other unrecognised
instructions are also flagged as errors - but it's useful to
explicitly reserve opcode 0x00 for this function due to the
high probability of it being executed by broken programs.</td>
</tr>
</table>
<H3> OPCODE_LINE_NUMBER </H3>
INTRUCTION BYTES: 3
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Updates the 'current line number' from the two bytes
embedded in the instruction.</td>
</tr>
</table>
<H3> OPCODE_PUSH_INT_CONSTANT </H3>
INTRUCTION BYTES: 5
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Takes four bytes from the instruction and pushes them
onto the stack as an integer.</td>
</tr>
</table>
<H3> OPCODE_PUSH_FLOAT_CONSTANT </H3>
INTRUCTION BYTES: 5
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Takes four bytes from the instruction and pushes them
onto the stack as a float.</td>
</tr>
</table>
<H3> OPCODE_PUSH_STRING_CONSTANT </H3>
INTRUCTION BYTES: 1 + strlen string + 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Takes a null-terminated string from the instruction
stream and pushes it onto the stack.</td>
</tr>
</table>
<H3> OPCODE_GET_PARAMETER </H3>
INTRUCTION BYTES: 3
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Fetches the value of a function's parameter from the
depths of the stack and puts it into a local variable.
<p>
The second byte of the instruction is the
index of the variable. The third byte is a small
integer offset - which is the number of the parameter
you want.
<p>
Look at the number two down from the top of the stack
(which should be
the number of parameters of a recently called
function).
<p>
Now copy the stack element at
<code> sp - ( nargs + 2 ) + offset </code>
into the variable.</td>
</tr>
</table>
<H3> OPCODE_POP </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Throws away the top element of the stack.</td>
</tr>
</table>
<H3> OPCODE_CALLEXT </H3>
INTRUCTION BYTES: 3
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The second byte of the instruction is the index of
a PSL 'extension function', the third
is the number of arguments being passed to it.
<p>
Pop that number of values off the stack and pass them
to the extension function.
<p>
Call the extension function.
Push the result onto the stack.</td>
</tr>
</table>
<H3> OPCODE_CALL </H3>
INTRUCTION BYTES: 6
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> [The number of aguments will already have been pushed
onto the stack.]
<p>
The four bytes after the instruction is the function address.
The fifth byte is the number of arguments.
<p>
Push return address.<br>
PC = address of function.
<p>
popNumber ( &amp;result ) ;<br>
&nbsp;&nbsp;&nbsp;pc = popInt () ;<br>
&nbsp;&nbsp;&nbsp;nargs = popInt () ;<br>
&nbsp;&nbsp;&nbsp;popVoid ( nargs ) ;<br>
pushNumber ( &amp;result ) ;</td>
</tr>
</table>
<H3> OPCODE_STACK_DUPLICATE </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Duplicate the top element of the stack.</td>
</tr>
</table>
<H3> OPCODE_EXCHANGE </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Exchange the top two elements of the stack.</td>
</tr>
</table>
<H3> OPCODE_LESS </H3>
<H3> OPCODE_LESSEQUAL </H3>
<H3> OPCODE_GREATER </H3>
<H3> OPCODE_GREATEREQUAL </H3>
<H3> OPCODE_NOTEQUAL </H3>
<H3> OPCODE_EQUAL </H3>
<H3> OPCODE_ADD </H3>
<H3> OPCODE_SUB </H3>
<H3> OPCODE_SHIFTLEFT </H3>
<H3> OPCODE_SHIFTRIGHT </H3>
<H3> OPCODE_OROR </H3>
<H3> OPCODE_ANDAND </H3>
<H3> OPCODE_OR </H3>
<H3> OPCODE_AND </H3>
<H3> OPCODE_XOR </H3>
<H3> OPCODE_DIV </H3>
<H3> OPCODE_MOD </H3>
<H3> OPCODE_MULT </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Pop the top element from the stack and operate on it
and the next element down - leaving the result on
the stack in it's place. So (for example) if the
operation was 'SUB' (Subtract), and A is on top of
the stack and B is beneath it - then the result of
this operation would be to leave (B-A) on the stack
with no sign of either A or B.
<p>
The 'ADD' operator also works with strings by concatenating
them.</td>
</tr>
</table>
<H3> OPCODE_NOT </H3>
<H3> OPCODE_TWIDDLE </H3>
<H3> OPCODE_NEG </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Perform the C unary '!', '~' or '-' operator on the top
element of the stack.</td>
</tr>
</table>
<H3> OPCODE_PAUSE </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Informs application program that the script wishes
to be paused until next frame.</td>
</tr>
</table>
<H3> OPCODE_HALT </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Informs the application that the script wishes to halt.
Even if the application ignores this request, the script
will continue looping at this location for ever.</td>
</tr>
</table>
<H3> OPCODE_PEEK_JUMP_TRUE </H3>
<H3> OPCODE_PEEK_JUMP_FALSE </H3>
INTRUCTION BYTES: 3
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The two bytes at the end of the instruction contain
an address. Inspect the number off the top of the stack
(without popping it) - and branch to the specified
instruction if the value is TRUE (or FALSE as applicable).</td>
</tr>
</table>
<H3> OPCODE_JUMP_TRUE </H3>
<H3> OPCODE_JUMP_FALSE </H3>
INTRUCTION BYTES: 3
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The two bytes at the end of the instruction contain
an address. POP the number off the top of the stack
(without popping it) - and branch to the specified
instruction if the value is TRUE (or FALSE as applicable).</td>
</tr>
</table>
<H3> OPCODE_JUMP </H3>
INTRUCTION BYTES: 3
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The two bytes at the end of the instruction contain
an address. Jump to that address.</td>
</tr>
</table>
<H3> OPCODE_PUSH_VARIABLE </H3>
INTRUCTION BYTES: 2
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The second byte of the instruction is the index of
a variable. The value of that variable is pushed onto
the stack.</td>
</tr>
</table>
<H3> OPCODE_POP_ADD_VARIABLE </H3>
<H3> OPCODE_POP_SUB_VARIABLE </H3>
<H3> OPCODE_POP_MUL_VARIABLE </H3>
<H3> OPCODE_POP_MOD_VARIABLE </H3>
<H3> OPCODE_POP_DIV_VARIABLE </H3>
<H3> OPCODE_POP_AND_VARIABLE </H3>
<H3> OPCODE_POP_OR_VARIABLE </H3>
<H3> OPCODE_POP_XOR_VARIABLE </H3>
<H3> OPCODE_POP_SHL_VARIABLE </H3>
<H3> OPCODE_POP_SHR_VARIABLE </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Three things are on the stack when this function is called.<br>
The thing on top is the result of an expression evaluation.<br>
The thing beneath that is the index of a variable.<br>
The thing beneath that is the dimension of the variable.<br>
The value is added to/subtracted from/multiplied by/etc
the variable - and stored back into the variable.<br>
The new value of the variable is left on the stack.</td>
</tr>
</table>
<H3> OPCODE_POP_VARIABLE </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> Three things are on the stack when this function is called.<br>
The thing on top is the result of an expression evaluation.<br>
The thing beneath that is the index of a variable.<br>
The thing beneath that is the dimension of the variable.<br>
The value is stored into the variable.<br>
The new value of the variable is left on the stack.</td>
</tr>
</table>
<H3> OPCODE_SET_INT_ARRAY </H3>
<H3> OPCODE_SET_FLOAT_ARRAY </H3>
<H3> OPCODE_SET_STRING_ARRAY </H3>
INTRUCTION BYTES: 2
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The second byte of the instruction is the index of an array
variable.<br>
On the top of the stack is an integer.<br>
This instruction allocates that number of elements of storage to
the array.</td>
</tr>
</table>
<H3> OPCODE_SET_INT_VARIABLE </H3>
<H3> OPCODE_SET_FLOAT_VARIABLE </H3>
<H3> OPCODE_SET_STRING_VARIABLE </H3>
INTRUCTION BYTES: 2
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The second byte of the instruction is the index of a variable.<br>
That variable is created, set to the appropriate type and
initialised appropriately.</td>
</tr>
</table>
<H3> OPCODE_FETCH </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The index of a variable is on top of the stack.<br>
The thing beneath that is the dimension of the variable.<br>
Replace those with the value of that variable.</td>
</tr>
</table>
<H3> OPCODE_INCREMENT_FETCH </H3>
<H3> OPCODE_DECREMENT_FETCH </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The index of a variable is on top of the stack.<br>
The thing beneath that is the dimension of the variable.<br>
Replace those
with the value of that variable. Post-increment/decrement the
variable.</td>
</tr>
</table>
<H3> OPCODE_INCREMENT_LVALUE </H3>
<H3> OPCODE_DECREMENT_LVALUE </H3>
INTRUCTION BYTES: 1
<table>
<tr>
<td valign="top">
EFFECT:
</td>
<td> The index and dimension of a variable is on top of the stack.<br>
Increment/decrement the variable leaving the stack
contents undisturbed.</td>
</tr>
</table>
<hr>
<address>
<a href="http://www.sjbaker.org">Steve J. Baker.</a> &lt;<a href="mailto:sjbaker1@airmail.net">sjbaker1@airmail.net</a>&gt;</address>
</body>
</html>