This commit is contained in:
Alexander Deynichenko
2013-02-25 07:23:44 +04:00
parent 35ff18a6a1
commit 03b62f3315
809 changed files with 211135 additions and 0 deletions

430
doc/psl/appl_guide.html Normal file
View File

@@ -0,0 +1,430 @@
<!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: Applications 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 Application Programmer's Guide.</h1></center>
<center>By Steve Baker</center>
</td>
</tr>
</table>
<H1>Introduction</H1>
This document is to help people writing C++ applications to include
scripting abilities using the PSL interpreter.
<p>
To include PSL scripts into your application requires that you:
<pre>
#include &lt;plib/psl.h&gt;
</pre>
...and link with '<code>-lplibpsl</code>'
<p>
Then, sometime before you call any other PSL functions, you must call:
<pre>
pslInit () ;
</pre>
Each PSL script is represented by an object of class <code>pslProgram</code>
<H1>Example Application</H1>
This is the simplest possible PSL application, it
loads a script called "test.psl", compiles and runs it.
<pre>
#include &lt;plib/psl.h&gt;
void main ()
{
pslInit () ;
pslExtension extensions [] = { { NULL, 0, NULL } } ;
pslProgram *prog = new pslProgram ( extensions, "Program1" ) ;
prog -&gt; compile ( "test.psl" ) ;
while ( prog -&gt; step () != PSL_PROGRAM_END ) /* Nothing */ ;
}
</pre>
Here is a line-by-line explanation:
<p>
<center>
<TABLE border="1">
<tr><td><code> pslInit () ;</code></td><td>
Initialise PSL - this must be the first thing you do.</td></tr>
<tr><td><code> pslExtension extensions [] ...</code></td><td>
Make a list of PSL extension functions.<br>
This program doesn't have any. </td></tr>
<tr><td><code> pslProgram *prog = new pslProgram...</code> </td><td>
Declare a program (called "MyProgram").</td></tr>
<tr><td><code> prog -&gt; compile ( "test.psl" ) ;</code></td><td>
Compile the program to bytecode.</td></tr>
<tr><td><code> while ( prog -&gt; step () != PSL_PROGRAM_END )...</code>
</td><td>
Tell the PSL program to execute one 'step'
<br>Keep doing that until we reach the end of the program.
</td></tr>
</TABLE>
</center>
<p>
Easy!
<p>
Now let's look at <code>class pslProgram</code> in more detail.
<H1><code>class pslProgram</code></H1>
Each PSL script is represented by an object of class <code>pslProgram</code>.
<pre>
class pslProgram
{
public:
pslProgram ( const pslExtension *extns, const char *name ) ;
pslProgram ( pslProgram *prog, const char *name ) ;
void setUserData ( void *data ) ;
void *getUserData () const ;
void setProgName ( const char *name ) ;
char *getProgName () const ;
void dump () const ;
void reset () ;
pslResult step () ;
pslResult trace () ;
int compile ( const char *memptr, const char *fname ) ;
int compile ( const char *fname ) ;
int compile ( FILE *fd ) ;
} ;
</pre>
<H1><code>pslProgram::pslProgram</code></H1>
There are two constructor functions to choose from. The first
takes an array of 'extension functions' and the name by which
this program will be known (for error messages and such). The
second constructor takes an existing, compiled PSL program and
makes a copy of it - it too needs a program name.
<p>
The second version of the constructor is especially efficient
because this enables the script to be compiled just once - and
run multiple times in parallel. The second and subsequent
copies of the program consume much less RAM than the first
copy because they share the 'code' part of the script.
<p>
For example, you can run two copies of a script in parallel
like this:
<pre>
pslInit () ;
pslProgram *prog_1 = new pslProgram ( extensions, "code1" ) ;
prog_1 -&gt; compile ( "data/test.psl" ) ;
pslProgram *prog_2 = new pslProgram ( prog_1, "code2" ) ;
while ( prog_1 -&gt; step () != PSL_PROGRAM_END &&
prog_2 -&gt; step () != PSL_PROGRAM_END )
/* NOTHING */ ;
</pre>
<H1><code>pslProgram::compile</code></H1>
When you compile a PSL program, any errors or warnings are reported
to stderr (by default) and the number of fatal compilation errors
is returned as the result of the 'compile' function. Programs may
choose to ignore any compilation errors - but executing the resulting
program will immediately produce a PSL_PROGRAM_END.
<p>
You can pass to the compiler either:
<ol>
<li> The filename of the file containing the PSL source code...or...
<li> A 'FILE *' descriptor for the file containing the PSL source...or...
<li> The address of a null terminated string containing the
program source PLUS a name to use for the program when reporting
errors, etc.
</ol>
If you pass the filename (1) or the address of the source with a name (3),
then error messages from PSL will refer to that name. But if you pass a
file destriptor then the program name that you passed to the constructor
function will be reported.
<p>
Applications that would like to report scripting errors in a more elegant
way, may register a callback function that will be called whenever there
is a problem within PSL:
<pre>
void pslSetErrorCallback ( void (*CB) ( pslProgram *, int, char *,
int, char * ) ) ;
</pre>
Your function will be called with five parameters:
<pre>
void myErrorCB ( pslProgram *prog, int severity,
char *progname, int lineno, char *message ) ) ;
</pre>
<ul>
<li> The 'prog' parameter is a pointer to the pslProgram that had the
problem.
<li> The 'severity' parameter is the error type and severity:
<ul>
<li> PSL_COMPILETIME_WARNING - A problem was found while
compiling the PSL program - but it may not be serious enough
to prevent it from running.
<li> PSL_COMPILETIME_ERROR - A serious problem was found while
compiling the PSL program - it won't run correctly.
<li> PSL_RUNTIME_WARNING - A problem was found while running
the PSL program - but it wasn't serious enough to prevent
the program from continuing to execute.
<li> PSL_RUNTIME_ERROR - The PSL program 'crashed' while being
executed.
</ul>
<li> The 'progname' parameter is the name of the program.
<li> The 'lineno' parameter is the line number at which the problem
occurred (if compiling) or the byte-code address at which it
failed (if at runtime). The latter isn't much use unless you
are a developer of the PSL interpreter.
<li> The 'message' parameter is the actual text of the error message.
</ul>
Notice that at compiletime, the 'progname' parameter is the name of the
file or string being compiled (if that's known to the compiler). Since it's
possible for one PSL source file to '#include' another, you should
always use the 'progName' parameter in your error messages in preference
to <code>prog-&gt;getProgName()</code> member function.
<H1><code>pslExtension</code></H1>
We have not yet talked about this mysterious 'extensions' array that's passed
into the pslProgram constructor function.
<p>
It's important that your PSL scripts are able to interact with your C++
program - and this is done by creating a number of C++ functions that
can be called by the PSL program as it executes. These are called
'extensions' because they extend the functionality of PSL.
<p>
The extension parameter to the pslProgram constructor is an array of
pslExtension structures:
<pre>
class pslExtension
{
public:
const char *symbol ;
int argc ;
pslValue (*func) ( int, pslValue *, pslProgram *p ) ;
} ;
</pre>
<ul>
<li>The 'symbol' field is the name of the extension function AS IT APPEARS INSIDE
PSL PROGRAMS. This doesn't have to be the same as the actual name of
your C++ function.
<li>The 'argc' field is the number of parameters the function expects. You can
set 'argc' to -1 to allow any number of parameters to be passed - so that you
can create functions that work like 'printf' does.
<li>The 'func' field is a pointer to your C++ function.
</ul>
The list of pslExtensions is terminated by a <code>{ NULL, 0, NULL}</code>
entry.
<p>
The C++ function has to look like this:
<pre>
pslValue my_func ( int argc, pslValue *argv, pslProgram *p )
</pre>
<ul>
<li>The 'argc' parameter to the C++ function is the number of
PSL parameters that were passed to it. It's useful to know this
number when your pslExtension had 'argc' set to -1.
<p>
<li>The 'argv' parameter is an array containing the parameters
that PSL is passing to this function. Each element is a 'pslValue'
class which could contain any of the PSL variable types.
<p>
<li>The 'p' parameter is a pointer to the pslProgram that was
running at the time this function was called. Notice that pslProgram's
can have user data associated with them - so this gives you quite a
bit of scope for accessing script-specific data structures.
<p>
<li>When your script has finished doing it's job, it has to return
some kind of result. This is another one of those 'pslValue'
class objects.
</ul>
<H3>Example Extension Function</H3>
This C++ function prints it's arguments to stdout and returns the
value 123.456.
<pre>
pslValue print ( int argc, pslValue *argv, pslProgram *p )
{
for ( int i = 0 ; i &lt; argc ; i++ )
{
switch ( argv[i].getType () )
{
case PSL_INT : printf ( "%d ", argv[i].getInt () ) ; break ;
case PSL_FLOAT : printf ( "%f ", argv[i].getFloat () ) ; break ;
case PSL_STRING : printf ( "%s ", argv[i].getString () ) ; break ;
case PSL_VOID : printf ( "(void) " ) ; break ;
default : printf ( "Illegal parameter passed to 'print'." ) ; break ;
}
}
pslValue ret ;
ret.set ( 123.456f ) ;
return ret ;
}
</pre>
Adding this to the example program above, requires only that you
change the declaration of 'extensions' as follows:
<pre>
pslExtension extensions [] =
{
{ "print", -1, print },
{ NULL, 0, NULL }
} ;
</pre>
Now, now you can write "Hello World" in PSL script:
<pre>
int main ()
{
print ( "Hello World.\n" ) ;
}
</pre>
...and your C++ function 'print' will be called with one parameter
that'll contain the string value "Hello World.\n".
<H3><code>pslValue</code></H3>
The 'pslValue' class is used to pass numbers into and out of extension
functions. It contains the type and value of a number or string in PSL
and it looks like this:
<pre>
class pslValue
{
public:
pslType getType () const ;
int getInt () const ;
float getFloat () const ;
char *getString () const ;
void set () ;
void set ( int v ) ;
void set ( float v ) ;
void set ( const char *v ) ;
void set ( const pslNumber *v ) ;
} ;
</pre>
Setting <b>nothing</b> into your pslValue ("my_value-&gt;set()") is used to
return a 'void' result from your extension function - that is the default
type for a pslValue.
<p>
The 'getType' call returns the type of this value - currently,
it can be: PSL_INT, PSL_FLOAT, PSL_STRING or PSL_VOID. If you 'set' the
pslValue, it automatically changes it's 'getType' result to match.
<p>
Doing a 'get' for a type that DOESN'T match the 'getType' of the pslValue
causes it to try to convert to that type. However, a 'getString' on a
non-string pslValue will return NULL. Doing a 'getInt' or 'getFloat'
on a PSL_STRING will perform an atoi() or atof() (respectively) in an
attempt to get a number from the string.
<H1>Running, Tracing, Debugging.</H1>
You run the PSL program one byte-code instruction at a time by calling the
<code>pslProgram::step()</code> function. A byte-code
instruction is rather like the 'machine code' of a physical computer and
it typically takes several byte-code instructions to implement each line
of PSL source code.
<p>
The 'step' function returns one of three possible results:
<ul>
<li> PSL_PROGRAM_CONTINUE -- The PSL program is running normally.
<li> PSL_PROGRAM_END -- The PSL program has finished running. This
could be because it simply ended normally - but it could also
be because it 'crashed' with a fatal runtime problem of some kind.
<li> PSL_PROGRAM_PAUSE -- There is a special 'pause' statement in PSL
and when that statement is executed, it causes 'step' to return
this value.
</ul>
The PSL_PROGRAM_PAUSE return is intended to cope with the specific
case when PSL is being used in an interactive graphical application.
Typically, such applications will not want to run PSL scripts to
completion every frame - but instead run them up to the next 'pause'
statement.
<p>
A typical game might have dozens of PSL scripts running in parallel
and wish to run each of them until the script 'pause's.
<p>
So, your application's main loop might look something like this:
<pre>
read_the_joystick () ;
for ( int i = 0 ; i &lt; num_scripts ; i++ )
while ( program [ i ] -&gt; step () == PSL_PROGRAM_CONTINUE )
/* Do Nothing */ ;
render_the_graphics () ;
swap_the_doublebuffer () ;
</pre>
Then, one of those scripts (to move a monster for example)
might look like this:
<pre>
int main ()
{
int i = getMyMonster () ;
while ( 1 )
{
moveMonster ( i ) ;
pause ;
}
}
</pre>
The 'pause' command indicates that this script has completed it's
work for this frame.
<p>
Alternatively, some applications may wish to run the scripts for
fixed amounts of time, fixed numbers of byte-codes - or until
some other criterion is satisfied.
<H3> Resetting a Script </H3>
There is a <code>pslProgram::reset()</code> function that
restarts the PSL program from the beginning having first
reset all of its internal variables.
<H3> Debugging PSL scripts </H3>
For debugging PSL scripts, you may replace the 'step' call with
'trace' - which causes the byte-code for each instruction to be
printed to stderr as it's executed.
<p>
You can also call <code>pslProgram::dump()</code> to print out
all of the byte-code and the PSL symbol table for the program.
<H3> Include paths. </H3>
By default, PSL searches for files with relative pathnames in
the current directory - but you can override this by setting:
<pre>
pslScriptPath ( "directory" ) ;
</pre>
<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>

463
doc/psl/impl_guide.html Normal file
View File

@@ -0,0 +1,463 @@
<!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>

55
doc/psl/index.html Normal file
View File

@@ -0,0 +1,55 @@
<!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.</title>
</head>
<body text="#B5A642" bgcolor="#005000" link="#8FFF8F" vlink="#18A515" alink="#20336B" background="../marble.png">
&nbsp;
<table>
<tr>
<td>
<center>
<h1>PSL: PLIB's Scripting Language.</h1></center>
<center>By Steve Baker</center>
</td>
</tr>
</table>
<H1>Introduction</H1>
Whilst applications can use any suitable scripting
language (Python, PERL, Lua, etc) in conjunction with PLIB, there are
attractions to using PLIB's own scripting language: PSL.
<p>
In particular, in using PSL, you do not add any dependancies on
your application. If the end user has the correct version of PLIB
installed - then the scripting language is already there - for sure.
<p>
PSL is a very light-weight C-like language with some features borrowed
from C++. It's also 'stackless' and very friendly to games applications.
<p>
There are two PSL documents:
<ul>
<li><a href="appl_guide.html">The PSL-enabled Applications Guide.</a>
-- If you are planning on including a PSL interpreter into your program,
(making it 'PSL-enabled') then you should read the Applications Guide.
<li><a href="prog_guide.html">The PSL Programmers Guide.</a>
-- If you are writing scripts for a PSL-enabled application, then you'll
only need to read the Programmer's Guide.
<li><a href="impl_guide.html">The PSL Implementation Guide.</a>
-- Explains some of PSL's internals, especially, the byte-code
virtual machine.
</ul>
<p>
Each application can extend PSL by providing additional built-in
functions - so if you are a PSL programer then you'll probably need to
read the documentation for whatever PSL-enabled application
you are writing for. If you are writing a PSL-enabled application, then
you'd better sit down and WRITE that document!
<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>

209
doc/psl/prog_guide.html Normal file
View File

@@ -0,0 +1,209 @@
<!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: Programming Guide.</title>
</head>
<body text="#B5A642" bgcolor="#005000" link="#8FFF8F" vlink="#18A515" alink="#20336B" background="../marble.png">
&nbsp;
<table>
<tr>
<td>
<center>
<h1>The PLIB Scripting Language Programming Guide </h1></center>
<center>By Steve Baker</center>
</td>
</tr>
</table>
<H1>Introduction</H1>
This document explains how to write PSL programs.
<p>
How you actually run those programs depends on which PSL-enabled
application you are running. There is a stand-alone PSL interpreter
in plib/examples/src/psl/psl_demo - but it doesn't include any
application-specific language extensions - so a PSL program
that's written for a specific application may not run
on <code>psl_demo</code>.
<p>
However, psl_demo is great for learning to write PSL scripts.
<H1>The PSL Language</H1>
PSL is designed to be as close to the C Programming
Language - although we
cut a few corners - we extended the language in a few places - and
we consciously omitted other features that are dangerous in a
scripting language.
<p>
The following C features are implemented much as you'd expect:
<ul>
<li> Types 'void', 'int' and 'float' (and arrays of those things).
<li> Function definitions.
<li> Global variable definitions.
<li> Statement types:
<ul>
<li> Local variable definitions.
<li> Static variable definitions.
<li> "return"
<li> "break"
<li> "continue"
<li> "for"
<li> "do/while"
<li> "switch/case/default"
<li> "while"
<li> "if"
<li> "if/else"
<li> "{}" compound statements.
<li> Assignment statements.
<li> Procedure calls.
</ul>
<li> Most Arithmetic operators.
<li> Comments '/*' '*/'.
<li> C preprocessor directives:
<ul>
<li> "#include"
<li> "#define" without parameters.
<li> "#undef"
<li> "#ifdef/#endif"
<li> "#ifdef/#else/#endif"
<li> "#ifndef/#endif"
<li> "#ifndef/#else/#endif"
</ul>
<li> Special characters in strings:
<ul>
<li> "\n"
<li> "\r"
<li> "\a"
<li> "\b"
<li> "\f"
<li> "\t"
<li> "\\"
<li> "\""
</ul>
<li> Recursion, etc.
</ul>
Some new features have been added that are not part of C:
<ul>
<li> "pause" -- Pause the program until next frame.
<li> "string" data type (and arrays of strings).
<li> Casts are unnecessary between compatible types.
<li> C++ style '//' comments.
<li> C++ style local variable declarations.
</ul>
Some features of C are NOT IMPLEMENTED in PSL:
<ul>
<li> Pointers.
<li> Casts.
<li> Dynamic Memory Allocation.
<li> ',' and '?:' operators in expressions.
<li> "static", "auto" and "register" storage class reserved words.
<li> "char", "short", "unsigned", "signed", "long", "double".
<li> "typedef"
<li> "enum", "union", bitfields.
<li> "goto".
<li> "#if"
<li> "#pragma"
<li> "#define" with parameters.
<li> 'f' and 'l' suffixes for float and long numbers.
<li> All preprocessor directives must have the '#' as the
very first character on the line - they cannot be
preceded with whitespace.
</ul>
The following features are "NOT IMPLEMENTED YET" - but will
hopefully arrive soon:
<ul>
<li> Multiple variable definitions like 'int i, j, k ;'
<li> Structs.
<li> '\' to escape the end-of-line character in strings and macro's.
<li> Parameter passing by name.
<li> Many of C's standard library functions are needed.
</ul>
<H1> Compatibility Notes: </H1>
<H3> C++ style local variables. </H3>
With PSL's C++ style locals, you can say things like this:
<pre>
for ( int i = 0 ; i < 10 ; i++ ) /* Do something */ ;
</pre>
In standard C++, the scope of the variable 'i' is from it's
declaration to the end of the 'for' loop. However, Microsoft's
Visual C++ uses an obsolete version of the C++ standard that
allows the scope of 'i' to continue to the end of the block
that contains the for loop. So:
<p>
WINDOWS USERS BEWARE: PSL IMPLEMENTS THIS CORRECTLY - *NOT* LIKE
MSVC.
<H1>Hard Limits</H1>
Currently there are hard limits in many places - the number of
variables, the size of the program, the depth of nesting, etc.
These limits will gradually be removed as PSL is developed.
<H1>Debugging PSL Programs</H1>
Specific PSL-enabled applications may have their own
special features to assist with debugging - but all
PSL-enabled applications support several 'shell variables'
that enable certain debugging features.
<p>
When using a command line shell, you can set these
variables using one of the following commands before
you run your application:
<pre>
setenv VARIABLE value -- csh or tcsh
export VARIABLE=value -- bash or sh
set VARIABLE=value -- DOS shell
</pre>
<H3> Byte-Code Dump </H3>
It's possible to view the byte code that PSL generated
by setting the shell variable 'PSL_DUMP' to either:
<ul>
<li> <b>never</b> (the default) -- Never produce a dump unless
the application demands it.
<li> <b>on_error</b> -- Produce a dump whenever the PSL program
fails to compile for whatever reason.
<li> <b>always</b> -- Always produce a dump after the PSL program
finishes compiling.
</ul>
<H3> Byte-Code Execution Trace </H3>
It's possible to view the byte code as it's executed
by setting the shell variable 'PSL_TRACE' to either:
<ul>
<li> <b>never</b> (the default) -- Never produce a trace unless
the application demands it.
<li> <b>always</b> -- Always produce a trace.
</ul>
When the execution trace is enabled, extra instructions will be
inserted into the byte code to enable the PSL interpreter to
produce debug indicating which lines of the source code are
being traced.
<H3> Byte-Code Stack Display </H3>
If you have PSL_TRACE turned on (either via the config variable or
by the application program), then the shell variable 'PSL_STACK'
can be set to display the contents of the top eight stack locations
as the program is traced. If PSL_TRACE is disabled then PSL_STACK
has no effect.
<ul>
<li> <b>never</b> (the default) -- Never produce stack dumps
within a trace.
<li> <b>always</b> -- Always produce a stack dump within trace.
</ul>
<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>