SeeR - a multipurpose C-scripting library

              ____         ______
             /    \         \   \\
            |               |     |   Scripting engine
             \____  ____ ___|     |
                  \/   \\  \\____/      v 0.94a
            /      |_____|___|   \
           |      /\    \   |     |
            \____/  \___/\___/     \

              by 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."

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/C++ compiler.

# Contents

####
- Using SeeR
- How do I set up SeeR
- Basics
- Compilation
- Instance
- Multitasking
- Error reporting
- Scripting language quick reference
- Builtin internal headers
- Conclusion

##
- Using SeeR
- How do I set up SeeR
- Basics

####
- SeeR_VERSION
- SeeR_VERSION_STR
- SeeR_DATE
- SeeR_DATE_STR
- scInit_SeeR
- scSeeR_Get
- scSeeR_Set
- scToggle_Debug
- scOpen_Debug
- scClose_Debug

- Compilation

  ####
  - scCompile_File
  - scCompile_Text
  - scLoad_Script

- Instance

  ####
  - scCreate_Instance
  - scFree_Instance
  - scGet_Script_Size
  - scGet_This
  - scActual_Instance
  - scGet_Symbol
  - scCall_Instance
  - scVCall_Instance
  - scStart_Instance
  - scVar
  - scNameVar
  - scAdd_Internal_Header
  - scAdd_External_Symbol
  - scAdd_Member_Symbol
  - scExport_Kernel
  - scGet_Title
  - scGet_Author
  - scGet_Instance_Title
  - scStandardDispatcher
  - scIgnore_Rights
  - scSet_Priority
  - scGet_Priority
  - scGet_Actual_Priority
  - scPriorityGuard
  - scKernelOnly

- Multitasking

  ####
  - scGet_Scheduler
  - scSet_Scheduler
  - scPause_Instance
  - scKill_Instance
  - scGet_Instance_Status
  - scVLaunch_Instance
  - scLaunch_Instance
  - scContinue_Instances
  - scFork_Instance
  - scGet_Forked
  - scGet_Actual_Forked
  - scKill_Forked_Instances
  - scGet_Forked_Status
  - scKill_My_Forked_Instances
  - scKill_Forked

- Error reporting

  ####
  - scErrorNo
  - scErrorMsg
  - scErrorLine

- Scripting language quick reference

  ####
  - import
  - export
  - secured
  - __vcpu
  - fork
  - author
  - title
  - typeof
  - script
  - SeeR
  - WAIT
  - NULL
  - c_import
  - include

- Builtin internal headers

  ####
  - Instances
  - Kernel
  - stdlib

- Conclusion

# Using SeeR

For GENERAL RELEASE INFORMATION see readme.txt. There you will find general introduction, copyright details, and information about how to install SeeR and link your program with it. There is all about seerc compiler, examples and so on.

This document is only the manual of SeeR the scripting lib.

# How do I set up SeeR

But first I would like to explain some vocabulary. So:

- program - the normal C/C++ program, in which you may load/compile/execute scripts;
- script source - that's difficult - the source code of the script;
- script - the script source after compilation;
- instance - the script prepared for execution - with allocated space for stack, data, registers. Only instance you can execute. You can do this as many time as you wish. You do this by calling script's functions. Between such calls the contents of global variables is preserved.

  The first thing you shouldn't forget is to include SeeR header:

         #include < seer.h >

  Then init SeeR (some functions may try to initialize SeeR if you haven't done this before, like compilation routines, but some may crash!):

         scInit_SeeR();

  Using scSeeR_Get(...) and scSeeR_Set(...) functions you may get some SeeR informations, like SeeR version and release mode (release, debug), the number of lines compiled recently. There are also some options you may alter, like optimization flags, dispatcher functions, callback function etc.

  What next? You may export all symbols your scripts may use. SeeR can use any main-program function or variable (I call them symbols) you give him. Use scAdd_External_Symbol (scAddExtSym for shorter) or scAdd_Member_Symbol to do this.Examples:

          scAdd_External_Symbol("printf",printf);
          scAddExtSym(scanf);//this is the shorter version
          scAdd_External_Symbol("cls",my_clear_screen);//the names can differ

  In the script you can import also class member functions. But to import such a function your main program does not have to be written in C++. With non-objective C you can have objective scripts without any problems. Below you see two member-functions imported: from the normal C++ member and from the C function pretending to be member-function.

          scAdd_Member_Symbol("string.append",string::append);
          scAdd_Member_Symbol("string.operator[]",string_operatorINDEX);

  You may also make some internal headers. In a script you can #include files (like #include "file.h") or include special internal headers (#include internal). The internal header is just a string (char *) in the program, which contains what a normal header files use to.

  You can provide also custom dispatchers (quite advanced, only for experienced, but see exclassc for details).

  When you have a script-source, you may compile it. The compiled script is stored in a variable of type scScript. There are two special functions for this : scCompile_File and scCompile_Text. Examples:

         scScript s1,s2;

         s1=scCompile_File("script.sc");

         if (!s1)
          {printf("Error during compilation:\n%s\nIn line:%s\n",scErrorMsg,scErrorLine);
           exit(scErrorNo);
          }

  or the text version

         s2=scCompile_Text(
         "#title \"The textual script\"\n"

         "import int printf(char *,...);\n"

         "export Info;\n"
         "export life;\n"

         "int life=21;\n"

         "int Info(int age)\n"
         "{\n"
         " life+=age;\n"
         " printf(\"I'm Goldfryd. I'm %d years old.\",life);\n"
         " return life;\n"
         "}\n"
         );

         if (!s2)
          {printf("Error during compilation:\n%s\nIn line:%s\n",scErrorMsg,scErrorLine);
           exit(scErrorNo);
          }

  Now create instances (scCreate_Instance) for the scripts (each script can have plenty of them). The instance is of type scInstance. Here the script s2 has two instances: in1 and in2.

         scInstance *in1,*in2;

         in1=scCreate_Instance(s2,"");

         if (scErrorNo) //in scErrorNo there is an error numer
            printf("Runtime error :\n%s\n",scErrorMsg);

         in2=scCreate_Instance(s2,"");

         if (scErrorNo)
            printf("Runtime error :\n%s\n",scErrorMsg);

  Since now you can access variables from the instances, call functions, and so on. You can do even multitasking (several instances running together in peace).
  The first thing is that the symbol has to be exported. That is done in the script-source using keyword export:

         export life;
         int life=21;

  To access such a function/variable, the program has to find out its address. You do it with scGet_Symbol.
  To access a variable:

         scVar(in1,scGet_Symbol(in1,"life"),int)=24;
          or
         scNameVar(in1,"life",int)=24;

  Or, when you access the variable more often, you can get the address only once to make it faster:

         int address=scGet_Symbol(in1,"life");

         for(i=0;i<50;i++);
            scVar(in1,address,int)=i;

  To call a function:

         i=scCall_Instance(in1,scGet_Symbol(in1,"Info"),1);

  Above, the 1 is the parameter to script-function Info. This is the normal way of calling. In this situation SeeR knows how many arguments the function Info needs.
  But when you want to call a function with variable number of arguments, SeeR does not know how many arguments you really pass. In those situations you should use the other, more general way, where you explicitly give the size (in bytes) of arguments:

         int argument=1;
         i=scVCall_Instance(in1,scGet_Symbol(in1,"Info"),sizeof(int),&argument);

  This function does not take the arguments to script-function explicitly, but needs the pointer to arguments. That's why &argument is given.

  When you are finished with this, you can deallocate instance with

         scFree_Instance(in1);
         scFree_Instance(in2);

  The script you deallocate with standard C free:

         free(s1);
         free(s2);

  So, peace!

  # Basics

  #define SeeR_VERSION 100
  #define SeeR_VERSION_STR "1.00"
  #define SeeR_DATE 20000101
  #define SeeR_DATE_STR "2000-01-01"
  The SeeR defines SeeR version and date. To obtain numeric version, write:

       SeeR_VERSION/100.0

  SeeR_DATE stores the date in yyyymmdd format. There are also string versions of above (*_STR).

  void scInit_SeeR(void)
  Initialises the SeeR library. A good thing is to call this before any play with SeeR. But you may also forget it. Some functions just check if SeeR has been inited, and if not they init it (so call this function).

  int scSeeR_Get(int,...);
  This function is provided for common unified method of getting state of SeeR.
  The first parameter is the option which state you want to get. Following parameters are just parameters to those options.

  This is the list of valid get-only options. If it is not stated explicitly what parameters they require, they take no parameters.

  - scSeeR_Version - returns SeeR_VERSION
  - scSeeR_Build - returns build version, that is:
    scSeeR_Build_Release - SeeR may not debug, but is fastest
    scSeeR_Build_Debug - SeeR may generate debug files
  - scSeeR_LinesCompiled - returns number of lines compiled during latest compilation
  - scSeeR_ParamCount - returns the size in bytes of parameters passed to imported function

  This is the list of other options, which can be both set and get. When get:

  - scSeeR_SafeMode - if SeeR restricts user from using some unsafe features (like pointers - in future) (UNIMPLEMENTED)
  - scSeeR_Debugging - if debugging is on
  - scSeeR_Dispatcher - get function dispatcher,
    parameter:int nr
  - scSeeR_ExprOpcode - if SeeR outputs statement separator opcode EXPR
  - scSeeR_StackSize - get stack size in bytes

  bool scSeeR_Set(int,...);
  This function is provided for common unified method of setting options to SeeR.
  The first parameter is the option which state you want to set. Following parameters are just parameters to those options.

  This is the list of valid set-only options. If it is not stated explicitly what parameters they require, they take no parameters.

  - scSeeR_OpenDebug - open debug file, starts debugging
    parameter:char *filename
  - scSeeR_CloseDebug - close file,Stop debugging

  This is the list of other options, which can be both set and get. When set:

  - scSeeR_SafeMode - if SeeR restricts user from using some unsafe features (like pointers - in future) (UNIMPLEMENTED)
    parameter:int mode
  - scSeeR_Debugging - if debugging is on
    parameter:int on
  - scSeeR_Dispatcher - set function dispatcher,
    parameter:int nr,void *scFunctionDispatcher
  - scSeeR_ExprOpcode - output statement separator opcode (EXPR), false - execution is faster, but in multitasking script may not be interrupted every X instructions
    parameter:bool EXPR
  - scSeeR_StackSize - set stack size for next compiled script, in bytes
    parameter:int stack_size_in_bytes

  scSeeR_Set and scSeeR_Get Examples:

       if (!scSeeR_Set(scSeeR_OpenDebug,"debug.txt"))
          {printf("Unable to start debugging.!\n");exit(1);}

       if (scSeeR_Get(scSeeR_Debugging))
          {scSeeR_Set(scSeeR_CloseDebug);}

       scSeeR_Set(scSeeR_StackSize,512);

  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). This can be also done with -->scSeeR_Set. Debugging makes compilation and execution a lot slower, so you should have this in mind when using this.

  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. This can be also done with -->scSeeR_Set.

  void scClose_Debug();
  Closes debug file and also turns debugging off. This can be also done with -->scSeeR_Set.

  # Compilation

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

  If return NULL, that means something went wrong. The scErrorNo contains the info on this.

  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. It can be useful when you have many scripts and compilation of them take some time or you don't want final users to change them. In these situations you simply compile the script using SeeRC (or WSeeRC) or with your custom- built "level-designer", or something...

  This function is very simple thingy. As this loads only from normal files, you may be in need of loading a script from for example datafile. You may implement it very easly. Follow this (I hope I'm not wrong somewhere there):

        scScript MyLoad(char *filename)
        {int size=my_file_size(filename);
         scScript JA=malloc(size+1);
         MyFile *f=my_open_file(filename);
         my_fileread(f,JA,size);
         my_close_file(f);
         JA[size]=0;//remember to add this!!
        }

  (if you have problems, see to the sources before mailing me;-)

  # Instance

  scInstance* scCreate_Instance(scScript script,char* variables,...);
  To run a script, first you have to create instance of it using this routine. Having an instance, you can then call any function, access any variable from the script. (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 script)

  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 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 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).

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

  macro 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;

  macro scNameVar(scInstance *ins,char *name,type)

  This macro is just shortcut for: scVar(ins,scGet_Symbol(ins,name),type).

  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 scAdd_Member_Symbol(char *,...);
  Does the same as scAdd_External_Symbol, you can give it anything. Also class-members (hence the name). You can even forget about the previous(scAdd_External_Symbol). The must example:

         Add_Member_Symbol("NPC.move",NPC::move);

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

  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).

  void scStandardDispatcher (int *result,void *function,int *params,int paramcount,unsigned int options);
  Dispatchers have been introduced in SeeR 0.93. It happened that I wanted SeeR to be used in a bigger project. And they wanted it to be portable. Problem! While I had written routines for calling functions/member functions for GCC and VC on Intels only, to make it portable I wrote some C equivalents. But they are still not portable (they would although work on many systems). That's why I made DISPATCHERs. This is the way to let the user implement the calling convention mechanism himself.

  When you import a function normally, the dispatcher # 0 will be used to call it (which is btw scStandardDispatcher). But when you use "import(1)", the dispatcher # 1 will be used. SeeR implements both dispatchers number 0 and 1. You may implement some more dispatchers - up to 15 (14 should be enough for everyone ;-).

  So the dispatcher must be something like this:

         typedef void (*scFunctionDispatcher)
           (int *result,void *function,int *params,int paramcount,unsigned int options);

  What the arguments mean:

  - result is pointer to something, where you should store the result of the function, e.g. int or double (don't care that it's defined as int *, it may be equally good double *);
  - function is a pointer to function, that should be called;
  - params is a table of parameters to function (it's part of the stack);
  - paramcount is the size of parameters in bytes;
  - options:
    options & scDispatch_Double - true, if result is a double, not int;
    options & scDispatch_Member - true, if the function is member of a class; in this situation the first parameter is 'this' (a pointer to the object).

  Example taken from SeeR's source distribution:

         void scCDispatcher
         (int *result,void *function,int *params,int paramcount,unsigned int options)
         {
           if (options&scDispatch_Member)
           {//C++ call - convert to typical C call, so 'this' is the first param.
                 options^=scDispatch_Member;//erase member flag
           }
           //call the default dispatcher
           scStandardDispatcher(result,function,params,paramcount,options);
         }

  and somewhere below I set scCDispatcher as dispatcher # 1:

         scSeeR_Set(scSeeR_Dispatcher,1,scCDispatcher);

  Since version 0.94, SeeR provides some classes, which use this dispatcher (because SeeR is written in pure C, it cannot use dispatcher 0 for calling member functions).

  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* ins);
  Gets priority of an instance. If ins==NULL returns scNONE.

  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 exmulti.

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

  # 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. In regulation-systems this is called a layer model (OK, maybe it has a different term in English, I only know the Polish terms in this matter :-(.

  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.

  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.

  # 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;
  May holds following value:

  - scOK if operation was successful
  - other if it wasn't - then you should report it somehow (or whatever)

  char *scErrorMsg;
  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 (SeeR's source file and line, that reported that error).

  char *scErrorLine;
  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.

  NOTE: when I write something in {}, it does not mean you have to put this in {}, but I want to accent that it's not a keyword. So

              import {declaration}

  may extend to

              import int x;

  and not

              import {int x;}

  ### New keywords:

  keyword import
  Usage:
  import {declaration}
  import (dispatcher_number) {declaration}
  import (dispatcher_number)(import_name) {declaration}

  The declaration of imported from outside (the program) function or variable. Default import uses dispatcher 0.

  In the second version (with a number) you can explicitly put the dispatcher number. See also dispatcher.

  WARNING:dispatcher 0 and 1 are both implemented in SeeR and we recommend you don't change them. Use 2nd and above (up to 15).

  If you want to import functions with the same name, but different parameters, you will have problem with import names (they will be the same). In such situation you use the third variant, where you can explicitly state the import name. Example:

         class string{
         import string operator+(string& x);
         import(operator+(char*)) string operator+(char *x);
         };

  keyword export
  Usage:
  export {name}

  Specifies symbol (function or variable) that can be accessed from outside the script. Example: script.sc

         export main;
         int go() {printf("go()\n");return 0;}
         int main() {printf("main()\n");return 1;}

  In prog.c you may use

           i=scCall_Instance(in,scGet_Symbol(in,"main"));

  but not

           i=scCall_Instance(in,scGet_Symbol(in,"go"));

  (where in is a valid scInstance* ).

  keyword secured
  Usage:
  secured statement

  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 values.

  keyword __vcpu
  Usage:
  __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.

  keyword fork
  Usage:
  fork statement
  fork (int_variable) statement

  Only in multitasking mode: creates fork instance that will execute the statement and exit while actual instance continues.

  See also forking in Multitasking section above.

  The int_variable will contain the number of forked instance, so later we can check if it has finished.

  Example

         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;}
         }

  directive #author
  Usage:
  #author "Author full name"
  #author one_word_nick

  Sets the author to be stored in script. This information may be retrieved with scGet_Author.

  Examples:

         #author "William Shakespeare"

  or

         #author Billy

  (but not #author William Shakespeare! (that's more than one word) directive #title
  Usage:
  #title "The Long Title"
  #title one_word_title

  Sets the title to be stored in script. This information is used in error-reporting. It may be retrieved with scGet_Title.

  keyword typeof
  Usage:
  typeof(type-declaration)

  Returns text description of a type, e.g.

         "int"
         "double*"
         "char[256]"
         "struct{int int int}"
         "script{name name name}"

  It was created specially for the type script. When you initialize the script, you have to pass the 'typeof' to the function that does it, so that it knows which functions or variables you may need.

  type script
  There was always a problem how to easy communicate between scripts. To solve this I created the script type.

  ### Built-in macros:

  #define SeeR "1.00" // the current version
  #define WAIT __vcpu(56)
  #define NULL (void *)0
  #define c_import import(1)

  ### Differences to C:

  directive #include
  Usage:
  #include "file"
  #include internal-header

  Internal headers is a feature of SeeR, that lets you make a header-file inside your program as (char *) variable. Use scAdd_Internal_Header to let SeeR know about specific header (and to assign it a name).

  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 in a C++ way

           void Foo(TYPE_NAME x);

  So all those typedefs to make the life easy are now unnecessary.

  List of unimplemented C features:

  - old function declaration scheme,
  - unions, bitfields and enums,
  - goto instruction and labels,
  - static variables in functions

  List of unimplemented C++ features:

  - templates,
  - exceptions,
  - class inheritance,
  - static members,
  - operator new/delete,
  - and many other that came with ANSI C++(like namespaces,etc.)

  So you see the implementation of C++ is quite limited.

  # 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 the script, so use it with care!

         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
         ";

  #include stdlib
  This header contains some classes ready to use by every SeeR script. That is:

  - class string - for easy string operation, like concatention, substrings, comparison, conversion etc. Example:

           string x,y="eagle";
           x=y+" is flying";
           //You can normally pass it as char*.
           printf("%s\n",x);
           if (y=="eagle") y="hawk";
           x=y+" and "+x;
           printf("%s\n",x(5,3));//"and"
           if (x(9,5)=="eagle") is_eagle=1;

  - class vector - for easy use of 3d vectors. Example:

           vector x(1,2,3),y(3,4,5);
           x+=y;
           if (x+y>vector(10,11,12)) {x-=y;}
           else {x+=y;}

  - class hashInt - for easy use of hashes:unlimited-size arrays using hash-functions. Unimplemented. Example:

           hashInt x;
           (int)x[1000000]=1;
           (int)x[-100000]=-1;
           if (x.exists(1000000)) printf("OK.\n");

  - class hashStr - for easy use of hashes:arrays indexed with strings. Unimplemented. Example:

           hashStr x;
           (int)x["Jola"]=1;
           (int)x["Jas"]=-1;
           if (x.exists("Yaga")) printf("Danger\n");

         char *hdrStdLib=
         "
         #ifndef SeeR_Internal_StdLib
         #include Instances

         /* class string */
         class string{

         public:

          char *cstr;

          c_import(string) string();
          c_import(string_SZ) string(char *x);
          c_import(string_I) string(int x);
          c_import(stringCC) string(string& f);

          c_import ~string();

          c_import(operator=(int)) string& operator=(int x);
          c_import string& operator=(string& s);
          c_import(operator=(char*)) string& operator=(char *s);

          c_import string operator+(string& x);
          c_import(operator+(char*)) string operator+(char *s);

          c_import string sub(int start,int len);
          c_import string operator()(int start,int len);

          c_import int cmp(string& x);
          c_import bool operator==(string& x);
          c_import bool operator!=(string& x);
          c_import(operator==(char*)) bool operator==(char *x);
          c_import bool operator>(string& x);
          c_import bool operator<(string& x);
          c_import bool operator>=(string& x);
          c_import bool operator<=(string& x);
          c_import void operator+=(string& x);
          c_import(operator+=(char*)) void operator+=(char* x);

          c_import void del(int start,int len);
          c_import void insert(int start,string& x);
         //index of first found occurance
          c_import int find(string& x);
         //returns number of replaces
         //when global==false, it replaces only once
          c_import int replace(string& what,string& with,bool global=false);
         //returns length of a string
          c_import int length();

         /* operators */
          c_import int toInt();//toint
          c_import int operator(int)();//toint
          c_import char& operator[](int idx);
         /* for future, actually does nothing */
          c_import void reconstruct();

         // class hashInt
         class hashInt{
         public:
          c_import hashInt();
          c_import ~hashInt();

          c_import void*& operator[](int id);

          c_import void add(int id,void *data);
          c_import bool exists(int id);
          c_import void *remove(int id);
          c_import void *get(int id);

          c_import bool empty();

          c_import int first();
          c_import int next();

         };

         // class hashStr
         class hashStr{
         public:
          c_import hashStr();
          c_import ~hashStr();

          c_import void*& operator[](char *id);

          c_import void add(char* id,void *data);
          c_import bool exists(char* id);
          c_import void *remove(char* id);
          c_import void *get(char* id);

          c_import bool empty();

          c_import char *first();
          c_import char *next();
         };

         struct vector{
          double x,y,z;
         public:
          c_import(vectorVOID) vector();
          c_import vector(double,double,double);
          c_import(vectorCC) vector(vector& v);

          c_import vector& operator=(vector& v);

          c_import vector operator+(vector& v);
          c_import vector operator-(vector& v);
          c_import vector operator*(vector& v);//cross product

          c_import void operator+=(vector& v);
          c_import void operator-=(vector& v);
          c_import void operator*=(vector& v);

          c_import bool operator==(vector& v);
          c_import bool operator<(vector& v);
          c_import bool operator>(vector& v);
          c_import bool operator<=(vector& v);
          c_import bool operator>=(vector& v);

          c_import void normalize();
          c_import double length();

         };

         #define SeeR_Internal_StdLib
         #endif
         "

  # Conclusion

  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)
  12 Modrzewiowa Street,
  08-110 Siedlce, Poland.

  ppodsiad@elka.pw.edu.pl

  http://home.elka.pw.edu.pl/~ppodsiad/seer/