case NODETYPE_NOP: break;
case NODETYPE_VARIABLE: break;
case NODETYPE_CONSTANT: break;
- case NODETYPE_BREAK: break;
+ case NODETYPE_BREAK:
case NODETYPE_CONTINUE: break;
case NODETYPE_STRING:
tAST_Node *AST_NewLoop(tParser *Parser, const char *Tag, tAST_Node *Init, int bPostCheck, tAST_Node *Condition, tAST_Node *Increment, tAST_Node *Code)
{
- tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_LOOP, strlen(Tag) + 1);
+ tAST_Node *ret;
+ if(!Tag) Tag = "";
+ ret = AST_int_AllocateNode(Parser, NODETYPE_LOOP, strlen(Tag) + 1);
ret->For.Init = Init;
ret->For.bCheckAfter = !!bPostCheck;
ret->For.Condition = Condition;
extern void Object_Dereference(tSpiderValue *Object);
extern void Object_Reference(tSpiderValue *Object);
extern tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
+extern tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right);
+extern tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value);
#endif
char *arg_names[ASTFcn->ArgumentCount];
int arg_types[ASTFcn->ArgumentCount];
- for(arg = ASTFcn->Arguments; arg; arg = arg->NextSibling)
+ for(arg = ASTFcn->Arguments, i = 0; arg; arg = arg->NextSibling, i ++)
{
arg_names[i] = arg->DefVar.Name;
arg_types[i] = arg->DefVar.DataType;
#ifndef _BYTECODE_H_
#define _BYTECODE_H_
-struct sBytecodeHeader
+#include "bytecode_ops.h"
+
+typedef struct sBC_Op tBC_Op;
+typedef struct sBC_Function tBC_Function;
+
+struct sBC_Op
{
- 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[];
+ tBC_Op *Next;
+ int Operation;
+ int bUseInteger; // Used for serialisation
+ union {
+ struct {
+ const char *String;
+ int Integer;
+ } StringInt;
+
+ uint64_t Integer;
+ double Real;
+ } Content;
};
-enum eBytecodeOperations
+struct sBC_Function
{
- BCOP_UNDEF,
- BCOP_NOP,
+ const char *Name;
- BCOP_DEFVAR,
- BCOP_RETURN,
+ int LabelCount;
+ int LabelSpace;
+ tBC_Op **Labels;
- NUM_BCOP
-}
+ int MaxVariableCount;
+ // NOTE: These fields are invalid after compilation
+ int VariableCount;
+ int VariableSpace;
+ const char **VariableNames; // Only type needs to be stored
+ int CurContextDepth; // Used to get the real var count
+
+ int OperationCount;
+ tBC_Op *Operations;
+ tBC_Op *OperationsEnd;
+
+ int ArgumentCount;
+ struct {
+ char *Name;
+ int Type;
+ } Arguments[];
+};
#endif
#include <stdio.h>
#include "bytecode_gen.h"
#include <string.h>
+#include "bytecode.h"
// === IMPORTS ===
// === STRUCTURES ===
-typedef struct sBC_Op tBC_Op;
-
-struct sBC_Op
-{
- tBC_Op *Next;
- int Operation;
- int bUseInteger;
- union {
- struct {
- const char *String;
- int Integer;
- } StringInt;
-
- uint64_t Integer;
- double Real;
- } Content;
-};
-
-struct sBC_Function
-{
- const char *Name;
-
- int LabelCount;
- int LabelSpace;
- tBC_Op **Labels;
-
- int MaxVariableCount;
- // NOTE: These fields are invalid after compilation
- int VariableCount;
- int VariableSpace;
- const char **VariableNames; // Only type needs to be stored
- int CurContextDepth; // Used to get the real var count
-
- int OperationCount;
- tBC_Op *Operations;
- tBC_Op *OperationsEnd;
-
- int ArgumentCount;
- struct {
- char *Name;
- int Type;
- } Arguments[];
-};
// === PROTOTYPES ===
tBC_Op *Bytecode_int_AllocateOp(int Operation);
+ int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name);
// === GLOBALS ===
ret->Name = Name;
ret->LabelSpace = ret->LabelCount = 0;
ret->Labels = NULL;
-
+
+ ret->MaxVariableCount = 0;
+ ret->CurContextDepth = 0;
ret->VariableCount = ret->VariableSpace = 0;
ret->VariableNames = NULL;
{
ret->Arguments[i].Name = strdup(ArgNames[i]);
ret->Arguments[i].Type = ArgTypes[i];
+ Bytecode_int_AddVariable(ret, ret->Arguments[i].Name);
}
return ret;
Fcn->OperationsEnd = Op;
}
-void Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name)
+int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name)
{
if(Handle->VariableCount == Handle->VariableSpace) {
void *tmp;
Handle->VariableSpace += 10;
tmp = realloc(Handle->VariableNames, Handle->VariableSpace * sizeof(Handle->VariableNames[0]));
- if(!tmp) return ; // TODO: Error
+ if(!tmp) return -1; // TODO: Error
Handle->VariableNames = tmp;
}
Handle->VariableNames[Handle->VariableCount] = Name;
// Get max count (used when executing to get the frame size)
if(Handle->VariableCount - Handle->CurContextDepth >= Handle->MaxVariableCount)
Handle->MaxVariableCount = Handle->VariableCount - Handle->CurContextDepth;
+ return Handle->VariableCount - 1;
}
int Bytecode_int_GetVarIndex(tBC_Function *Handle, const char *Name)
// Get the start of this context
for( i = Handle->VariableCount; i --; )
{
- if( Handle->VariableNames[i] == NULL ) break;
- }
- // Check for duplicate allocation
- for( ; i < Handle->VariableCount; i ++ )
- {
- if( strcmp(Name, Handle->VariableNames[i]) == 0 )
+ if( Handle->VariableNames[i] && strcmp(Name, Handle->VariableNames[i]) == 0 )
return i;
}
return -1;
if( Handle->VariableNames[i] == NULL ) break;
}
Handle->CurContextDepth --;
+ Handle->VariableCount = i;
DEF_BC_NONE(BC_OP_LEAVECONTEXT)
}
// DEF_BC_STRINT(BC_OP_IMPORTNS, Name, 0)
void Bytecode_AppendDefineVar(tBC_Function *Handle, const char *Name, int Type)
{
+ int i;
#if 1
- // Check for duplicates
- if( Bytecode_int_GetVarIndex(Handle, Name) )
- return ; // TODO: Error
+ // Get the start of this context
+ for( i = Handle->VariableCount; i --; )
+ {
+ if( Handle->VariableNames[i] == NULL ) break;
+ }
+ // Check for duplicate allocation
+ for( i ++; i < Handle->VariableCount; i ++ )
+ {
+ if( strcmp(Name, Handle->VariableNames[i]) == 0 )
+ return ;
+ }
#endif
- Bytecode_int_AddVariable(Handle, Name);
+ i = Bytecode_int_AddVariable(Handle, Name);
- DEF_BC_STRINT(BC_OP_DEFINEVAR, Name, Type)
+ DEF_BC_STRINT(BC_OP_DEFINEVAR, Name, (Type&0xFFFF) | (i << 16))
}
#define _BYTECODE_GEN_H_
#include "ast.h"
+#include "bytecode.h"
-typedef struct sBC_Function tBC_Function;
typedef struct sStringList tStringList;
typedef struct sString tString;
//typedef struct sAST_Function tAST_Function;
code = Bytecode_SerialiseFunction(bc_fcn, &len, &strings);
Bytecode_DeleteFunction(bc_fcn);
fwrite(code, len, 1, fp);
+ free(code);
}
// String table
string_offset += str->Length + 1;
}
// Data
- for(str = strings.Head; str; str = str->Next)
+ for(str = strings.Head; str;)
{
+ tString *nextstr = str->Next;
fwrite(str->Data, str->Length, 1, fp);
_put8(0);
+ free(str);
+ str = nextstr;
}
+ strings.Head = NULL;
+ strings.Tail = NULL;
}
// Fix header
_put32(strings.Count);
_put32(strtab_ofs);
+ fclose(fp);
+
return 0;
}
// === PROTOTYPES ===
// - Node Execution
tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
-tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right);
-tSpiderValue *AST_ExecuteNode_UniOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Value);
+tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right);
+tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value);
// - Variables
tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value);
int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value);
// varVal->ReferenceCount);
}
#endif
- value = AST_ExecuteNode_BinOp(Block, Node, Node->Assign.Operation, varVal, ret);
+ value = AST_ExecuteNode_BinOp(Block->Script, Node, Node->Assign.Operation, varVal, ret);
if(value == ERRPTR) return ERRPTR;
if(ret) SpiderScript_DereferenceValue(ret);
varVal = Variable_GetValue(Block, Node->UniOp.Value);
if( Node->Type == NODETYPE_POSTDEC )
- value = AST_ExecuteNode_BinOp(Block, Node, NODETYPE_SUBTRACT, varVal, &one);
+ value = AST_ExecuteNode_BinOp(Block->Script, Node, NODETYPE_SUBTRACT, varVal, &one);
else
- value = AST_ExecuteNode_BinOp(Block, Node, NODETYPE_ADD, varVal, &one);
+ value = AST_ExecuteNode_BinOp(Block->Script, Node, NODETYPE_ADD, varVal, &one);
if( value == ERRPTR )
return ERRPTR;
case NODETYPE_NEGATE: // Negation (-)
op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
if(op1 == ERRPTR) return ERRPTR;
- ret = AST_ExecuteNode_UniOp(Block, Node, Node->Type, op1);
+ ret = AST_ExecuteNode_UniOp(Block->Script, Node, Node->Type, op1);
SpiderScript_DereferenceValue(op1);
break;
return ERRPTR;
}
- ret = AST_ExecuteNode_BinOp(Block, Node, Node->Type, op1, op2);
+ ret = AST_ExecuteNode_BinOp(Block->Script, Node, Node->Type, op1, op2);
// Free intermediate objects
SpiderScript_DereferenceValue(op1);
return ret;
}
-tSpiderValue *AST_ExecuteNode_UniOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Value)
+tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value)
{
tSpiderValue *ret;
#if 0
return ret;
}
-tSpiderValue *AST_ExecuteNode_BinOp(tAST_BlockState *Block, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right)
+tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right)
{
tSpiderValue *preCastValue = Right;
tSpiderValue *ret;
#endif
// If implicit casts are allowed, convert Right to Left's type
- if(Block->Script->Variant->bImplicitCasts)
+ if(Script->Variant->bImplicitCasts)
{
Right = SpiderScript_CastValueTo(Left->Type, Right);
if(Right == ERRPTR)
* - Generate a bytecode file
*/
#include <stdlib.h>
-#include "bytecode_ops.h"
+#include <stdint.h>
+#include <spiderscript.h>
+#include "bytecode.h"
+#include <string.h>
+#include "ast.h"
-typedef sBC_StackEnt tBC_StackEnt;
+typedef struct sBC_StackEnt tBC_StackEnt;
+typedef struct sBC_Stack tBC_Stack;
enum eBC_StackEntTypes
{
ET_NULL, // Start of the stack
- ET_FUNCTION_START, // Start of the function
- ET_INTEGER, // Integer / Boolean
- ET_REAL, // Real number
- ET_OBJECT, // Object
+ // SS_DATATYPE_*
+ ET_FUNCTION_START = NUM_SS_DATATYPES,
ET_REFERENCE // Reference to a tSpiderValue
};
struct sBC_StackEnt
{
- uint8_t EntType;
- uint8_t _padding[3];
+ uint8_t Type;
union {
uint64_t Integer;
double Real;
- tSpiderValue *Reference;
+ tSpiderValue *Reference; // Used for everything else
tSpiderObject *Object;
};
};
return 0;
}
+int Bytecode_int_IsStackEntTrue(tBC_StackEnt *Ent)
+{
+ switch(Ent->Type)
+ {
+ case SS_DATATYPE_INTEGER:
+ return !!Ent->Integer;
+ case SS_DATATYPE_REAL:
+ return (-.5f < Ent->Real && Ent->Real < 0.5f);
+ case SS_DATATYPE_OBJECT:
+ return Ent->Object != NULL;
+ case ET_FUNCTION_START:
+ return -1;
+ default:
+ return SpiderScript_IsValueTrue(Ent->Reference);
+ }
+}
+
+tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp)
+{
+ switch(Ent->Type)
+ {
+ case SS_DATATYPE_INTEGER:
+ tmp->Type = SS_DATATYPE_INTEGER;
+ tmp->ReferenceCount = 2; // Stops it being freed
+ tmp->Integer = Ent->Integer;
+ return tmp;
+ case SS_DATATYPE_REAL:
+ tmp->Type = SS_DATATYPE_REAL;
+ tmp->ReferenceCount = 2; // Stops it being freed
+ tmp->Real = Ent->Real;
+ return tmp;
+ case SS_DATATYPE_OBJECT:
+ tmp->Type = SS_DATATYPE_OBJECT;
+ tmp->ReferenceCount = 2;
+ tmp->Object = Ent->Object;
+ return tmp;
+ case ET_FUNCTION_START:
+ return NULL;
+ default:
+ return Ent->Reference;
+ }
+}
+
+void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value)
+{
+ switch(Value->Type)
+ {
+ case SS_DATATYPE_INTEGER:
+ Ent->Type = SS_DATATYPE_INTEGER;
+ Ent->Integer = Value->Integer;
+ break;
+ case SS_DATATYPE_REAL:
+ Ent->Type = SS_DATATYPE_REAL;
+ Ent->Real = Value->Real;
+ break;
+ case SS_DATATYPE_OBJECT:
+ Ent->Type = SS_DATATYPE_OBJECT;
+ Ent->Object = Value->Object;
+ break;
+ default:
+ SpiderScript_ReferenceValue(Value);
+ Ent->Reference = Value;
+ break;
+ }
+}
+
#define GET_STACKVAL(dst) if((ret = Bytecode_int_StackPop(Stack, &dst))) return ret;
+#define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
+#define OP_STRING(op_ptr) ((op_ptr)->Content.StringInt.String)
-int Bytecode_ExecuteFunction(tBC_Function *Fcn, tBC_Stack *Stack, int ArgCount);
+int Bytecode_ExecuteFunction(tSpiderScript *Script, tBC_Function *Fcn, tBC_Stack *Stack, int ArgCount)
{
+ int ret, ast_op, i;
tBC_Op *op;
tBC_StackEnt val1, val2;
- tBC_StackEnt local_vars[Fcn->MaxVariableCount+Fcn->ArgumentCount];
+ tBC_StackEnt local_vars[Fcn->MaxVariableCount]; // Includes arguments
+ tSpiderValue tmpVal1, tmpVal2; // temp storage
+ tSpiderValue *pval1, *pval2, *ret_val;
// Pop off arguments
+ if( ArgCount > Fcn->ArgumentCount ) return -1;
+ for( i = Fcn->ArgumentCount; --i != ArgCount; )
+ {
+ local_vars[i].Integer = 0;
+ local_vars[i].Type = Fcn->Arguments[i].Type;
+ }
+ for( ; i --; )
+ {
+ GET_STACKVAL(local_vars[i]);
+ // TODO: Type checks / enforcing
+ }
// Mark the start
+ memset(&val1, 0, sizeof(val1));
+ val1.Type = ET_FUNCTION_START;
+ Bytecode_int_StackPush(Stack, &val1);
// Execute!
op = Fcn->Operations;
while(op)
{
tBC_Op *nextop = op->Next;
- switch(op->Type)
+ ast_op = 0;
+ switch(op->Operation)
{
+ // Jumps
case BC_OP_JUMP:
- nextop = Fcn->Labels[op->StringInt.Integer];
+ nextop = Fcn->Labels[ OP_INDX(op) ];
break;
case BC_OP_JUMPIF:
GET_STACKVAL(val1);
if( Bytecode_int_IsStackEntTrue(&val1) )
- nextop = Fcn->Labels[op->StringInt.Integer];
+ nextop = Fcn->Labels[op->Content.StringInt.Integer];
break;
case BC_OP_JUMPIFNOT:
GET_STACKVAL(val1);
if( !Bytecode_int_IsStackEntTrue(&val1) )
- nextop = Fcn->Labels[op->StringInt.Integer];
+ nextop = Fcn->Labels[op->Content.StringInt.Integer];
+ break;
+
+ // Define variables
+ case BC_OP_DEFINEVAR: {
+ int type, slot;
+ type = OP_INDX(op) & 0xFFFF;
+ slot = OP_INDX(op) >> 16;
+ if(slot < 0 || slot >= sizeof(local_vars)/sizeof(local_vars[0])) return -1;
+ memset(&local_vars[slot], 0, sizeof(local_vars[0]));
+ local_vars[slot].Type = type;
+ } break;
+
+ // Operations
+ case BC_OP_ADD:
+ ast_op = NODETYPE_ADD;
+ case BC_OP_SUBTRACT:
+ if(!ast_op) ast_op = NODETYPE_SUBTRACT;
+
+ GET_STACKVAL(val2);
+ GET_STACKVAL(val1);
+ pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
+ pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
+ ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
+ if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
+ if(pval2 != &tmpVal2) SpiderScript_DereferenceValue(pval2);
+ Bytecode_int_SetSpiderValue(&val1, ret_val);
+ if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
break;
+
default:
// TODO:
break;
}
// Clean up
+ // - Delete local vars
+
+
+ // - Restore stack
+
+
+ return 0;
}
+
csaTOKEN_NAMES[tok]);
return NULL;
}
+ if(ident) free(ident);
}
break;
case TOK_RWD_FOR:
{
- const char *tag = "";
+ char *tag = NULL;
tAST_Node *init=NULL, *cond=NULL, *inc=NULL, *code;
GetToken(Parser); // Eat 'for'
code = Parse_DoCodeBlock(Parser);
ret = AST_NewLoop(Parser, tag, init, 0, cond, inc, code);
+ if(tag) free(tag);
}
return ret;