3 * by John Hodge (thePowersGang)
15 typedef struct sBC_StackEnt tBC_StackEnt;
16 typedef struct sBC_Stack tBC_Stack;
18 enum eBC_StackEntTypes
20 ET_NULL, // Start of the stack
22 ET_FUNCTION_START = NUM_SS_DATATYPES,
23 ET_REFERENCE // Reference to a tSpiderValue
32 tSpiderValue *Reference; // Used for everything else
33 tSpiderObject *Object;
41 tBC_StackEnt Entries[];
45 tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args);
46 int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount);
49 int Bytecode_int_StackPop(tBC_Stack *Stack, tBC_StackEnt *Dest)
51 if( Stack->EntryCount == 0 ) return 1;
53 *Dest = Stack->Entries[Stack->EntryCount];
57 int Bytecode_int_StackPush(tBC_Stack *Stack, tBC_StackEnt *Src)
59 if( Stack->EntryCount == Stack->EntrySpace ) return 1;
60 Stack->Entries[Stack->EntryCount] = *Src;
65 int Bytecode_int_IsStackEntTrue(tBC_StackEnt *Ent)
69 case SS_DATATYPE_INTEGER:
70 return !!Ent->Integer;
71 case SS_DATATYPE_REAL:
72 return (-.5f < Ent->Real && Ent->Real < 0.5f);
73 case SS_DATATYPE_OBJECT:
74 return Ent->Object != NULL;
75 case ET_FUNCTION_START:
78 return SpiderScript_IsValueTrue(Ent->Reference);
82 tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp)
86 case SS_DATATYPE_INTEGER:
87 tmp->Type = SS_DATATYPE_INTEGER;
88 tmp->ReferenceCount = 2; // Stops it being freed
89 tmp->Integer = Ent->Integer;
91 case SS_DATATYPE_REAL:
92 tmp->Type = SS_DATATYPE_REAL;
93 tmp->ReferenceCount = 2; // Stops it being freed
94 tmp->Real = Ent->Real;
96 case SS_DATATYPE_OBJECT:
97 tmp->Type = SS_DATATYPE_OBJECT;
98 tmp->ReferenceCount = 2;
99 tmp->Object = Ent->Object;
101 case ET_FUNCTION_START:
104 return Ent->Reference;
108 void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value)
112 case SS_DATATYPE_INTEGER:
113 Ent->Type = SS_DATATYPE_INTEGER;
114 Ent->Integer = Value->Integer;
116 case SS_DATATYPE_REAL:
117 Ent->Type = SS_DATATYPE_REAL;
118 Ent->Real = Value->Real;
120 case SS_DATATYPE_OBJECT:
121 Ent->Type = SS_DATATYPE_OBJECT;
122 Ent->Object = Value->Object;
125 SpiderScript_ReferenceValue(Value);
126 Ent->Reference = Value;
131 #define GET_STACKVAL(dst) if((ret = Bytecode_int_StackPop(Stack, &dst))) return ret;
132 #define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
133 #define OP_STRING(op_ptr) ((op_ptr)->Content.StringInt.String)
135 tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args)
137 const int stack_size = 100;
138 tSpiderValue *ret, tmpsval;
143 stack = malloc(sizeof(tBC_Stack) + stack_size*sizeof(tBC_StackEnt));
144 stack->EntrySpace = stack_size;
145 stack->EntryCount = 0;
147 // Push arguments in order (so top is last arg)
148 for( i = 0; i < NArguments; i ++ )
150 Bytecode_int_SetSpiderValue(&val, Args[i]);
151 Bytecode_int_StackPush(stack, &val);
155 Bytecode_int_ExecuteFunction(Script, Fcn, stack, NArguments);
158 Bytecode_int_StackPop(stack, &val);
159 ret = Bytecode_int_GetSpiderValue(&val, &tmpsval);
160 // Ensure it's a heap value
161 if(ret == &tmpsval) {
162 ret = malloc(sizeof(tSpiderValue));
163 memcpy(ret, &tmpsval, sizeof(tSpiderValue));
169 * \brief Execute a bytecode function with a stack
171 int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount)
175 tBC_StackEnt val1, val2;
176 tBC_StackEnt local_vars[Fcn->BCFcn->MaxVariableCount]; // Includes arguments
177 tSpiderValue tmpVal1, tmpVal2; // temp storage
178 tSpiderValue *pval1, *pval2, *ret_val;
181 if( ArgCount > Fcn->ArgumentCount ) return -1;
182 for( i = Fcn->ArgumentCount; --i != ArgCount; )
184 local_vars[i].Integer = 0;
185 local_vars[i].Type = Fcn->Arguments[i].Type;
189 GET_STACKVAL(local_vars[i]);
190 // TODO: Type checks / enforcing
194 memset(&val1, 0, sizeof(val1));
195 val1.Type = ET_FUNCTION_START;
196 Bytecode_int_StackPush(Stack, &val1);
199 op = Fcn->BCFcn->Operations;
202 tBC_Op *nextop = op->Next;
204 switch(op->Operation)
208 nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
212 if( Bytecode_int_IsStackEntTrue(&val1) )
213 nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
215 case BC_OP_JUMPIFNOT:
217 if( !Bytecode_int_IsStackEntTrue(&val1) )
218 nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
222 case BC_OP_DEFINEVAR: {
224 type = OP_INDX(op) & 0xFFFF;
225 slot = OP_INDX(op) >> 16;
226 if(slot < 0 || slot >= sizeof(local_vars)/sizeof(local_vars[0])) return -1;
227 memset(&local_vars[slot], 0, sizeof(local_vars[0]));
228 local_vars[slot].Type = type;
233 ast_op = NODETYPE_ADD;
235 if(!ast_op) ast_op = NODETYPE_SUBTRACT;
239 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
240 pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
241 ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
242 if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
243 if(pval2 != &tmpVal2) SpiderScript_DereferenceValue(pval2);
244 Bytecode_int_SetSpiderValue(&val1, ret_val);
245 if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
256 // - Delete local vars