          ____         ______
         /    \         \   \\
        |               |     |   Scripting engine
         \____  ____ ___|     |
              \/   \\  \\____/      v 0.92a
        /      |_____|___|   \
       |      /\    \   |     |
        \____/  \___/\___/     \
          by Theur - Przemyslaw Podsiadly 1998-99

#include <std_disclaimer.h>

   "I do not accept responsibility for any effects, adverse or otherwise,
    that this code may have on you, your computer, your sanity, your dog,
    and anything else that you can think of. Use it at your own risk."

                         SEER REFERENCE

  //                                                                 \\
 |                         Idea                                        |
  \___________________________________________________________________/

  The idea was to make a script engine for any purpose you would need.
This can be for AI in the game, for macros in an editor or whatever.
This is for things you cannot (or don't want to) have compiled
(hard-coded) inside your program. The idea was to make it easy to
learn, and though it's a C library, SeeR is (or will be) an almost
complete C compiler.


  //                                                                 \\
 |                       SeeR interface                                |
  \___________________________________________________________________/

  All SeeR functions you can use have their prototypes in seer.h.

=> scScript scCompile_File(char *);
=> scScript scCompile_Text(char *);
  Compiles the source loaded from File or from memory (stored simply as
char*). Return the compiled script in scScript (which is btw. simply a char*).

=> scScript scLoad_Script(char *);
  This one only loads precompiled (e.g using SeeRC) script to memory. It's
now ready to be used as instance.

=> scInstance* scCreate_Instance(scScript script,char* variables,...);
  To run a script, first you have to create instance of it using this routine.
  (Not implemented:)
  Variables is a list of variables in script you want to initialize with
  specific values,like this:
   Character* Human[2];
   Human[1].inst=scCreate_Instance(scrpt,"this group",&Human[1],1);
  (with `Character* this' and 'int group' in the scrpt)

=> void scFree_Instance(scInstance *sci);
  Frees memory allocated to the instance (WARNING:first it should be killed
if in multitasking mode!!!).

=> int scGet_Script_Size(scScript);
  Returns size of script in bytes (e.g. for storing in file), or 0 if not
a valid SeeR script.

=> scInstance* scGet_This();
  Returns scActual_Instance, that is an instance being run actually run
(the instance that called an imported function calling scGet_This).
If none is actually running, it returns NULL.

=>scInstance *scActual_Instance;
  This is set every time you call scCall_Instance, scVCall_Instance and
for every instance in scContinue_Instances. When these functions exit,
it's set to NULL. It points to an instance being actually executed.

=> int scGet_Symbol(scInstance*,char *);
  Returns an address of specified symbol in instance - not a valid pointer,
just address relative to the script address. It may be different for
two different instances of the same script, but doesn't change in time.
So you can read address only once per instance, and then use stored address
(that will significantly increase speed of accessing variables and calling
functions).
If symbol hasn't been not found in the instance, it returns -1.

=> int scCall_Instance(scInstance*,int address,...);
  Starts a function from specified address in the script. Parameters after
address are parameters to this function. The function address can be obtained
using scGet_Symbol(...),e.g.
  x=scCall_Instance(inst,scGet_Symbol(inst,"move"),10);//10 is a parameter
The function returns the return value of this function (only if it's 4-bytes
long, so it cant be long long, double or struct). It also sets -->scErrorNo
if any error happens during execution.

=> int scVCall_Instance(scInstance* inst,int address,int paramc,int *params);
  Alike previous function it calls a function, but parameters are passed
via params pointer(paramc is size of parameters in BYTES).

=> int scGet_Script_Size(scScript);
  Returns size in bytes of the script. It returns 0, if not a script was
passed.

=> void scStart_Instance(scInstance *,...);
  Starts `main' function in the script.

=> scVar(scInstance* inst,int adr,type)
 Macro for accessing a variable exported in script of inst-instance.
 e.g x=scVar(inst,scGet_Symbol(inst,"x"),int);
  or scVar(inst,scGet_Symbol(inst,"x"),int)=5;

=> void scAdd_Internal_Header(char *name,char *contents);
 Specifies the include contents of a header "file" that can be included
in script using #include name (without ""!).

=> void scAdd_External_Symbol(char *,void *);
 Specifies the symbol (function or variable) you give (export to)
your scripts.
This affects all instances & scripts.
 e.g. Add_External_Symbol("printf",printf);       //for a function
      Add_External_Symbol("gamelogic",&gamelogic);// for a variable

=> void scExport_Kernel();
  Sets up an internal header `Kernel' and adds all external symbol
it lists. (->Builtin internal headers)

=> void scToggle_Debug(bool debon);
  Toggles debugging on and off. When debugging is on, compilation and
 execution process is described in a debug file (this is done by
 SeeRC for example).
WARNING: Debug does work only in debug version of library. In release
version these 3 functions do completely NOTHING. This restriction is
set for speed reasons.

=> void scOpen_Debug(char *filename);
  Opens a debug file named filename and toggles debugging on.

=> void scClose_Debug();
  Closes debug file and also turns debugging off.

=> char* scGet_Title(scScript);
=> char* scGet_Author(scScript);
=> char* scGet_Instance_Title(scInstance*);
  Retrieves author and title information out of the script or instance.
Not existing scGet_Instance_Author(i) would be equivalent to
scGet_Author(i->code).

=> bool scIgnore_Rights;
  If true, makes all the functions ignore priorities at all, even if they
check the priority via scPriority_Guard or scKernel_Only.

=> void scSet_Priority(scInstance*, int priority_level);
  Sets the priority to an instance. Priority is simply an int number.
Here are the standard values:
scrights_USER     0   lowest priority
scrights_KERNEL 256
scrights_TOP MAXINT   maximum priority - no instance is being run

=> int scGet_Priority(scInstance*);//if NULL returns scNONE
  Gets priority of an instance.

=> int scGet_Actual_Priority();
 = scGet_Priority(scActual_Instance);

=> #define scPriorityGuard(priority,rets)
  This macro is to be used in functions that are protected, i.e that
cannot be called by instances that do not have enough priority.
This sets a runtime error and returns rets (can be `;' for functions
returning void). See example 9.

=> #define scKernelOnly(rets)
  =scPriorityGuard(scrights_KERNEL,rets);

  //                                                                 \\
 |                   SeeR interface to multitasking                    |
  \___________________________________________________________________/
  Multitasking mode is a simple way to run many instance at the same
 time. For example, when you make RPG engine, each character (NPC)
 has it's own instance running. He is also able to have more instances
 of the same script operating on the same data (by forking).
  The scheduler (scScheduler) contains list of all running instances
 (processes). It is used by scContinue_Instances() to run all of them.
 Now you are able to switch schedulers, so you can set up two or more
 schedulers being run in different frequency. For example you
 can have scheduler for real-time instances, that move characters,
 and more rare ones, that do more complex operations, like working
 out the main tactics and sending orders to computer's characters.

=> scScheduler* scGet_Scheduler();
 Returns actual scheduler.

=> scScheduler* scSet_Scheduler(scScheduler*);
  Sets new scheduler. It returns the previous one.
If you pass NULL to it, it'll create a new empty one.

=> void scPause_Instance(scInstance*,int pause);
 If (pause) freezes the instance in scheduler queue, else unfreezes.
Freezed (paused) instance is not processed by the scheduler.

=> void scKill_Instance(scInstance*);
 Removes an instance from the scheduler queue - it won't run in all
further calls of scContinue_Instance until next scLaunch_Instance.

=> int scGet_Instance_Status(scInstance *);
 Returns status of an instance:
  scstatus_FREE    - instance is not run or does not exist
  scstatus_RUNNING - it's in scheduler and is not paused
  scstatus_PAUSED  - it's paused

=>int scVLaunch_Instance(scInstance* inst,int spd,int address,int paramc,int *params);
 This function is the same to scLaunch_Instance like function
scVCall_Instance to scCall_Instance.
It does the same as scLaunch_Instance, but here we pass parameters via
params, and size in _BYTES_ of parameters should be in paramc.

=> int scLaunch_Instance(scInstance* inst,int spd,int address,...);
 Tells SeeR scheduler that you want the instance and function at
address to be processed in multitasking mode. It's not executed
yet. You have to call scContinue_Instances to execute the scheduler -
a list of instances (you can launch many simoultanously running different
instances).
WARNING:You cannot launch previously launched and not killed instance!!!
     (to launch instance twice at the same time, use forking-desc. below)
     The error will be returned.
The spd parameter is speed of instance running
(ie spd=10 - every 10th instruction or WAIT instruction, scheduler
freezes instance and calls next one in scContinue_Instances function).

=> int scContinue_Instances(void);
 Continues running all previously launched instances. Returns number of
running instances (ie 0 if none). If it returns -1 - an error must have
occured during process of running any instance. Flag scErrorNo is then
set to appropriate error value. The instance that caused a problem is
removed (killed) from the running queue and scheduler doesn't process further
instances till the next call of scContinue_Instances.

=> forking:see also ->Scripting language quick reference:fork
 Fork is a way to create instances from already existing instance (parent).
But these instances aren't typical - they use the same data segment as it's
parent. There are many ways to fork an instance and operate on them.
Each forked instance has it's number.

=> scInstance* scFork_Instance(scInstance*);
 It's one of the ways to create a forked instance. It returns forked instance,
that has it's number (identifying it). Now these instances (parent and child)
can be executed independently. They share only common data segment (global
script variables).

=> scInstance* scGet_Forked(scInstance* parent,int no);
 Returns instance forked from parent and has number no. If there is not
such an instance, it returns NULL.

=> scInstance* scGet_Actual_Forked(int);
 The same as scGet_Forked, but for actually running instance (scGet_This()).

=> void scKill_Forked_Instances(scInstance* parent);
 Kills and frees (scFree_Instance) all instances forked from parent. Of
course you can also kill each forked one by one. When you kill an
instance that has children (forks), one of children will become a parent
of others.

=> int scGet_Forked_Status(int);
=> void scKill_My_Forked_Instances();
=> void scKill_Forked(int);
  All these functions operate on scActual_Instance. They do
what is done by scGet_Instance_Status, scKill_Forked_Instances and
scKill_Instance, but operate on scActual_Instance or it's forks.

  //                                                                 \\
 |                       SeeR error reporting                          |
  \___________________________________________________________________/

 When the compilation finishes, in scErrorNo holds the status of operation.
Also after creating or executing an instance scErrorNo is set.
WARNING: all compile, run (call & continueing intance) instructions clear
scErrorNo flag at their begining!

=> int scErrorNo;
    -scOK if it was successful
    -other if it wasn't - then you should report it somehow (or whatever)

=> char scErrorMsg[255];
 Here SeeR stors an error message, like "Script( 31):parse error"
 (in brackets there is a line number). The debug version of SeeR generates
some more information (like SeeR's source file and line, that caused that
error).

=> char scErrorLine[256];
 Here is stored a copy of line that caused an error (valid if error appeared
during compilation).


  //                                                                 \\
 |               Scripting language quick reference                    |
  \___________________________________________________________________/

  The language is almost like C. See restrictions for not implemented
features of the language.

--==< New keywords:

=> import {declaration}
  The declaration of imported from outside (the program) function or
variable.

=> export {name}
  Specifies symbol (function or variable) that can be accessed from outside
the script.

=> secured instruction(s)
    The group of instructions specified after `secured' are embrased with
  CLI ... STI (virtual opcodes, not processor) - this group (and all functions
  called inside) cannot be interrupted while multitasking. This can be helpful
  when you compute some numbers inside a script, and while doing so script
  is interrupted and you use those numbers, they may contain quite undefined
  numbers.

=> __vcpu(i1,...)
    Generate VCPU opcode(s) specified as integers, eg.
  56 - wait
  57 - cli
  58 - sti
  61 - nop
CAUTION: wait (opcode 56) has to be passed alone,
         e.g __vcpu(57,56,58); won't work OK(but separately 3 x __vcpu will)!!!
WARNING: Better not use it other way that via macro WAIT. The numbers, that
         SeeRVitualCPU stores its instructions may change in next version of
         SeeR.
=> fork (int_variable) statement
=> fork statement
    Only in multitasking mode: creates fork instance that will execute
  the statement and exit while actual instance continues.
   *See also forking in "SeeR interface to multitasking" (above)
    The int_variable will contain the number of forked instance, so
  later we can check if it has finished.
  e.g.

   int main(int c)
   {int i,x,y;
    fork(i) //creates new process
     {int l;
      for (l=0;l<100;l++)x=l*2;
     }
    y=5*c+12;
    while (scGet_Forked_Status(i));//wait till fork ends.
    //we can also fork like below, when we don't care about the number of forked inst.
    fork y+=x;//equal to: fork {y+=x;}
   }

=> #title "The Long Title"
=> #title one_word_title
=> #author "Author full name"
=> #author one_word_nick
  Sets the author and title to be stored in script. This information is
  used in error-reporting.
  Examples:
  #author "William Shakespeare"
  or
  #author Billy
  (but not #author William Shakespeare! (that's more than one word)

--==< Built-in macros:
=> SeeR
=> WAIT __vcpu(56)
=> NULL (void *)0

--==< Differences to C:
=> #include "file"
=> #include internal-header
=> Structures can be declared in C++ way:
 struct TYPE_NAME{
 ...
 };
 However, they shouldn't be accessed as `struct TYPE_NAME', like
   void Foo(struct TYPE_NAME x);
 but simply
   void Foo(TYPE_NAME x);

--==< Restrictions:
 - unions and enums not implemented,
 - goto instruction not implemented
 - bitfields not implemented
 - SeeR is not a C++, but some features of C++ may appear in SeeR


  //                                                                 \\
 |               Builtin internal headers                              |
  \___________________________________________________________________/
=> #include Instances
  This header is used to make some operations on SeeR instances (other than
fork) available in scripts as a standard. The instructions don't operate on
true scInstance*, so they seem safe that one instance won't kill all the
others.
char *hdrInstances=
"
#ifndef SeeR_Internal_Instances
#define scstatus_FREE    0
#define scstatus_RUNNING 1
#define scstatus_PAUSED  2

import void scKill_My_Forked_Instances();
import void scKill_Forked(int);
import int scGet_Forked_Status(int);
import int scGet_Actual_Priority();
#define SeeR_Internal_Instances
#endif
";

=> #include Kernel
  Does not require any priority (before v0.8 it required scKernel right)
to run any specified function. To make the functions accessible,
scExport_Kernel() function should be used in your main program, which will
export all required functions. These functions give great freedom to script!
char *hdrKernel=
"
#ifndef SeeR_Internal_Kernel
#include Instances
//can call all imported kernel API function
#define scrights_KERNEL 256
//cannot ---
#define scrights_USER     0
//when no instance is being run:
#define scrights_TOP MAXINT

typedef void scInstance;
typedef void* scScript;
import scInstance* scCreate_Instance(scScript,char*,...);
import scInstance* scFork_Instance(scInstance*);
import void scFree_Instance(scInstance *);

import scScript scCompile_File(char *);
import scScript scCompile_Text(char *);
import scScript scLoad_Script(char *);

import scInstance* scGet_This();
import scInstance* scGet_Forked(scInstance*,int);
import scInstance* scGet_Actual_Forked(int);
import void scPause_Instance(scInstance*,int);
import void scKill_Instance(scInstance*);
import void scKill_Forked_Instances(scInstance*);

import int scGet_Script_Size(scScript);
import int scCall_Instance(scInstance*,int address,...);
import int scVCall_Instance(scInstance*,int,int,int*);
import int scStart_Instance(scInstance *,...);
import int scGet_Symbol(scInstance*,char*);
import int scLaunch_Instance(scInstance* inst,int spd,int address,...);

import void scSet_Priority(scInstance*, int priority_level);
import int scGet_Priority(scInstance*);

#define SeeR_Internal_Kernel
#endif
";

  //                                                                 \\
 |                        Conclusion                                   |
  \___________________________________________________________________/

  This software is free , but if you use it
        -= PUT MY NAME (and the lib's ) IN THE CREDITS!! =-
and send me a note about it.
That's all for now (sorry if you find it not complete).
If you find something unclear in the documentation, first look
at the examples. They show almost every feature of SeeR. Then,
if you're still confused, email me.
                        Enjoy !!!
I'd be happy to see what you've used it for...


By Przemyslaw Podsiadly (just Przemek)
28 Mlynarska Street 37,
08-110 Siedlce, Poland.

ppodsiad@elka.pw.edu.pl

page:      http://home.elka.pw.edu.pl/~ppodsiad/
SeeR page: http://home.elka.pw.edu.pl/~ppodsiad/english/program/
