123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- /* GCSx
- ** BYTECODE.H
- **
- ** Bytecode-related utilities/datatypes/structures
- */
- /*****************************************************************************
- ** 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.
- *****************************************************************************/
- #ifndef __GCSx_BYTECODE_H_
- #define __GCSx_BYTECODE_H_
- // Bits combine to form datatypes
- enum {
- // Base types- all but VAR match with OM_
- DATA_VOID = -2,
- DATA_VAR = -1, // 0 reserved for none
- DATA_INT = 1,
- DATA_FLOAT = 2,
- DATA_STR = 3,
- DATA_ENTITY = 7,
- DATA_OBJECT = 8,
-
- // Flags
- DATA_ARRAY = 1,
- DATA_HASH = 2,
- DATA_CONST = 4,
- DATA_LOCAL = 8,
- DATA_GLOBAL = 16,
- DATA_PRIVATE = 32,
- DATA_PUBLIC = 64,
- };
- struct DataType {
- int baseType;
- int subType; // 0 for unapplicable OR unspecified/unknown
- int flags;
- };
- // datatype to wart conversion; doesn't consider local/global/private/public
- // type C + baseType (A void B var D int E float etc.)
- // followed by A + flags (A none B array C hash E const)
- // followed by hexadecimal subtype (optional)
- std::string dataTypeToWart(const DataType& dt);
- // wart to datatype; returns pointer to first unused character within string,
- // for reading next wart etc. returns NULL if error decoding wart
- const char* wartToDataType(const char* wart, DataType& result);
- // Labels within a codespace; also marks loops
- // Labels cannot be accessed between workspaces
- struct Label {
- int scope;
- int offset;
- int isLoop;
- // Stack depth at moment of label creation
- int stackDepth;
- };
- // Maps names to labels; names are newly-allocated char*s
- // Blank name for anonymous loops
- typedef hash_map<const char*, std::list<Label>, hash<const char*>, hash_eqstr> LabelMap;
- void destroyLabelMap(LabelMap* map);
- std::list<Label>& addLabelMap(LabelMap* map, const std::string& name);
- // Functions listed within an individual script/etc
- // Keyed off of name within a map
- struct Function {
- int numparam;
- DataType* parameters; // All have LOCAL added
- DataType returntype;
- // -1 = unknown
- // during compile, offset is within functions section
- int offset;
- };
- // Maps names to functions; names are newly-allocated char*s
- typedef hash_map<const char*, Function, hash<const char*>, hash_eqstr> FunctionMap;
- void destroyFunctionMap(FunctionMap* map);
- Function& addFunctionMap(FunctionMap* map, const std::string& name);
- // Variables listed within an individual script/etc
- // Keyed off of name within a map
- struct Variable {
- DataType datatype;
- int scope; // <0 global, 0 main local, >0 subscope (incl function param)
- union {
- Sint32 offs; // locals- stack offset
- Sint32 constI;
- BCfloat constF;
- const char* constS; // Allocated and owned
- } val;
- const char* name; // Backreference to name
- };
- // Maps names to varaibles; names are newly-allocated char*s
- typedef hash_map<const char*, std::list<Variable>, hash<const char*>, hash_eqstr> VariableMap;
- void destroyVariableMap(VariableMap* map);
- // storeName is gauranteed to point to a valid string as long as map entry exists
- std::list<Variable>& addVariableMap(VariableMap* map, const std::string& name, const char*& storeName);
- // Linker entries (global variables, built-in functions, function libraries)
- // Also used for global consts, to check consistency during linking
- // Also used for local strings/functions/loops, but removed before final result
- struct LinkEntry {
- enum LinkEntryType {
- LINK_GLOBAL = 1, // Link to global var's data
- LINK_GLOBALVAR, // Link directly to global var (may be different)
- LINK_BUILTIN,
- LINK_LIBRARY,
- LINK_CONST,
- LINK_STRING,
- LINK_FUNCTION,
- LINK_LOOP_CONTINUE,
- LINK_LOOP_END,
- // @TODO: links directly to other entity members/functions
- } type; // What type of link
- int offset; // Offset within bytecode to place/adjust ptr (ignored for const)
- std::string scope; // Library name, if specified (ignored for globals/local strings/functions/loops)
- std::string name; // Name of global/function/loop (ignored for local strings)
- // Combination of return/parameter types to verify at linking
- // For global variables, type
- // For global consts, includes const value
- // (ignored for local strings/functions/loops)
- std::string wart;
- };
- // Opcodes
- enum Opcode {
- OP_NOOP = 0,
- // These may be alphabetical, but future opcodes add at end
- OP_ADD,
- OP_ADDf,
- OP_AND,
- OP_CONCAT,
- OP_CONVERT,
- OP_CREATEa,
- OP_CREATEe,
- OP_CREATEh,
- OP_CREATEo,
- OP_DEBUG,
- OP_DISCARD,
- OP_DISCARDL,
- OP_DIV,
- OP_DIVf,
- OP_EQ,
- OP_EQf,
- OP_EQo,
- OP_EQs,
- OP_GE,
- OP_GEf,
- OP_GEs,
- OP_GT,
- OP_GTf,
- OP_GTs,
- OP_IFFALSE,
- OP_IFFALSEa,
- OP_IFFALSEf,
- OP_IFFALSEh,
- OP_IFFALSEo,
- OP_IFFALSEs,
- OP_IFFALSEv,
- OP_IFTRUE,
- OP_IFTRUEa,
- OP_IFTRUEf,
- OP_IFTRUEh,
- OP_IFTRUEo,
- OP_IFTRUEs,
- OP_IFTRUEv,
- OP_INIT,
- OP_JUMP,
- OP_LE,
- OP_LEf,
- OP_LEs,
- OP_LT,
- OP_LTf,
- OP_LTs,
- OP_MOD,
- OP_MULT,
- OP_MULTf,
- OP_NE,
- OP_NEf,
- OP_NEo,
- OP_NEs,
- OP_OR,
- OP_PUSH,
- OP_PUSHa,
- OP_PUSHf,
- OP_PUSHh,
- OP_PUSHo,
- OP_PUSHs,
- OP_PUSHv,
- OP_RET,
- OP_SHIFTL,
- OP_SHIFTR,
- OP_STOP,
- OP_STORE,
- OP_STOREa,
- OP_STOREf,
- OP_STOREh,
- OP_STOREo,
- OP_STOREs,
- OP_STOREv,
- OP_SUB,
- OP_SUBf,
- OP_SUBR,
- OP_XOR,
- OP_GETe,
- OP_SETe,
- OP_GETo,
- OP_SETo,
- OP_IDLE,
- OP_RETVOID,
- OP_SETef,
- OP_SETei,
- OP_SETof,
- OP_SEToi,
- // (not an actual opcode)
- OP_LAST,
- };
- // O)perand addressing M)odes
- // Most bit combinations are valid
- // - Unused object types are reserved (types 9-15)
- // - Array/hash literals not supported (types 5-6)
- // - Reserved literals not supported (types 10-15)
- // - Cannot use OM_INDIRECT with entry, array, hash, local, global
- // - Cannot use OM_POP with entry, non-const, or convert
- // - Const and copy go together; non-const and convert go together
- enum OperMode {
- // Non-literals
- OM_ENTRY = 0, // Represents a variant
- OM_INT = 1,
- OM_FLOAT = 2,
- OM_STR = 3,
- OM_STR_CONST = 4,
- OM_ARRAY = 5,
- OM_HASH = 6,
- OM_ENTITY = 7,
- OM_OBJECT = 8,
- // (these types are reserved)
- OM_RESERVED_1 = 9,
- OM_RESERVED_2 = 10,
- OM_RESERVED_3 = 11,
- OM_RESERVED_4 = 12,
- OM_RESERVED_5 = 13,
- OM_RESERVED_6 = 14,
- OM_RESERVED_7 = 15,
- // Literals
- OM_NONE = 0,
- // OM_INT also used as literal for offsets
- // OM_FLOAT
- // [OM_STR not legal but used during compilation]
- // OM_STR_CONST
- // [OM_ARRAY / OM_HASH reserved for literals later]
- OM_ALL = 7, // entity, always w/subtype even if 0
- OM_ALL_OTHER = 8, // entity, always w/subtype even if 0
- OM_NOTHING = 9, // entity or object, no subtype
- OM_THIS = 10, // entity, no subtype
- // 11-14 reserved; currently assumed to be other OBJ_ literals
- OM_POINTER = 15,
-
- // Location
- OM_POP = 0, // Must always use with one of two flags
- OM_STACK = 16,
- OM_LOCAL = 32,
- OM_GLOBAL = 48,
-
- // Use with pop/stack to indicate stack entry is a POINTER
- // directly within an array/hash to the noted type, NO CONVERSION
- OM_INDIRECT = 192,
-
- // Flags
- // If present type is preknown and no conversion needed
- // If not, item is converted 'in place' if necessary
- // Converting an array or hash makes a new copy, but this
- // will NOT make a new copy if type is already correct
- OM_NO_CONVERT = 64,
- // If conversion performed, don't affect original
- // Also *gaurantees* a new array/hash copy (no ref)
- OM_COPY = 128,
-
- // Masks
- OM_BASETYPE = 15,
- OM_LOCATION = 48,
- OM_FLAGS = 192,
- };
- // Use these to ensure proper handling due to overlapping operand mode bits
- // These may not be used in bytecode interpreting for speed/efficiency reasons
- #define OM_IS_NONE(x) ((x) == OM_NONE)
- #define OM_IS_OFFSET(x) ((x) == OM_INT)
- #define OM_IS_POINTER(x) ((x) == OM_POINTER)
- #define OM_IS_LITERAL(x) (((x) & OM_BASETYPE) == (x))
- #define OM_IS_INT(x) (((x) & OM_BASETYPE) == OM_INT)
- #define OM_IS_FLOAT(x) (((x) & OM_BASETYPE) == OM_FLOAT)
- #define OM_IS_STR(x) (((x) & OM_BASETYPE) == OM_STR || ((x) & OM_BASETYPE) == OM_STR_CONST)
- #define OM_IS_CONST(x) (((x) & OM_BASETYPE) == OM_STR_CONST)
- // Be prepared for literal arrays/hashes in the future
- #define OM_IS_ARRAY(x) (((x) & OM_BASETYPE) == OM_ARRAY)
- #define OM_IS_HASH(x) (((x) & OM_BASETYPE) == OM_HASH)
- // Always check for literal status first before anything further
- #define OM_IS_ENTITY(x) (((x) & OM_BASETYPE) == OM_ENTITY)
- #define OM_IS_OBJECT(x) (((x) & OM_BASETYPE) == OM_OBJECT)
- // (or can check for 'none' instead of literal, before this one)
- #define OM_IS_ENTRY(x) (((x) & OM_BASETYPE) == OM_ENTRY)
- #define OM_IS_LOCAL(x) (((x) & OM_LOCATION) == OM_LOCAL)
- #define OM_IS_STACK(x) (((x) & OM_LOCATION) == OM_STACK)
- #define OM_IS_GLOBAL(x) (((x) & OM_LOCATION) == OM_GLOBAL)
- #define OM_IS_POP(x) (((x) & OM_LOCATION) == OM_POP && ((x) & OM_BASETYPE) != (x))
- #define OM_IS_INDIRECT(x) (((x) & OM_FLAGS) == OM_INDIRECT)
- #define OM_IS_KNOWN(x) (((x) & OM_FLAGS) == OM_NO_CONVERT)
- #define OM_IS_CONVERT(x) (((x) & OM_FLAGS) != OM_NO_CONVERT && ((x) & OM_FLAGS) != OM_INDIRECT)
- #define OM_IS_COPY(x) (((x) & OM_FLAGS) == OM_COPY)
- #ifdef COMPILEASSERT
- // Checks for valid opcode/mode combinations
- void checkOpcode(Opcode opc, Uint8 mode1, Uint8 mode2, Uint8 mode3);
- #endif
- // Dumps program to debug (uses static globals, not thread-safe)
- void decompileBytecode(const Uint32* bytecode, const std::list<LinkEntry>* links);
- int debugBytecode(std::string& line, const Uint32* bytecode);
- #endif
|