123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- /* GCSx
- ** COMPILE.H
- **
- ** Bytecode compilation (to pre-link state)
- */
- /*****************************************************************************
- ** 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_COMPILE_H_
- #define __GCSx_COMPILE_H_
- class Compiler {
- private:
- // Only valid after entire compile process
- int errorCount;
- int warningCount;
- struct Parameter {
- DataType type;
- std::string name;
- };
-
- const std::list<std::string>* source;
- const World* world;
- int scriptType;
- class Tokenizer* t;
- FunctionMap* func;
- VariableMap* vars;
- LabelMap* labels;
- int scope;
- // current function
- int inFunctionScope;
- int funcEntryStackDepth;
- int funcParamStackDepth;
-
- // Offsets of all existing strings, to prevent duplication
- typedef hash_map<const char*, int, hash<const char*>, hash_eqstr> StringMap;
- StringMap stringMap;
-
- struct Codespace {
- std::vector<Uint32> code;
- // Add to all var accesses on stack
- // Should (must) be 0 when merging before an existing codeblock
- int stackDepth;
- // Linker entries
- std::list<LinkEntry> links;
- };
- Codespace main; // Main code outside of functions
- Codespace localInit; // Local var initialization (pre-main-code)
- Codespace functions; // All functions
- Codespace strings; // All static strings
- std::vector<Codespace*> workspaces; // Points to where we're writing code
- Codespace* ws; // Optimized reference to workspace.back()
-
- void pushWorkspace(Codespace* newWorkspace) { workspaces.push_back(ws = newWorkspace); }
- void popWorkspace() { workspaces.pop_back(); ws = workspaces.back(); }
- // Append a codespace to end of another, merges links as well
- // Doesn't modify src but you should probably delete it afterwards
- void appendWorkspaces(Codespace* dest, const Codespace* src);
- // Removes and finishes string/function links, copies others to final link table and adds offset
- void completeLinkage(std::list<LinkEntry>* links, Codespace& code, int linkOffset, int strOffset, int funcOffset);
-
- void doParseSymbols();
- void doCompile(Uint32** bytecode, std::list<LinkEntry>* links);
- // (returns various ended values, used by parent blocks)
- struct Ended {
- int how;
- int scope;
- int breakInfinite;
- };
- // returnType may be present without parameters, for subscopes of functions
- void compileBlock(Ended& ended, const std::vector<Parameter>* parameters = NULL, DataType* returnType = NULL);
-
- static int isDataType(int tokenType);
- DataType parseDataType();
- void checkDataType(DataType& type, int noConst, int noScope, int noVisibility, int noVoid);
-
- // Returns true if successful enough to use; either way, uses up tokens
- // Returns -1 if successful, but no tokens used (ie, blank param list no parens)
- // May use as little as no tokens if no datatype or paren present (does not use brace)
- int parseParameterList(std::vector<Parameter>& list);
-
- // All cmds that post code assume they're working on stack top unless noted
- // i.e. temporaries are on stack top, results will be on stack top
-
- struct Operand {
- // The operand mode
- // ALL flags/types allowed except-
- // OM_COPY filled in at last moment
- // OM_POP filled in at last moment
- // Strings convert to OM_STR_CONST at last moment (even literals)
- // 0 typically results no operand or ERROR condition
- OperMode mode;
- int arrayType; // (or hash type) A OM_BASETYPE constant, or OM_ENTRY
-
- // The literal data written to the bytecode
- // operand data is NOT tracked accurately for temporaries on stack (O_IS_TEMP)
- union {
- Sint32 i; // Used for offsets, obj types, etc. also
- BCfloat f;
- void* p;
- } data;
- int subType;
- // Flags
- enum {
- // is a variable- don't modify directly or pop (used with OM_STACK)
- OF_IS_VAR = 1,
- // is gauranteed to not reference another array/hash (only used when O_IS_TEMP)
- OF_IS_COPY = 2,
- // used with a constant INT value to prevent mode looking like an error
- OF_IS_VOID = 4,
- // is a function return value or assignment result or other result that had side-effects
- OF_IS_SIDEFX = 8,
- };
- int flags;
- // Reference to source of data
- union {
- // for global vars ONLY, pointer to original variable for creating a linker ref
- const Variable* global;
- // for string literals ONLY; not turned into data until used
- // if NULL, data is already correct
- std::string* strLiteral;
- } ref;
- };
-
- static void createEmpty(Operand& o);
- static void createInt(Operand& o, Sint32 value);
- static void createFloat(Operand& o, BCfloat value);
- // You must add a local/global/stack, and any flags; always adds OM_NO_CONVERT
- static Operand dataTypeToOperand(DataType dt);
- // Easy access to flags
- #define O_IS_VAR(x) ((x).flags & Operand::OF_IS_VAR)
- #define O_IS_COPY(x) ((x).flags & Operand::OF_IS_COPY)
- #define O_IS_VOID(x) ((x).flags & Operand::OF_IS_VOID)
- #define O_IS_SIDEFX(x) ((x).flags & Operand::OF_IS_SIDEFX)
- // Is an operand a "temporary"?
- #define O_IS_TEMP(x) (OM_IS_STACK((x).mode) && !O_IS_VAR(x))
-
- // Parse any valid expression, posts code to get to result
- // warnAssign should start at 2 if you want to allow 1 set of parenthesis and still warn
- // These never return operand modes listed as "last minute"; 0 = error; all other modes possible
- // "usingValue" is basically "don't want a void result"
- Operand parseExpression(int warnAssign = 0, int usingValue = 1, Operand* firstOperand = NULL, int stopPrecedence = 100, const Variable* varToCount = NULL);
- Operand parseOperand(int warnAssign = 0, int usingValue = 1, const Variable* varToCount = NULL, Operand* memberOf = NULL);
- Operand variableToOperand(const Variable& var);
- // (opertoken is just there to assist with error msgs)
- // uses up both operands and produces another
- Operand parseOperation(int oper, const std::string& operToken, Operand& a, Operand& b);
- // Assumes you've moved past the =, posts code to get result
- void parseAssignment(Operand& var, DataType varType, const Variable* varToCount = NULL, int memberPos = -1);
- // Function call- Parses any parameters for you; returns o.mode=0 if void return value
- Operand parseFunction(const Function& function, const std::string& funcName);
- // Returns true if found
- int findFunction(const std::string& name, Function& function) const;
- // (uses up operand)
- void processReturn(Operand& o, DataType* returnType);
- // Convert various operand modes, posting code if needed and converting operand itself
- // Assumes and produces no "last minute" modes or 0.
- // Handles ANY other type of conversion- makes no assumptions- uses FORCE* if needed
- void convertToInt(Operand& o);
- void convertToFloat(Operand& o);
- void convertToStr(Operand& o);
- void convertToArray(Operand& o, DataType datatype);
- void convertToHash(Operand& o, DataType datatype);
- // Handles subtype if present
- void convertToEntity(Operand& o, DataType datatype);
- // Handles subtype if present
- void convertToObject(Operand& o, DataType datatype);
- // Displays errors if conversion is not a "naturally" allowed conversion
- void convertToMatch(Operand& o, DataType datatype, const char* errorTarget);
-
- // Converts something to a temporary (O_IS_TEMP)
- // Gauranteed to be ref-free from original version
- // partialConvert is only intended for literals-
- // -skips defining literal string
- // -leaves o.data
- // This allows undoing or "completing" the conversion later.
- // Returns true if string needs to be converted later
- int convertToTemp(Operand& o, int partialConvert = 0, int refOK = 0);
-
- // Frees any string, pops if temporary, asserts on top of stack and not OM_POP
- // Safe to call with o.mode = 0
- void destroyOperand(Operand& o);
-
- // Pushes an appropriate empty value on the stack (doesn't modify stackdepth)
- void generateBlank(DataType& type);
-
- // (these use no tokens)
- const Variable& defineVariable(DataType type, const std::string& name, int isParam = 0);
- int defineString(const std::string& str); // Returns offset within strings
- void defineString(Operand& o); // Converts a static string to a ready-to-use operand
- static int precedence(int oper);
-
- // Call before using a postCmd* function to post appropriate linker entries
- // Link to local function; assumes first oper
- void prepLinker(const std::string& funcName);
- // Link to loop continue or break; assumes first oper
- void prepLinker(int isContinue, const std::string& loopName);
- // Link to local string at current position- called from within postCmdRaw
- void prepLinker();
- // Link to global var or it's data- called from within postCmdRaw
- void prepLinker(const Variable* var, int toData = 1);
- // All possible variations of opcode and operands; returns total int32s used
- int postCmdRaw(Opcode opc, Operand* o1 = NULL, Operand* o2 = NULL, Operand* o3 = NULL);
- // Quick/convenient versions
- void postCmd(Opcode opc);
- void postCmdI(Opcode opc, Sint32 int1);
- void postCmdII(Opcode opc, Sint32 int1, Sint32 int2);
- void postCmdF(Opcode opc, BCfloat float1);
- void postCmdS(Opcode opc, Sint32 str1);
- // (doesn't define string for you- just uses data.i)
- void postCmdPush(Operand& oper, int refOK = 0);
- // Offset is from current end-of-code and will be adjusted
- // Returns position of offset in bytecode in case you want to adjust further
- // (original offset is adjusted based on <0 or >=0, so at least get that right)
- // Returns -1 if no offset (if condition was always true/false this can occur)
- // Tells you if it always/never jumps using last two parameters
- int postCmdIf(int ifTrue, Sint32 offset, Operand& oper, int& alwaysJumps, int& neverJumps);
- public:
- Compiler(const std::list<std::string>* src, const World* srcWorld);
- ~Compiler();
-
- // Just parse symbols
- // Returns true if fatal errors and deletes entire map
- int parseSymbols(FunctionMap* funcMap);
-
- // Do a full compile
- // Assumes symbols have been parsed, above
- // Returns true if errors
- // Code may or may not be allocated in error situation
- int compile(Uint32** bytecode, FunctionMap* funcMap, std::list<LinkEntry>* links, int scriptId);
- int numErrors() { return errorCount; }
- int numWarnings() { return warningCount; }
- };
- #endif
|