123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142 |
- /* GCSx
- ** ENTITY.CPP
- **
- ** Entity support (instance of a script) (no edit-specific version)
- ** Includes bytecode interpreter
- */
- /*****************************************************************************
- ** Copyright (C) 2003-2006 Janson
- **
- ** This program is free software; you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation; either version 2 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program; if not, write to the Free Software
- ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
- #include "all.h"
- // @TODO: respect ref
- Entity::Entity(int myId) { start_func
- id = myId;
- script = NULL;
- active = 0;
- scriptLocked = 0;
- scriptType = 0;
- ref = 0;
- runStatus = RUN_UNINIT;
- i = NULL;
- endOfLocals = 0;
- createStack(&stack);
-
- varTable[PROP_NAME].p = new string;
- varTable[PROP_SPRITE].p = NULL;
- varTable[PROP_PRIORITY].i = DEFAULT_PRIORITY;
- }
- Entity::~Entity() { start_func
- // @TODO: assert ref=0?
- wipeStack();
- destroyStack(&stack);
- setScript(NULL);
- // @TODO: this is only safe if we ensure to destroy entities before sprites
- setSprite(NULL);
- delete (string*)varTable[PROP_NAME].p;
- }
- void Entity::setSprite(Sprite* newSprite) { start_func
- if (varTable[PROP_SPRITE].p) --(((ObjectBase*)varTable[PROP_SPRITE].p)->ref);
- varTable[PROP_SPRITE].p = (ObjectBase*)newSprite;
- if (newSprite) ++newSprite->ref;
- }
- void Entity::setScript(Script* newScript) { start_func
- if ((script) && (scriptLocked))
- script->markUnlock();
-
- wipeStack();
- i = NULL;
- runStatus = RUN_UNINIT;
- scriptLocked = 0;
- script = newScript;
- if (script) scriptType = newScript->getId();
- if ((script) && (active))
- activateResource();
- }
- void Entity::activateResource() { start_func
- if ((script) && (!scriptLocked)) {
- assert(!i);
- assert((runStatus == RUN_UNINIT) || (runStatus == RUN_STOPPED));
- // @TODO: throw_File
- script->markLock();
- script->link();
- scriptLocked = 1;
- if (runStatus == RUN_UNINIT) {
- i = script->getCode();
- runStatus = RUN_INIT;
- }
- }
- }
- void Entity::deactivateResource() { start_func
- if ((script) && (scriptLocked) && (!i)) {
- assert((runStatus == RUN_UNINIT) || (runStatus == RUN_STOPPED));
- script->markUnlock();
- scriptLocked = 0;
- }
- }
- void Entity::setActive() { start_func
- if (!active) {
- activateResource();
- active = 1;
- }
- }
- void Entity::setInactive() { start_func
- if (active) {
- deactivateResource();
- active = 0;
- }
- }
- /*
- ** BYTECODE INTERPRETER follows
- **
- ** All functions except main loop can be considered throw_Interpret,
- ** therefore follow dynamic allocations CAREFULLY.
- */
- // @TODO: consolidate duplicate opcode/etc functions as much as possible
- // once mostly debugged and otherwise optimized (reduce space = optimize cache)
- //
- // State data- interpreter runs outside class to prevent passing 'this'
- // and allow simple function tables; all tables and data together.
- //
- static Uint32 opdata = 0;
- static Uint8 addrmode = 0;
- static Uint32* i_p = NULL;
- // A note on stack usage- an opcode should not push onto the stack until it's
- // done with it's operands, as we sometimes reference "popped" data directly
- // at it's original, technically-invalid position
- static Stack stackP;
- static Entity* entity = NULL;
- static StackEntry* operand = NULL;
- static StackEntry* operandGrab = NULL;
- static StackEntry* operandWrite = NULL;
- static Sint32 operandDataI = 0;
- static BCfloat operandDataF = 0;
- static const char* operandDataS = NULL;
- static void* operandDataP = NULL;
- // 'toDeref' should always contain anything needing dereferencing
- #define MAX_TODEREF 8
- // (room for at least 2 derefs per operand)
- static StackEntry toDeref[MAX_TODEREF];
- static StackEntry* toDerefPos = toDeref;
- static StackEntry* toDerefLast = toDeref + MAX_TODEREF;
- // Two-element array (flip-flops) to store temporary operands that
- // DON'T need dereferencing (int, float)
- static StackEntry tempOperand[2];
- static int tempPos = 0;
- // Pre-created 'empty' int/float/entity/object operands
- static StackEntry emptyOperand[4];
- typedef void (*OperandFunc)();
- typedef void (*OperandFuncDeref)(StackEntry*);
- // Operand function sequence- (/ means 'or')
- // opcodes[]
- // ->grabbers[] -> extractors[] / copiers[] -> extractors[]
- // ->grabbersStore[] -> converters[]
- // ->grabbersWrite[]
- // ->grabbersUse[] -> copiersUse[] / converters[]
- // Anyone can call dereferencers[] or referencers[] as needed
- // Anyone can call copiersUse[] with _UNDEF for existing type to create blank entries
- // Function tables-
- // Dereferencing table- Indexed via 8 bits of existing datatype
- // Referencing- only intended to support basic types
- // May clobber operand IF you call on a RETURN type
- static OperandFuncDeref dereferencers[STACK_TYPE_COUNT];
- static OperandFuncDeref referencers[STACK_TYPE_COUNT];
- // Copy/conversion tables- Indexed via 4 bits of desired datatype concatenated with 4 bits of existing datatype
- // copiersUse[] ensures the copy is a usable, properly ref counted StackEntry and does NOT put in "toderef"
- // copiersUse[] with _UNDEF existing is gauranteed to just make a blank entry, so can be
- // used for creating empties.; copiersUse[] expects it's result to be stored via assignment
- // copiers[] calls extractors immediately after or instead.
- static OperandFunc converters[256]; // into operand
- static OperandFunc copiers[256]; // into operandData* (clobbers operandGrab/2)
- static OperandFunc copiersUse[256]; // into operand
- // Extractor table- indexed by 8 bit operand; don't call if called copiers[]
- // @TODO: create specialized types for all grabbers[] that use extractors and
- // remove this array? (some functions are still needed for copiers[] array)
- static OperandFunc extractors[256]; // into operandData* (from operandGrab)
- // Decoder (grabber) table- indexed by 8 bit operand- grabs const into operandData*
- static OperandFunc grabbers[256]; // into operandData* (clobbers operandGrab/2)
- // Grabs non-const, pointer in operand ready to store/modify directly
- // Write "destroys" AND DEREFS original contents without conversion! and
- // also does not garauntee that the 'type' field is correct.
- static OperandFunc grabbersStore[256]; // into operand
- static OperandFunc grabbersWrite[256]; // into operandWrite
- // Grabs into a ready-to-use StackEntry in operand (proper ref counting and all)
- static OperandFunc grabbersUse[256]; // into operand
- // Opcode table
- static OperandFunc opcodes[OP_LAST];
- #ifdef INTERPRETASSERT
- static void interpretError() { start_func
- interpretAssert(0);
- }
- static void interpretErrorDeref(StackEntry*) { start_func
- interpretAssert(0);
- }
- #else
- #define interpretError NULL
- #define interpretErrorDeref NULL
- #endif
- static void doNothing() { start_func
- }
- //
- // dereferencers[]
- //
- // Dereferencing/destruction (the seDeref* functions already assert)
- static void derefNothing(StackEntry* s) { start_func
- }
- static void derefString(StackEntry* s) { start_func
- seDerefString(s);
- }
- static void derefArray(StackEntry* s) { start_func
- seDerefArray(s);
- }
- static void derefHash(StackEntry* s) { start_func
- seDerefHash(s);
- }
- static void derefEntity(StackEntry* s) { start_func
- Entity::seDerefEntity(s);
- }
- static void derefObject(StackEntry* s) { start_func
- seDerefObject(s);
- }
- static void derefReturn(StackEntry* s) { start_func
- interpretAssert(s->type == STACK_RETURNPTR);
- StackEntry* target = (StackEntry*)(s->data.p);
- if (target) {
- interpretAssert(target->type & STACK_REPLYPTR);
- interpretAssert((target->type | ~STACK_REPLYPTR) <= STACK_BASETYPE);
- // Generate empty of requested type
- // Assumes STACK_UNDEF is 0 otherwise we should have | STACK_UNDEF here
- interpretAssert(STACK_UNDEF == 0);
- copiersUse[(target->type | ~STACK_REPLYPTR) << 4]();
- *target = *operand;
- }
- }
- static void derefReply(StackEntry* s) { start_func
- interpretAssert(s->type == STACK_REPLYPTR);
- StackEntry* target = (StackEntry*)(s->data.p);
- interpretAssert(target);
- interpretAssert(target->type == STACK_RETURNPTR);
- target->data.p = NULL;
- }
- //
- // referencers[]
- //
- static void refNothing(StackEntry* s) { start_func
- }
- static void refString(StackEntry* s) { start_func
- s->data.p = new string(*(string*)s->data.p);
- }
- static void refArray(StackEntry* s) { start_func
- interpretAssert(s->type == STACK_ARRAY);
- refIncArray((Array*)s->data.p);
- }
- static void refHash(StackEntry* s) { start_func
- interpretAssert(s->type == STACK_HASH);
- refIncHash((Hash*)s->data.p);
- }
- static void refEntity(StackEntry* s) { start_func
- Entity::seRefEntity(s);
- }
- static void refObject(StackEntry* s) { start_func
- interpretAssert(s->type == STACK_OBJECT);
- if (s->data.p) ++(((ObjectBase*)s->data.p)->ref);
- }
- //
- // converters[]
- //
- // Converting- dereferences old operand, replaces with new in-place
- static void convertEmptyToInt() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- // (always deref, as it's not float/int at this point)
- dereferencers[operand->type](operand);
- operand->type = STACK_INT;
- operand->data.i = 0;
- }
- static void convertEmptyToFloat() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- operand->type = STACK_FLOAT;
- operand->data.f = 0.0;
- }
- static void convertEmptyToStr() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- operand->type = STACK_STRING;
- operand->data.p = new string(blankString);
- }
- static void convertEmptyToArray() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- // @TODO:
- }
- static void convertEmptyToHash() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- // @TODO:
- }
- static void convertEmptyToEntity() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- operand->type = STACK_ENTITY;
- operand->data.p = NULL;
- }
- static void convertEmptyToObject() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- operand->type = STACK_OBJECT;
- operand->data.p = NULL;
- }
- static void convertIntToFloat() { start_func
- operand->type = STACK_FLOAT;
- operand->data.f = (BCfloat)operand->data.i;
- }
- static void convertFloatToInt() { start_func
- operand->type = STACK_INT;
- operand->data.i = (Sint32)operand->data.f;
- }
- static void convertIntToString() { start_func
- operand->type = STACK_STRING;
- operand->data.p = new string(intToStr(operand->data.i));
- }
- static void convertStringToInt() { start_func
- operand->type = STACK_INT;
- string* myStr = (string*)operand->data.p;
- operand->data.i = strToInt(*myStr);
- delete myStr;
- }
- static void convertFloatToString() { start_func
- operand->type = STACK_STRING;
- operand->data.p = new string(floatToStr(operand->data.f));
- }
- static void convertStringToFloat() { start_func
- operand->type = STACK_FLOAT;
- string* myStr = (string*)operand->data.p;
- operand->data.f = strToFloat(*myStr);
- delete myStr;
- }
- //
- // copiers[]
- //
- // Copying- ignores old operand, replaces with new in operandData* (doesn't deref old)
- // New version is set up to deref for you automatically
- // Handles the work of extractors[] too
- static void copyCreateInt() { start_func
- operandDataI = emptyOperand[0].data.i;
- }
- static void copyCreateFloat() { start_func
- operandDataF = emptyOperand[1].data.f;
- }
- static void copyCreateStr() { start_func
- operandDataS = "";
- }
- static void copyCreateArray() { start_func
- // @TODO:
- }
- static void copyCreateHash() { start_func
- // @TODO:
- }
- static void copyCreateEntity() { start_func
- operandDataP = NULL;
- }
- static void copyCreateObject() { start_func
- operandDataP = NULL;
- }
- static void copyIntToFloat() { start_func
- operandDataF = (BCfloat)operandGrab->data.i;
- }
- static void copyFloatToInt() { start_func
- operandDataI = (Sint32)operandGrab->data.f;
- }
- static void copyIntToString() { start_func
- if (++toDerefPos == toDerefLast) toDerefPos = toDeref;
- interpretAssert(toDerefPos->type != STACK_RETURNPTR);
- dereferencers[toDerefPos->type](toDerefPos);
- // (need to set type to ensure dereferencing)
- toDerefPos->type = STACK_STRING;
- toDerefPos->data.p = new string(intToStr(toDerefPos->data.i));
- operandDataS = ((string*)toDerefPos->data.p)->c_str();
- }
- static void copyStringToInt() { start_func
- operandDataI = strToInt(*(string*)operandGrab->data.p);
- }
- static void copyFloatToString() { start_func
- if (++toDerefPos == toDerefLast) toDerefPos = toDeref;
- interpretAssert(toDerefPos->type != STACK_RETURNPTR);
- dereferencers[toDerefPos->type](toDerefPos);
- // (need to set type to ensure dereferencing)
- toDerefPos->type = STACK_STRING;
- toDerefPos->data.p = new string(floatToStr(operandGrab->data.f));
- operandDataS = ((string*)toDerefPos->data.p)->c_str();
- }
- static void copyStringToFloat() { start_func
- operandDataF = strToFloat(*(string*)operandGrab->data.p);
- }
- //
- // copiersUse[]
- //
- // Copying for Use- ignores old operand, replaces with new in operand (doesn't deref old)
- // 'Use' versions don't set new up to be deref'd either, expecting it will get stored VIA ASSIGNMENT
- static void copyCreateIntUse() { start_func
- operand = emptyOperand;
- }
- static void copyCreateFloatUse() { start_func
- operand = emptyOperand + 1;
- }
- static void copyCreateStrUse() { start_func
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_STRING;
- operand->data.p = new string;
- }
- static void copyCreateArrayUse() { start_func
- // @TODO:
- }
- static void copyCreateHashUse() { start_func
- // @TODO:
- }
- static void copyCreateEntityUse() { start_func
- operand = emptyOperand + 2;
- }
- static void copyCreateObjectUse() { start_func
- operand = emptyOperand + 3;
- }
- static void copyStringUse() { start_func
- string* prev = (string*)operand->data.p;
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_STRING;
- operand->data.p = new string(*prev);
- }
- static void copyIntToFloatUse() { start_func
- BCfloat result = (BCfloat)operand->data.i;
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_FLOAT;
- operand->data.f = result;
- }
- static void copyFloatToIntUse() { start_func
- Sint32 result = (Sint32)operand->data.f;
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_INT;
- operand->data.i = result;
- }
- static void copyIntToStringUse() { start_func
- Uint32 val = operand->data.i;
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_STRING;
- operand->data.p = new string(intToStr(val));
- }
- static void copyStringToIntUse() { start_func
- Sint32 result = strToInt(*(string*)operand->data.p);
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_INT;
- operand->data.i = result;
- }
- static void copyFloatToStringUse() { start_func
- BCfloat val = operand->data.f;
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_STRING;
- operand->data.p = new string(floatToStr(val));
- }
- static void copyStringToFloatUse() { start_func
- BCfloat result = strToFloat(*(string*)operand->data.p);
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_FLOAT;
- operand->data.f = result;
- }
- //
- // extractors[]
- //
- // Extracting- always goes in operandData* off of operandGrab
- static void extractInt() { start_func
- interpretAssert(operandGrab->type == STACK_INT);
- operandDataI = operandGrab->data.i;
- }
- static void extractFloat() { start_func
- interpretAssert(operandGrab->type == STACK_FLOAT);
- operandDataF = operandGrab->data.f;
- }
- static void extractStringConst() { start_func
- interpretAssert(operandGrab->type == STACK_STRING);
- operandDataS = ((string*)operandGrab->data.p)->c_str();
- }
- static void extractArray() { start_func
- interpretAssert(operandGrab->type == STACK_ARRAY);
- // @TODO:
- }
- static void extractHash() { start_func
- interpretAssert(operandGrab->type == STACK_HASH);
- // @TODO:
- }
- static void extractEntity() { start_func
- interpretAssert(operandGrab->type == STACK_ENTITY);
- operandDataP = operandGrab->data.p;
- }
- static void extractObject() { start_func
- interpretAssert(operandGrab->type == STACK_OBJECT);
- operandDataP = operandGrab->data.p;
- }
- //
- // grabbers[]
- //
- // Grabbing into operandData*, via operandGrab/2
- static void grabInt() { start_func
- operandDataI = *i_p++;
- }
- static void grabFloat() { start_func
- operandDataF = *((BCfloat*)i_p);
- i_p += bcFloatSize;
- }
- static void grabStringConst() { start_func
- operandDataS = (const char*)(i_p + *i_p);
- ++i_p;
- }
- static void grabThis() { start_func
- operandDataP = entity;
- }
- static void grabNothing() { start_func
- operandDataP = NULL;
- }
- static void grabStack() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operandGrab = stackP.top - 1 - *i_p++;
- extractors[addrmode]();
- }
- // Int/Float optimized due to commonality (@TODO: strconst? all!?)
- static void grabStackInt() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandDataI = (stackP.top - 1 - *i_p++)->data.i;
- }
- static void grabStackFloat() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandDataF = (stackP.top - 1 - *i_p++)->data.f;
- }
- static void grabStackCopy() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operandGrab = stackP.top - 1 - *i_p++;
- interpretAssert(operandGrab->type <= 0x0F);
- // @TODO: can optimize (once we start testing copy/convert)
- // if operand->type is already in the 0xF0 nibble (we don't
- // use operand->type anywhere else but as a dereferencers[] index!)
- // OR flip addrmode! (addrmode is only used with OM_* for this reason!
- // but may be "converted" silently to STACK_* or DATA_* somewhere- see *Write functions)
- copiers[((addrmode & 0x0F) << 4) | operandGrab->type]();
- }
- static void grabLocal() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandGrab = stackP.data + *i_p++;
- extractors[addrmode]();
- }
- // Int/Float optimized due to commonality (@TODO: strconst? all!?)
- static void grabLocalInt() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandDataI = (stackP.data + *i_p++)->data.i;
- }
- static void grabLocalFloat() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandDataF = (stackP.data + *i_p++)->data.f;
- }
- static void grabLocalCopy() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandGrab = stackP.data + *i_p++;
- interpretAssert(operandGrab->type <= 0x0F);
- copiers[((addrmode & 0x0F) << 4) | operandGrab->type]();
- }
- static void grabPop() { start_func
- interpretAssert((Uint32)(stackP.top - stackP.data) > entity->getEndOfLocals());
- if (++toDerefPos == toDerefLast) toDerefPos = toDeref;
- operandGrab = toDerefPos;
- interpretAssert(operandGrab->type != STACK_RETURNPTR);
- dereferencers[operandGrab->type](operandGrab);
- *operandGrab = *--stackP.top;
- extractors[addrmode]();
- }
- // Int/Float optimized due to commonality
- // @TODO: versions for other types like strconst? (do for Local/Stack versions too)
- static void grabPopInt() { start_func
- interpretAssert((Uint32)(stackP.top - stackP.data) > entity->getEndOfLocals());
- operandDataI = (--stackP.top)->data.i;
- }
- static void grabPopFloat() { start_func
- interpretAssert((Uint32)(stackP.top - stackP.data) > entity->getEndOfLocals());
- operandDataF = (--stackP.top)->data.f;
- }
- static void grabPopCopy() { start_func
- interpretAssert((Uint32)(stackP.top - stackP.data) > entity->getEndOfLocals());
- operandGrab = --stackP.top;
- interpretAssert(operandGrab->type <= 0x0F);
- // Instead of dereferencing immediately, we just add to the dereferencing array
- // so the copier has the most flexibility (to point to it still, etc.)
- if (++toDerefPos == toDerefLast) toDerefPos = toDeref;
- interpretAssert(toDerefPos->type != STACK_RETURNPTR);
- dereferencers[toDerefPos->type](toDerefPos);
- *toDerefPos = *operandGrab;
- copiers[((addrmode & 0x0F) << 4) | operandGrab->type]();
- }
- //
- // grabbersStore[]
- //
- static void grabStackStore() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operand = stackP.top - 1 - *i_p++;
- }
- static void grabStackConvertStore() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operand = stackP.top - 1 - *i_p++;
- interpretAssert(operand->type <= 0x0F);
- converters[((addrmode & 0x0F) << 4) | operand->type]();
- }
- static void grabLocalStore() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operand = stackP.data + *i_p++;
- }
- static void grabLocalConvertStore() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operand = stackP.data + *i_p++;
- interpretAssert(operand->type <= 0x0F);
- converters[((addrmode & 0x0F) << 4) | operand->type]();
- }
- //
- // grabbersWrite[]
- //
- static void grabStackNumWrite() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operandWrite = stackP.top - 1 - *i_p++;
- }
- static void grabStackWrite() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operandWrite = stackP.top - 1 - *i_p++;
- dereferencers[operandWrite->type](operandWrite);
- }
- static void grabLocalNumWrite() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandWrite = stackP.data + *i_p++;
- }
- static void grabLocalWrite() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandWrite = stackP.data + *i_p++;
- dereferencers[operandWrite->type](operandWrite);
- }
- //
- // grabbersUse[]
- //
- // Grabbing into StackEntry (properly referenced as it's own copy)
- static void grabIntUse() { start_func
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_INT;
- operand->data.i = *i_p++;
- }
- static void grabFloatUse() { start_func
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_INT;
- operand->data.f = *((BCfloat*)i_p);
- i_p += bcFloatSize;
- }
- static void grabStringUse() { start_func
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_STRING;
- operand->data.p = new string((const char*)(i_p + *i_p));
- ++i_p;
- }
- static void grabThisUse() { start_func
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_ENTITY;
- operand->data.p = entity;
- Entity::seRefEntity(operand);
- }
- static void grabNothingUse() { start_func
- operand = tempOperand + (tempPos ^= 1);
- // @TODO: faster to assign copy from empty operand?
- operand->type = STACK_ENTITY;
- operand->data.p = NULL;
- }
- static void grabStackUse() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operand = tempOperand + (tempPos ^= 1);
- *operand = *(stackP.top - 1 - *i_p++);
- referencers[operand->type](operand);
- }
- static void grabStackNumUse() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operand = stackP.top - 1 - *i_p++;
- }
- static void grabStackCopyUse() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operand = stackP.top - 1 - *i_p++;
- interpretAssert(operand->type <= 0x0F);
- copiersUse[((addrmode & 0x0F) << 4) | operand->type]();
- }
- static void grabLocalUse() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operand = tempOperand + (tempPos ^= 1);
- *operand = *(stackP.data + *i_p++);
- referencers[operand->type](operand);
- }
- static void grabLocalNumUse() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operand = stackP.data + *i_p++;
- }
- static void grabLocalCopyUse() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operand = stackP.data + *i_p++;
- interpretAssert(operand->type <= 0x0F);
- copiersUse[((addrmode & 0x0F) << 4) | operand->type]();
- }
- static void grabPopUse() { start_func
- interpretAssert((Uint32)(stackP.top - stackP.data) > entity->getEndOfLocals());
-
- operand = --stackP.top;
- }
- static void grabPopCopyUse() { start_func
- interpretAssert((Uint32)(stackP.top - stackP.data) > entity->getEndOfLocals());
- operand = --stackP.top;
- interpretAssert(operand->type <= 0x0F);
- converters[((addrmode & 0x0F) << 4) | operand->type]();
- }
- //
- // Opcode functions
- //
- // Standard operand pulling, when it can't be optimized
- #define OPERAND_0 \
- interpretAssert((opdata & 0xFFFFFF00) == 0);
- #define ASSERT_1 \
- interpretAssert(opdata & 0xFF00); \
- interpretAssert((opdata & 0xFFFF0000) == 0);
- #define OPERAND_1 \
- ASSERT_1 \
- grabbers[addrmode = opdata >> 8]();
-
- #define ASSERT_2 \
- interpretAssert(opdata & 0xFF00); \
- interpretAssert(opdata & 0xFF0000); \
- interpretAssert((opdata & 0xFF000000) == 0);
- #define OPERAND_2 \
- ASSERT_2 \
- grabbersStore[addrmode = opdata >> 8](); \
- grabbers[addrmode = opdata >> 16]();
- #define OPERAND_2CI \
- ASSERT_2 \
- grabbers[addrmode = opdata >> 8](); \
- Sint32 operandData2I = operandDataI; \
- grabbers[addrmode = opdata >> 16]();
- #define OPERAND_2CF \
- ASSERT_2 \
- grabbers[addrmode = opdata >> 8](); \
- BCfloat operandData2F = operandDataF; \
- grabbers[addrmode = opdata >> 16]();
- #define OPERAND_2CS \
- ASSERT_2 \
- grabbers[addrmode = opdata >> 8](); \
- const char* operandData2S = operandDataS; \
- grabbers[addrmode = opdata >> 16]();
- #define OPERAND_2CP \
- ASSERT_2 \
- grabbers[addrmode = opdata >> 8](); \
- void* operandData2P = operandDataP; \
- grabbers[addrmode = opdata >> 16]();
- #define ASSERT_3 \
- interpretAssert(opdata & 0xFF00); \
- interpretAssert(opdata & 0xFF0000); \
- interpretAssert(opdata & 0xFF000000);
-
- // Opcodes
- static void op_noop() { start_func
- OPERAND_0
- }
- void Entity::op_init() { start_func
- interpretAssert(entity->runStatus == RUN_INIT);
- OPERAND_0
-
- entity->runStatus = RUN_ACTIVE;
- entity->endOfLocals = stackP.top - stackP.data;
- }
- void Entity::op_idle() { start_func
- OPERAND_0
- entity->runStatus = RUN_IDLE;
- }
- static void op_jump() { start_func
- interpretAssert(((opdata & 0xFF00) >> 8) == OM_INT);
- ASSERT_1
- // @TODO: + 1 when creating?
- i_p += *((Sint32*)i_p) + 1;
- }
- void Entity::op_ret() { start_func
- interpretAssert(stackP.top);
- interpretAssert(((opdata & 0xFF00) >> 8) == OM_INT);
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- interpretAssert(*i_p + *(i_p + 1) + 2 <= stackP.top - stackP.data - entity->getEndOfLocals());
- ASSERT_2
- // @TODO: this is one opcode that's had no real optimization attempts and
- // yet is reasonably important and should be looked at in more detail due to
- // its length. One specific optimization that probably isn't worth it is if
- // both parameters are 0 AND there's no return pointer, we don't have to do
- // anything. This would be better off as another opcode.
- // Return value
- operand = --stackP.top;
- // Pop function locals
- Uint32 toKill = *i_p++;
- while (toKill--) {
- --stackP.top;
- interpretAssert(stackP.top->type != STACK_RETURNPTR);
- dereferencers[stackP.top->type](stackP.top);
- }
- // (# of parameters)
- toKill = *i_p;
- // Jump back
- i_p = (Uint32*)((--stackP.top)->data.p);
- // @TODO: optimize away RUN_STOPPED and just use i_p=NULL for stopped?
- // @TODO: if stopped, assert stack is locals only left
- if (!i_p)
- entity->runStatus = RUN_STOPPED;
- // Pop parameters
- while (toKill--) {
- --stackP.top;
- interpretAssert(stackP.top->type != STACK_RETURNPTR);
- dereferencers[stackP.top->type](stackP.top);
- }
- // If at least one stack entry left and it's a return ptr...
- // (we don't need to check for endoflocals as locals can never be return ptrs)
- if ((stackP.top != stackP.data) && (stackP.top[-1].type == STACK_RETURNPTR)) {
- // Return or destroy value
- StackEntry* target = (StackEntry*)((--stackP.top)->data.p);
- if (target) {
- interpretAssert(target->type & STACK_REPLYPTR);
- interpretAssert((target->type | ~STACK_REPLYPTR) <= STACK_BASETYPE);
- interpretAssert(((target->type | ~STACK_REPLYPTR) == operand->type) ||
- ((target->type | ~STACK_REPLYPTR) == STACK_UNDEF));
- *target = *operand;
- }
- else {
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- }
- }
- // Otherwise, push back onto stack UNLESS we stopped
- else {
- if (i_p) {
- *stackP.top++ = *operand;
- }
- else {
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- }
- }
- }
- void Entity::op_retvoid() { start_func
- interpretAssert(stackP.top);
- interpretAssert(((opdata & 0xFF00) >> 8) == OM_INT);
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- interpretAssert(*i_p + *(i_p + 1) + 1 <= stackP.top - stackP.data - entity->getEndOfLocals());
- ASSERT_2
- // @TODO: this is one opcode that's had no real optimization attempts and
- // yet is reasonably important and should be looked at in more detail due to
- // its length. One specific optimization that probably isn't worth it is if
- // both parameters are 0 AND there's no return pointer, we don't have to do
- // anything. This would be better off as another opcode.
- // Pop function locals
- Uint32 toKill = *i_p++;
- while (toKill--) {
- --stackP.top;
- interpretAssert(stackP.top->type != STACK_RETURNPTR);
- dereferencers[stackP.top->type](stackP.top);
- }
- // (# of parameters)
- toKill = *i_p;
- // Jump back
- i_p = (Uint32*)((--stackP.top)->data.p);
- // @TODO: optimize away RUN_STOPPED and just use i_p=NULL for stopped?
- // @TODO: if stopped, assert stack is locals only left
- if (!i_p)
- entity->runStatus = RUN_STOPPED;
- // Pop parameters
- while (toKill--) {
- --stackP.top;
- interpretAssert(stackP.top->type != STACK_RETURNPTR);
- dereferencers[stackP.top->type](stackP.top);
- }
- // If at least one stack entry left and it's a return ptr...
- // (we don't need to check for endoflocals as locals can never be return ptrs)
- if ((stackP.top != stackP.data) && (stackP.top[-1].type == STACK_RETURNPTR)) {
- // Return empty value
- StackEntry* target = (StackEntry*)((--stackP.top)->data.p);
- if (target) {
- interpretAssert(target->type & STACK_REPLYPTR);
- interpretAssert((target->type | ~STACK_REPLYPTR) <= STACK_BASETYPE);
- // Generate empty of requested type
- // Assumes STACK_UNDEF is 0 otherwise we should have | STACK_UNDEF here
- interpretAssert(STACK_UNDEF == 0);
- copiersUse[(target->type | ~STACK_REPLYPTR) << 4]();
- *target = *operand;
- }
- }
- }
- void Entity::op_stop() { start_func
- interpretAssert(entity->runStatus != RUN_INIT);
- OPERAND_0
-
- entity->runStatus = RUN_STOPPED;
- i_p = NULL;
-
- // wipe stack minus locals (small chance stack is completely empty)
- if (stackP.top) {
- Uint32 toKill = stackP.top - stackP.data - entity->endOfLocals;
- while (toKill--) {
- --stackP.top;
- // (return ptrs ok)
- dereferencers[stackP.top->type](stackP.top);
- }
- }
- }
- static void op_subr() { start_func
- interpretAssert(((opdata & 0xFF00) >> 8) == OM_INT);
- ASSERT_1
- prepStack(stackP);
- stackP.top->type = STACK_CODEPTR;
- // @TODO: perform + 1 on return? etc
- stackP.top++->data.p = i_p + 1;
- // @TODO: + 1 when creating?
- i_p += *((Sint32*)i_p) + 1;
- }
- void Entity::op_debug() { start_func
- OPERAND_1
-
- // No need to optimize this, and could turn up ANYTHING depending on
- // how we use it
- switch (addrmode) {
- // @TODO: remove the ones of these that can't appear anyway
- // @TODO: add script/object types to @/O
- case OM_ALL:
- debugWrite("%s: @ ALL", entity->getName()->c_str());
- break;
- case OM_ALL_OTHER:
- debugWrite("%s: @ ALL_OTHER", entity->getName()->c_str());
- break;
- case OM_NOTHING:
- debugWrite("%s: @ NOTHING", entity->getName()->c_str());
- break;
- case OM_THIS:
- debugWrite("%s: @ THIS", entity->getName()->c_str());
- break;
- case OM_POINTER:
- debugWrite("%s: * %p", entity->getName()->c_str(), operandDataS);
- break;
- default:
- switch (addrmode & 0x0F) {
- case OM_INT:
- debugWrite("%s: # %d", entity->getName()->c_str(), operandDataI);
- break;
- case OM_FLOAT:
- debugWrite("%s: %% %"BC_FLOAT_PRINTF, entity->getName()->c_str(), operandDataF);
- break;
- case OM_STR_CONST:
- debugWrite("%s: $ %s", entity->getName()->c_str(), operandDataS);
- break;
- case OM_ENTITY:
- if (operandDataP)
- debugWrite("%s: @ %s", entity->getName()->c_str(), ((Entity*)operandDataP)->getName()->c_str());
- else
- debugWrite("%s: @ NOTHING", entity->getName()->c_str());
- break;
- case OM_OBJECT:
- if (operandDataP)
- debugWrite("%s: O %p", entity->getName()->c_str(), operandDataP);
- else
- debugWrite("%s: O NOTHING", entity->getName()->c_str());
- break;
- case OM_ENTRY:
- case OM_ARRAY:
- case OM_HASH:
- // @TODO:
- break;
- }
-
- break;
- }
- }
- static void op_addI() { start_func
- OPERAND_2
- operand->data.i += operandDataI;
- }
- static void op_divI() { start_func
- OPERAND_2
- if (operandDataI)
- operand->data.i /= operandDataI;
- }
- static void op_modI() { start_func
- OPERAND_2
- if (operandDataI)
- operand->data.i %= operandDataI;
- }
- static void op_multI() { start_func
- OPERAND_2
- operand->data.i *= operandDataI;
- }
- static void op_subI() { start_func
- OPERAND_2
- operand->data.i -= operandDataI;
- }
- static void op_addF() { start_func
- OPERAND_2
- operand->data.f += operandDataF;
- }
- static void op_divF() { start_func
- OPERAND_2
- // (allow floating point div/0- results in INF)
- operand->data.f /= operandDataF;
- }
- static void op_multF() { start_func
- OPERAND_2
- operand->data.f *= operandDataF;
- }
- static void op_subF() { start_func
- OPERAND_2
- operand->data.f -= operandDataF;
- }
- static void op_andI() { start_func
- OPERAND_2
- operand->data.i &= operandDataI;
- }
- static void op_orI() { start_func
- OPERAND_2
- operand->data.i |= operandDataI;
- }
- static void op_shiftlI() { start_func
- OPERAND_2
- // Uint so bit shift operators do not sign-extend
- (Uint32&)operand->data.i <<= operandDataI;
- }
- static void op_shiftrI() { start_func
- OPERAND_2
- // Uint so bit shift operators do not sign-extend
- (Uint32&)operand->data.i >>= operandDataI;
- }
- static void op_xorI() { start_func
- OPERAND_2
- operand->data.i ^= operandDataI;
- }
- static void op_concatS() { start_func
- OPERAND_2
-
- ((string*)operand->data.p)->append(operandDataS);
- }
- static void op_iffalseO() { start_func
- interpretAssert((((opdata & 0xFF0000) >> 16) == OM_OBJECT) || (((opdata & 0xFF0000) >> 16) == OM_ENTITY));
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (operandDataP == NULL) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iftrueO() { start_func
- interpretAssert((((opdata & 0xFF0000) >> 16) == OM_OBJECT) || (((opdata & 0xFF0000) >> 16) == OM_ENTITY));
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (operandDataP) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iffalseI() { start_func
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (operandDataI == 0) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iftrueI() { start_func
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (operandDataI) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iffalseF() { start_func
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (operandDataF == 0.0) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iftrueF() { start_func
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (operandDataF != 0.0) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iffalseS() { start_func
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (*operandDataS == 0) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iftrueS() { start_func
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (*operandDataS) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_eqO() { start_func
- OPERAND_2CP
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2P == operandDataP);
- }
- static void op_neO() { start_func
- OPERAND_2CP
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2P != operandDataP);
- }
- static void op_eqI() { start_func
- OPERAND_2CI
-
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2I == operandDataI);
- }
- static void op_geI() { start_func
- OPERAND_2CI
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2I >= operandDataI);
- }
- static void op_gtI() { start_func
- OPERAND_2CI
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2I > operandDataI);
- }
- static void op_leI() { start_func
- OPERAND_2CI
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2I <= operandDataI);
- }
- static void op_ltI() { start_func
- OPERAND_2CI
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2I < operandDataI);
- }
- static void op_neI() { start_func
- OPERAND_2CI
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2I != operandDataI);
- }
- static void op_eqF() { start_func
- OPERAND_2CF
- prepStack(stackP);
- stackP.top->type = STACK_FLOAT;
- stackP.top++->data.i = (operandData2F == operandDataF);
- }
- static void op_geF() { start_func
- OPERAND_2CF
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2F >= operandDataF);
- }
- static void op_gtF() { start_func
- OPERAND_2CF
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2F > operandDataF);
- }
- static void op_leF() { start_func
- OPERAND_2CF
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2F <= operandDataF);
- }
- static void op_ltF() { start_func
- OPERAND_2CF
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2F < operandDataF);
- }
- static void op_neF() { start_func
- OPERAND_2CF
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2F != operandDataF);
- }
- static void op_eqS() { start_func
- OPERAND_2CS
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = myStricmp(operandData2S, operandDataS) == 0;
- }
- static void op_geS() { start_func
- OPERAND_2CS
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = myStricmp(operandData2S, operandDataS) >= 0;
- }
- static void op_gtS() { start_func
- OPERAND_2CS
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = myStricmp(operandData2S, operandDataS) > 0;
- }
- static void op_leS() { start_func
- OPERAND_2CS
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = myStricmp(operandData2S, operandDataS) <= 0;
- }
- static void op_ltS() { start_func
- OPERAND_2CS
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = myStricmp(operandData2S, operandDataS) < 0;
- }
- static void op_neS() { start_func
- OPERAND_2CS
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = myStricmp(operandData2S, operandDataS) != 0;
- }
- static void op_pushI() { start_func
- OPERAND_1
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = operandDataI;
- }
- static void op_pushF() { start_func
- OPERAND_1
- prepStack(stackP);
- stackP.top->type = STACK_FLOAT;
- stackP.top++->data.f = operandDataF;
- }
- // @TODO: Might be faster using grabbersUse (see op_pushAHO)
- static void op_pushS() { start_func
- OPERAND_1
- prepStack(stackP);
- stackP.top->type = STACK_STRING;
- stackP.top++->data.p = new string(operandDataS);
- }
- static void op_pushAHO() { start_func
- // (must prepstack BEFORE pulling operands anytime we use operand+prepstack together)
- prepStack(stackP);
- ASSERT_1
- grabbersUse[addrmode = opdata >> 8]();
- *stackP.top++ = *operand;
- /* @TODO: this code snippet MIGHT be faster, but unlikely
- OPERAND_1
- prepStack(stackP);
- stackP.top->type = STACK_OBJECT;
- stackP.top++->data.p = operandDataP;
- referencers[...];
- */
- }
- static void op_createE() { start_func
- OPERAND_0
- prepStack(stackP);
- stackP.top->type = STACK_ENTITY;
- stackP.top++->data.p = NULL;
- }
- static void op_createO() { start_func
- OPERAND_0
- prepStack(stackP);
- stackP.top->type = STACK_OBJECT;
- stackP.top++->data.p = NULL;
- }
- // @TODO: consolidate into one, if they remain the same; may obsolete grabbersWrite[]
- static void op_storeI() { start_func
- ASSERT_2
- grabbersUse[addrmode = opdata >> 8]();
- grabbersWrite[addrmode = opdata >> 16]();
- *operandWrite = *operand;
- }
- static void op_storeF() { start_func
- ASSERT_2
- grabbersUse[addrmode = opdata >> 8]();
- grabbersWrite[addrmode = opdata >> 16]();
- *operandWrite = *operand;
- }
- static void op_storeS() { start_func
- ASSERT_2
- grabbersUse[addrmode = opdata >> 8]();
- grabbersWrite[addrmode = opdata >> 16]();
- *operandWrite = *operand;
- }
- static void op_storeO() { start_func
- ASSERT_2
- grabbersUse[addrmode = opdata >> 8]();
- grabbersWrite[addrmode = opdata >> 16]();
- *operandWrite = *operand;
- }
- static void op_storeA() { start_func
- ASSERT_2
- grabbersUse[addrmode = opdata >> 8]();
- grabbersWrite[addrmode = opdata >> 16]();
- *operandWrite = *operand;
- }
- static void op_storeH() { start_func
- ASSERT_2
- grabbersUse[addrmode = opdata >> 8]();
- grabbersWrite[addrmode = opdata >> 16]();
- *operandWrite = *operand;
- }
- // @TODO: these have not been fully optimized yet
- // further opcode splitting may be in order as well-
- // ex: versions that garauntee it's not all/all_other/string/nothing(null)
- static void op_getE() { start_func
- ASSERT_3
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 8]();
- prepStack(stackP);
- // could be NULL (nothing)
- if (operandDataP) {
- stackP.top->data = ((Entity*)operandDataP)->varTable[*i_p++];
- stackP.top->type = *i_p++;
- referencers[stackP.top->type](stackP.top);
- stackP.top++;
- }
- else {
- interpretAssert(*i_p <= STACK_BASETYPE);
- // Generate empty of requested type
- // Assumes STACK_UNDEF is 0 otherwise we should have | STACK_UNDEF here
- interpretAssert(STACK_UNDEF == 0);
- copiersUse[*i_p++ << 4]();
- *stackP.top++ = *operand;
- }
- }
- static void op_getO() { start_func
- ASSERT_3
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbers[addrmode = opdata >> 8]();
- prepStack(stackP);
- // could be NULL (nothing)
- if (operandDataP) {
- stackP.top->data = ((ObjectBase*)operandDataP)->members[*i_p++];
- stackP.top->type = *i_p++;
- referencers[stackP.top->type](stackP.top);
- stackP.top++;
- }
- else {
- interpretAssert(*i_p <= STACK_BASETYPE);
- // Generate empty of requested type
- // Assumes STACK_UNDEF is 0 otherwise we should have | STACK_UNDEF here
- interpretAssert(STACK_UNDEF == 0);
- copiersUse[*i_p++ << 4]();
- *stackP.top++ = *operand;
- }
- }
- static void op_setE() { start_func
- ASSERT_3
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbersUse[addrmode = opdata >> 8]();
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 16]();
- if (operandDataP)
- swap(((Entity*)operandDataP)->varTable[*i_p++], operand->data);
- dereferencers[operand->type](operand);
- }
- static void op_setO() { start_func
- ASSERT_3
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbersUse[addrmode = opdata >> 8]();
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 16]();
- if (operandDataP)
- swap(((ObjectBase*)operandDataP)->members[*i_p++], operand->data);
- dereferencers[operand->type](operand);
- }
- // Setting float or int can be optimized due to lack of deref need
- // @TODO: but grabbersUse might be faster anyway? dblcheck
- static void op_setEF() { start_func
- ASSERT_3
- interpretAssert((((opdata & 0xFF00) >> 8) & OM_BASETYPE) == OM_FLOAT);
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbers[addrmode = opdata >> 8]();
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 16]();
- if (operandDataP)
- ((Entity*)operandDataP)->varTable[*i_p++].f = operandDataF;
- }
- static void op_setEI() { start_func
- ASSERT_3
- interpretAssert((((opdata & 0xFF00) >> 8) & OM_BASETYPE) == OM_INT);
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbers[addrmode = opdata >> 8]();
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 16]();
- if (operandDataP)
- ((Entity*)operandDataP)->varTable[*i_p++].i = operandDataI;
- }
- static void op_setOF() { start_func
- ASSERT_3
- interpretAssert((((opdata & 0xFF00) >> 8) & OM_BASETYPE) == OM_FLOAT);
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbers[addrmode = opdata >> 8]();
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 16]();
- if (operandDataP)
- ((ObjectBase*)operandDataP)->members[*i_p++].f = operandDataF;
- }
- static void op_setOI() { start_func
- ASSERT_3
- interpretAssert((((opdata & 0xFF00) >> 8) & OM_BASETYPE) == OM_INT);
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbers[addrmode = opdata >> 8]();
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 16]();
- if (operandDataP)
- ((ObjectBase*)operandDataP)->members[*i_p++].i = operandDataI;
- }
- static void op_convert() { start_func
- OPERAND_1
- // (do nothing- pulling the operand did the work of converting it)
- // @TODO: Optimization possible, as we're wasting time extracting- grabbersStore?
- }
- static void op_discard() { start_func
- interpretAssert(stackP.top);
- interpretAssert(((opdata & 0xFF00) >> 8) == OM_INT);
- interpretAssert(*i_p > 0);
- interpretAssert(*i_p <= stackP.top - stackP.data - entity->getEndOfLocals());
- ASSERT_1
-
- Uint32 toKill = *i_p++;
- do {
- --stackP.top;
- // (return ptrs ok)
- dereferencers[stackP.top->type](stackP.top);
- } while (--toKill);
- }
- static void op_discardl() { start_func
- interpretAssert(stackP.top);
- interpretAssert(((opdata & 0xFF00) >> 8) == OM_INT);
- interpretAssert(*i_p > 0);
- interpretAssert(*i_p <= stackP.top - stackP.data - entity->getEndOfLocals());
- ASSERT_1
-
- // if debugging enabled, assert everything discarded is 0/1/2/128
- #ifdef INTERPRETASSERT
- Uint32 toKill = *i_p++;
- do {
- --stackP.top;
- interpretAssert((stackP.top->type == STACK_INT) ||
- (stackP.top->type == STACK_FLOAT) ||
- (stackP.top->type == STACK_UNDEF) ||
- (stackP.top->type == STACK_CODEPTR));
- } while (--toKill);
- #else
- stackP.top -= *i_p++;
- #endif
- }
- //
- // Main interpreter loop
- //
- void Entity::cycle() { start_func
- // Entity must be active and have a script.
- if ((!active) || (!script)) return;
- // If asserts on, we need to handle exceptions
- #ifdef INTERPRETASSERT
- try {
- #endif
-
- // Entity must not be stopped.
- interpretAssert(runStatus != RUN_UNINIT);
- if (runStatus == RUN_STOPPED) return;
- if (runStatus == RUN_IDLE) runStatus = RUN_ACTIVE;
-
- /*
- // @TODO: temp chunk for benchmarking
- int startTicks2 = SDL_GetTicks();
- int a = 1;
- int b = 1;
- while (a < 10000000) {
- a = a + 1;
- if (a & 1) b = b + a;
- }
- debugWrite("(in C ticks: %d)", startTicks2 - SDL_GetTicks(), b);
- debugWrite("%d %d", a, b);
- */
- #ifndef NDEBUG
- int startTicks = SDL_GetTicks();
- if (debugLevel() & DEBUG_INTERPRET)
- debugWrite("%s [", getName()->c_str());
- #endif
- // Prepare state data
- interpretAssert(i);
- i_p = i;
- stackP = stack;
- entity = this;
- do {
- #ifndef NDEBUG
- if (debugLevel() & DEBUG_INTERPRET) {
- string toWrite;
- debugBytecode(toWrite, i_p);
- debugWrite(" %s", toWrite.c_str());
- }
- #endif
-
- // Perform next opcode; includes pulling operands
- // @TODO: assert valid opcode
- opcodes[(opdata = *i_p++) & 0xFF]();
-
- // Loop continuously until an opcode stops us
- // @TODO: could just be == RUN_ACTIVE if we get rid of INIT state
- } while ((runStatus != RUN_STOPPED) && (runStatus != RUN_IDLE));
- // @TODO: reduce stack size if significant empty space?
-
- // Copy changes in state data back
- i = i_p;
- stack = stackP;
- #ifndef NDEBUG
- if (debugLevel() & DEBUG_INTERPRET)
- debugWrite("] %s (ticks: %d)", getName()->c_str(), SDL_GetTicks() - startTicks);
- #endif
- #ifdef INTERPRETASSERT
- }
- catch (InterpretException& e) {
- runStatus = RUN_STOPPED;
- i_p = NULL;
- stack = stackP;
- debugWrite("%s", e.details);
-
- // @TODO: Display runtime error
- }
- #endif
- }
- void Entity::wipeStack() { start_func
- // wipe stack including locals
- if (stack.top) {
- Uint32 toKill = stack.top - stack.data;
- while (toKill--) {
- --stack.top;
- // (return ptrs ok)
- dereferencers[stack.top->type](stack.top);
- }
- }
-
- stack.top = stack.data;
- endOfLocals = 0;
- }
- //
- // Init/deinit
- //
- void fillInterpreterTables() { start_func
- for (int i = 0; i < 256; ++i) {
- converters[i] = interpretError;
- copiers[i] = interpretError;
- copiersUse[i] = interpretError;
- grabbers[i] = interpretError;
- grabbersStore[i] = interpretError;
- grabbersWrite[i] = interpretError;
- grabbersUse[i] = interpretError;
- extractors[i] = interpretError;
- }
- for (int i = 0; i < STACK_TYPE_COUNT; ++i) {
- dereferencers[i] = interpretErrorDeref;
- referencers[i] = interpretErrorDeref;
- }
- // Referencing
- referencers[STACK_INT] = refNothing;
- referencers[STACK_FLOAT] = refNothing;
- referencers[STACK_STRING] = refString;
- referencers[STACK_ARRAY] = refArray;
- referencers[STACK_HASH] = refHash;
- referencers[STACK_ENTITY] = refEntity;
- referencers[STACK_OBJECT] = refObject;
- // Dereferencing
- dereferencers[STACK_UNDEF] = derefNothing;
- dereferencers[STACK_INT] = derefNothing;
- dereferencers[STACK_FLOAT] = derefNothing;
- dereferencers[STACK_STRING] = derefString;
- dereferencers[STACK_ARRAY] = derefArray;
- dereferencers[STACK_HASH] = derefHash;
- dereferencers[STACK_ENTITY] = derefEntity;
- dereferencers[STACK_OBJECT] = derefObject;
- dereferencers[STACK_CODEPTR] = derefNothing;
- dereferencers[STACK_RETURNPTR] = derefReturn;
- for (int i = STACK_INDIRECT; i <= STACK_INDIRECT + STACK_BASETYPE; ++i) {
- dereferencers[i] = derefNothing;
- }
- for (int i = STACK_REPLYPTR; i <= STACK_REPLYPTR + STACK_BASETYPE; ++i) {
- dereferencers[i] = derefReply;
- }
-
- // Existing datatypes that we support (conversion)
- // We support conversion from UNDEF so that we can use these
- // arrays to quickly create empty values of any type as well
- int existTypes[8] = {
- STACK_UNDEF,
- STACK_INT,
- STACK_FLOAT,
- STACK_STRING,
- STACK_ARRAY,
- STACK_HASH,
- STACK_ENTITY,
- STACK_OBJECT,
- };
-
- // Start by assuming every conversion "fails", returning empty
- for (int i = 0; i < 8; ++i) {
- converters[(OM_INT << 4) | existTypes[i]] = convertEmptyToInt;
- copiers[(OM_INT << 4) | existTypes[i]] = copyCreateInt;
- copiersUse[(OM_INT << 4) | existTypes[i]] = copyCreateIntUse;
- converters[(OM_FLOAT << 4) | existTypes[i]] = convertEmptyToFloat;
- copiers[(OM_FLOAT << 4) | existTypes[i]] = copyCreateFloat;
- copiersUse[(OM_FLOAT << 4) | existTypes[i]] = copyCreateFloatUse;
- converters[(OM_STR << 4) | existTypes[i]] = convertEmptyToStr;
- copiers[(OM_STR_CONST << 4) | existTypes[i]] = copyCreateStr;
- copiersUse[(OM_STR_CONST << 4) | existTypes[i]] = copyCreateStrUse;
- converters[(OM_ARRAY << 4) | existTypes[i]] = convertEmptyToArray;
- copiers[(OM_ARRAY << 4) | existTypes[i]] = copyCreateArray;
- copiersUse[(OM_ARRAY << 4) | existTypes[i]] = copyCreateArrayUse;
- converters[(OM_HASH << 4) | existTypes[i]] = convertEmptyToHash;
- copiers[(OM_HASH << 4) | existTypes[i]] = copyCreateHash;
- copiersUse[(OM_HASH << 4) | existTypes[i]] = copyCreateHashUse;
- converters[(OM_ENTITY << 4) | existTypes[i]] = convertEmptyToEntity;
- copiers[(OM_ENTITY << 4) | existTypes[i]] = copyCreateEntity;
- copiersUse[(OM_ENTITY << 4) | existTypes[i]] = copyCreateEntityUse;
- converters[(OM_OBJECT << 4) | existTypes[i]] = convertEmptyToObject;
- copiers[(OM_OBJECT << 4) | existTypes[i]] = copyCreateObject;
- copiersUse[(OM_OBJECT << 4) | existTypes[i]] = copyCreateObjectUse;
- }
-
- // Conversions/copies we explicitly support-
- // int<->float<->string
- // Copy/convert from type to itself also needs to be supported
- // h<->h, a<->a, e<->e, and o<->o are special because the type may match
- // but the subtype needs to be converted
- converters[(OM_INT << 4) | STACK_INT] = doNothing;
- converters[(OM_FLOAT << 4) | STACK_FLOAT] = doNothing;
- converters[(OM_STR << 4) | STACK_STRING] = doNothing;
-
- converters[(OM_INT << 4) | STACK_FLOAT] = convertFloatToInt;
- converters[(OM_INT << 4) | STACK_STRING] = convertStringToInt;
- converters[(OM_FLOAT << 4) | STACK_INT] = convertIntToFloat;
- converters[(OM_FLOAT << 4) | STACK_STRING] = convertStringToFloat;
- converters[(OM_STR << 4) | STACK_INT] = convertIntToString;
- converters[(OM_STR << 4) | STACK_FLOAT] = convertFloatToString;
-
- // Copiers know their value will be unmodified, so if copier
- // needs to do nothing, we can just leave the old reference alone.
- copiers[(OM_INT << 4) | STACK_INT] = extractInt;
- copiers[(OM_FLOAT << 4) | STACK_FLOAT] = extractFloat;
- copiers[(OM_STR_CONST << 4) | STACK_STRING] = extractStringConst;
-
- copiers[(OM_INT << 4) | STACK_FLOAT] = copyFloatToInt;
- copiers[(OM_INT << 4) | STACK_STRING] = copyStringToInt;
- copiers[(OM_FLOAT << 4) | STACK_INT] = copyIntToFloat;
- copiers[(OM_FLOAT << 4) | STACK_STRING] = copyStringToFloat;
- copiers[(OM_STR_CONST << 4) | STACK_INT] = copyIntToString;
- copiers[(OM_STR_CONST << 4) | STACK_FLOAT] = copyFloatToString;
- // @TODO: temp, should be actual copy+convert and for hash/array
- // include making a new copy even if no conversion
- copiers[(OM_ENTITY << 4) | STACK_ENTITY] = extractEntity;
- copiers[(OM_OBJECT << 4) | STACK_OBJECT] = extractObject;
- copiers[(OM_ARRAY << 4) | STACK_ARRAY] = extractArray;
- copiers[(OM_HASH << 4) | STACK_HASH] = extractHash;
-
- // Copiers for use expect their result to be assigned somewhere,
- // but not modified before then, so we just leave the old reference alone.
- copiersUse[(OM_INT << 4) | STACK_INT] = doNothing;
- copiersUse[(OM_FLOAT << 4) | STACK_FLOAT] = doNothing;
- copiersUse[(OM_STR_CONST << 4) | STACK_STRING] = copyStringUse;
- copiersUse[(OM_INT << 4) | STACK_FLOAT] = copyFloatToIntUse;
- copiersUse[(OM_INT << 4) | STACK_STRING] = copyStringToIntUse;
- copiersUse[(OM_FLOAT << 4) | STACK_INT] = copyIntToFloatUse;
- copiersUse[(OM_FLOAT << 4) | STACK_STRING] = copyStringToFloatUse;
- copiersUse[(OM_STR_CONST << 4) | STACK_INT] = copyIntToStringUse;
- copiersUse[(OM_STR_CONST << 4) | STACK_FLOAT] = copyFloatToStringUse;
- /* @TODO:
-
- converters[(OM_ENTITY << 4) | STACK_ENTITY] (ensure if subtype doesn't match, = NULL)
- converters[(OM_OBJECT << 4) | STACK_OBJECT] (ensure if subtype doesn't match, = NULL)
- converters[(OM_ARRAY << 4) | STACK_ARRAY]
- converters[(OM_HASH << 4) | STACK_HASH]
- @TODO: copiers, note that copying to an entity/object doesn't need
- to be dereferenced if we choose to just not ref++ it in the first place!
-
- copiersUse needs to always ++ref even if nothing changes (entity/object)
-
- both types of copiers for array/hash ALWAYS create a new copy even if no change.
-
- */
-
- // Grabbers
- grabbers[OM_INT] = grabInt;
- grabbers[OM_FLOAT] = grabFloat;
- grabbers[OM_STR_CONST] = grabStringConst;
- // @TODO: OM_ALL
- // @TODO: OM_ALL_OTHER
- grabbers[OM_NOTHING] = grabNothing;
- grabbers[OM_THIS] = grabThis;
- // @TODO: OM_POINTER?
-
- grabbersUse[OM_INT] = grabIntUse;
- grabbersUse[OM_FLOAT] = grabFloatUse;
- grabbersUse[OM_STR_CONST] = grabStringUse;
- // @TODO: OM_ALL
- // @TODO: OM_ALL_OTHER
- grabbersUse[OM_NOTHING] = grabNothingUse;
- grabbersUse[OM_THIS] = grabThisUse;
- // @TODO: OM_POINTER?
-
- for (int i = OM_STACK; i < OM_STACK + OM_BASETYPE; ++i) {
- grabbersStore[i] = grabStackConvertStore;
- grabbersWrite[i] = grabStackWrite;
- }
- for (int i = OM_LOCAL; i < OM_LOCAL + OM_BASETYPE; ++i) {
- grabbersStore[i] = grabLocalConvertStore;
- grabbersWrite[i] = grabLocalWrite;
- }
- for (int i = OM_GLOBAL; i < OM_GLOBAL + OM_BASETYPE; ++i) {
- grabbersStore[i] = interpretError; // @TODO: global+convert-in-place
- grabbersWrite[i] = interpretError; // @TODO: global+convert-in-place
- }
- for (int i = OM_POP + OM_NO_CONVERT; i < OM_POP + OM_NO_CONVERT + OM_BASETYPE; ++i) {
- grabbers[i] = grabPop;
- grabbersUse[i] = grabPopUse;
- }
- grabbers[OM_POP + OM_NO_CONVERT + OM_INT] = grabPopInt;
- grabbers[OM_POP + OM_NO_CONVERT + OM_FLOAT] = grabPopFloat;
- // @TODO: specialized POP+ConstStr (shouldn't be able to have POP+Str)
- for (int i = OM_STACK + OM_NO_CONVERT; i < OM_STACK + OM_NO_CONVERT + OM_BASETYPE; ++i) {
- grabbers[i] = grabStack;
- grabbersStore[i] = grabStackStore;
- grabbersWrite[i] = grabStackWrite;
- grabbersUse[i] = grabStackUse;
- }
- grabbers[OM_STACK + OM_NO_CONVERT + OM_INT] = grabStackInt;
- grabbers[OM_STACK + OM_NO_CONVERT + OM_FLOAT] = grabStackFloat;
- grabbersUse[OM_STACK + OM_NO_CONVERT + OM_INT] = grabStackNumUse;
- grabbersUse[OM_STACK + OM_NO_CONVERT + OM_FLOAT] = grabStackNumUse;
- grabbersWrite[OM_STACK + OM_NO_CONVERT + OM_INT] = grabStackNumWrite;
- grabbersWrite[OM_STACK + OM_NO_CONVERT + OM_FLOAT] = grabStackNumWrite;
- for (int i = OM_LOCAL + OM_NO_CONVERT; i < OM_LOCAL + OM_NO_CONVERT + OM_BASETYPE; ++i) {
- grabbers[i] = grabLocal;
- grabbersStore[i] = grabLocalStore;
- grabbersWrite[i] = grabLocalWrite;
- grabbersUse[i] = grabLocalUse;
- }
- grabbers[OM_LOCAL + OM_NO_CONVERT + OM_INT] = grabLocalInt;
- grabbers[OM_LOCAL + OM_NO_CONVERT + OM_FLOAT] = grabLocalFloat;
- grabbersUse[OM_LOCAL + OM_NO_CONVERT + OM_INT] = grabLocalNumUse;
- grabbersUse[OM_LOCAL + OM_NO_CONVERT + OM_FLOAT] = grabLocalNumUse;
- grabbersWrite[OM_LOCAL + OM_NO_CONVERT + OM_INT] = grabLocalNumWrite;
- grabbersWrite[OM_LOCAL + OM_NO_CONVERT + OM_FLOAT] = grabLocalNumWrite;
- for (int i = OM_GLOBAL + OM_NO_CONVERT; i < OM_GLOBAL + OM_NO_CONVERT + OM_BASETYPE; ++i) {
- grabbers[i] = interpretError; // @TODO: global+no-convert
- grabbersStore[i] = interpretError; // @TODO: global+no-convert
- grabbersWrite[i] = interpretError; // @TODO: global+no-convert
- grabbersUse[i] = interpretError; // @TODO: global+no-convert
- }
- // @TODO: global+no-convert+int/float
- for (int i = OM_POP + OM_COPY; i < OM_POP + OM_COPY + OM_BASETYPE; ++i) {
- grabbers[i] = grabPopCopy;
- grabbersUse[i] = grabPopCopyUse;
- }
- for (int i = OM_STACK + OM_COPY; i < OM_STACK + OM_COPY + OM_BASETYPE; ++i) {
- grabbers[i] = grabStackCopy;
- grabbersUse[i] = grabStackCopyUse;
- }
- for (int i = OM_LOCAL + OM_COPY; i < OM_LOCAL + OM_COPY + OM_BASETYPE; ++i) {
- grabbers[i] = grabLocalCopy;
- grabbersUse[i] = grabLocalCopyUse;
- }
- for (int i = OM_GLOBAL + OM_COPY; i < OM_GLOBAL + OM_COPY + OM_BASETYPE; ++i) {
- grabbers[i] = interpretError; // @TODO: global+copy-convert
- grabbersUse[i] = interpretError; // @TODO: global+copy-convert
- }
-
- /* @TODO: indirects (unsure which modes will be needed yet)
-
- for (int i = OM_POP + OM_INDIRECT; i < OM_POP + OM_INDIRECT + OM_BASETYPE; ++i) {
- grabbers[i] = interpretError;
- grabbersStore[i] = interpretError;
- grabbersWrite[i] = interpretError;
- grabbersUse[i] = interpretError;
- }
- for (int i = OM_STACK + OM_INDIRECT; i < OM_STACK + OM_INDIRECT + OM_BASETYPE; ++i) {
- grabbers[i] = interpretError;
- grabbersStore[i] = interpretError;
- grabbersWrite[i] = interpretError;
- grabbersUse[i] = interpretError;
- }
-
- */
- // Extractors
- for (int i = 0; i < 256; i += 16) {
- extractors[i + OM_INT] = extractInt;
- extractors[i + OM_FLOAT] = extractFloat;
- // (should never occur) extractors[i + OM_STR] = extractStringConst;
- extractors[i + OM_STR_CONST] = extractStringConst;
- extractors[i + OM_ARRAY] = extractArray;
- extractors[i + OM_HASH] = extractHash;
- extractors[i + OM_ENTITY] = extractEntity;
- extractors[i + OM_OBJECT] = extractObject;
- }
-
- // Opcodes
- opcodes[OP_NOOP] = op_noop;
- opcodes[OP_ADD] = op_addI;
- opcodes[OP_ADDf] = op_addF;
- opcodes[OP_AND] = op_andI;
- opcodes[OP_CONCAT] = op_concatS;
- opcodes[OP_CONVERT] = op_convert;
- opcodes[OP_CREATEa] = interpretError; // @TODO:
- opcodes[OP_CREATEe] = op_createE;
- opcodes[OP_CREATEh] = interpretError; // @TODO:
- opcodes[OP_CREATEo] = op_createO;
- opcodes[OP_DEBUG] = Entity::op_debug;
- opcodes[OP_DISCARD] = op_discard;
- opcodes[OP_DISCARDL] = op_discardl;
- opcodes[OP_DIV] = op_divI;
- opcodes[OP_DIVf] = op_divF;
- opcodes[OP_EQ] = op_eqI;
- opcodes[OP_EQf] = op_eqF;
- opcodes[OP_EQo] = op_eqO;
- opcodes[OP_EQs] = op_eqS;
- opcodes[OP_GE] = op_geI;
- opcodes[OP_GEf] = op_geF;
- opcodes[OP_GEs] = op_geS;
- opcodes[OP_GT] = op_gtI;
- opcodes[OP_GTf] = op_gtF;
- opcodes[OP_GTs] = op_gtS;
- opcodes[OP_IFFALSE] = op_iffalseI;
- opcodes[OP_IFFALSEa] = interpretError; // @TODO:
- opcodes[OP_IFFALSEf] = op_iffalseF;
- opcodes[OP_IFFALSEh] = interpretError; // @TODO:
- opcodes[OP_IFFALSEo] = op_iffalseO;
- opcodes[OP_IFFALSEs] = op_iffalseS;
- opcodes[OP_IFFALSEv] = interpretError; // @TODO:
- opcodes[OP_IFTRUE] = op_iftrueI;
- opcodes[OP_IFTRUEa] = interpretError; // @TODO:
- opcodes[OP_IFTRUEf] = op_iftrueF;
- opcodes[OP_IFTRUEh] = interpretError; // @TODO:
- opcodes[OP_IFTRUEo] = op_iftrueO;
- opcodes[OP_IFTRUEs] = op_iftrueS;
- opcodes[OP_IFTRUEv] = interpretError; // @TODO:
- opcodes[OP_INIT] = Entity::op_init;
- opcodes[OP_JUMP] = op_jump;
- opcodes[OP_LE] = op_leI;
- opcodes[OP_LEf] = op_leF;
- opcodes[OP_LEs] = op_leS;
- opcodes[OP_LT] = op_ltI;
- opcodes[OP_LTf] = op_ltF;
- opcodes[OP_LTs] = op_ltS;
- opcodes[OP_MOD] = op_modI;
- opcodes[OP_MULT] = op_multI;
- opcodes[OP_MULTf] = op_multF;
- opcodes[OP_NE] = op_neI;
- opcodes[OP_NEf] = op_neF;
- opcodes[OP_NEo] = op_neO;
- opcodes[OP_NEs] = op_neS;
- opcodes[OP_OR] = op_orI;
- opcodes[OP_PUSH] = op_pushI;
- opcodes[OP_PUSHa] = op_pushAHO;
- opcodes[OP_PUSHf] = op_pushF;
- opcodes[OP_PUSHh] = op_pushAHO;
- opcodes[OP_PUSHo] = op_pushAHO;
- opcodes[OP_PUSHs] = op_pushS;
- opcodes[OP_PUSHv] = interpretError; // @TODO:
- opcodes[OP_RET] = Entity::op_ret;
- opcodes[OP_SHIFTL] = op_shiftlI;
- opcodes[OP_SHIFTR] = op_shiftrI;
- opcodes[OP_STOP] = Entity::op_stop;
- opcodes[OP_STORE] = op_storeI;
- opcodes[OP_STOREa] = op_storeA;
- opcodes[OP_STOREf] = op_storeF;
- opcodes[OP_STOREh] = op_storeH;
- opcodes[OP_STOREo] = op_storeO;
- opcodes[OP_STOREs] = op_storeS;
- opcodes[OP_STOREv] = interpretError; // @TODO:
- opcodes[OP_SUB] = op_subI;
- opcodes[OP_SUBf] = op_subF;
- opcodes[OP_SUBR] = op_subr;
- opcodes[OP_XOR] = op_xorI;
- opcodes[OP_GETe] = op_getE;
- opcodes[OP_SETe] = op_setE;
- opcodes[OP_GETo] = op_getO;
- opcodes[OP_SETo] = op_setO;
- opcodes[OP_IDLE] = Entity::op_idle;
- opcodes[OP_RETVOID] = Entity::op_retvoid;
- opcodes[OP_SETef] = op_setEF;
- opcodes[OP_SETei] = op_setEI;
- opcodes[OP_SETof] = op_setOF;
- opcodes[OP_SEToi] = op_setOI;
- // Empty operands
- emptyOperand[0].data.i = 0;
- emptyOperand[0].type = STACK_INT;
- emptyOperand[1].data.f = 0.0;
- emptyOperand[1].type = STACK_FLOAT;
- emptyOperand[2].data.p = NULL;
- emptyOperand[2].type = STACK_ENTITY;
- emptyOperand[3].data.p = NULL;
- emptyOperand[3].type = STACK_OBJECT;
- // Init deref array
- for (int i = 0; i < MAX_TODEREF; ++i) {
- toDeref[i].data.i = 0;
- toDeref[i].type = STACK_INT;
- }
- }
- void interpreterCleanup() { start_func
- // Clear deref array
- for (int i = 0; i < MAX_TODEREF; ++i) {
- dereferencers[toDeref[i].type](toDeref + i);
- toDeref[i].data.i = 0;
- toDeref[i].type = STACK_INT;
- }
- }
|