Fixed behavior of VTerm when driver is set at runtime
authorJohn Hodge <[email protected]>
Sat, 7 Aug 2010 00:45:12 +0000 (08:45 +0800)
committerJohn Hodge <[email protected]>
Sat, 7 Aug 2010 00:45:12 +0000 (08:45 +0800)
Writing a script parser for use with init (SpiderScript)
NOTE: Init does not compile atm, please go to an old commit or remove
 the references to spiderscript in it to compile

21 files changed:
Kernel/arch/x86_64/Makefile
Kernel/arch/x86_64/include/mm_virt.h
Kernel/drv/vga.c
Kernel/drv/vterm.c
Kernel/include/modules.h
Kernel/lib.c
Kernel/modules.c
Usermode/Applications/init_src/Makefile
Usermode/Applications/init_src/main.c
Usermode/Libraries/Makefile.tpl
Usermode/Libraries/libc.so_src/string.c
Usermode/Libraries/libspiderscript.so_src/Makefile [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/ast.c [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/ast.h [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/bytecode.h [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/exec_ast.c [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/lex.c [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/main.c [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/parse.c [new file with mode: 0644]
Usermode/Libraries/libspiderscript.so_src/tokens.h [new file with mode: 0644]
Usermode/include/string.h

index 647a49a..22ad8c9 100644 (file)
@@ -14,9 +14,9 @@ ifeq ($(ARCH),amd64)
        ASFLAGS += -D AMD64=1
        CPPFLAGS += -DAMD64=1
 else
-       ifeq ($(ARCH),ia64)
-               ASFLAGS += -D AMD64=0 -D IA64=1
-               CPPFLAGS += -DAMD64=0 -DIA64=1
+       ifeq ($(ARCH),x86_64)
+               ASFLAGS += -D AMD64=0 -D X86_64=1
+               CPPFLAGS += -DAMD64=0 -DX86_64=1
        endif
 endif
        
index f1e0794..ca50855 100644 (file)
@@ -28,7 +28,7 @@
  *       C000 00000000 -       D000 00000000   44      16      TiB     Hardware Mappings
  *       D000 00000000 -       D080 00000000   39      512     GiB     Per-Process Data
  *       D080 00000000 -       D100 00000000   39      512     GiB     Kernel Supplied User Code
- *       ---- GAP ----                                       TiB
+ *       ---- GAP ----                                 15      TiB
  *       E000 00000000 -       E400 00000000   42      4       TiB     Physical Page Reference Counts (2**40 = 2**52 bytes)
  *       E400 00000000 -       E480 00000000   39      512     GiB     Physical Page Bitmap (1 page per bit)
  *       E480 00000000 -       E500 00000000   39      512     GiB     Physical Page DblAlloc Bitmap (1 page per bit)
index ff83e53..ac00c78 100644 (file)
@@ -123,7 +123,6 @@ Uint8 VGA_int_GetColourNibble(Uint16 col)
        col = ((col>>2)&3) | ((col>>4)&0xC) | ((col>>6)&0x30);
        bright = ( (col & 2 ? 1 : 0) + (col & 8 ? 1 : 0) + (col & 32 ? 1 : 0) ) / 2;
        
-       
        switch(col)
        {
        //      Black
index b940afa..094903c 100644 (file)
@@ -148,12 +148,10 @@ int VT_Install(char **Arguments)
                        val = arg + strpos(arg, '=');   *val++ = '\0';
                        
                        if( strcmp(opt, "Video") == 0 ) {
-                               if(gsVT_OutputDevice)   free(gsVT_OutputDevice);
-                               gsVT_OutputDevice = strdup(val);
+                               gsVT_OutputDevice = val;
                        }
                        else if( strcmp(opt, "Input") == 0 ) {
-                               if(gsVT_InputDevice)    free(gsVT_InputDevice);
-                               gsVT_InputDevice = strdup(val);
+                               gsVT_InputDevice = val;
                        }
                        else if( strcmp(opt, "Width") == 0 ) {
                                giVT_RealWidth = atoi( val );
@@ -167,9 +165,25 @@ int VT_Install(char **Arguments)
                }
        }
        
+       if(gsVT_OutputDevice)   Modules_InitialiseBuiltin( gsVT_OutputDevice );
+       if(gsVT_InputDevice)    Modules_InitialiseBuiltin( gsVT_InputDevice );
+       
        // Apply Defaults
-       if(!gsVT_OutputDevice)  gsVT_OutputDevice = "/Devices/"DEFAULT_OUTPUT;
-       if(!gsVT_InputDevice)   gsVT_InputDevice = "/Devices/"DEFAULT_INPUT;
+       if(!gsVT_OutputDevice)  gsVT_OutputDevice = DEFAULT_OUTPUT;
+       if(!gsVT_InputDevice)   gsVT_InputDevice = DEFAULT_INPUT;
+       
+       // Create paths
+       {
+               char    *tmp;
+               tmp = malloc( 9 + strlen(gsVT_OutputDevice) + 1 );
+               strcpy(tmp, "/Devices/");
+               strcpy(&tmp[9], gsVT_OutputDevice);
+               gsVT_OutputDevice = tmp;
+               tmp = malloc( 9 + strlen(gsVT_InputDevice) + 1 );
+               strcpy(tmp, "/Devices/");
+               strcpy(&tmp[9], gsVT_InputDevice);
+               gsVT_InputDevice = tmp;
+       }
        
        Log_Log("VTerm", "Using '%s' as output", gsVT_OutputDevice);
        Log_Log("VTerm", "Using '%s' as input", gsVT_InputDevice);
index fb737be..db3f91a 100644 (file)
@@ -113,4 +113,11 @@ typedef struct sModuleLoader
  */
 extern int     Module_RegisterLoader(tModuleLoader *Loader);
 
+/**
+ * \brief Initialise a named builtin module
+ * \param Name Module name to initialise
+ * \return -1 on not existing, 0 if the module initialised (or if it was already initialised)
+ */
+extern int     Modules_InitialiseBuiltin(const char *Name);
+
 #endif
index 586a2e8..88ab367 100644 (file)
@@ -180,6 +180,9 @@ void itoa(char *buf, Uint num, int base, int minLength, char pad)
        if(pos==__maxlen){return pos;}\
        if(__s){__s[pos++]=ch;}else{pos++;}\
        }while(0)
+/**
+ * \brief VArg String Number Print Formatted
+ */
 int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
 {
        char    c, pad = ' ';
index 009ade3..0409711 100644 (file)
@@ -17,7 +17,7 @@ void  Modules_SetBuiltinParams(char *Name, char *ArgString);
  int   Module_LoadMem(void *Buffer, Uint Length, char *ArgString);
  int   Module_LoadFile(char *Path, char *ArgString);
  int   Module_int_ResolveDeps(tModule *Info);
- int   Module_IsLoaded(char *Name);
+ int   Module_IsLoaded(const char *Name);
 
 // === EXPORTS ===
 EXPORT(Module_RegisterLoader);
@@ -252,6 +252,32 @@ void Modules_LoadBuiltins()
                free(gasBuiltinModuleArgs);
 }
 
+/**
+ * \brief Initialise a builtin module given it's name
+ * \example Used by VTerm to load an alternate video driver at runtime
+ */
+int Modules_InitialiseBuiltin(const char *Name)
+{
+        int    i;
+       
+       // Check if it's loaded
+       if( Module_IsLoaded(Name) )
+               return 0;
+       
+       if( !gapBuiltinModules )
+               Modules_int_GetBuiltinArray();
+       
+       for( i = 0; i < giNumBuiltinModules; i++ )
+       {
+               if( strcmp(gapBuiltinModules[i]->Name, Name) == 0 ) {
+                       return Module_int_Initialise(gapBuiltinModules[i],
+                               (gasBuiltinModuleArgs ? gasBuiltinModuleArgs[i] : NULL)
+                               );
+               }
+       }
+       return -1;
+}
+
 /**
  * \brief Sets the parameters for a builtin module
  */
@@ -383,11 +409,11 @@ int Module_int_ResolveDeps(tModule *Info)
 }
 
 /**
- * \fn int Module_IsLoaded(char *Name)
+ * \fn int Module_IsLoaded(const char *Name)
  * \brief Checks if a module is loaded
  * \param Name Name of module to find
  */
-int Module_IsLoaded(char *Name)
+int Module_IsLoaded(const char *Name)
 {
        tModule *mod = gLoadedModules;
        
index f60ea49..641503d 100644 (file)
@@ -4,7 +4,7 @@
 
 CPPFLAGS += 
 CFLAGS  += -Wall -Werror -O3
-LDFLAGS  += 
+LDFLAGS  += -lspiderscript
 
 BIN = ../init
 OBJ = main.o
index d9a3dad..eb2e931 100644 (file)
@@ -2,12 +2,49 @@
  * Acess2 System Init Task
  */
 #include <acess/sys.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <spiderscript.h>
+//#include "common.h"
 
 // === CONSTANTS ===
 #define NULL   ((void*)0)
 #define NUM_TERMS      4
 #define        DEFAULT_TERMINAL        "/Devices/VTerm/0"
 #define DEFAULT_SHELL  "/Acess/SBin/login"
+#define DEFAULT_SCRIPT "/Acess/Conf/BootConf.isc"
+
+#define ARRAY_SIZE(x)  ((sizeof(x))/(sizeof((x)[0])))
+
+// === PROTOTYPES ===
+tSpiderVariable        *Script_System_IO_Open(tSpiderScript *, int, tSpiderVariable *);
+
+// === GLOBALS ===
+tSpiderFunction        gaScriptNS_IO_Fcns[] = {
+       {"Open", Script_System_IO_Open}
+};
+tSpiderNamespace       gaScriptNS_System[] = {
+       {
+               "IO",
+               0, NULL,
+               ARRAY_SIZE(gaScriptNS_IO_Fcns), gaScriptNS_IO_Fcns,
+               0, NULL
+       }
+};
+
+tSpiderNamespace       gaScriptNamespaces[] = {
+       {
+               "System",
+               ARRAY_SIZE(gaScriptNS_System), gaScriptNS_System,
+               0, NULL,
+               0, NULL
+       }
+};
+
+tSpiderVariant gScriptVariant = {
+       "init", 0,
+       ARRAY_SIZE(gaScriptNamespaces), gaScriptNamespaces
+};
 
 // === CODE ===
 /**
@@ -21,6 +58,9 @@ int main(int argc, char *argv[])
        char    termpath[sizeof(DEFAULT_TERMINAL)] = DEFAULT_TERMINAL;
        char    *child_argv[2] = {DEFAULT_SHELL, 0};
        
+       // - Parse init script
+       
+       // - Start virtual terminals
        for( i = 0; i < NUM_TERMS; i++ )
        {               
                tid = clone(CLONE_VM, 0);
@@ -41,3 +81,23 @@ int main(int argc, char *argv[])
        
        return 42;
 }
+
+/**
+ * \brief Reads and parses the boot configuration script
+ * \param Filename     File to parse and execute
+ */
+void ExecuteScript(const char *Filename)
+{
+       tSpiderScript   *script;
+       script = SpiderScript_ParseFile(&gScriptVariant, Filename);
+       SpiderScript_ExecuteMethod(script, "");
+       SpiderScript_Free(script);
+}
+
+/**
+ * \brief Open a file
+ */
+tSpiderVariable        *Script_System_IO_Open(tSpiderScript *Script, int NArgs, tSpiderVariable *Args)
+{
+       return NULL;
+}
index b501b7d..eedd9d3 100644 (file)
@@ -1,6 +1,8 @@
 # Acess 2 SQLite 3 Library
 #
 
+DEPFILES := $(OBJ:%.o=%.d)
+
 .PHONY: all clean install
 
 all: $(BIN)
@@ -12,8 +14,13 @@ install: $(BIN)
        $(xCP) $(BIN) $(DISTROOT)/Libs/
 
 $(BIN): $(OBJ)
-       $(LD) $(LDFLAGS) -o $(BIN) $(OBJ)
+       @echo [LD] -o $(BIN) $(OBJ)
+       @$(LD) $(LDFLAGS) -o $(BIN) $(OBJ)
        @$(OBJDUMP) -d -S $(BIN) > $(BIN).dsm
 
 %.o: %.c
-       $(CC) $(CFLAGS) -o $@ -c $<
+       @echo [CC] -o $@
+       @$(CC) $(CFLAGS) -o $@ -c $<
+       @$(CC) -M -MT $@ $(CPPFLAGS) $< -o $*.d
+
+-include $(DEPFILES)
index 98692b2..e85356d 100644 (file)
@@ -101,6 +101,24 @@ EXPORT char *strdup(const char *str)
        return ret;
 }
 
+/**
+ * \fn EXPORT char *strndup(const char *str, size_t maxlen)
+ * \brief Duplicate a string into the heap with a maximum length
+ * \param str  Input string buffer
+ * \param maxlen       Maximum valid size of the \a str buffer
+ * \return Heap string with the same value of \a str
+ */
+EXPORT char *strndup(const char *str, size_t maxlen)
+{
+       size_t  len;
+       char    *ret;
+       for( len = 0; len < maxlen && str[len]; len ++) ;
+       ret = malloc( len + 1);
+       memcpy( ret, str, len );
+       ret[len] = '\0';
+       return ret;
+}
+
 /**
  * \fn EXPORT char *strchr(char *str, int character)
  * \brief Locate a character in a string
diff --git a/Usermode/Libraries/libspiderscript.so_src/Makefile b/Usermode/Libraries/libspiderscript.so_src/Makefile
new file mode 100644 (file)
index 0000000..fd42a31
--- /dev/null
@@ -0,0 +1,13 @@
+# Acess 2
+#
+
+include ../Makefile.cfg
+
+CPPFLAGS +=
+CFLAGS   += -Wall
+LDFLAGS  += -lc -lgcc -soname libspiderscript.so --no-allow-shlib-undefined
+
+OBJ = main.o lex.o parse.o ast.o exec_ast.o
+BIN = ../libspiderscript.so
+
+include ../Makefile.tpl
diff --git a/Usermode/Libraries/libspiderscript.so_src/ast.c b/Usermode/Libraries/libspiderscript.so_src/ast.c
new file mode 100644 (file)
index 0000000..e0e1e37
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Acess2 Init
+ * - Script AST Manipulator
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "ast.h"
+
+// === CODE ===
+tAST_Script *AST_NewScript(void)
+{
+       tAST_Script     *ret = malloc( sizeof(tAST_Script) );
+       
+       ret->Functions = NULL;
+       ret->LastFunction = NULL;
+       
+       return ret;
+}
+
+/**
+ * \brief Append a function to a script
+ */
+tAST_Function *AST_AppendFunction(tAST_Script *Script, const char *Name)
+{
+       tAST_Function   *ret;
+       
+       ret = malloc( sizeof(tAST_Function) );
+       ret->Next = NULL;
+       ret->Name = strdup(Name);
+       ret->Code = NULL;
+       ret->Arguments = NULL;
+       
+       if(Script->LastFunction == NULL) {
+               Script->Functions = Script->LastFunction = ret;
+       }
+       else {
+               Script->LastFunction->Next = ret;
+               Script->LastFunction = ret;
+       }
+       
+       return ret;
+}
+
+void AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root)
+{
+       Function->Code = Root;
+}
+
+/**
+ * \name Node Manipulation
+ * \{
+ */
+void AST_FreeNode(tAST_Node *Node)
+{
+       tAST_Node       *node;
+       switch(Node->Type)
+       {
+       // Block of code
+       case NODETYPE_BLOCK:
+               for( node = Node->Block.FirstChild; node; )
+               {
+                       tAST_Node       *savedNext = node->NextSibling;
+                       AST_FreeNode(node);
+                       node = savedNext;
+               }
+               break;
+       
+       // Function Call
+       case NODETYPE_FUNCTIONCALL:
+               for( node = Node->FunctionCall.FirstArg; node; )
+               {
+                       tAST_Node       *savedNext = node->NextSibling;
+                       AST_FreeNode(node);
+                       node = savedNext;
+               }
+               break;
+       
+       // Asignment
+       case NODETYPE_ASSIGN:
+               AST_FreeNode(Node->Assign.Dest);
+               AST_FreeNode(Node->Assign.Value);
+               break;
+       
+       // Unary Operations
+       case NODETYPE_RETURN:
+               AST_FreeNode(Node->UniOp.Value);
+               break;
+       
+       // Binary Operations
+       case NODETYPE_ADD:
+       case NODETYPE_SUBTRACT:
+       case NODETYPE_MULTIPLY:
+       case NODETYPE_DIVIDE:
+       case NODETYPE_MODULO:
+       case NODETYPE_BITSHIFTLEFT:
+       case NODETYPE_BITSHIFTRIGHT:
+       case NODETYPE_BITROTATELEFT:
+       case NODETYPE_BWAND:    case NODETYPE_LOGICALAND:
+       case NODETYPE_BWOR:     case NODETYPE_LOGICALOR:
+       case NODETYPE_BWXOR:    case NODETYPE_LOGICALXOR:
+       case NODETYPE_EQUALS:
+       case NODETYPE_LESSTHAN:
+       case NODETYPE_GREATERTHAN:
+               AST_FreeNode( Node->BinOp.Left );
+               AST_FreeNode( Node->BinOp.Right );
+               break;
+       
+       // Node types with no children
+       case NODETYPE_NOP:      break;
+       case NODETYPE_VARIABLE: break;
+       case NODETYPE_CONSTANT: break;
+       case NODETYPE_STRING:   break;
+       case NODETYPE_INTEGER:  break;
+       case NODETYPE_REAL:     break;
+       }
+       free( Node );
+}
+
+tAST_Node *AST_NewCodeBlock(void)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) );
+       
+       ret->NextSibling = NULL;
+       ret->Type = NODETYPE_BLOCK;
+       ret->Block.FirstChild = NULL;
+       ret->Block.LastChild = NULL;
+       
+       return ret;
+}
+
+void AST_AppendNode(tAST_Node *Parent, tAST_Node *Child)
+{
+       if(Parent->Type != NODETYPE_BLOCK)      return ;
+       
+       if(Parent->Block.FirstChild == NULL) {
+               Parent->Block.FirstChild = Parent->Block.LastChild = Child;
+       }
+       else {
+               Parent->Block.LastChild->NextSibling = Child;
+               Parent->Block.LastChild = Child;
+       }
+}
+
+tAST_Node *AST_NewAssign(int Operation, tAST_Node *Dest, tAST_Node *Value)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) );
+       
+       ret->NextSibling = NULL;
+       ret->Type = NODETYPE_ASSIGN;
+       ret->Assign.Operation = Operation;
+       ret->Assign.Dest = Dest;
+       ret->Assign.Value = Value;
+       
+       return ret;
+}
+
+tAST_Node *AST_NewBinOp(int Operation, tAST_Node *Left, tAST_Node *Right)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) );
+       
+       ret->NextSibling = NULL;
+       ret->Type = Operation;
+       ret->BinOp.Left = Left;
+       ret->BinOp.Right = Right;
+       
+       return ret;
+}
+
+/**
+ * \brief Create a new string node
+ */
+tAST_Node *AST_NewString(const char *String, int Length)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) + Length + 1 );
+       
+       ret->NextSibling = NULL;
+       ret->Type = NODETYPE_STRING;
+       ret->String.Length = Length;
+       memcpy(ret->String.Data, String, Length);
+       ret->String.Data[Length] = '\0';
+       
+       return ret;
+}
+
+/**
+ * \brief Create a new integer node
+ */
+tAST_Node *AST_NewInteger(uint64_t Value)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) );
+       ret->NextSibling = NULL;
+       ret->Type = NODETYPE_INTEGER;
+       ret->Integer = Value;
+       return ret;
+}
+
+/**
+ * \brief Create a new variable reference node
+ */
+tAST_Node *AST_NewVariable(const char *Name)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) + strlen(Name) + 1 );
+       ret->NextSibling = NULL;
+       ret->Type = NODETYPE_VARIABLE;
+       strcpy(ret->Variable.Name, Name);
+       return ret;
+}
+
+/**
+ * \brief Create a new runtime constant reference node
+ */
+tAST_Node *AST_NewConstant(const char *Name)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) + strlen(Name) + 1 );
+       ret->NextSibling = NULL;
+       ret->Type = NODETYPE_CONSTANT;
+       strcpy(ret->Variable.Name, Name);
+       return ret;
+}
+
+/**
+ * \brief Create a function call node
+ * \note Argument list is manipulated using AST_AppendFunctionCallArg
+ */
+tAST_Node *AST_NewFunctionCall(const char *Name)
+{
+       tAST_Node       *ret = malloc( sizeof(tAST_Node) + strlen(Name) + 1 );
+       
+       ret->NextSibling = NULL;
+       ret->Type = NODETYPE_FUNCTIONCALL;
+       ret->FunctionCall.FirstArg = NULL;
+       ret->FunctionCall.LastArg = NULL;
+       strcpy(ret->FunctionCall.Name, Name);
+       return ret;
+}
+
+/**
+ * \brief Append an argument to a function call
+ */
+void AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg)
+{
+       if( Node->Type != NODETYPE_FUNCTIONCALL )       return ;
+       
+       if(Node->FunctionCall.LastArg) {
+               Node->FunctionCall.LastArg->NextSibling = Arg;
+               Node->FunctionCall.LastArg = Arg;
+       }
+       else {
+               Node->FunctionCall.FirstArg = Arg;
+               Node->FunctionCall.LastArg = Arg;
+       }
+}
+
+/**
+ * \}
+ */
diff --git a/Usermode/Libraries/libspiderscript.so_src/ast.h b/Usermode/Libraries/libspiderscript.so_src/ast.h
new file mode 100644 (file)
index 0000000..820167b
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ */
+#ifndef _AST_H_
+#define _AST_H_
+
+#include <spiderscript.h>
+
+typedef struct sAST_Script     tAST_Script;
+typedef struct sAST_Function   tAST_Function;
+typedef struct sAST_Node       tAST_Node;
+typedef enum eAST_NodeTypes    tAST_NodeType;
+
+/**
+ * \brief Node Types
+ */
+enum eAST_NodeTypes
+{
+       NODETYPE_NOP,
+       
+       NODETYPE_BLOCK, //!< Node Block
+       
+       NODETYPE_VARIABLE,      //!< Variable
+       NODETYPE_CONSTANT,      //!< Runtime Constant
+       NODETYPE_STRING,        //!< String Constant
+       NODETYPE_INTEGER,       //!< Integer Constant
+       NODETYPE_REAL,  //!< Real Constant
+       
+       NODETYPE_RETURN,        //!< Return from a function (reserved word)
+       NODETYPE_ASSIGN,        //!< Variable assignment operator
+       NODETYPE_FUNCTIONCALL,  //!< Call a function
+       
+       NODETYPE_LOGICALAND,    //!< Logical AND operator
+       NODETYPE_LOGICALOR,     //!< Logical OR operator
+       NODETYPE_LOGICALXOR,    //!< Logical XOR operator
+       
+       NODETYPE_EQUALS,        //!< Comparison Equals
+       NODETYPE_LESSTHAN,      //!< Comparison Less Than
+       NODETYPE_GREATERTHAN,   //!< Comparison Greater Than
+       
+       NODETYPE_BWAND, //!< Bitwise AND
+       NODETYPE_BWOR,  //!< Bitwise OR
+       NODETYPE_BWXOR, //!< Bitwise XOR
+       
+       NODETYPE_BITSHIFTLEFT,  //!< Bitwise Shift Left (Grow)
+       NODETYPE_BITSHIFTRIGHT, //!< Bitwise Shift Right (Shrink)
+       NODETYPE_BITROTATELEFT, //!< Bitwise Rotate Left (Grow)
+       
+       NODETYPE_ADD,   //!< Add
+       NODETYPE_SUBTRACT,      //!< Subtract
+       NODETYPE_MULTIPLY,      //!< Multiply
+       NODETYPE_DIVIDE,        //!< Divide
+       NODETYPE_MODULO,        //!< Modulus
+};
+
+struct sSpiderScript
+{
+       tSpiderVariant  *Variant;
+       tAST_Script     *Script;
+};
+
+struct sAST_Script
+{
+       tAST_Function   *Functions;
+       tAST_Function   *LastFunction;
+};
+
+struct sAST_Function
+{
+       tAST_Function   *Next;
+       char    *Name;
+       tAST_Node       *Code;
+       tAST_Node       *Arguments;     // HACKJOB (Only NODETYPE_VARIABLE is allowed)
+};
+
+struct sAST_Node
+{
+       tAST_Node       *NextSibling;
+       tAST_NodeType   Type;
+       
+       union
+       {
+               struct {
+                       tAST_Node       *FirstChild;
+                       tAST_Node       *LastChild;
+               }       Block;
+               
+               struct {
+                        int    Operation;
+                       tAST_Node       *Dest;
+                       tAST_Node       *Value;
+               }       Assign;
+               
+               struct {
+                       tAST_Node       *Value;
+               }       UniOp;
+               
+               struct {
+                       tAST_Node       *Left;
+                       tAST_Node       *Right;
+               }       BinOp;
+               
+               struct {
+                        int    Length;
+                       char    Data[];
+               }       String;
+               
+               struct {
+                       tAST_Node       *FirstArg;
+                       tAST_Node       *LastArg;
+                       char    Name[];
+               }       FunctionCall;
+               
+               /**
+                * \note Used for \a NODETYPE_VARIABLE and \a NODETYPE_CONSTANT
+                */
+               struct {
+                       char    _unused;        // Shut GCC up
+                       char    Name[];
+               }       Variable;
+               
+               uint64_t        Integer;
+               double  Real;
+       };
+};
+
+// === FUNCTIONS ===
+tAST_Script    *AST_NewScript(void);
+
+tAST_Function  *AST_AppendFunction(tAST_Script *Script, const char *Name);
+void   AST_AppendFunctionArg(tAST_Function *Function, int Type, tAST_Node *Arg);
+void   AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root);
+
+tAST_Node      *AST_NewString(const char *String, int Length);
+tAST_Node      *AST_NewInteger(uint64_t Value);
+tAST_Node      *AST_NewVariable(const char *Name);
+tAST_Node      *AST_NewConstant(const char *Name);
+tAST_Node      *AST_NewFunctionCall(const char *Name);
+void   AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg);
+
+tAST_Node      *AST_NewCodeBlock(void);
+void   AST_AppendNode(tAST_Node *Parent, tAST_Node *Child);
+tAST_Node      *AST_NewAssign(int Operation, tAST_Node *Dest, tAST_Node *Value);
+tAST_Node      *AST_NewBinOp(int Operation, tAST_Node *Left, tAST_Node *Right);
+
+void   AST_FreeNode(tAST_Node *Node);
+
+tSpiderVariable        *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node);
+
+#endif
diff --git a/Usermode/Libraries/libspiderscript.so_src/bytecode.h b/Usermode/Libraries/libspiderscript.so_src/bytecode.h
new file mode 100644 (file)
index 0000000..bff4cae
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * SpiderScript
+ * - Bytecode definitions
+ */
+#ifndef _BYTECODE_H_
+#define _BYTECODE_H_
+
+struct sBytecodeHeader
+{
+       uint32_t        Magic;  //!< Magic Value (identifier) "\x8FSS\r"
+       uint32_t        NFunctions;     //!< Number of functions
+       struct {
+               uint32_t        NameOffset;     //!< Offset to the name 
+               uint32_t        CodeOffset;     //!< Offset to the code
+       }       Functions[];
+};
+
+enum eBytecodeOperations
+{
+       BCOP_UNDEF,
+       BCOP_NOP,
+       
+       BCOP_DEFVAR,
+       BCOP_RETURN,
+       
+       NUM_BCOP
+}
+
+#endif
diff --git a/Usermode/Libraries/libspiderscript.so_src/exec_ast.c b/Usermode/Libraries/libspiderscript.so_src/exec_ast.c
new file mode 100644 (file)
index 0000000..90045bc
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "ast.h"
+
+#define ERRPTR ((void*)((intptr_t)0-1))
+
+// === PROTOTYPES ===
+void   Object_Dereference(tSpiderVariable *Object);
+void   Object_Reference(tSpiderVariable *Object);
+tSpiderVariable        *Object_CreateInteger(uint64_t Value);
+tSpiderVariable        *Object_CreateReal(double Value);
+tSpiderVariable        *Object_CreateString(int Length, const char *Data);
+tSpiderVariable        *Object_CastTo(int Type, tSpiderVariable *Source);
+ int   Object_IsTrue(tSpiderVariable *Value);
+
+void   Variable_SetValue(tSpiderScript *Script, const char *Name, tSpiderVariable *Value);
+tSpiderVariable        *Variable_GetValue(tSpiderScript *Script, const char *Name);
+
+// === CODE ===
+/**
+ * \brief Dereference a created object
+ */
+void Object_Dereference(tSpiderVariable *Object)
+{
+       Object->ReferenceCount --;
+       if( Object->ReferenceCount == 0 )       free(Object);
+}
+
+void Object_Reference(tSpiderVariable *Object)
+{
+       Object->ReferenceCount ++;
+}
+
+/**
+ * \brief Create an integer object
+ */
+tSpiderVariable        *Object_CreateInteger(uint64_t Value)
+{
+       tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) );
+       ret->Type = SS_DATATYPE_INTEGER;
+       ret->ReferenceCount = 1;
+       ret->Integer = Value;
+       return ret;
+}
+
+/**
+ * \brief Create an real number object
+ */
+tSpiderVariable        *Object_CreateReal(double Value)
+{
+       tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) );
+       ret->Type = SS_DATATYPE_REAL;
+       ret->ReferenceCount = 1;
+       ret->Real = Value;
+       return ret;
+}
+
+/**
+ * \brief Create an string object
+ */
+tSpiderVariable        *Object_CreateString(int Length, const char *Data)
+{
+       tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) + Length + 1 );
+       ret->Type = SS_DATATYPE_STRING;
+       ret->ReferenceCount = 1;
+       ret->String.Length = Length;
+       memcpy(ret->String.Data, Data, Length);
+       ret->String.Data[Length] = '\0';
+       return ret;
+}
+
+/**
+ */
+tSpiderVariable        *Object_CastTo(int Type, tSpiderVariable *Source)
+{
+       tSpiderVariable *ret;
+       // Check if anything needs to be done
+       if( Source->Type == Type ) {
+               Object_Reference(Source);
+               return Source;
+       }
+       
+       switch(Type)
+       {
+       case SS_DATATYPE_UNDEF:
+       case SS_DATATYPE_NULL:
+       case SS_DATATYPE_ARRAY:
+               fprintf(stderr, "Object_CastTo - Invalid cast to %i\n", Type);
+               return ERRPTR;
+       
+       case SS_DATATYPE_INTEGER:
+               ret = malloc(sizeof(tSpiderVariable));
+               ret->Type = SS_DATATYPE_INTEGER;
+               ret->ReferenceCount = 1;
+               switch(Source->Type)
+               {
+               case SS_DATATYPE_INTEGER:       break;  // Handled above
+               case SS_DATATYPE_STRING:        ret->Integer = atoi(Source->String.Data);       break;
+               case SS_DATATYPE_REAL:  ret->Integer = Source->Real;    break;
+               default:
+                       fprintf(stderr, "Object_CastTo - Invalid cast from %i\n", Source->Type);
+                       break;
+               }
+               break;
+       }
+       
+       return ret;
+}
+
+/**
+ * \brief Condenses a value down to a boolean
+ */
+int Object_IsTrue(tSpiderVariable *Value)
+{
+       switch(Value->Type)
+       {
+       case SS_DATATYPE_UNDEF:
+       case SS_DATATYPE_NULL:
+               return 0;
+       
+       case SS_DATATYPE_INTEGER:
+               return !!Value->Integer;
+       
+       case SS_DATATYPE_REAL:
+               return (-.5f < Value->Real && Value->Real < 0.5f);
+       
+       case SS_DATATYPE_STRING:
+               return Value->String.Length > 0;
+       
+       case SS_DATATYPE_OBJECT:
+               return Value->Object != NULL;
+       
+       case SS_DATATYPE_ARRAY:
+               return Value->Array.Length > 0;
+       }
+       return 0;
+}
+
+tSpiderVariable *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node)
+{
+       tAST_Node       *node;
+       tSpiderVariable *ret, *tmpvar;
+       tSpiderVariable *op1, *op2;     // Binary operations
+        int    cmp;    // Used in comparisons
+       
+       switch(Node->Type)
+       {
+       // No Operation
+       case NODETYPE_NOP:      ret = NULL;     break ;
+       
+       // Code block
+       case NODETYPE_BLOCK:
+               ret = NULL;
+               for(node = Node->Block.FirstChild; node; node = node->NextSibling )
+               {
+                       if(node->Type == NODETYPE_RETURN) {
+                               ret = AST_ExecuteNode(Script, node);
+                               break ;
+                       }
+                       else {
+                               tmpvar = AST_ExecuteNode(Script, node);
+                               if(tmpvar == ERRPTR)    return ERRPTR;  // Error check
+                               if(tmpvar)      Object_Dereference(tmpvar);     // Free unused value
+                       }
+               }
+               break;
+       
+       // Assignment
+       case NODETYPE_ASSIGN:
+               if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
+                       fprintf(stderr, "Syntax error: LVALUE of assignment is not a variable\n");
+                       return ERRPTR;
+               }
+               ret = AST_ExecuteNode(Script, Node->Assign.Value);
+               // TODO: Apply operation
+               Variable_SetValue( Script, Node->Assign.Dest->Variable.Name, ret );
+               break;
+       
+       case NODETYPE_FUNCTIONCALL:
+               // TODO: Find a function from the export list in variant
+               //SpiderScript_ExecuteMethod(Script, Node->FunctionCall.Name
+               ret = ERRPTR;
+               fprintf(stderr, "TODO: Implement function calls\n");
+               break;
+       
+       // Return's special handling happens elsewhere
+       case NODETYPE_RETURN:
+               ret = AST_ExecuteNode(Script, Node->UniOp.Value);
+               break;
+       
+       // Variable
+       case NODETYPE_VARIABLE: ret = Variable_GetValue( Script, Node->Variable.Name ); break;
+       
+       // TODO: Implement runtime constants
+       case NODETYPE_CONSTANT: ret = ERRPTR;   break;
+       // Constant Values
+       case NODETYPE_STRING:   ret = Object_CreateString( Node->String.Length, Node->String.Data );    break;
+       case NODETYPE_INTEGER:  ret = Object_CreateInteger( Node->Integer );    break;
+       case NODETYPE_REAL:     ret = Object_CreateReal( Node->Real );  break;
+       
+       // --- Operations ---
+       // Boolean Operations
+       case NODETYPE_LOGICALAND:       // Logical AND (&&)
+       case NODETYPE_LOGICALOR:        // Logical OR (||)
+       case NODETYPE_LOGICALXOR:       // Logical XOR (^^)
+               op1 = AST_ExecuteNode(Script, Node->BinOp.Left);
+               op2 = AST_ExecuteNode(Script, Node->BinOp.Right);
+               switch( Node->Type )
+               {
+               case NODETYPE_LOGICALAND:
+                       ret = Object_CreateInteger( Object_IsTrue(op1) && Object_IsTrue(op2) );
+                       break;
+               case NODETYPE_LOGICALOR:
+                       ret = Object_CreateInteger( Object_IsTrue(op1) || Object_IsTrue(op2) );
+                       break;
+               case NODETYPE_LOGICALXOR:
+                       ret = Object_CreateInteger( Object_IsTrue(op1) ^ Object_IsTrue(op2) );
+                       break;
+               default:        break;
+               }
+               break;
+       
+       // Comparisons
+       case NODETYPE_EQUALS:
+       case NODETYPE_LESSTHAN:
+       case NODETYPE_GREATERTHAN:
+               op1 = AST_ExecuteNode(Script, Node->BinOp.Left);
+               op2 = AST_ExecuteNode(Script, Node->BinOp.Right);
+               
+               // No conversion done for NULL
+               // TODO: Determine if this will ever be needed
+               if( op1->Type == SS_DATATYPE_NULL )
+               {
+                       // NULLs always typecheck
+                       ret = Object_CreateInteger(op2->Type == SS_DATATYPE_NULL);
+                       break;
+               }
+               
+               // Convert types
+               if( op1->Type != op2->Type ) {
+                       // If dynamically typed, convert op2 to op1's type
+                       if(Script->Variant->bDyamicTyped)
+                       {
+                               tmpvar = op2;
+                               op2 = Object_CastTo(op1->Type, op2);
+                               Object_Dereference(tmpvar);
+                       }
+                       // If statically typed, this should never happen, but catch it anyway
+                       else {
+                               ret = ERRPTR;
+                               break;
+                       }
+               }
+               // Do operation
+               switch(op1->Type)
+               {
+               // - NULL
+               case SS_DATATYPE_NULL:  break;
+               // - String Compare (does a strcmp, well memcmp)
+               case SS_DATATYPE_STRING:
+                       // Call memcmp to do most of the work
+                       cmp = memcmp(
+                               op1->String.Data, op2->String.Data,
+                               (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
+                               );
+                       // Handle reaching the end of the string
+                       if( cmp == 0 ) {
+                               if( op1->String.Length == op2->String.Length )
+                                       cmp = 0;
+                               else if( op1->String.Length < op2->String.Length )
+                                       cmp = 1;
+                               else
+                                       cmp = -1;
+                       }
+                       break;
+               }
+               
+               // Free intermediate objects
+               Object_Dereference(op1);
+               Object_Dereference(op2);
+               
+               // Create return
+               switch(Node->Type)
+               {
+               case NODETYPE_EQUALS:   ret = Object_CreateInteger(cmp == 0);   break;
+               case NODETYPE_LESSTHAN: ret = Object_CreateInteger(cmp < 0);    break;
+               case NODETYPE_GREATERTHAN:      ret = Object_CreateInteger(cmp > 0);    break;
+               default:
+                       fprintf(stderr, "SpiderScript internal error: Exec,CmpOp unknown op %i", Node->Type);
+                       ret = ERRPTR;
+                       break;
+               }
+               break;
+       
+       // General Binary Operations
+       case NODETYPE_ADD:
+       case NODETYPE_SUBTRACT:
+       case NODETYPE_MULTIPLY:
+       case NODETYPE_DIVIDE:
+       case NODETYPE_MODULO:
+       case NODETYPE_BWAND:
+       case NODETYPE_BWOR:
+       case NODETYPE_BWXOR:
+       case NODETYPE_BITSHIFTLEFT:
+       case NODETYPE_BITSHIFTRIGHT:
+       case NODETYPE_BITROTATELEFT:
+               // Get operands
+               op1 = AST_ExecuteNode(Script, Node->BinOp.Left);
+               op2 = AST_ExecuteNode(Script, Node->BinOp.Right);
+               
+               // Convert types
+               if( op1->Type != op2->Type ) {
+                       // If dynamically typed, convert op2 to op1's type
+                       if(Script->Variant->bDyamicTyped)
+                       {
+                               tmpvar = op2;
+                               op2 = Object_CastTo(op1->Type, op2);
+                               Object_Dereference(tmpvar);
+                       }
+                       // If statically typed, this should never happen, but catch it anyway
+                       else {
+                               ret = ERRPTR;
+                               break;
+                       }
+               }
+               
+               // Do operation
+               switch(op1->Type)
+               {
+               case SS_DATATYPE_NULL:  break;
+               // String Concatenation
+               case SS_DATATYPE_STRING:
+                       switch(Node->Type)
+                       {
+                       default:
+                               fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Node->Type);
+                               ret = ERRPTR;
+                               break;
+                       }
+                       break;
+               case SS_DATATYPE_INTEGER:
+                       switch(Node->Type)
+                       {
+                       case NODETYPE_ADD:      ret = Object_CreateInteger( op1->Integer + op2->Integer );      break;
+                       case NODETYPE_SUBTRACT: ret = Object_CreateInteger( op1->Integer - op2->Integer );      break;
+                       case NODETYPE_MULTIPLY: ret = Object_CreateInteger( op1->Integer * op2->Integer );      break;
+                       case NODETYPE_DIVIDE:   ret = Object_CreateInteger( op1->Integer / op2->Integer );      break;
+                       case NODETYPE_MODULO:   ret = Object_CreateInteger( op1->Integer % op2->Integer );      break;
+                       case NODETYPE_BWAND:    ret = Object_CreateInteger( op1->Integer & op2->Integer );      break;
+                       case NODETYPE_BWOR:     ret = Object_CreateInteger( op1->Integer | op2->Integer );      break;
+                       case NODETYPE_BWXOR:    ret = Object_CreateInteger( op1->Integer ^ op2->Integer );      break;
+                       case NODETYPE_BITSHIFTLEFT:     ret = Object_CreateInteger( op1->Integer << op2->Integer );     break;
+                       case NODETYPE_BITSHIFTRIGHT:ret = Object_CreateInteger( op1->Integer >> op2->Integer ); break;
+                       case NODETYPE_BITROTATELEFT:
+                               ret = Object_CreateInteger( (op1->Integer << op2->Integer) | (op1->Integer >> (64-op2->Integer)) );
+                               break;
+                       default:
+                               fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Node->Type);
+                               ret = ERRPTR;
+                               break;
+                       }
+                       break;
+               }
+               
+               // Free intermediate objects
+               Object_Dereference(op1);
+               Object_Dereference(op2);
+               break;
+       
+       //default:
+       //      ret = NULL;
+       //      fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
+       //      break;
+       }
+       return ret;
+}
diff --git a/Usermode/Libraries/libspiderscript.so_src/lex.c b/Usermode/Libraries/libspiderscript.so_src/lex.c
new file mode 100644 (file)
index 0000000..6badd45
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Acess2 init
+ * - Script Lexer
+ */
+#include "tokens.h"
+#include <stdlib.h>
+
+// === PROTOTYPES ===
+ int   is_ident(char ch);
+ int   isdigit(char ch);
+ int   isspace(char ch);
+ int   GetToken(tParser *File);
+
+// === CONSTANTS ===
+const struct {
+       const  int      Value;
+       const char      *Name;
+} csaReservedWords[] = {
+       {TOK_RWD_FUNCTION, "function"},
+       {TOK_RWD_INTEGER, "integer"},
+       {TOK_RWD_REAL, "string"}
+};
+
+// === CODE ===
+/**
+ * \brief Read a token from a buffer
+ * \param File Parser state
+ */
+int GetToken(tParser *File)
+{
+        int    ret;
+       
+       if( File->NextToken != -1 ) {
+               File->Token = File->NextToken;
+               File->TokenStr = File->NextTokenStr;
+               File->TokenLen = File->NextTokenLen;
+               File->NextToken = -1;
+               return File->Token;
+       }
+       
+       // Clear whitespace (including comments)
+       for( ;; )
+       {
+               // Whitespace
+               while( isspace( *File->CurPos ) )
+                       File->CurPos ++;
+               
+               // # Line Comments
+               if( *File->CurPos == '#' ) {
+                       while( *File->CurPos && *File->CurPos != '\n' )
+                               File->CurPos ++;
+                       continue ;
+               }
+               
+               // C-Style Line Comments
+               if( *File->CurPos == '/' && File->CurPos[1] == '/' ) {
+                       while( *File->CurPos && *File->CurPos != '\n' )
+                               File->CurPos ++;
+                       continue ;
+               }
+               
+               // C-Style Block Comments
+               if( *File->CurPos == '/' && File->CurPos[1] == '*' ) {
+                       File->CurPos += 2;
+                       while( *File->CurPos && !(File->CurPos[-1] == '*' && *File->CurPos == '/') )
+                               File->CurPos ++;
+                       continue ;
+               }
+               
+               // No more "whitespace"
+               break;
+       }
+       
+       // Save previous tokens (speeds up PutBack and LookAhead)
+       File->LastToken = File->Token;
+       File->LastTokenStr = File->TokenStr;
+       File->LastTokenLen = File->TokenLen;
+       
+       // Read token
+       File->TokenStr = File->CurPos;
+       switch( *File->CurPos++ )
+       {
+       // Operations
+       case '/':       ret = TOK_DIV;  break;
+       case '*':       ret = TOK_MUL;  break;
+       case '+':       ret = TOK_PLUS; break;
+       case '-':
+               if( *File->CurPos == '>' ) {
+                       File->CurPos ++;
+                       ret = TOK_ELEMENT;
+               }
+               else
+                       ret = TOK_MINUS;
+               break;
+       
+       // Strings
+       case '"':
+               File->TokenStr ++;
+               while( *File->CurPos && !(*File->CurPos == '"' && *File->CurPos != '\\') )
+                       File->CurPos ++;
+               ret = TOK_STR;
+               break;
+       
+       // Brackets
+       case '(':       ret = TOK_PAREN_OPEN;   break;
+       case ')':       ret = TOK_PAREN_CLOSE;  break;
+       case '{':       ret = TOK_BRACE_OPEN;   break;
+       case '}':       ret = TOK_BRACE_CLOSE;  break;
+       case '[':       ret = TOK_SQUARE_OPEN;  break;
+       case ']':       ret = TOK_SQUARE_CLOSE; break;
+       
+       // Core symbols
+       case ';':       ret = TOK_SEMICOLON;    break;
+       case '.':       ret = TOK_SCOPE;        break;
+       
+       // Equals
+       case '=':
+               // Comparison Equals
+               if( *File->CurPos == '=' ) {
+                       File->CurPos ++;
+                       ret = TOK_EQUALS;
+                       break;
+               }
+               // Assignment Equals
+               ret = TOK_ASSIGN;
+               break;
+       
+       // Variables
+       // \$[0-9]+ or \$[_a-zA-Z][_a-zA-Z0-9]*
+       case '$':
+               File->TokenStr ++;
+               // Numeric Variable
+               if( isdigit( *File->CurPos ) ) {
+                       while( isdigit(*File->CurPos) )
+                               File->CurPos ++;
+               }
+               // Ident Variable
+               else {
+                       while( is_ident(*File->CurPos) )
+                               File->CurPos ++;
+               }
+               ret = TOK_VARIABLE;
+               break;
+       
+       // Default (Numbers and Identifiers)
+       default:
+               // Numbers
+               if( isdigit(*File->CurPos) )
+               {
+                       while( isdigit(*File->CurPos) )
+                               File->CurPos ++;
+                       ret = TOK_INTEGER;
+                       break;
+               }
+       
+               // Identifier
+               if( is_ident(*File->CurPos) )
+               {
+                       // Identifier
+                       while( is_ident(*File->CurPos) || isdigit(*File->CurPos) )
+                               File->CurPos ++;
+                       
+                       ret = TOK_IDENT;
+                       break;
+               }
+               // Syntax Error
+               ret = 0;
+               break;
+       }
+       // Return
+       File->Token = ret;
+       File->TokenLen = File->CurPos - File->TokenStr;
+       return ret;
+}
+
+void PutBack(tParser *File)
+{
+       if( File->LastToken == -1 ) {
+               // ERROR:
+               return ;
+       }
+       // Save
+       File->NextToken = File->Token;
+       File->NextTokenStr = File->TokenStr;
+       File->NextTokenLen = File->TokenLen;
+       // Restore
+       File->Token = File->LastToken;
+       File->TokenStr = File->LastTokenStr;
+       File->TokenLen = File->LastTokenLen;
+       File->CurPos = File->NextTokenStr;
+       // Invalidate
+       File->LastToken = -1;
+}
+
+int LookAhead(tParser *File)
+{
+        int    ret = GetToken(File);
+       PutBack(File);
+       return ret;
+}
+
+// --- Helpers ---
+/**
+ * \brief Check for ident characters
+ * \note Matches Regex [a-zA-Z_]
+ */
+int is_ident(char ch)
+{
+       if('a' <= ch && ch <= 'z')      return 1;
+       if('Z' <= ch && ch <= 'Z')      return 1;
+       if(ch == '_')   return 1;
+       if(ch < 0)      return 1;
+       return 0;
+}
+
+int isdigit(char ch)
+{
+       if('0' <= ch && ch <= '9')      return 1;
+       return 0;
+}
+
+int isspace(char ch)
+{
+       if(' ' == ch)   return 1;
+       if('\t' == ch)  return 1;
+       if('\b' == ch)  return 1;
+       if('\n' == ch)  return 1;
+       if('\r' == ch)  return 1;
+       return 0;
+}
diff --git a/Usermode/Libraries/libspiderscript.so_src/main.c b/Usermode/Libraries/libspiderscript.so_src/main.c
new file mode 100644 (file)
index 0000000..ce39c08
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Acess2 - SpiderScript
+ * Interpreter Library
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <spiderscript.h>
+#include "ast.h"
+
+// === IMPORTS ===
+extern tAST_Script     *Parse_Buffer(tSpiderVariant *Variant, char *Buffer);
+
+// === CODE ===
+/**
+ * \brief Library Entry Point
+ */
+int SoMain()
+{
+       return 0;
+}
+
+/**
+ * \brief Parse a script
+ */
+tSpiderScript *SpiderScript_ParseFile(tSpiderVariant *Variant, const char *Filename)
+{
+       char    *data;
+        int    fLen;
+       FILE    *fp;
+       tSpiderScript   *ret;
+       
+       fp = fopen(Filename, "r");
+       if( !fp ) {
+               return NULL;
+       }
+       
+       ret = malloc(sizeof(tSpiderScript));
+       ret->Variant = Variant;
+       
+       fseek(fp, 0, SEEK_END);
+       fLen = ftell(fp);
+       fseek(fp, 0, SEEK_SET);
+       
+       data = malloc(fLen);
+       if(!data)       return NULL;
+       fread(data, fLen, 1, fp);
+       
+       fclose(fp);
+       
+       ret->Script = Parse_Buffer(Variant, data);
+       
+       free(data);
+       
+       return ret;
+}
+
+/**
+ * \brief Execute a script function
+ * \todo Arguments?
+ */
+tSpiderVariable *SpiderScript_ExecuteMethod(tSpiderScript *Script, const char *Function)
+{
+       tAST_Function   *fcn = Script->Script->Functions;
+       
+       // Find the function
+       for( ; fcn; fcn = fcn->Next ) {
+               if( strcmp(fcn->Name, Function) == 0 )
+                       break;
+       }
+       if(!fcn)        return NULL;
+       
+       // Execute!
+       return AST_ExecuteNode(Script, fcn->Code);
+}
+
+/**
+ * \brief Free a script
+ */
+void SpiderScript_Free(tSpiderScript *Script)
+{
+       tAST_Function   *fcn = Script->Script->Functions;
+       tAST_Function   *nextFcn;
+       tAST_Node       *var, *nextVar;
+       
+       // Free functions
+       while(fcn) {
+               AST_FreeNode( fcn->Code );
+               
+               var = fcn->Arguments;
+               while(var)
+               {
+                       nextVar = var->NextSibling;
+                       AST_FreeNode( var );
+                       var = nextVar;
+               }
+               
+               nextFcn = fcn->Next;
+               free( fcn );
+               fcn = nextFcn;
+       }
+}
diff --git a/Usermode/Libraries/libspiderscript.so_src/parse.c b/Usermode/Libraries/libspiderscript.so_src/parse.c
new file mode 100644 (file)
index 0000000..2ccf5d8
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * Acess2 - SpiderScript
+ * - Parser
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <spiderscript.h>
+#include "tokens.h"
+#include "ast.h"
+
+// === PROTOTYPES ===
+tAST_Script    *Parse_Buffer(tSpiderVariant *Variant, char *Buffer);
+tAST_Node      *Parse_DoCodeBlock(tParser *Parser);
+tAST_Node      *Parse_DoExpr(tParser *Parser);
+
+tAST_Node      *Parse_DoExpr0(tParser *Parser);        // Assignment
+tAST_Node      *Parse_DoExpr1(tParser *Parser);        // Boolean Operators
+tAST_Node      *Parse_DoExpr2(tParser *Parser);        // Comparison Operators
+tAST_Node      *Parse_DoExpr3(tParser *Parser);        // Bitwise Operators
+tAST_Node      *Parse_DoExpr4(tParser *Parser);        // Bit Shifts
+tAST_Node      *Parse_DoExpr5(tParser *Parser);        // Arithmatic
+tAST_Node      *Parse_DoExpr6(tParser *Parser);        // Mult & Div
+
+tAST_Node      *Parse_DoParen(tParser *Parser);        // Parenthesis (Always Last)
+tAST_Node      *Parse_DoValue(tParser *Parser);        // Values
+
+tAST_Node      *Parse_GetString(tParser *Parser);
+tAST_Node      *Parse_GetNumeric(tParser *Parser);
+tAST_Node      *Parse_GetVariable(tParser *Parser);
+tAST_Node      *Parse_GetIdent(tParser *Parser);
+
+void   SyntaxAssert(int Have, int Want);
+
+// === CODE ===
+/**
+ * \brief Parse a buffer into a syntax tree
+ */
+tAST_Script    *Parse_Buffer(tSpiderVariant *Variant, char *Buffer)
+{
+       tParser parser = {0};
+       tParser *Parser = &parser;      //< Keeps code consitent
+       tAST_Script     *ret;
+       tAST_Node       *mainCode;
+       char    *name;
+       tAST_Function   *fcn;
+       
+       // Initialise parser
+       parser.BufStart = Buffer;
+       parser.CurPos = Buffer;
+       
+       ret = AST_NewScript();
+       mainCode = AST_NewCodeBlock();
+       
+       for(;;)
+       {
+               switch( GetToken(Parser) )
+               {
+               case TOK_RWD_FUNCTION:                  
+                       // Define a function
+                       SyntaxAssert( GetToken(Parser), TOK_IDENT );
+                       name = strndup( Parser->TokenStr, Parser->TokenLen );
+                       fcn = AST_AppendFunction( ret, name );
+                       free(name);
+                       
+                       SyntaxAssert( GetToken(Parser), TOK_PAREN_OPEN );
+                       // TODO: Arguments
+                       SyntaxAssert( GetToken(Parser), TOK_PAREN_CLOSE );
+                       
+                       AST_SetFunctionCode( fcn, Parse_DoCodeBlock(Parser) );
+                       break;
+               
+               default:
+                       PutBack(&parser);
+                       AST_AppendNode( mainCode, Parse_DoExpr(Parser) );
+                       break;
+               }
+       }
+       
+       fcn = AST_AppendFunction( ret, "" );
+       AST_SetFunctionCode( fcn, mainCode );
+       
+       return ret;
+}
+
+/**
+ * \brief Parse a block of code surrounded by { }
+ */
+tAST_Node *Parse_DoCodeBlock(tParser *Parser)
+{
+       tAST_Node       *ret;
+       SyntaxAssert( GetToken(Parser), TOK_BRACE_OPEN );
+       
+       ret = AST_NewCodeBlock();
+       
+       while( GetToken(Parser) != TOK_BRACE_CLOSE )
+       {
+               AST_AppendNode( ret, Parse_DoExpr(Parser) );
+               SyntaxAssert( GetToken(Parser), TOK_SEMICOLON );
+       }
+       return ret;
+}
+
+/**
+ * \brief Parse an expression
+ */
+tAST_Node *Parse_DoExpr(tParser *Parser)
+{
+       return Parse_DoExpr0(Parser);
+}
+
+/**
+ * \brief Assignment Operations
+ */
+tAST_Node *Parse_DoExpr0(tParser *Parser)
+{
+       tAST_Node       *ret = Parse_DoExpr1(Parser);
+
+       // Check Assignment
+       switch(LookAhead(Parser))
+       {
+       case TOK_ASSIGN:
+               GetToken(Parser);               // Eat Token
+               ret = AST_NewAssign(NODETYPE_NOP, ret, Parse_DoExpr0(Parser));
+               break;
+       #if 0
+       case TOK_DIV_EQU:
+               GetToken(Parser);               // Eat Token
+               ret = AST_NewAssignOp(ret, NODETYPE_DIVIDE, DoExpr0(Parser));
+               break;
+       case TOK_MULT_EQU:
+               GetToken(Parser);               // Eat Token
+               ret = AST_NewAssignOp(ret, NODETYPE_MULTIPLY, DoExpr0(Parser));
+               break;
+       #endif
+       default:        break;
+       }
+       return ret;
+}
+
+/**
+ * \brief Logical/Boolean Operators
+ */
+tAST_Node *Parse_DoExpr1(tParser *Parser)
+{
+       tAST_Node       *ret = Parse_DoExpr2(Parser);
+       
+       switch(GetToken(Parser))
+       {
+       case TOK_LOGICAND:
+               ret = AST_NewBinOp(NODETYPE_LOGICALAND, ret, Parse_DoExpr1(Parser));
+               break;
+       case TOK_LOGICOR:
+               ret = AST_NewBinOp(NODETYPE_LOGICALOR, ret, Parse_DoExpr1(Parser));
+               break;
+       case TOK_LOGICXOR:
+               ret = AST_NewBinOp(NODETYPE_LOGICALXOR, ret, Parse_DoExpr1(Parser));
+               break;
+       default:
+               PutBack(Parser);
+               break;
+       }
+       return ret;
+}
+
+// --------------------
+// Expression 2 - Comparison Operators
+// --------------------
+tAST_Node *Parse_DoExpr2(tParser *Parser)
+{
+       tAST_Node       *ret = Parse_DoExpr3(Parser);
+
+       // Check token
+       switch(GetToken(Parser))
+       {
+       case TOK_EQUALS:
+               ret = AST_NewBinOp(NODETYPE_EQUALS, ret, Parse_DoExpr2(Parser));
+               break;
+       case TOK_LT:
+               ret = AST_NewBinOp(NODETYPE_LESSTHAN, ret, Parse_DoExpr2(Parser));
+               break;
+       case TOK_GT:
+               ret = AST_NewBinOp(NODETYPE_GREATERTHAN, ret, Parse_DoExpr2(Parser));
+               break;
+       default:
+               PutBack(Parser);
+               break;
+       }
+       return ret;
+}
+
+/**
+ * \brief Bitwise Operations
+ */
+tAST_Node *Parse_DoExpr3(tParser *Parser)
+{
+       tAST_Node       *ret = Parse_DoExpr4(Parser);
+
+       // Check Token
+       switch(GetToken(Parser))
+       {
+       case TOK_OR:
+               ret = AST_NewBinOp(NODETYPE_BWOR, ret, Parse_DoExpr3(Parser));
+               break;
+       case TOK_AND:
+               ret = AST_NewBinOp(NODETYPE_BWAND, ret, Parse_DoExpr3(Parser));
+               break;
+       case TOK_XOR:
+               ret = AST_NewBinOp(NODETYPE_BWXOR, ret, Parse_DoExpr3(Parser));
+               break;
+       default:
+               PutBack(Parser);
+               break;
+       }
+       return ret;
+}
+
+// --------------------
+// Expression 4 - Shifts
+// --------------------
+tAST_Node *Parse_DoExpr4(tParser *Parser)
+{
+       tAST_Node *ret = Parse_DoExpr5(Parser);
+
+       switch(GetToken(Parser))
+       {
+       case TOK_SHL:
+               ret = AST_NewBinOp(NODETYPE_BITSHIFTLEFT, ret, Parse_DoExpr5(Parser));
+               break;
+       case TOK_SHR:
+               ret = AST_NewBinOp(NODETYPE_BITSHIFTRIGHT, ret, Parse_DoExpr5(Parser));
+               break;
+       default:
+               PutBack(Parser);
+               break;
+       }
+
+       return ret;
+}
+
+// --------------------
+// Expression 5 - Arithmatic
+// --------------------
+tAST_Node *Parse_DoExpr5(tParser *Parser)
+{
+       tAST_Node *ret = Parse_DoExpr6(Parser);
+
+       switch(GetToken(Parser))
+       {
+       case TOK_PLUS:
+               ret = AST_NewBinOp(NODETYPE_ADD, ret, Parse_DoExpr5(Parser));
+               break;
+       case TOK_MINUS:
+               ret = AST_NewBinOp(NODETYPE_SUBTRACT, ret, Parse_DoExpr5(Parser));
+               break;
+       default:
+               PutBack(Parser);
+               break;
+       }
+
+       return ret;
+}
+
+// --------------------
+// Expression 6 - Multiplcation & Division
+// --------------------
+tAST_Node *Parse_DoExpr6(tParser *Parser)
+{
+       tAST_Node *ret = Parse_DoParen(Parser);
+
+       switch(GetToken(Parser))
+       {
+       case TOK_MUL:
+               ret = AST_NewBinOp(NODETYPE_MULTIPLY, ret, Parse_DoExpr6(Parser));
+               break;
+       case TOK_DIV:
+               ret = AST_NewBinOp(NODETYPE_DIVIDE, ret, Parse_DoExpr6(Parser));
+               break;
+       default:
+               PutBack(Parser);
+               break;
+       }
+
+       return ret;
+}
+
+
+// --------------------
+// 2nd Last Expression - Parens
+// --------------------
+tAST_Node *Parse_DoParen(tParser *Parser)
+{
+       if(LookAhead(Parser) == TOK_PAREN_OPEN)
+       {
+               tAST_Node       *ret;
+               GetToken(Parser);
+               ret = Parse_DoExpr0(Parser);
+               SyntaxAssert(GetToken(Parser), TOK_PAREN_CLOSE);
+               return ret;
+       }
+       else
+               return Parse_DoValue(Parser);
+}
+
+// --------------------
+// Last Expression - Value
+// --------------------
+tAST_Node *Parse_DoValue(tParser *Parser)
+{
+        int    tok = LookAhead(Parser);
+
+       switch(tok)
+       {
+       case TOK_STR:   return Parse_GetString(Parser);
+       case TOK_INTEGER:       return Parse_GetNumeric(Parser);
+       case TOK_IDENT: return Parse_GetIdent(Parser);
+       case TOK_VARIABLE:      return Parse_GetVariable(Parser);
+
+       default:
+               //ParseError2( tok, TOK_T_VALUE );
+               return NULL;
+       }
+}
+
+/**
+ * \brief Get a string
+ */
+tAST_Node *Parse_GetString(tParser *Parser)
+{
+       tAST_Node       *ret;
+       GetToken( Parser );
+       // TODO: Parse Escape Codes
+       ret = AST_NewString( Parser->TokenStr+1, Parser->TokenLen-2 );
+       return ret;
+}
+
+/**
+ * \brief Get a numeric value
+ */
+tAST_Node *Parse_GetNumeric(tParser *Parser)
+{
+       uint64_t        value;
+       GetToken( Parser );
+       value = atoi( Parser->TokenStr );
+       return AST_NewInteger( value );
+}
+
+/**
+ * \brief Get a variable
+ */
+tAST_Node *Parse_GetVariable(tParser *Parser)
+{
+       char    *name;
+       tAST_Node       *ret;
+       SyntaxAssert( GetToken(Parser), TOK_VARIABLE );
+       name = strndup( Parser->TokenStr+1, Parser->TokenLen-1 );
+       ret = AST_NewVariable( name );
+       free(name);
+       return ret;
+}
+
+/**
+ * \brief Get an identifier (constand or function call)
+ */
+tAST_Node *Parse_GetIdent(tParser *Parser)
+{
+       tAST_Node       *ret;
+       char    *name;
+       SyntaxAssert( GetToken(Parser), TOK_IDENT );
+       name = strndup( Parser->TokenStr, Parser->TokenLen );
+       
+       if( GetToken(Parser) == TOK_PAREN_OPEN )
+       {
+               // Function Call
+               ret = AST_NewFunctionCall( name );
+               // Read arguments
+               if( GetToken(Parser) != TOK_PAREN_CLOSE )
+               {
+                       PutBack(Parser);
+                       do {
+                               AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) );
+                       } while(GetToken(Parser) == TOK_COMMA);
+                       SyntaxAssert( Parser->Token, TOK_PAREN_CLOSE );
+               }
+       }
+       else {
+               // Runtime Constant
+               PutBack(Parser);
+               ret = AST_NewConstant( name );
+       }
+       
+       free(name);
+       return ret;
+}
+
+/**
+ * \brief Check for an error
+ */
+void SyntaxAssert(int Have, int Want)
+{
+       if(Have != Want) {
+               fprintf(stderr, "ERROR: Expected %i, got %i\n", Want, Have);
+               //longjmp(jmpTarget, 1);
+               return;
+       }
+}
+
diff --git a/Usermode/Libraries/libspiderscript.so_src/tokens.h b/Usermode/Libraries/libspiderscript.so_src/tokens.h
new file mode 100644 (file)
index 0000000..44c3a81
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ */
+#ifndef _TOKENS_H_
+#define _TOKENS_H_
+
+// === TYPES ===
+typedef struct
+{      
+       // Lexer State
+       char    *BufStart;
+       char    *CurPos;
+       
+        int    LastToken, LastTokenLen;
+       char    *LastTokenStr;
+       
+        int    NextToken, NextTokenLen;
+       char    *NextTokenStr;
+       
+        int    Token, TokenLen;
+       char    *TokenStr;
+}      tParser;
+
+// === FUNCTIONS ===
+ int   GetToken(tParser *File);
+void   PutBack(tParser *File);
+ int   LookAhead(tParser *File);
+
+// === CONSTANTS ===
+enum eTokens
+{
+       TOK_INVAL,
+       TOK_EOF,
+       
+       TOK_STR,
+       TOK_INTEGER,
+       TOK_VARIABLE,
+       TOK_IDENT,
+       
+       TOK_RWD_FUNCTION,
+       TOK_RWD_STRING,
+       TOK_RWD_INTEGER,
+       TOK_RWD_REAL,
+       
+       TOK_ASSIGN,
+       TOK_SEMICOLON,
+       TOK_COMMA,
+       TOK_SCOPE,
+       TOK_ELEMENT,
+       
+       TOK_EQUALS,
+       TOK_LT, TOK_LTE,
+       TOK_GT, TOK_GTE,
+       
+       TOK_DIV,        TOK_MUL,
+       TOK_PLUS,       TOK_MINUS,
+       TOK_SHL,        TOK_SHR,
+       TOK_LOGICAND,   TOK_LOGICOR,    TOK_LOGICXOR,
+       TOK_AND,        TOK_OR, TOK_XOR,
+       
+       TOK_PAREN_OPEN,
+       TOK_PAREN_CLOSE,
+       TOK_BRACE_OPEN,
+       TOK_BRACE_CLOSE,
+       TOK_SQUARE_OPEN,
+       TOK_SQUARE_CLOSE,
+       
+       TOK_LAST
+};
+
+#endif
index 1e72197..a3c4d31 100644 (file)
@@ -15,6 +15,7 @@ extern char   *strcpy(char *dst, const char *src);
 extern char    *strncpy(char *dst, const char *src, size_t num);
 extern char    *strcat(char *dst, const char *src);
 extern char    *strdup(const char *src);
+extern char    *strndup(const char *src, int length);
 extern char    *strchr(char *str, int character);
 extern char    *strrchr(char *str, int character);
 extern char    *strstr(char *str1, const char *str2);

UCC git Repository :: git.ucc.asn.au