static void deleteToken (tokenInfo *const token) { vStringDelete (token->string); vStringDelete (token->scope); eFree (token); }
void eval( Node *node ) { int i, j; Number n1, n2, n3, n4; char *string1; Symbol *s; Node *n; Array *a; /* debugging */ #ifdef __DEBUG_TRACE__ SourceCode *sc; #endif /* init vars */ n1=0; n2=0; n3=0; n4=0; if (node == NULL) { return; } /* test node */ eMemTest( "eval: node is corrupt", node ); eMemTest( "eval: node->left is corrupt", node->left ); eMemTest( "eval: node->right is corrupt", node->right ); /* tracing */ if (node->trace != -1) { runLineId = node->trace; #ifdef __DEBUG_TRACE__ sc = eFindSource( runLineId ); eConsole("%d: %s\n", sc->lineNum, sc->text ); #endif /* sdlBasic_debugging */ if (debug==1){ screendebug(); //////////////////////////////////// } } /* debugging */ #ifdef __DEBUG_TRACE__ eConsole( "Op:%s\n", opcodeName[node->op] ); #endif switch( node->op ) { //case NULL: // break; case OpAdd: eval( node->left ); eval( node->right ); /* add or concat? */ if (getStackType( tos ) == DATA_STRING) { basConcat(); } else { n2 = popNumber(); n1 = popNumber(); pushNumber( n1 + n2 ); } break; case OpAnd: /* short circuit */ eval( node->left ); if (!popNumber()) { pushNumber( (Number)0 ); } else { eval( node->right ); if (popNumber()) { pushNumber( (Number)1 ); } else { pushNumber( (Number)0 ); } } break; case OpArgList: eval( node->left ); eval( node->right ); break; case OpArrayGet: eval( node->left ); /* indices and index */ getArrayElement( node->value.symbol ); break; case OpArrayPtr: pushArray( node->value.symbol ); break; case OpArraySet: eval( node->right ); /* value to store */ eval( node->left ); /* indices and index */ setArrayElement( node->value.symbol ); break; case OpAssign: /* value to be assigned. note the *right* node is used */ eval( node->right ); /* variable to assign to */ setVar( node->value.symbol ); break; case OpBuiltin: case OpBuiltinCall: /* for argcount */ n1 = tos; /* mark start of created objects */ pushCreateStack( 0 ); /* the args */ eval( node->left ); /* builtin symbol */ s = node->value.symbol; if (s == NULL) { ePrintf( Runtime, "builtin pointer is null"); } /* set args */ argCount = (int)(tos - n1); /* call the c function */ (*s->builtin)(); /* destroy created objects */ clearCreateStack(); /* drop result? */ if (node->op == OpBuiltinCall) { dropTos(); } break; case OpCaseSelect: /* top level of a case statement */ /* value to compare */ eval( node->left ); /* resolve into real data */ switch (getStackType( tos )) { case DATA_NUMBER: pushNumber( popNumber() ); break; case DATA_STRING: pushString( popString() ); break; default: ePrintf( Runtime, "OpCaseSelect: can't resolve type %s", datumName[getStackType( tos )] ); } /* get first test */ if (node == NULL) { /* no tests */ break; } else { node = node->right; } /* walk the chain of cases */ while (1) { /* get a test/action pair */ n = node->left; /* perform the tests */ eval( n->left ); /* true? */ if (popNumber()) { /* perform action and leave loop */ eval( n->right ); break; } /* move to next test */ node = node->right; if (node == NULL) { break; } } /* drop the test value from the stack */ dropTos(); break; case OpCaseCmp: case OpCaseRange: case OpCaseElse: /* perform chain of tests until true or end */ while (1) { switch (node->op) { case OpCaseCmp: /* value to compare */ eval(node->left); /* what type of test? */ switch (getStackType( tos-1 )) { case DATA_NUMBER: numberCompare( node->value.iValue, 0 ); break; case DATA_STRING: stringCompare( node->value.iValue, 0 ); break; default: ePrintf( Runtime, "OpCaseCmp: bad data type" ); } break; case OpCaseRange: /* values to compare */ n = node->left; eval( n->left ); eval( n->right ); /* what type of comparison? */ switch (getStackType( tos-2 )) { case DATA_NUMBER: numberRangeCompare(); break; case DATA_STRING: stringRangeCompare(); break; default: ePrintf( Runtime, "OpCaseRange: bad data type" ); break; } break; case OpCaseElse: /* put true on stack */ pushNumber( 1 ); break; default: ePrintf( Runtime, "opcode %s found in Case test chain", opcodeName[node->op] ); } /* was result true? */ if (stack[tos].value.number) { /* leave true flag on stack and exit */ break; } /* move to next test */ node = node->right; if (node == NULL) { /* exit with false flag */ break; } /* drop test result flag */ dropTos(); } break; case OpClassMethod: case OpClassMethodCall: /* the args */ n1 = tos; /* mark start of created objects */ pushCreateStack( 0 ); /* the args */ eval( node->right ); argCount = (int)(tos - n1); me = 0; runMethod( node->left->value.symbol->klass, node->value.string ); /* destroy created objects */ clearCreateStack(); /* drop result? */ if (node->op == OpClassMethodCall) { dropTos(); } break; case OpClose: if (node->left == NULL) { fileCloseAll(); } else { eval( node->left ); i = (int)popNumber(); fileClose( i ); } break; case OpCmp: eval( node->left ); eval( node->right ); switch(getStackType(tos)) { case DATA_NUMBER: numberCompare( node->value.iValue, 1 ); break; case DATA_STRING: stringCompare( node->value.iValue, 1 ); break; default: ePrintf( Runtime, "opCmp: can't handle datatype" ); } break; case OpComma: /* optimized for linked lists */ while (1) { /* exit flag set? */ if (exitForFlag != 0 || exitRoutineFlag != 0 || exitDoFlag != 0 || exitWhileFlag != 0 || continueFlag ) { break; } if (node->left != NULL ) { eval( node->left ); } /* end of list? */ if (node->right == NULL ) { break; /* linked list? */ } else if (node->right->op == OpComma) { node = node->right; /* not a list */ } else { eval( node->right ); break; } } break; case OpConcat: eval( node->left ); eval( node->right ); basConcat(); break; case OpConstGet: s = node->value.symbol; i = s->stackPos; /* this better not be indirected! */ switch (stack[i].datatype) { case DATA_STRING: pushString( stack[i].value.string ); break; case DATA_NUMBER: pushNumber( stack[i].value.number ); break; default: ePrintf( Runtime, "Can't fetch Const type %s", datumName[stack[i].datatype] ); break; } break; case OpConstSet: s = node->value.symbol; eval( node->left ); switch (stack[tos].datatype) { case DATA_STRING: stack[s->stackPos].datatype = DATA_STRING; stack[s->stackPos].value.string = stack[tos].value.string; stack[tos].datatype = DATA_NUMBER; tos--; break; case DATA_NUMBER: stack[s->stackPos].datatype = DATA_NUMBER; stack[s->stackPos].value.number = stack[tos].value.number; tos--; break; default: ePrintf( Runtime, "Can't set Const to %s", datumName[stack[tos].datatype] ); break; } break; case OpDelete: eval( node->left ); runDestructor( (int)popNumber(), OpDelete ); break; case OpDestroy: eval( node->left ); runDestructor( (int)popNumber(), OpDestroy ); break; case OpContinue: continueFlag = 1; break; case OpDiv: eval( node->left ); eval( node->right ); n2 = popNumber(); n1 = popNumber(); if (n2 == 0.0) { ePrintf( Runtime, "Division by zero" ); } pushNumber( n1 / n2 ); break; case OpDo: while (1) { /* test */ eval( node->left ); /*if (!popNumber()){ break; }*/ /* code */ eval( node->right ); //printf("exitDoFlag:%d\n",exitDoFlag); if (exitDoFlag != 0) { exitDoFlag = 0; break; } else if (continueFlag) { continueFlag = 0; } } break; case OpEnd: eShutdown(0); break; case OpErase: if (node->left == NULL) { /* erase entire array */ eraseArray( node->value.symbol ); } else { /* evaluate the indexes */ eval( node->left ); /* erase single element from array */ eraseArrayElement( node->value.symbol ); } break; case OpExitDo: exitDoFlag = 1; break; case OpExitFor: exitForFlag = 1; break; case OpExitRoutine: currentScope=oldScope[oldScopeP--]; exitRoutineFlag = 1; break; case OpExitWhile: exitWhileFlag = 1; break; case OpFloat: pushNumber( node->value.fValue ); break; case OpFor: s = node->value.symbol; eval( node->left ); n2 = popNumber(); n1 = popNumber(); /* initial value */ pushNumber( n3 ); setVar( s ); for( n3=n1; n3 <= n2; n3++ ) { /* set loop variable */ pushNumber( n3 ); setVar( s ); /* run code */ eval( node->right ); /* special exit condition? */ if (exitForFlag) { exitForFlag = 0; break; } else if (continueFlag) { continueFlag = 0; } /* get loop value (in case it changed) */ getVar( s ); n3 = popNumber(); } break; case OpForEach: /* variable to assign */ s = node->value.symbol; /* array to read from */ a = getArray( node->left->value.symbol ); /* iterate through keys */ i = 0; /* put key on stack, or exit */ while (getDynamicKey( a, i )) { /* assign to variable */ setVar( s ); /* run block */ eval( node->right ); /* next */ i += 1; } break; case OpForStep: s = node->value.symbol; eval( node->left ); n3 = popNumber(); /* step */ n2 = popNumber(); /* end */ n1 = popNumber(); /* start */ /* which direction? */ if (n3 > 0) { n2 += ALLOWABLE_ERROR; for( n4=n1; n2 >= n4; n4 += n3 ) { /* set loop variable */ pushNumber( n4 ); setVar( s ); /* run code */ eval( node->right ); /* special exit condition? */ if (exitForFlag) { exitForFlag = 0; break; } else if (continueFlag) { continueFlag = 0; } /* get loop value (in case it changed) */ getVar( s ); n4 = popNumber(); } } else { n2 -= ALLOWABLE_ERROR; for( n4=n1; n2 <= n4; n4 += n3 ) { /* set loop variable */ pushNumber( n4 ); setVar( s ); /* run code */ eval( node->right ); /* special exit condition? */ if (exitForFlag) { exitForFlag = 0; break; } else if (continueFlag) { continueFlag = 0; } /* get loop value (in case it changed) */ getVar( s ); n4 = popNumber(); } } break; case OpFunction: case OpFunctionCall: callFunction( node ); break; case OpInitArray: if (node->left == NULL) { createDynamicArray( node->value.symbol ); } else { eval( node->left ); createStaticArray( node->value.symbol ); } break; case OpInput: if (node->value.iValue == 1) { eval( node->left ); i = (int)popNumber(); string1 = fileLineInput( i ); pushString( string1 ); } else { /* command line */ ePrintf( Runtime, "Input statement is not currently supported" ); } break; case OpInt: pushNumber( node->value.iValue ); break; case OpMethod: case OpMethodCall: /* the index */ eval( node->left ); n1 = popNumber(); /* method name */ string1 = node->value.string; /* mark start of created objects */ pushCreateStack( 0 ); /* args */ n2 = tos; eval( node->right ); argCount = (int)(tos - n2); /* resolve and run method */ resolveMethod( (int)n1, string1 ); /* drop result? */ if (node->op == OpMethodCall) { dropTos(); } /* destroy created objects */ clearCreateStack(); break; case OpMod: eval( node->left ); eval( node->right ); n2 = popNumber(); n1 = popNumber(); //pushNumber( (long)n1 % (long)n2 ); pushNumber( fmod(n1,n2) ); break; case OpMul: eval( node->left ); eval( node->right ); n2 = popNumber(); n1 = popNumber(); pushNumber( n1 * n2 ); break; case OpOpen: /* file name */ eval( node->left ); string1 = popString(); /* mode */ i = node->value.iValue; /* file number */ eval( node->right ); n1 = popNumber(); fileOpen( string1, i, (int)n1 ); free( string1 ); break; case OpOr: /* short circuit */ eval( node->left ); if (popNumber()) { pushNumber( (Number)1 ); } else { eval( node->right ); if (popNumber()) { pushNumber( (Number)1 ); } else { pushNumber( (Number)0 ); } } break; case OpOrBits: eval( node->left ); eval( node->right); i = popNumber(); j = popNumber(); pushNumber( i | j ); break; case OpIDiv: eval( node->left ); eval( node->right ); n2 = popNumber(); n1 = popNumber(); /* check for division by zero */ if (n2 == 0.0) { ePrintf( Runtime, "Division by zero" ); } pushNumber( floor(n1 / n2) ); break; case OpIf: n = node->left; /* test */ eval( n->left ); n1 = popNumber(); if (n1 != 0) { /* true portion */ eval( n->right ); } else { /* false portion */ eval( node->right ); } break; case OpIfTrue: ePrintf( Runtime, "OpIfTrue: internal error" ); break; case OpIn: /* evaluate key */ eval( node->left ); /* look for it in array */ pushNumber( inArray( node->value.symbol ) ); break; case OpInv: ePrintf( Runtime, "Inv is not implemented yet" ); break; case OpNegate: eval( node->left ); n1 = popNumber(); pushNumber( -n1 ); break; case OpNew: case OpNewTmp: /* mark start of created objects */ pushCreateStack( 0 ); /* the args */ n1 = tos; eval( node->left ); argCount = (int)(tos - n1); runMethod( node->value.symbol->klass, "new" ); /* destroy created objects *before* adding new object to stack */ clearCreateStack(); /* add new object to create stack? */ if (node->op == OpNewTmp) { /* track on stack */ copyStackItem( tos ); pushCreateStack( (int)popNumber() ); } break; case OpNoOp: break; case OpNot: eval( node->left ); n1 = popNumber(); pushNumber( !n1 ); break; case OpPower: eval( node->left ); eval( node->right ); n2 = popNumber(); n1 = popNumber(); pushNumber( pow( n1, n2 ) ); break; case OpPrint: if (node->left == NULL) { i = 0; } else { eval( node->left ); i = (int)popNumber(); } node = node->right; /* empty print statement */ if (node == NULL) { if (i==0) { eConsole("\n"); } else { filePrintString( i, "\n" ); } } /* process nodes */ while(node != NULL) { /* data value */ if (node->left != NULL) { eval( node->left ); string1 = popString(); if (i==0) { eConsole("%s", string1 ); } else { filePrintString( i, string1 ); } eFree( string1 ); } /* field delimiter */ switch (node->value.iValue) { case PRINT_TAB: if (i==0) { eConsole("\t"); } else { filePrintString( i, "\t" ); } break; case PRINT_NEWLINE: if (i==0) { eConsole("\n"); } else { filePrintString( i, "\n" ); } break; default: /* no action */ break; } /* link */ node = node->right; } break; case OpReturnValue: eval( node->left ); setReturn(); exitRoutineFlag = 1; break; case OpReturnSetValue: eval( node->left ); setReturn(); break; case OpShl: eval( node->left ); eval( node->right ); n2 = popNumber(); n1 = popNumber(); pushNumber( (long)n1 << (long)n2 ); break; case OpShr: eval( node->left ); eval( node->right ); n2 = popNumber(); n1 = popNumber(); pushNumber( (long)n1 >> (long)n2 ); break; case OpString: pushStringCopy( node->value.string ); break; case OpSub: eval( node->left ); eval( node->right ); n2 = popNumber(); n1 = popNumber(); pushNumber( n1 - n2 ); break; case OpUndefined: ePrintf( Runtime, "Opcode is undefined" ); break; case OpVar: /* check type */ getVar( node->value.symbol ); if (getStackType(tos) == DATA_UNDEFINED) { ePrintf( Runtime, "the value of %s is undefined", node->value.symbol->name ); } break; case OpWhile: while (1) { /* test */ eval( node->left ); if (!popNumber()){ break; } /* code */ eval( node->right ); if (exitWhileFlag != 0) { exitWhileFlag = 0; break; } else if (continueFlag) { continueFlag = 0; } } break; case OpXor: eval( node->left ); eval( node->right ); n2 = popNumber(); n1 = popNumber(); pushNumber( (long)n1 ^ (long)n2 ); break; default: ePrintf( Runtime, "Unknown Opcode: %d", node->op ); } }
extern void freeRoutineResources (void) { if (CurrentDirectory != NULL) eFree (CurrentDirectory); }
extern void freeTagFileResources (void) { if (TagFile.directory != NULL) eFree (TagFile.directory); vStringDelete (TagFile.vLine); }
extern void circularRefCheckerDestroy (struct circularRefChecker * checker) { hashTableDelete (checker->visitTable); checker->visitTable = NULL; eFree (checker); }