3 * by John Hodge (thePowersGang)
16 typedef struct sBC_StackEnt tBC_StackEnt;
17 typedef struct sBC_Stack tBC_Stack;
19 enum eBC_StackEntTypes
21 ET_NULL, // Start of the stack
23 ET_FUNCTION_START = NUM_SS_DATATYPES,
24 ET_REFERENCE // Reference to a tSpiderValue
33 tSpiderValue *Reference; // Used for everything else
34 tSpiderObject *Object;
42 tBC_StackEnt Entries[];
46 tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args);
47 int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount);
50 int Bytecode_int_StackPop(tBC_Stack *Stack, tBC_StackEnt *Dest)
52 if( Stack->EntryCount == 0 ) return 1;
54 *Dest = Stack->Entries[Stack->EntryCount];
58 int Bytecode_int_StackPush(tBC_Stack *Stack, tBC_StackEnt *Src)
60 if( Stack->EntryCount == Stack->EntrySpace ) return 1;
61 Stack->Entries[Stack->EntryCount] = *Src;
66 int Bytecode_int_IsStackEntTrue(tBC_StackEnt *Ent)
70 case SS_DATATYPE_INTEGER:
71 return !!Ent->Integer;
72 case SS_DATATYPE_REAL:
73 return (-.5f < Ent->Real && Ent->Real < 0.5f);
74 case SS_DATATYPE_OBJECT:
75 return Ent->Object != NULL;
76 case ET_FUNCTION_START:
79 return SpiderScript_IsValueTrue(Ent->Reference);
83 tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp)
87 case SS_DATATYPE_INTEGER:
88 tmp->Type = SS_DATATYPE_INTEGER;
89 tmp->ReferenceCount = 2; // Stops it being freed
90 tmp->Integer = Ent->Integer;
92 case SS_DATATYPE_REAL:
93 tmp->Type = SS_DATATYPE_REAL;
94 tmp->ReferenceCount = 2; // Stops it being freed
95 tmp->Real = Ent->Real;
97 case SS_DATATYPE_OBJECT:
98 tmp->Type = SS_DATATYPE_OBJECT;
99 tmp->ReferenceCount = 2;
100 tmp->Object = Ent->Object;
102 case ET_FUNCTION_START:
105 return Ent->Reference;
109 void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value)
113 case SS_DATATYPE_INTEGER:
114 Ent->Type = SS_DATATYPE_INTEGER;
115 Ent->Integer = Value->Integer;
117 case SS_DATATYPE_REAL:
118 Ent->Type = SS_DATATYPE_REAL;
119 Ent->Real = Value->Real;
121 case SS_DATATYPE_OBJECT:
122 Ent->Type = SS_DATATYPE_OBJECT;
123 Ent->Object = Value->Object;
126 SpiderScript_ReferenceValue(Value);
127 Ent->Reference = Value;
132 #define GET_STACKVAL(dst) if((ret = Bytecode_int_StackPop(Stack, &dst))) return ret;
133 #define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
134 #define OP_STRING(op_ptr) ((op_ptr)->Content.StringInt.String)
136 tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args)
138 const int stack_size = 100;
139 tSpiderValue *ret, tmpsval;
144 stack = malloc(sizeof(tBC_Stack) + stack_size*sizeof(tBC_StackEnt));
145 stack->EntrySpace = stack_size;
146 stack->EntryCount = 0;
148 // Push arguments in order (so top is last arg)
149 for( i = 0; i < NArguments; i ++ )
151 Bytecode_int_SetSpiderValue(&val, Args[i]);
152 Bytecode_int_StackPush(stack, &val);
156 Bytecode_int_ExecuteFunction(Script, Fcn, stack, NArguments);
159 Bytecode_int_StackPop(stack, &val);
161 ret = Bytecode_int_GetSpiderValue(&val, &tmpsval);
162 // Ensure it's a heap value
163 if(ret == &tmpsval) {
164 ret = malloc(sizeof(tSpiderValue));
165 memcpy(ret, &tmpsval, sizeof(tSpiderValue));
173 * \brief Execute a bytecode function with a stack
175 int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount)
179 tBC_StackEnt val1, val2;
180 tBC_StackEnt local_vars[Fcn->BCFcn->MaxVariableCount]; // Includes arguments
181 tSpiderValue tmpVal1, tmpVal2; // temp storage
182 tSpiderValue *pval1, *pval2, *ret_val;
185 if( ArgCount > Fcn->ArgumentCount ) return -1;
186 printf("Fcn->ArgumentCount = %i\n", Fcn->ArgumentCount);
187 for( i = Fcn->ArgumentCount; i > ArgCount; )
190 local_vars[i].Integer = 0;
191 local_vars[i].Type = Fcn->Arguments[i].Type;
195 GET_STACKVAL(local_vars[i]);
196 // TODO: Type checks / enforcing
200 memset(&val1, 0, sizeof(val1));
201 val1.Type = ET_FUNCTION_START;
202 Bytecode_int_StackPush(Stack, &val1);
205 op = Fcn->BCFcn->Operations;
208 tBC_Op *nextop = op->Next;
210 switch(op->Operation)
214 nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
218 if( Bytecode_int_IsStackEntTrue(&val1) )
219 nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
221 case BC_OP_JUMPIFNOT:
223 if( !Bytecode_int_IsStackEntTrue(&val1) )
224 nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
228 case BC_OP_DEFINEVAR: {
230 type = OP_INDX(op) & 0xFFFF;
231 slot = OP_INDX(op) >> 16;
232 if(slot < 0 || slot >= sizeof(local_vars)/sizeof(local_vars[0])) return -1;
233 memset(&local_vars[slot], 0, sizeof(local_vars[0]));
234 local_vars[slot].Type = type;
239 ast_op = NODETYPE_ADD;
241 if(!ast_op) ast_op = NODETYPE_SUBTRACT;
245 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
246 pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
247 ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
248 if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
249 if(pval2 != &tmpVal2) SpiderScript_DereferenceValue(pval2);
250 Bytecode_int_SetSpiderValue(&val1, ret_val);
251 if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
256 printf("Unknown operation %i\n", op->Operation);
263 // - Delete local vars