return (int)*s1 - (int)*s2;
}
+/**
+ * \fn EXPORT int strncmp(const char *s1, const char *s2)
+ * \brief Compare two strings
+ */
+EXPORT int strncmp(const char *s1, const char *s2, size_t n)
+{
+ if( n == 0 ) return 0;
+ while(n -- && *s1 == *s2 && *s1 != '\0' && *s2 != '\0') {
+ s1++; s2++;
+ }
+ return (int)*s1 - (int)*s2;
+}
+
/**
* \fn EXPORT char *strcpy(char *dst, const char *src)
* \brief Copy a string to another
CFLAGS += -Wall
LDFLAGS += -lc -lgcc -soname libspiderscript.so --no-allow-shlib-undefined
-OBJ = main.o lex.o parse.o ast.o exec_ast.o
+OBJ = main.o lex.o parse.o ast.o exec_ast.o exports.o
BIN = ../libspiderscript.so
include ../Makefile.tpl
--- /dev/null
+
+# Should I use brackets in this language?
+# Well, considering that all whitespace is ignored, it might be an idea
+
+# Well, it would make VVV a little simpler
+# Just define a funciton with the name 'Sys.IO.Open'
+# Not a namespace Sys, with a child Sys
+
+$fp = Sys.IO.Open( "/Devices/ipstack" );
+$ifname = Sys.IO.IOCtl( $fp, 4, "/Devices/ne2k/0" );
+Sys.IO.Close($fp);
+
+# Let's see:
+# b - Signed 8-bit integer, B - unsigned
+# w - 16 bit
+# l - 32 bit
+# q - 64 bit
+# f - 32-bit float
+# d - 64-bit double
+# Fields can be prefixed by a size for arrays (taking only one argument)
+# * indicates a variable size array
+# E.g.
+# Sys.Mem.MakeStruct( "L*B", $len, $len, $str );
+# Hmm.. that would mean I will need arrays... fuck it, do them later
+
+function SetIPv4($ifaceName, $addr)
+{
+ $fp = Sys.IO.Open( "/Devices/ipstack/$ifaceName" );
+ $data = Lang.MakeStruct( "l", 4 );
+ Sys.IO.IOCtl( $fp, 4, $data );
+ $data = Lang.Struct( "BBBB", $addr[0], $addr[1], $addr[2], $addr[3] );
+ Sys.IO.IOCtl( $fp, 6, $data );
+ Sys.IO.Close( $fp );
+}
+
+SetIPv4( $ifname, Lang.Array(10, 0, 2, 55) );
* Acess2 Init
* - Script AST Manipulator
*/
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ast.h"
{
tAST_Function *ret;
- ret = malloc( sizeof(tAST_Function) );
+ ret = malloc( sizeof(tAST_Function) + strlen(Name) + 1 );
ret->Next = NULL;
- ret->Name = strdup(Name);
+ strcpy(ret->Name, Name);
ret->Code = NULL;
ret->Arguments = NULL;
return ret;
}
+void AST_AppendFunctionArg(tAST_Function *Function, tAST_Node *Node)
+{
+ if( !Function->Arguments ) {
+ Function->Arguments_Last = Function->Arguments = Node;
+ }
+ else {
+ Function->Arguments_Last->NextSibling = Node;
+ Function->Arguments_Last = Node;
+ }
+}
+
+/**
+ * \brief Set the code for a function
+ */
void AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root)
{
Function->Code = Root;
* \name Node Manipulation
* \{
*/
+/**
+ * \brief Free a node and all subnodes
+ */
void AST_FreeNode(tAST_Node *Node)
{
tAST_Node *node;
AST_FreeNode(Node->Assign.Value);
break;
+ // Casting
+ case NODETYPE_CAST:
+ AST_FreeNode(Node->Cast.Value);
+ break;
+
+ // Define a variable
+ case NODETYPE_DEFVAR:
+ for( node = Node->DefVar.LevelSizes; node; )
+ {
+ tAST_Node *savedNext = node->NextSibling;
+ AST_FreeNode(node);
+ node = savedNext;
+ }
+ break;
+
// Unary Operations
case NODETYPE_RETURN:
AST_FreeNode(Node->UniOp.Value);
break;
// Binary Operations
+ case NODETYPE_INDEX:
case NODETYPE_ADD:
case NODETYPE_SUBTRACT:
case NODETYPE_MULTIPLY:
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;
+ Child->NextSibling = NULL;
+ switch( Parent->Type )
+ {
+ case NODETYPE_BLOCK:
+ if(Parent->Block.FirstChild == NULL) {
+ Parent->Block.FirstChild = Parent->Block.LastChild = Child;
+ }
+ else {
+ Parent->Block.LastChild->NextSibling = Child;
+ Parent->Block.LastChild = Child;
+ }
+ break;
+ case NODETYPE_DEFVAR:
+ if(Parent->DefVar.LevelSizes == NULL) {
+ Parent->DefVar.LevelSizes = Parent->DefVar.LevelSizes_Last = Child;
+ }
+ else {
+ Parent->DefVar.LevelSizes_Last->NextSibling = Child;
+ Parent->DefVar.LevelSizes_Last = Child;
+ }
+ break;
+ default:
+ fprintf(stderr, "BUG REPORT: AST_AppendNode on an invalid node type (%i)\n", Parent->Type);
+ break;
}
}
return ret;
}
+/**
+ */
+tAST_Node *AST_NewUniOp(int Operation, tAST_Node *Value)
+{
+ tAST_Node *ret = malloc( sizeof(tAST_Node) );
+
+ ret->NextSibling = NULL;
+ ret->Type = Operation;
+ ret->UniOp.Value = Value;
+
+ return ret;
+}
+
/**
* \brief Create a new string node
*/
return ret;
}
+/**
+ * \brief Create a new variable definition node
+ */
+tAST_Node *AST_NewDefineVar(int Type, const char *Name)
+{
+ tAST_Node *ret = malloc( sizeof(tAST_Node) + strlen(Name) + 1 );
+ ret->NextSibling = NULL;
+ ret->Type = NODETYPE_DEFVAR;
+ ret->DefVar.DataType = Type;
+ ret->DefVar.LevelSizes = NULL;
+ strcpy(ret->DefVar.Name, Name);
+ return ret;
+}
+
/**
* \brief Create a new runtime constant reference node
*/
#include <spiderscript.h>
+typedef enum eAST_NodeTypes tAST_NodeType;
typedef struct sAST_Script tAST_Script;
typedef struct sAST_Function tAST_Function;
typedef struct sAST_Node tAST_Node;
-typedef enum eAST_NodeTypes tAST_NodeType;
+typedef struct sAST_BlockState tAST_BlockState;
+typedef struct sAST_Variable tAST_Variable;
/**
* \brief Node Types
NODETYPE_INTEGER, //!< Integer Constant
NODETYPE_REAL, //!< Real Constant
+ NODETYPE_DEFVAR, //!< Define a variable (Variable)
+ NODETYPE_CAST, //!< Cast a value to another (Uniop)
+
NODETYPE_RETURN, //!< Return from a function (reserved word)
NODETYPE_ASSIGN, //!< Variable assignment operator
NODETYPE_FUNCTIONCALL, //!< Call a function
+ NODETYPE_INDEX, //!< Index into an array
+
NODETYPE_LOGICALAND, //!< Logical AND operator
NODETYPE_LOGICALOR, //!< Logical OR operator
NODETYPE_LOGICALXOR, //!< Logical XOR operator
{
tSpiderVariant *Variant;
tAST_Script *Script;
+ char *CurNamespace; //!< Current namespace prefix (NULL = Root) - No trailing .
};
struct sAST_Script
struct sAST_Function
{
- tAST_Function *Next;
- char *Name;
- tAST_Node *Code;
- tAST_Node *Arguments; // HACKJOB (Only NODETYPE_VARIABLE is allowed)
+ tAST_Function *Next; //!< Next function in list
+ tAST_Node *Code; //!< Function Code
+ tAST_Node *Arguments; // HACKJOB (Only NODETYPE_DEFVAR is allowed)
+ tAST_Node *Arguments_Last;
+ char Name[]; //!< Function Name
};
struct sAST_Node
char Name[];
} Variable;
+ struct {
+ int DataType;
+ int Depth;
+ tAST_Node *LevelSizes;
+ tAST_Node *LevelSizes_Last;
+ char Name[];
+ } DefVar;
+
+ struct {
+ int DataType;
+ tAST_Node *Value;
+ } Cast;
+
uint64_t Integer;
double Real;
};
};
+/**
+ * \brief Code Block state (stores local variables)
+ */
+struct sAST_BlockState
+{
+ tAST_BlockState *Parent;
+ tSpiderScript *Script; //!< Script
+ tAST_Variable *FirstVar; //!< First variable in the list
+};
+
+struct sAST_Variable
+{
+ tAST_Variable *Next;
+ int Type; // Only used for static typing
+ tSpiderObject *Object;
+ char Name[];
+};
+
// === FUNCTIONS ===
-tAST_Script *AST_NewScript(void);
+extern 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);
+extern tAST_Function *AST_AppendFunction(tAST_Script *Script, const char *Name);
+extern void AST_AppendFunctionArg(tAST_Function *Function, tAST_Node *Arg);
+extern 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);
+extern tAST_Node *AST_NewString(const char *String, int Length);
+extern tAST_Node *AST_NewInteger(uint64_t Value);
+extern tAST_Node *AST_NewVariable(const char *Name);
+extern tAST_Node *AST_NewDefineVar(int Type, const char *Name);
+extern tAST_Node *AST_NewConstant(const char *Name);
+extern tAST_Node *AST_NewFunctionCall(const char *Name);
+extern 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);
+extern tAST_Node *AST_NewCodeBlock(void);
+extern void AST_AppendNode(tAST_Node *Parent, tAST_Node *Child);
+extern tAST_Node *AST_NewAssign(int Operation, tAST_Node *Dest, tAST_Node *Value);
+extern tAST_Node *AST_NewBinOp(int Operation, tAST_Node *Left, tAST_Node *Right);
+extern tAST_Node *AST_NewUniOp(int Operation, tAST_Node *Value);
-void AST_FreeNode(tAST_Node *Node);
+extern void AST_FreeNode(tAST_Node *Node);
-tSpiderVariable *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node);
+// exec_ast.h
+extern tSpiderObject *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
#endif
#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 Object_Dereference(tSpiderObject *Object);
+void Object_Reference(tSpiderObject *Object);
+tSpiderObject *Object_CreateInteger(uint64_t Value);
+tSpiderObject *Object_CreateReal(double Value);
+tSpiderObject *Object_CreateString(int Length, const char *Data);
+tSpiderObject *Object_CastTo(int Type, tSpiderObject *Source);
+ int Object_IsTrue(tSpiderObject *Value);
+
+tSpiderObject *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
-void Variable_SetValue(tSpiderScript *Script, const char *Name, tSpiderVariable *Value);
-tSpiderVariable *Variable_GetValue(tSpiderScript *Script, const char *Name);
+tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name);
+void Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderObject *Value);
+tSpiderObject *Variable_GetValue(tAST_BlockState *Block, const char *Name);
+void Variable_Destroy(tAST_Variable *Variable);
// === CODE ===
/**
* \brief Dereference a created object
*/
-void Object_Dereference(tSpiderVariable *Object)
+void Object_Dereference(tSpiderObject *Object)
{
+ if(!Object) return ;
Object->ReferenceCount --;
if( Object->ReferenceCount == 0 ) free(Object);
}
-void Object_Reference(tSpiderVariable *Object)
+void Object_Reference(tSpiderObject *Object)
{
+ if(!Object) return ;
Object->ReferenceCount ++;
}
/**
* \brief Create an integer object
*/
-tSpiderVariable *Object_CreateInteger(uint64_t Value)
+tSpiderObject *Object_CreateInteger(uint64_t Value)
{
- tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) );
+ tSpiderObject *ret = malloc( sizeof(tSpiderObject) );
ret->Type = SS_DATATYPE_INTEGER;
ret->ReferenceCount = 1;
ret->Integer = Value;
/**
* \brief Create an real number object
*/
-tSpiderVariable *Object_CreateReal(double Value)
+tSpiderObject *Object_CreateReal(double Value)
{
- tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) );
+ tSpiderObject *ret = malloc( sizeof(tSpiderObject) );
ret->Type = SS_DATATYPE_REAL;
ret->ReferenceCount = 1;
ret->Real = Value;
/**
* \brief Create an string object
*/
-tSpiderVariable *Object_CreateString(int Length, const char *Data)
+tSpiderObject *Object_CreateString(int Length, const char *Data)
{
- tSpiderVariable *ret = malloc( sizeof(tSpiderVariable) + Length + 1 );
+ tSpiderObject *ret = malloc( sizeof(tSpiderObject) + Length + 1 );
ret->Type = SS_DATATYPE_STRING;
ret->ReferenceCount = 1;
ret->String.Length = Length;
}
/**
+ * \brief Concatenate two strings
*/
-tSpiderVariable *Object_CastTo(int Type, tSpiderVariable *Source)
+tSpiderObject *Object_StringConcat(tSpiderObject *Str1, tSpiderObject *Str2)
{
- tSpiderVariable *ret;
+ int newLen = 0;
+ tSpiderObject *ret;
+ if(Str1) newLen += Str1->String.Length;
+ if(Str2) newLen += Str2->String.Length;
+ ret = malloc( sizeof(tSpiderObject) + newLen + 1 );
+ ret->Type = SS_DATATYPE_STRING;
+ ret->ReferenceCount = 1;
+ ret->String.Length = newLen;
+ if(Str1)
+ memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
+ if(Str2) {
+ if(Str1)
+ memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
+ else
+ memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
+ }
+ ret->String.Data[ newLen ] = '\0';
+ return ret;
+}
+
+/**
+ * \brief Cast one object to another
+ */
+tSpiderObject *Object_CastTo(int Type, tSpiderObject *Source)
+{
+ tSpiderObject *ret = ERRPTR;
// Check if anything needs to be done
if( Source->Type == Type ) {
Object_Reference(Source);
return ERRPTR;
case SS_DATATYPE_INTEGER:
- ret = malloc(sizeof(tSpiderVariable));
+ ret = malloc(sizeof(tSpiderObject));
ret->Type = SS_DATATYPE_INTEGER;
ret->ReferenceCount = 1;
switch(Source->Type)
case SS_DATATYPE_REAL: ret->Integer = Source->Real; break;
default:
fprintf(stderr, "Object_CastTo - Invalid cast from %i\n", Source->Type);
+ free(ret);
+ ret = ERRPTR;
break;
}
break;
+ default:
+ fprintf(stderr, "BUG REPORT: Unimplemented cast target\n");
+ break;
}
return ret;
/**
* \brief Condenses a value down to a boolean
*/
-int Object_IsTrue(tSpiderVariable *Value)
+int Object_IsTrue(tSpiderObject *Value)
{
switch(Value->Type)
{
return 0;
}
-tSpiderVariable *AST_ExecuteNode(tSpiderScript *Script, tAST_Node *Node)
+/**
+ * \brief Execute an AST node and return its value
+ */
+tSpiderObject *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
{
tAST_Node *node;
- tSpiderVariable *ret, *tmpvar;
- tSpiderVariable *op1, *op2; // Binary operations
+ tSpiderObject *ret, *tmpobj;
+ tSpiderObject *op1, *op2; // Binary operations
int cmp; // Used in comparisons
switch(Node->Type)
{
// No Operation
- case NODETYPE_NOP: ret = NULL; break ;
+ 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 ;
+ tAST_BlockState blockInfo;
+ blockInfo.FirstVar = NULL;
+ blockInfo.Parent = Block;
+ blockInfo.Script = Block->Script;
+ ret = NULL;
+ for(node = Node->Block.FirstChild; node; node = node->NextSibling )
+ {
+ if(node->Type == NODETYPE_RETURN) {
+ ret = AST_ExecuteNode(&blockInfo, node);
+ break ;
+ }
+ else {
+ tmpobj = AST_ExecuteNode(&blockInfo, node);
+ if(tmpobj == ERRPTR) { // Error check
+ ret = ERRPTR;
+ break ;
+ }
+ if(tmpobj) Object_Dereference(tmpobj); // Free unused value
+ }
}
- else {
- tmpvar = AST_ExecuteNode(Script, node);
- if(tmpvar == ERRPTR) return ERRPTR; // Error check
- if(tmpvar) Object_Dereference(tmpvar); // Free unused value
+ // Clean up variables
+ while(blockInfo.FirstVar)
+ {
+ tAST_Variable *nextVar = blockInfo.FirstVar->Next;
+ Variable_Destroy( blockInfo.FirstVar );
+ blockInfo.FirstVar = nextVar;
}
}
+
break;
// Assignment
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 );
+ ret = AST_ExecuteNode(Block, Node->Assign.Value);
+ if(ret != ERRPTR)
+ Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret );
break;
+ // Function Call
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");
+ {
+ int nParams = 0;
+ for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
+ nParams ++;
+ }
+ // Logical block (used to allocate `params`)
+ {
+ tSpiderObject *params[nParams];
+ int i=0;
+ for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
+ params[i] = AST_ExecuteNode(Block, node);
+ if( params[i] == ERRPTR ) {
+ while(i--) Object_Dereference(params[i]);
+ ret = ERRPTR;
+ goto _return;
+ }
+ i ++;
+ }
+
+ // Call the function (SpiderScript_ExecuteMethod does the
+ // required namespace handling)
+ ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
+
+ // Dereference parameters
+ while(i--) Object_Dereference(params[i]);
+
+ // falls out
+ }
+ }
break;
// Return's special handling happens elsewhere
case NODETYPE_RETURN:
- ret = AST_ExecuteNode(Script, Node->UniOp.Value);
+ ret = AST_ExecuteNode(Block, Node->UniOp.Value);
break;
- // Variable
- case NODETYPE_VARIABLE: ret = Variable_GetValue( Script, Node->Variable.Name ); break;
+ // Define a variable
+ case NODETYPE_DEFVAR:
+ ret = NULL;
+ if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
+ ret = ERRPTR;
+ break;
+ // Variable
+ case NODETYPE_VARIABLE:
+ ret = Variable_GetValue( Block, Node->Variable.Name );
+ break;
+
+ // Cast a value to another
+ case NODETYPE_CAST:
+ ret = Object_CastTo(
+ Node->Cast.DataType,
+ AST_ExecuteNode(Block, Node->Cast.Value)
+ );
+ break;
+
+ // Index into an array
+ case NODETYPE_INDEX:
+ fprintf(stderr, "TODO: Array indexing\n");
+ ret = ERRPTR;
+ break;
+
// TODO: Implement runtime constants
- case NODETYPE_CONSTANT: ret = ERRPTR; break;
+ case NODETYPE_CONSTANT:
+ fprintf(stderr, "TODO: Runtime Constants\n");
+ 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_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);
+ op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
+ if(op1 == ERRPTR) return ERRPTR;
+ op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
+ if(op2 == ERRPTR) {
+ Object_Dereference(op1);
+ return ERRPTR;
+ }
+
switch( Node->Type )
{
case NODETYPE_LOGICALAND:
break;
default: break;
}
+
+ // Free intermediate objects
+ Object_Dereference(op1);
+ Object_Dereference(op2);
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);
+ op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
+ if(op1 == ERRPTR) return ERRPTR;
+ op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
+ if(op2 == ERRPTR) {
+ Object_Dereference(op1);
+ return ERRPTR;
+ }
// No conversion done for NULL
// TODO: Determine if this will ever be needed
// Convert types
if( op1->Type != op2->Type ) {
// If dynamically typed, convert op2 to op1's type
- if(Script->Variant->bDyamicTyped)
+ if(Block->Script->Variant->bDyamicTyped)
{
- tmpvar = op2;
+ tmpobj = op2;
op2 = Object_CastTo(op1->Type, op2);
- Object_Dereference(tmpvar);
+ Object_Dereference(tmpobj);
+ if(op2 == ERRPTR) {
+ Object_Dereference(op1);
+ return ERRPTR;
+ }
}
// If statically typed, this should never happen, but catch it anyway
else {
+ fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
ret = ERRPTR;
break;
}
case NODETYPE_BITSHIFTRIGHT:
case NODETYPE_BITROTATELEFT:
// Get operands
- op1 = AST_ExecuteNode(Script, Node->BinOp.Left);
- op2 = AST_ExecuteNode(Script, Node->BinOp.Right);
+ op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
+ if(op1 == ERRPTR) return ERRPTR;
+ op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
+ if(op2 == ERRPTR) {
+ Object_Dereference(op1);
+ return ERRPTR;
+ }
// Convert types
- if( op1->Type != op2->Type ) {
+ if( op1 && op2 && op1->Type != op2->Type ) {
// If dynamically typed, convert op2 to op1's type
- if(Script->Variant->bDyamicTyped)
+ if(Block->Script->Variant->bDyamicTyped)
{
- tmpvar = op2;
+ tmpobj = op2;
op2 = Object_CastTo(op1->Type, op2);
- Object_Dereference(tmpvar);
+ Object_Dereference(tmpobj);
+ if(op2 == ERRPTR) {
+ Object_Dereference(op1);
+ return ERRPTR;
+ }
}
// If statically typed, this should never happen, but catch it anyway
else {
+ fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
ret = ERRPTR;
break;
}
case SS_DATATYPE_STRING:
switch(Node->Type)
{
+ case NODETYPE_ADD: // Concatenate
+ ret = Object_StringConcat(op1, op2);
+ break;
default:
- fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Node->Type);
+ fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i\n", Node->Type);
ret = ERRPTR;
break;
}
// fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
// break;
}
+_return:
return ret;
}
+
+/**
+ * \brief Define a variable
+ * \param Block Current block state
+ * \param Type Type of the variable
+ * \param Name Name of the variable
+ * \return Boolean Failure
+ */
+tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
+{
+ tAST_Variable *var, *prev = NULL;
+
+ for( var = Block->FirstVar; var; prev = var, var = var->Next )
+ {
+ if( strcmp(var->Name, Name) == 0 ) {
+ fprintf(stderr, "ERROR: Redefinition of variable '%s'\n", Name);
+ return ERRPTR;
+ }
+ }
+
+ var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
+ var->Next = NULL;
+ var->Type = Type;
+ var->Object = NULL;
+ strcpy(var->Name, Name);
+
+ if(prev) prev->Next = var;
+ else Block->FirstVar = var;
+
+ //printf("Defined variable %s (%i)\n", Name, Type);
+
+ return var;
+}
+
+/**
+ * \brief Set the value of a variable
+ */
+void Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderObject *Value)
+{
+ tAST_Variable *var;
+ tAST_BlockState *bs;
+
+ for( bs = Block; bs; bs = bs->Parent )
+ {
+ for( var = bs->FirstVar; var; var = var->Next )
+ {
+ if( strcmp(var->Name, Name) == 0 ) {
+ if( !Block->Script->Variant->bDyamicTyped
+ && (Value && var->Type != Value->Type) ) {
+ fprintf(stderr, "ERROR: Type mismatch assigning to '%s'\n", Name);
+ return ;
+ }
+ Object_Reference(Value);
+ Object_Dereference(var->Object);
+ var->Object = Value;
+ return ;
+ }
+ }
+ }
+
+ if( Block->Script->Variant->bDyamicTyped )
+ {
+ // Define variable
+ var = Variable_Define(Block, Value->Type, Name);
+ Object_Reference(Value);
+ var->Object = Value;
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Variable '%s' set while undefined\n", Name);
+ }
+}
+
+/**
+ * \brief Get the value of a variable
+ */
+tSpiderObject *Variable_GetValue(tAST_BlockState *Block, const char *Name)
+{
+ tAST_Variable *var;
+ tAST_BlockState *bs;
+
+ for( bs = Block; bs; bs = bs->Parent )
+ {
+ for( var = bs->FirstVar; var; var = var->Next )
+ {
+ if( strcmp(var->Name, Name) == 0 ) {
+ Object_Reference(var->Object);
+ return var->Object;
+ }
+ }
+ }
+
+ fprintf(stderr, "ERROR: Variable '%s' used undefined\n", Name);
+
+ return ERRPTR;
+}
+
+/**
+ * \brief Destorys a variable
+ */
+void Variable_Destroy(tAST_Variable *Variable)
+{
+ Object_Dereference(Variable->Object);
+ free(Variable);
+}
--- /dev/null
+/*
+ * Acess2 - SpiderScript
+ * - Script Exports (Lang. Namespace)
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <spiderscript.h>
+
+// === PROTOTYPES ===
+tSpiderObject *Exports_Lang_Struct(tSpiderScript *Script, int NArgs, tSpiderObject **Args);
+
+// === GLOBALS ===
+ int gaExports_Lang_Struct_Args[] = {SS_DATATYPE_STRING,-1};
+
+tSpiderFunction gaSpiderScript_Exports[] = {
+ {"Lang.Struct", Exports_Lang_Struct, gaExports_Lang_Struct_Args}
+};
+const int giSpiderScript_NumExports = sizeof(gaSpiderScript_Exports)/sizeof(tSpiderFunction);
+
+// === CODE ===
+tSpiderObject *Exports_Lang_Struct(tSpiderScript *Script, int NArgs, tSpiderObject **Args)
+{
+ int i;
+ printf("Exports_Lang_Struct: (Script=%p, NArgs=%i, Args=%p)\n", Script, NArgs, Args);
+
+ for( i = 0; i < NArgs; i ++ )
+ {
+ printf(" Args[%i] = {Type: %i, ", i, Args[i]->Type);
+ switch(Args[i]->Type)
+ {
+ case SS_DATATYPE_INTEGER:
+ printf(" Integer: 0x%lx", Args[i]->Integer);
+ break;
+ case SS_DATATYPE_REAL:
+ printf(" Real: %f", Args[i]->Real);
+ break;
+ case SS_DATATYPE_STRING:
+ printf(" Length: %i, Data = '%s'", Args[i]->String.Length, Args[i]->String.Data);
+ break;
+ default:
+ break;
+ }
+ printf("}\n");
+ }
+
+ return NULL;
+}
/*
- * Acess2 init
+ * SpiderScript
* - Script Lexer
*/
#include "tokens.h"
#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define USE_SCOPE_CHAR 0
+
+#define DEBUG 0
+
+#define ARRAY_SIZE(x) ((sizeof(x))/(sizeof((x)[0])))
// === PROTOTYPES ===
int is_ident(char ch);
- int isdigit(char ch);
- int isspace(char ch);
+ int isdigit(int ch);
+ int isspace(int ch);
int GetToken(tParser *File);
// === CONSTANTS ===
const char *Name;
} csaReservedWords[] = {
{TOK_RWD_FUNCTION, "function"},
- {TOK_RWD_INTEGER, "integer"},
- {TOK_RWD_REAL, "string"}
+ {TOK_RWD_RETURN, "return"},
+ {TOK_RWD_VOID, "void"},
+ {TOK_RWD_OBJECT, "Object"},
+ {TOK_RWD_INTEGER, "Integer"},
+ {TOK_RWD_REAL, "Real"},
+ {TOK_RWD_STRING, "String"}
};
// === CODE ===
int ret;
if( File->NextToken != -1 ) {
+ // Save Last
+ File->LastToken = File->Token;
+ File->LastTokenStr = File->TokenStr;
+ File->LastTokenLen = File->TokenLen;
+ File->LastLine = File->CurLine;
+ // Restore Next
File->Token = File->NextToken;
File->TokenStr = File->NextTokenStr;
File->TokenLen = File->NextTokenLen;
+ File->CurLine = File->NextLine;
+ // Set State
+ File->CurPos = File->TokenStr + File->TokenLen;
File->NextToken = -1;
+ {
+ char buf[ File->TokenLen + 1];
+ memcpy(buf, File->TokenStr, File->TokenLen);
+ buf[File->TokenLen] = 0;
+ #if DEBUG
+ printf(" GetToken: FAST Return %i (%i long) (%s)\n", File->Token, File->TokenLen, buf);
+ #endif
+ }
return File->Token;
}
+ //printf(" GetToken: File=%p, File->CurPos = %p\n", File, File->CurPos);
+
// Clear whitespace (including comments)
for( ;; )
{
// Whitespace
while( isspace( *File->CurPos ) )
+ {
+ //printf("whitespace 0x%x, line = %i\n", *File->CurPos, File->CurLine);
+ if( *File->CurPos == '\n' )
+ File->CurLine ++;
File->CurPos ++;
+ }
// # Line Comments
if( *File->CurPos == '#' ) {
// C-Style Block Comments
if( *File->CurPos == '/' && File->CurPos[1] == '*' ) {
- File->CurPos += 2;
+ File->CurPos += 2; // Eat the '/*'
while( *File->CurPos && !(File->CurPos[-1] == '*' && *File->CurPos == '/') )
+ {
+ if( *File->CurPos == '\n' ) File->CurLine ++;
File->CurPos ++;
+ }
+ File->CurPos ++; // Eat the '/'
continue ;
}
File->LastToken = File->Token;
File->LastTokenStr = File->TokenStr;
File->LastTokenLen = File->TokenLen;
+ File->LastLine = File->CurLine;
// Read token
File->TokenStr = File->CurPos;
switch( *File->CurPos++ )
{
+ case '\0': ret = TOK_EOF; break;
+
// Operations
case '/': ret = TOK_DIV; break;
case '*': ret = TOK_MUL; break;
// Strings
case '"':
- File->TokenStr ++;
while( *File->CurPos && !(*File->CurPos == '"' && *File->CurPos != '\\') )
File->CurPos ++;
+ File->CurPos ++;
ret = TOK_STR;
break;
// Core symbols
case ';': ret = TOK_SEMICOLON; break;
+ case ',': ret = TOK_COMMA; break;
+ #if USE_SCOPE_CHAR
case '.': ret = TOK_SCOPE; break;
+ #endif
// Equals
case '=':
// Variables
// \$[0-9]+ or \$[_a-zA-Z][_a-zA-Z0-9]*
case '$':
- File->TokenStr ++;
// Numeric Variable
if( isdigit( *File->CurPos ) ) {
while( isdigit(*File->CurPos) )
}
// Ident Variable
else {
- while( is_ident(*File->CurPos) )
+ while( is_ident(*File->CurPos) || isdigit(*File->CurPos) )
File->CurPos ++;
}
ret = TOK_VARIABLE;
// Default (Numbers and Identifiers)
default:
+ File->CurPos --;
// Numbers
if( isdigit(*File->CurPos) )
{
while( is_ident(*File->CurPos) || isdigit(*File->CurPos) )
File->CurPos ++;
+ // This is set later too, but we use it below
+ File->TokenLen = File->CurPos - File->TokenStr;
ret = TOK_IDENT;
+
+ // Check if it's a reserved word
+ {
+ char buf[File->TokenLen + 1];
+ int i;
+ memcpy(buf, File->TokenStr, File->TokenLen);
+ buf[File->TokenLen] = 0;
+ for( i = 0; i < ARRAY_SIZE(csaReservedWords); i ++ )
+ {
+ if(strcmp(csaReservedWords[i].Name, buf) == 0) {
+ ret = csaReservedWords[i].Value;
+ break ;
+ }
+ }
+ }
+ // If there's no match, just keep ret as TOK_IDENT
+
break;
}
// Syntax Error
- ret = 0;
+ ret = TOK_INVAL;
+
+ fprintf(stderr, "Syntax Error: Unknown symbol '%c'\n", *File->CurPos);
+ longjmp(File->JmpTarget, 1);
+
break;
}
// Return
File->Token = ret;
File->TokenLen = File->CurPos - File->TokenStr;
+
+ #if DEBUG
+ {
+ char buf[ File->TokenLen + 1];
+ memcpy(buf, File->TokenStr, File->TokenLen);
+ buf[File->TokenLen] = 0;
+ //printf(" GetToken: File->CurPos = %p\n", File->CurPos);
+ printf(" GetToken: Return %i (%i long) (%s)\n", ret, File->TokenLen, buf);
+ }
+ #endif
return ret;
}
{
if( File->LastToken == -1 ) {
// ERROR:
+ fprintf(stderr, "INTERNAL ERROR: Putback when LastToken==-1\n");
+ longjmp( File->JmpTarget, -1 );
return ;
}
+ #if DEBUG
+ printf(" PutBack: Was on %i\n", File->Token);
+ #endif
// Save
+ File->NextLine = File->CurLine;
File->NextToken = File->Token;
File->NextTokenStr = File->TokenStr;
File->NextTokenLen = File->TokenLen;
// Restore
+ File->CurLine = File->LastLine;
File->Token = File->LastToken;
File->TokenStr = File->LastTokenStr;
File->TokenLen = File->LastTokenLen;
int LookAhead(tParser *File)
{
+ // TODO: Should I save the entire state here?
int ret = GetToken(File);
PutBack(File);
return ret;
int is_ident(char ch)
{
if('a' <= ch && ch <= 'z') return 1;
- if('Z' <= ch && ch <= 'Z') return 1;
+ if('A' <= ch && ch <= 'Z') return 1;
if(ch == '_') return 1;
+ #if !USE_SCOPE_CHAR
+ if(ch == '.') return 1;
+ #endif
if(ch < 0) return 1;
return 0;
}
-int isdigit(char ch)
+int isdigit(int ch)
{
if('0' <= ch && ch <= '9') return 1;
return 0;
}
-int isspace(char ch)
+int isspace(int ch)
{
if(' ' == ch) return 1;
if('\t' == ch) return 1;
// === IMPORTS ===
extern tAST_Script *Parse_Buffer(tSpiderVariant *Variant, char *Buffer);
+extern const int giSpiderScript_NumExports;
+extern tSpiderFunction gaSpiderScript_Exports[];
+extern tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name);
+extern void Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderObject *Value);
// === CODE ===
/**
fLen = ftell(fp);
fseek(fp, 0, SEEK_SET);
- data = malloc(fLen);
+ // Allocate and read data
+ data = malloc(fLen + 1);
if(!data) return NULL;
fread(data, fLen, 1, fp);
+ data[fLen] = '\0';
fclose(fp);
+ ret->CurNamespace = NULL;
ret->Script = Parse_Buffer(Variant, data);
+ if( ret->Script == NULL ) {
+ free(data);
+ free(ret);
+ return NULL;
+ }
free(data);
/**
* \brief Execute a script function
- * \todo Arguments?
+ * \param Script Script context to execute in
+ * \param Function Function name to execute
+ * \param NArguments Number of arguments to pass
+ * \param Arguments Arguments passed
*/
-tSpiderVariable *SpiderScript_ExecuteMethod(tSpiderScript *Script, const char *Function)
+tSpiderObject *SpiderScript_ExecuteMethod(tSpiderScript *Script,
+ const char *Function, int NArguments, tSpiderObject **Arguments)
{
- tAST_Function *fcn = Script->Script->Functions;
+ char *trueName = NULL;
+ int i;
+ int bFound = 0; // Used to keep nesting levels down
+ tSpiderObject *ret = ERRPTR;
+
+ // Handle namespaces
+ if( Function[0] == '.' ) {
+ trueName = (char*)&Function[1];
+ }
+ else if( !Script->CurNamespace ) {
+ trueName = (char*)Function;
+ }
+ else {
+ int len = strlen(Script->CurNamespace) + 1 + strlen(Function);
+ trueName = malloc( len + 1 );
+ strcpy(trueName, Script->CurNamespace);
+ strcat(trueName, ".");
+ strcat(trueName, Function);
+ }
+
+ // First: Find the function in the script
+ {
+ tAST_Function *fcn = Script->Script->Functions;
+ for( ; fcn; fcn = fcn->Next ) {
+ if( strcmp(fcn->Name, trueName) == 0 )
+ break;
+ }
+ // Execute!
+ if(fcn) {
+ tAST_BlockState bs;
+ bs.FirstVar = NULL; //< TODO: Parameters
+ bs.Parent = NULL;
+ bs.Script = Script;
+ {
+ tAST_Node *arg;
+ int i = 0;
+ for( arg = fcn->Arguments; arg; arg = arg->NextSibling, i++ )
+ {
+ // TODO: Type checks
+ Variable_Define(&bs, arg->DefVar.DataType, arg->DefVar.Name);
+ if( i >= NArguments ) break; // TODO: Return gracefully
+ Variable_SetValue(&bs, arg->DefVar.Name, Arguments[i]);
+ }
+ }
+ ret = AST_ExecuteNode(&bs, fcn->Code);
+ bFound = 1;
+ }
+ }
+
+ // Didn't find it in script?
+ if(!bFound)
+ {
+ // Second: Search the variant's exports
+ for( i = 0; i < Script->Variant->NFunctions; i ++ )
+ {
+ if( strcmp( Script->Variant->Functions[i].Name, trueName) == 0 )
+ break;
+ }
+ // Execute!
+ if(i < Script->Variant->NFunctions) {
+ ret = Script->Variant->Functions[i].Handler( Script, NArguments, Arguments );
+ bFound = 1;
+ }
+ }
- // Find the function
- for( ; fcn; fcn = fcn->Next ) {
- if( strcmp(fcn->Name, Function) == 0 )
- break;
+ // Not in variant exports? Search the language internal ones
+ if(!bFound)
+ {
+ for( i = 0; i < giSpiderScript_NumExports; i ++ )
+ {
+ if( strcmp( gaSpiderScript_Exports[i].Name, trueName ) == 0 )
+ break;
+ }
+ // Execute!
+ if(i < giSpiderScript_NumExports) {
+ ret = gaSpiderScript_Exports[i].Handler( Script, NArguments, Arguments );
+ bFound = 1;
+ }
}
- if(!fcn) return NULL;
- // Execute!
- return AST_ExecuteNode(Script, fcn->Code);
+ // Not found?
+ if(!bFound)
+ {
+ fprintf(stderr, "Undefined reference to '%s'\n", trueName);
+ }
+
+ if( trueName != Function && trueName != &Function[1] )
+ free(trueName);
+
+ return ret;
+
}
/**
free( fcn );
fcn = nextFcn;
}
+
+ // TODO: Pass this off to AST for a proper cleanup
+ free(Script->Script);
+
+ free(Script);
}
#include <stdlib.h>
#include <stdio.h>
#include <spiderscript.h>
+#define WANT_TOKEN_STRINGS 1
#include "tokens.h"
#include "ast.h"
+#define DEBUG 0
+
// === PROTOTYPES ===
tAST_Script *Parse_Buffer(tSpiderVariant *Variant, char *Buffer);
tAST_Node *Parse_DoCodeBlock(tParser *Parser);
-tAST_Node *Parse_DoExpr(tParser *Parser);
+tAST_Node *Parse_DoBlockLine(tParser *Parser);
+tAST_Node *Parse_GetVarDef(tParser *Parser, int Type);
tAST_Node *Parse_DoExpr0(tParser *Parser); // Assignment
tAST_Node *Parse_DoExpr1(tParser *Parser); // Boolean Operators
tAST_Node *Parse_GetVariable(tParser *Parser);
tAST_Node *Parse_GetIdent(tParser *Parser);
-void SyntaxAssert(int Have, int Want);
+void SyntaxAssert(tParser *Parser, int Have, int Want);
// === CODE ===
/**
tAST_Node *mainCode;
char *name;
tAST_Function *fcn;
+ int type;
+
+ #if DEBUG >= 2
+ printf("Parse_Buffer: (Variant=%p, Buffer=%p)\n", Variant, Buffer);
+ #endif
// Initialise parser
+ parser.LastToken = -1;
+ parser.NextToken = -1;
+ parser.CurLine = 1;
parser.BufStart = Buffer;
parser.CurPos = Buffer;
ret = AST_NewScript();
mainCode = AST_NewCodeBlock();
- for(;;)
+ if( setjmp( parser.JmpTarget ) != 0 )
+ {
+ AST_FreeNode( mainCode );
+ return NULL;
+ }
+
+ while(Parser->Token != TOK_EOF)
{
switch( GetToken(Parser) )
{
- case TOK_RWD_FUNCTION:
- // Define a function
- SyntaxAssert( GetToken(Parser), TOK_IDENT );
+ case TOK_EOF:
+ break;
+
+ // Typed variables/functions
+ case TOKEN_GROUP_TYPES:
+ {
+ int tok, type;
+ TOKEN_GET_DATATYPE(type, Parser->Token);
+
+ tok = GetToken(Parser);
+ // Define a function (pass on to the other function definition code)
+ if( tok == TOK_IDENT ) {
+ goto defFcn;
+ }
+ // Define a variable
+ else if( tok == TOK_VARIABLE ) {
+ AST_AppendNode( mainCode, Parse_GetVarDef(Parser, type) );
+ SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
+ }
+ else {
+ fprintf(stderr, "ERROR: Unexpected %s, expected TOK_IDENT or TOK_VARIABLE\n",
+ csaTOKEN_NAMES[tok]);
+ }
+ }
+ break;
+
+ // Define a function
+ case TOK_RWD_FUNCTION:
+ if( !Variant->bDyamicTyped ) {
+ fprintf(stderr, "ERROR: Attempt to create a dynamic function\n");
+ longjmp(Parser->JmpTarget, -1);
+ }
+ type = SS_DATATYPE_DYNAMIC;
+ SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
+ defFcn:
name = strndup( Parser->TokenStr, Parser->TokenLen );
fcn = AST_AppendFunction( ret, name );
+ #if DEBUG
+ printf("DefFCN %s\n", name);
+ #endif
free(name);
- SyntaxAssert( GetToken(Parser), TOK_PAREN_OPEN );
- // TODO: Arguments
- SyntaxAssert( GetToken(Parser), TOK_PAREN_CLOSE );
+ // Get arguments
+ SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN );
+ if( LookAhead(Parser) != TOK_PAREN_CLOSE )
+ {
+ do {
+ type = SS_DATATYPE_DYNAMIC;
+ GetToken(Parser);
+ // Non dynamic typed variants must use data types
+ if( !Variant->bDyamicTyped ) {
+ TOKEN_GET_DATATYPE(type, Parser->Token);
+ GetToken(Parser);
+ }
+ AST_AppendFunctionArg(fcn, Parse_GetVarDef(Parser, type));
+ } while(GetToken(Parser) == TOK_COMMA);
+ }
+ else
+ GetToken(Parser);
+ SyntaxAssert(Parser, Parser->Token, TOK_PAREN_CLOSE );
AST_SetFunctionCode( fcn, Parse_DoCodeBlock(Parser) );
break;
default:
- PutBack(&parser);
- AST_AppendNode( mainCode, Parse_DoExpr(Parser) );
+ PutBack(Parser);
+ AST_AppendNode( mainCode, Parse_DoBlockLine(Parser) );
break;
}
}
fcn = AST_AppendFunction( ret, "" );
AST_SetFunctionCode( fcn, mainCode );
+ printf("---- %p parsed as SpiderScript ----\n", Buffer);
+
return ret;
}
tAST_Node *Parse_DoCodeBlock(tParser *Parser)
{
tAST_Node *ret;
- SyntaxAssert( GetToken(Parser), TOK_BRACE_OPEN );
+ SyntaxAssert(Parser, GetToken(Parser), TOK_BRACE_OPEN );
ret = AST_NewCodeBlock();
- while( GetToken(Parser) != TOK_BRACE_CLOSE )
+ while( LookAhead(Parser) != TOK_BRACE_CLOSE )
+ {
+ AST_AppendNode( ret, Parse_DoBlockLine(Parser) );
+ }
+ GetToken(Parser); // Omnomnom
+ return ret;
+}
+
+/**
+ * \brief Parse a line in a block
+ */
+tAST_Node *Parse_DoBlockLine(tParser *Parser)
+{
+ tAST_Node *ret;
+
+ //printf("Parse_DoBlockLine: Line %i\n", Parser->CurLine);
+
+ switch(LookAhead(Parser))
{
- AST_AppendNode( ret, Parse_DoExpr(Parser) );
- SyntaxAssert( GetToken(Parser), TOK_SEMICOLON );
+
+ // Return from a method
+ case TOK_RWD_RETURN:
+ //printf("return\n");
+ GetToken(Parser);
+ ret = AST_NewUniOp(NODETYPE_RETURN, Parse_DoExpr0(Parser));
+ break;
+
+ // Define Variables
+ case TOK_RWD_OBJECT:
+ case TOK_RWD_STRING:
+ case TOK_RWD_REAL:
+ case TOK_RWD_INTEGER:
+ {
+ int type;
+
+ switch(GetToken(Parser))
+ {
+ case TOK_RWD_INTEGER: type = SS_DATATYPE_INTEGER; break;
+ case TOK_RWD_OBJECT: type = SS_DATATYPE_OBJECT; break;
+ case TOK_RWD_REAL: type = SS_DATATYPE_REAL; break;
+ case TOK_RWD_STRING: type = SS_DATATYPE_STRING; break;
+ }
+
+ SyntaxAssert(Parser, GetToken(Parser), TOK_VARIABLE);
+
+ ret = Parse_GetVarDef(Parser, type);
+ }
+ break;
+
+ // Default
+ default:
+ //printf("exp0\n");
+ ret = Parse_DoExpr0(Parser);
+ break;
}
+
+ SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON );
return ret;
}
/**
- * \brief Parse an expression
+ * \brief Get a variable definition
*/
-tAST_Node *Parse_DoExpr(tParser *Parser)
+tAST_Node *Parse_GetVarDef(tParser *Parser, int Type)
{
- return Parse_DoExpr0(Parser);
+ char name[Parser->TokenLen];
+ tAST_Node *ret;
+
+ SyntaxAssert(Parser, Parser->Token, TOK_VARIABLE);
+
+ // copy the name (trimming the $)
+ memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
+ name[Parser->TokenLen-1] = 0;
+ // Define the variable
+ ret = AST_NewDefineVar(Type, name);
+ // Handle arrays
+ while( LookAhead(Parser) == TOK_SQUARE_OPEN )
+ {
+ GetToken(Parser);
+ AST_AppendNode(ret, Parse_DoExpr0(Parser));
+ SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
+ }
+ return ret;
}
/**
#if 0
case TOK_DIV_EQU:
GetToken(Parser); // Eat Token
- ret = AST_NewAssignOp(ret, NODETYPE_DIVIDE, DoExpr0(Parser));
+ ret = AST_NewAssign(NODETYPE_DIVIDE, ret, Parse_DoExpr0(Parser));
break;
case TOK_MULT_EQU:
GetToken(Parser); // Eat Token
- ret = AST_NewAssignOp(ret, NODETYPE_MULTIPLY, DoExpr0(Parser));
+ ret = AST_NewAssign(NODETYPE_MULTIPLY, ret, Parse_DoExpr0(Parser));
break;
#endif
- default: break;
+ default:
+ #if DEBUG >= 2
+ printf("Parse_DoExpr0: Parser->Token = %i\n", Parser->Token);
+ #endif
+ break;
}
return ret;
}
// --------------------
tAST_Node *Parse_DoParen(tParser *Parser)
{
+ #if DEBUG >= 2
+ printf("Parse_DoParen: (Parser=%p)\n", Parser);
+ #endif
if(LookAhead(Parser) == TOK_PAREN_OPEN)
{
tAST_Node *ret;
GetToken(Parser);
+
+ // TODO: Handle casts here
+
ret = Parse_DoExpr0(Parser);
- SyntaxAssert(GetToken(Parser), TOK_PAREN_CLOSE);
+ SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
return ret;
}
else
{
int tok = LookAhead(Parser);
+ #if DEBUG >= 2
+ printf("Parse_DoValue: tok = %i\n", tok);
+ #endif
+
switch(tok)
{
case TOK_STR: return Parse_GetString(Parser);
case TOK_VARIABLE: return Parse_GetVariable(Parser);
default:
- //ParseError2( tok, TOK_T_VALUE );
- return NULL;
+ fprintf(stderr, "Syntax Error: Unexpected %s on line %i, Expected TOK_T_VALUE\n",
+ csaTOKEN_NAMES[tok], Parser->CurLine);
+ longjmp( Parser->JmpTarget, -1 );
}
}
*/
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);
+ SyntaxAssert( Parser, GetToken(Parser), TOK_VARIABLE );
+ {
+ char name[Parser->TokenLen];
+ memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
+ name[Parser->TokenLen-1] = 0;
+ ret = AST_NewVariable( name );
+ #if DEBUG >= 2
+ printf("Parse_GetVariable: name = '%s'\n", name);
+ #endif
+ }
+ // Handle array references
+ while( LookAhead(Parser) == TOK_SQUARE_OPEN )
+ {
+ GetToken(Parser);
+ ret = AST_NewBinOp(NODETYPE_INDEX, ret, Parse_DoExpr0(Parser));
+ SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
+ }
return ret;
}
{
tAST_Node *ret;
char *name;
- SyntaxAssert( GetToken(Parser), TOK_IDENT );
+ SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
name = strndup( Parser->TokenStr, Parser->TokenLen );
+ #if 0
+ while( GetToken(Parser) == TOK_SCOPE )
+ {
+ ret = AST_New
+ }
+ PutBack(Parser);
+ #endif
+
if( GetToken(Parser) == TOK_PAREN_OPEN )
{
+ #if DEBUG >= 2
+ printf("Parse_GetIdent: Calling '%s'\n", name);
+ #endif
// Function Call
ret = AST_NewFunctionCall( name );
// Read arguments
{
PutBack(Parser);
do {
+ #if DEBUG >= 2
+ printf(" Parse_GetIdent: Argument\n");
+ #endif
AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) );
} while(GetToken(Parser) == TOK_COMMA);
- SyntaxAssert( Parser->Token, TOK_PAREN_CLOSE );
+ SyntaxAssert( Parser, Parser->Token, TOK_PAREN_CLOSE );
+ #if DEBUG >= 2
+ printf(" Parse_GetIdent: All arguments parsed\n");
+ #endif
}
}
else {
// Runtime Constant
+ #if DEBUG >= 2
+ printf("Parse_GetIdent: Referencing '%s'\n", name);
+ #endif
PutBack(Parser);
ret = AST_NewConstant( name );
}
/**
* \brief Check for an error
*/
-void SyntaxAssert(int Have, int Want)
+void SyntaxAssert(tParser *Parser, int Have, int Want)
{
if(Have != Want) {
- fprintf(stderr, "ERROR: Expected %i, got %i\n", Want, Have);
- //longjmp(jmpTarget, 1);
- return;
+ fprintf(stderr, "ERROR: SyntaxAssert Failed, Expected %s(%i), got %s(%i) on line %i\n",
+ csaTOKEN_NAMES[Want], Want, csaTOKEN_NAMES[Have], Have, Parser->CurLine);
+ longjmp(Parser->JmpTarget, -1);
}
}
#ifndef _TOKENS_H_
#define _TOKENS_H_
+#include <setjmp.h>
+
// === TYPES ===
typedef struct
{
char *BufStart;
char *CurPos;
+ int LastLine;
int LastToken, LastTokenLen;
char *LastTokenStr;
+ int NextLine;
int NextToken, NextTokenLen;
char *NextTokenStr;
+ int CurLine;
int Token, TokenLen;
char *TokenStr;
+
+ jmp_buf JmpTarget;
} tParser;
// === FUNCTIONS ===
TOK_IDENT,
TOK_RWD_FUNCTION,
+ TOK_RWD_NAMESPACE,
+ TOK_RWD_RETURN,
+
+ TOK_RWD_VOID,
+ TOK_RWD_OBJECT,
TOK_RWD_STRING,
TOK_RWD_INTEGER,
TOK_RWD_REAL,
TOK_LAST
};
+#define TOKEN_GROUP_TYPES TOK_RWD_VOID:\
+ case TOK_RWD_OBJECT:\
+ case TOK_RWD_INTEGER:\
+ case TOK_RWD_STRING:\
+ case TOK_RWD_REAL
+#define TOKEN_GROUP_TYPES_STR "TOK_RWD_VOID, TOK_RWD_OBJECT, TOK_RWD_INTEGER, TOK_RWD_STRING or TOK_RWD_REAL"
+
+#define TOKEN_GET_DATATYPE(_type, _tok) do { switch(_tok) {\
+ case TOK_RWD_VOID: _type = SS_DATATYPE_UNDEF; break;\
+ case TOK_RWD_INTEGER:_type = SS_DATATYPE_INTEGER; break;\
+ case TOK_RWD_OBJECT: _type = SS_DATATYPE_OBJECT; break;\
+ case TOK_RWD_REAL: _type = SS_DATATYPE_REAL; break;\
+ case TOK_RWD_STRING: _type = SS_DATATYPE_STRING; break;\
+ default:fprintf(stderr,\
+ "ERROR: Unexpected %s, expected "TOKEN_GROUP_TYPES_STR"\n",csaTOKEN_NAMES[Parser->Token]);\
+ break;\
+ } } while(0)
+
+# if WANT_TOKEN_STRINGS
+const char * const csaTOKEN_NAMES[] = {
+ "TOK_INVAL",
+ "TOK_EOF",
+
+ "TOK_STR",
+ "TOK_INTEGER",
+ "TOK_VARIABLE",
+ "TOK_IDENT",
+
+ "TOK_RWD_FUNCTION",
+ "TOK_RWD_NAMESPACE",
+ "TOK_RWD_RETURN",
+
+ "TOK_RWD_VOID",
+ "TOK_RWD_OBJECT",
+ "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
+
#endif