gcsx_compile.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /* GCSx
  2. ** COMPILE.H
  3. **
  4. ** Bytecode compilation (to pre-link state)
  5. */
  6. /*****************************************************************************
  7. ** Copyright (C) 2003-2006 Janson
  8. **
  9. ** This program is free software; you can redistribute it and/or modify
  10. ** it under the terms of the GNU General Public License as published by
  11. ** the Free Software Foundation; either version 2 of the License, or
  12. ** (at your option) any later version.
  13. **
  14. ** This program is distributed in the hope that it will be useful,
  15. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ** GNU General Public License for more details.
  18. **
  19. ** You should have received a copy of the GNU General Public License
  20. ** along with this program; if not, write to the Free Software
  21. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
  22. *****************************************************************************/
  23. #ifndef __GCSx_COMPILE_H_
  24. #define __GCSx_COMPILE_H_
  25. class Compiler {
  26. private:
  27. // Only valid after entire compile process
  28. int errorCount;
  29. int warningCount;
  30. struct Parameter {
  31. DataType type;
  32. std::string name;
  33. };
  34. const std::list<std::string>* source;
  35. const World* world;
  36. int scriptType;
  37. class Tokenizer* t;
  38. FunctionMap* func;
  39. VariableMap* vars;
  40. LabelMap* labels;
  41. int scope;
  42. // current function
  43. int inFunctionScope;
  44. int funcEntryStackDepth;
  45. int funcParamStackDepth;
  46. // Offsets of all existing strings, to prevent duplication
  47. typedef hash_map<const char*, int, hash<const char*>, hash_eqstr> StringMap;
  48. StringMap stringMap;
  49. struct Codespace {
  50. std::vector<Uint32> code;
  51. // Add to all var accesses on stack
  52. // Should (must) be 0 when merging before an existing codeblock
  53. int stackDepth;
  54. // Linker entries
  55. std::list<LinkEntry> links;
  56. };
  57. Codespace main; // Main code outside of functions
  58. Codespace localInit; // Local var initialization (pre-main-code)
  59. Codespace functions; // All functions
  60. Codespace strings; // All static strings
  61. std::vector<Codespace*> workspaces; // Points to where we're writing code
  62. Codespace* ws; // Optimized reference to workspace.back()
  63. void pushWorkspace(Codespace* newWorkspace) { workspaces.push_back(ws = newWorkspace); }
  64. void popWorkspace() { workspaces.pop_back(); ws = workspaces.back(); }
  65. // Append a codespace to end of another, merges links as well
  66. // Doesn't modify src but you should probably delete it afterwards
  67. void appendWorkspaces(Codespace* dest, const Codespace* src);
  68. // Removes and finishes string/function links, copies others to final link table and adds offset
  69. void completeLinkage(std::list<LinkEntry>* links, Codespace& code, int linkOffset, int strOffset, int funcOffset);
  70. void doParseSymbols();
  71. void doCompile(Uint32** bytecode, std::list<LinkEntry>* links);
  72. // (returns various ended values, used by parent blocks)
  73. struct Ended {
  74. int how;
  75. int scope;
  76. int breakInfinite;
  77. };
  78. // returnType may be present without parameters, for subscopes of functions
  79. void compileBlock(Ended& ended, const std::vector<Parameter>* parameters = NULL, DataType* returnType = NULL);
  80. static int isDataType(int tokenType);
  81. DataType parseDataType();
  82. void checkDataType(DataType& type, int noConst, int noScope, int noVisibility, int noVoid);
  83. // Returns true if successful enough to use; either way, uses up tokens
  84. // Returns -1 if successful, but no tokens used (ie, blank param list no parens)
  85. // May use as little as no tokens if no datatype or paren present (does not use brace)
  86. int parseParameterList(std::vector<Parameter>& list);
  87. // All cmds that post code assume they're working on stack top unless noted
  88. // i.e. temporaries are on stack top, results will be on stack top
  89. struct Operand {
  90. // The operand mode
  91. // ALL flags/types allowed except-
  92. // OM_COPY filled in at last moment
  93. // OM_POP filled in at last moment
  94. // Strings convert to OM_STR_CONST at last moment (even literals)
  95. // 0 typically results no operand or ERROR condition
  96. OperMode mode;
  97. int arrayType; // (or hash type) A OM_BASETYPE constant, or OM_ENTRY
  98. // The literal data written to the bytecode
  99. // operand data is NOT tracked accurately for temporaries on stack (O_IS_TEMP)
  100. union {
  101. Sint32 i; // Used for offsets, obj types, etc. also
  102. BCfloat f;
  103. void* p;
  104. } data;
  105. int subType;
  106. // Flags
  107. enum {
  108. // is a variable- don't modify directly or pop (used with OM_STACK)
  109. OF_IS_VAR = 1,
  110. // is gauranteed to not reference another array/hash (only used when O_IS_TEMP)
  111. OF_IS_COPY = 2,
  112. // used with a constant INT value to prevent mode looking like an error
  113. OF_IS_VOID = 4,
  114. // is a function return value or assignment result or other result that had side-effects
  115. OF_IS_SIDEFX = 8,
  116. };
  117. int flags;
  118. // Reference to source of data
  119. union {
  120. // for global vars ONLY, pointer to original variable for creating a linker ref
  121. const Variable* global;
  122. // for string literals ONLY; not turned into data until used
  123. // if NULL, data is already correct
  124. std::string* strLiteral;
  125. } ref;
  126. };
  127. static void createEmpty(Operand& o);
  128. static void createInt(Operand& o, Sint32 value);
  129. static void createFloat(Operand& o, BCfloat value);
  130. // You must add a local/global/stack, and any flags; always adds OM_NO_CONVERT
  131. static Operand dataTypeToOperand(DataType dt);
  132. // Easy access to flags
  133. #define O_IS_VAR(x) ((x).flags & Operand::OF_IS_VAR)
  134. #define O_IS_COPY(x) ((x).flags & Operand::OF_IS_COPY)
  135. #define O_IS_VOID(x) ((x).flags & Operand::OF_IS_VOID)
  136. #define O_IS_SIDEFX(x) ((x).flags & Operand::OF_IS_SIDEFX)
  137. // Is an operand a "temporary"?
  138. #define O_IS_TEMP(x) (OM_IS_STACK((x).mode) && !O_IS_VAR(x))
  139. // Parse any valid expression, posts code to get to result
  140. // warnAssign should start at 2 if you want to allow 1 set of parenthesis and still warn
  141. // These never return operand modes listed as "last minute"; 0 = error; all other modes possible
  142. // "usingValue" is basically "don't want a void result"
  143. Operand parseExpression(int warnAssign = 0, int usingValue = 1, Operand* firstOperand = NULL, int stopPrecedence = 100, const Variable* varToCount = NULL);
  144. Operand parseOperand(int warnAssign = 0, int usingValue = 1, const Variable* varToCount = NULL, Operand* memberOf = NULL);
  145. Operand variableToOperand(const Variable& var);
  146. // (opertoken is just there to assist with error msgs)
  147. // uses up both operands and produces another
  148. Operand parseOperation(int oper, const std::string& operToken, Operand& a, Operand& b);
  149. // Assumes you've moved past the =, posts code to get result
  150. void parseAssignment(Operand& var, DataType varType, const Variable* varToCount = NULL, int memberPos = -1);
  151. // Function call- Parses any parameters for you; returns o.mode=0 if void return value
  152. Operand parseFunction(const Function& function, const std::string& funcName);
  153. // Returns true if found
  154. int findFunction(const std::string& name, Function& function) const;
  155. // (uses up operand)
  156. void processReturn(Operand& o, DataType* returnType);
  157. // Convert various operand modes, posting code if needed and converting operand itself
  158. // Assumes and produces no "last minute" modes or 0.
  159. // Handles ANY other type of conversion- makes no assumptions- uses FORCE* if needed
  160. void convertToInt(Operand& o);
  161. void convertToFloat(Operand& o);
  162. void convertToStr(Operand& o);
  163. void convertToArray(Operand& o, DataType datatype);
  164. void convertToHash(Operand& o, DataType datatype);
  165. // Handles subtype if present
  166. void convertToEntity(Operand& o, DataType datatype);
  167. // Handles subtype if present
  168. void convertToObject(Operand& o, DataType datatype);
  169. // Displays errors if conversion is not a "naturally" allowed conversion
  170. void convertToMatch(Operand& o, DataType datatype, const char* errorTarget);
  171. // Converts something to a temporary (O_IS_TEMP)
  172. // Gauranteed to be ref-free from original version
  173. // partialConvert is only intended for literals-
  174. // -skips defining literal string
  175. // -leaves o.data
  176. // This allows undoing or "completing" the conversion later.
  177. // Returns true if string needs to be converted later
  178. int convertToTemp(Operand& o, int partialConvert = 0, int refOK = 0);
  179. // Frees any string, pops if temporary, asserts on top of stack and not OM_POP
  180. // Safe to call with o.mode = 0
  181. void destroyOperand(Operand& o);
  182. // Pushes an appropriate empty value on the stack (doesn't modify stackdepth)
  183. void generateBlank(DataType& type);
  184. // (these use no tokens)
  185. const Variable& defineVariable(DataType type, const std::string& name, int isParam = 0);
  186. int defineString(const std::string& str); // Returns offset within strings
  187. void defineString(Operand& o); // Converts a static string to a ready-to-use operand
  188. static int precedence(int oper);
  189. // Call before using a postCmd* function to post appropriate linker entries
  190. // Link to local function; assumes first oper
  191. void prepLinker(const std::string& funcName);
  192. // Link to loop continue or break; assumes first oper
  193. void prepLinker(int isContinue, const std::string& loopName);
  194. // Link to local string at current position- called from within postCmdRaw
  195. void prepLinker();
  196. // Link to global var or it's data- called from within postCmdRaw
  197. void prepLinker(const Variable* var, int toData = 1);
  198. // All possible variations of opcode and operands; returns total int32s used
  199. int postCmdRaw(Opcode opc, Operand* o1 = NULL, Operand* o2 = NULL, Operand* o3 = NULL);
  200. // Quick/convenient versions
  201. void postCmd(Opcode opc);
  202. void postCmdI(Opcode opc, Sint32 int1);
  203. void postCmdII(Opcode opc, Sint32 int1, Sint32 int2);
  204. void postCmdF(Opcode opc, BCfloat float1);
  205. void postCmdS(Opcode opc, Sint32 str1);
  206. // (doesn't define string for you- just uses data.i)
  207. void postCmdPush(Operand& oper, int refOK = 0);
  208. // Offset is from current end-of-code and will be adjusted
  209. // Returns position of offset in bytecode in case you want to adjust further
  210. // (original offset is adjusted based on <0 or >=0, so at least get that right)
  211. // Returns -1 if no offset (if condition was always true/false this can occur)
  212. // Tells you if it always/never jumps using last two parameters
  213. int postCmdIf(int ifTrue, Sint32 offset, Operand& oper, int& alwaysJumps, int& neverJumps);
  214. public:
  215. Compiler(const std::list<std::string>* src, const World* srcWorld);
  216. ~Compiler();
  217. // Just parse symbols
  218. // Returns true if fatal errors and deletes entire map
  219. int parseSymbols(FunctionMap* funcMap);
  220. // Do a full compile
  221. // Assumes symbols have been parsed, above
  222. // Returns true if errors
  223. // Code may or may not be allocated in error situation
  224. int compile(Uint32** bytecode, FunctionMap* funcMap, std::list<LinkEntry>* links, int scriptId);
  225. int numErrors() { return errorCount; }
  226. int numWarnings() { return warningCount; }
  227. };
  228. #endif