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
* 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 ---- 9 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)
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
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 );
}
}
+ 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);
*/
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
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 = ' ';
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);
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
*/
}
/**
- * \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;
CPPFLAGS +=
CFLAGS += -Wall -Werror -O3
-LDFLAGS +=
+LDFLAGS += -lspiderscript
BIN = ../init
OBJ = main.o
* 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 ===
/**
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);
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;
+}
# Acess 2 SQLite 3 Library
#
+DEPFILES := $(OBJ:%.o=%.d)
+
.PHONY: all clean install
all: $(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)
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
--- /dev/null
+# 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
--- /dev/null
+/*
+ * 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;
+ }
+}
+
+/**
+ * \}
+ */
--- /dev/null
+/*
+ */
+#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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ */
+#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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
+
--- /dev/null
+/*
+ */
+#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
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);