| | 1 | /* $Header: d:/cvsroot/tads/tads3/TCT3INT.H,v 1.3 1999/07/11 00:46:57 MJRoberts Exp $ */ |
| | 2 | |
| | 3 | /* |
| | 4 | * Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved. |
| | 5 | * |
| | 6 | * Please see the accompanying license file, LICENSE.TXT, for information |
| | 7 | * on using and copying this software. |
| | 8 | */ |
| | 9 | /* |
| | 10 | Name |
| | 11 | tct3int.h - T3-specific intermediate parse node classes |
| | 12 | Function |
| | 13 | |
| | 14 | Notes |
| | 15 | |
| | 16 | Modified |
| | 17 | 05/12/99 MJRoberts - Creation |
| | 18 | */ |
| | 19 | |
| | 20 | #ifndef TCT3INT_H |
| | 21 | #define TCT3INT_H |
| | 22 | |
| | 23 | /* include our T3-specific base classes */ |
| | 24 | #include "tct3base.h" |
| | 25 | |
| | 26 | /* include the target-independent intermediate classes */ |
| | 27 | #include "tcpnint.h" |
| | 28 | |
| | 29 | /* ------------------------------------------------------------------------ */ |
| | 30 | /* |
| | 31 | * Unary Operator Expression node |
| | 32 | */ |
| | 33 | class CTPNUnary: public CTPNUnaryBase |
| | 34 | { |
| | 35 | public: |
| | 36 | CTPNUnary(CTcPrsNode *subexpr) |
| | 37 | : CTPNUnaryBase(subexpr) { } |
| | 38 | |
| | 39 | /* |
| | 40 | * Generate code for a unary operator with no side effects. We'll |
| | 41 | * generate code for the subexpression, then generate the given |
| | 42 | * opcode. |
| | 43 | * |
| | 44 | * If 'discard' is true, we won't generate the opcode. We know the |
| | 45 | * opcode has no side effects, so if the result of the calculation |
| | 46 | * isn't going to be used, there's no point in calculating it in the |
| | 47 | * first place. |
| | 48 | */ |
| | 49 | void gen_unary(uchar opc, int discard, int for_condition); |
| | 50 | }; |
| | 51 | |
| | 52 | |
| | 53 | /* ------------------------------------------------------------------------ */ |
| | 54 | /* |
| | 55 | * Binary Operator Expression node |
| | 56 | */ |
| | 57 | class CTPNBin: public CTPNBinBase |
| | 58 | { |
| | 59 | public: |
| | 60 | CTPNBin(CTcPrsNode *lhs, CTcPrsNode *rhs) |
| | 61 | : CTPNBinBase(lhs, rhs) { } |
| | 62 | |
| | 63 | /* |
| | 64 | * Generate code for a binary operator with no side effects. We'll |
| | 65 | * generate code for the left operand, then for the right operand, |
| | 66 | * then generate the opcode. |
| | 67 | * |
| | 68 | * If 'discard' is true, we won't generate the opcode. We know that |
| | 69 | * the opcode has no side effects, so if the result of the |
| | 70 | * calculation isn't needed, we need not apply the opcode; we simply |
| | 71 | * want to evaluate the subexpressions for any side effects they |
| | 72 | * might have. |
| | 73 | */ |
| | 74 | void gen_binary(uchar opc, int discard, int for_condition); |
| | 75 | }; |
| | 76 | |
| | 77 | /* ------------------------------------------------------------------------ */ |
| | 78 | /* |
| | 79 | * generic statement |
| | 80 | */ |
| | 81 | class CTPNStm: public CTPNStmBase |
| | 82 | { |
| | 83 | public: |
| | 84 | /* initialize at the tokenizer's current source file position */ |
| | 85 | CTPNStm() : CTPNStmBase() { } |
| | 86 | |
| | 87 | /* initialize at the given source position */ |
| | 88 | CTPNStm(class CTcTokFileDesc *file, long linenum) |
| | 89 | : CTPNStmBase(file, linenum) { } |
| | 90 | |
| | 91 | /* |
| | 92 | * Generate code for a labeled 'continue'. These are called when |
| | 93 | * this statement is labeled, and the same label is used in a |
| | 94 | * 'continue' statement. |
| | 95 | * |
| | 96 | * Returns true if successful, false if not. This should return |
| | 97 | * false if the statement is not suitable for a 'continue'. By |
| | 98 | * default, we simply return false, since most statements cannot be |
| | 99 | * used as the target of a 'continue'. |
| | 100 | */ |
| | 101 | virtual int gen_code_labeled_continue() { return FALSE; } |
| | 102 | }; |
| | 103 | |
| | 104 | /* ------------------------------------------------------------------------ */ |
| | 105 | /* |
| | 106 | * Enclosing Statement class: this is the base class for statements that |
| | 107 | * have special needs for exiting due to break, continue, goto, and |
| | 108 | * return. Refer to tcpnint.h for details. |
| | 109 | */ |
| | 110 | class CTPNStmEnclosing: public CTPNStm |
| | 111 | { |
| | 112 | public: |
| | 113 | CTPNStmEnclosing(CTPNStmEnclosing *enclosing) |
| | 114 | { |
| | 115 | /* remember the statement that encloses me */ |
| | 116 | enclosing_ = enclosing; |
| | 117 | } |
| | 118 | |
| | 119 | /* get the enclosing statement */ |
| | 120 | CTPNStmEnclosing *get_enclosing() const { return enclosing_; } |
| | 121 | |
| | 122 | /* |
| | 123 | * Generate code for a 'break' to a given label, or an unlabeled |
| | 124 | * 'break' if lbl is null. Returns true if the break was fully |
| | 125 | * processed, false if not. If any work is necessary to unwind the |
| | 126 | * exception stack to break out of this block, that should be done |
| | 127 | * here. If this node doesn't actually accomplish the break, it |
| | 128 | * should recursively invoke the next enclosing statement's routine |
| | 129 | * to do the work. |
| | 130 | * |
| | 131 | * By default, we'll simply invoke the enclosing handler, if there |
| | 132 | * is one, or return failure (i.e., false) if not. |
| | 133 | */ |
| | 134 | virtual int gen_code_break(const textchar_t *lbl, size_t lbl_len) |
| | 135 | { |
| | 136 | if (enclosing_) |
| | 137 | return enclosing_->gen_code_break(lbl, lbl_len); |
| | 138 | else |
| | 139 | return 0; |
| | 140 | } |
| | 141 | |
| | 142 | /* |
| | 143 | * Generate code for a 'continue' to a given label, or an unlabeled |
| | 144 | * 'continue' if lbl is null. Same rules as gen_code_break(). |
| | 145 | * |
| | 146 | * By default, we'll simply invoke the enclosing handler, if there |
| | 147 | * is one, or return failure (i.e., false) if not. |
| | 148 | */ |
| | 149 | virtual int gen_code_continue(const textchar_t *lbl, size_t lbl_len) |
| | 150 | { |
| | 151 | if (enclosing_) |
| | 152 | return enclosing_->gen_code_continue(lbl, lbl_len); |
| | 153 | else |
| | 154 | return 0; |
| | 155 | } |
| | 156 | |
| | 157 | /* |
| | 158 | * Generate the code necessary to unwind the stack for returning |
| | 159 | * through this enclosing statement. This should generate any code |
| | 160 | * necessary (such as a call to a 'finally' block, for a 'try' |
| | 161 | * statement), then call the next enclosing statement to do the same |
| | 162 | * thing. By default, this does nothing except invoke the enclosing |
| | 163 | * statement, since most enclosing statements don't need to generate |
| | 164 | * any code to handle a 'return' through them. |
| | 165 | */ |
| | 166 | virtual void gen_code_unwind_for_return() |
| | 167 | { |
| | 168 | /* if there's an enclosing statement, ask it to unwind itself */ |
| | 169 | if (enclosing_ != 0) |
| | 170 | enclosing_->gen_code_unwind_for_return(); |
| | 171 | } |
| | 172 | |
| | 173 | /* |
| | 174 | * Determine if we'll generate any code to unwind the stack for |
| | 175 | * returning through this enclosing statement. This should return |
| | 176 | * true if any code will be generated by a call to |
| | 177 | * gen_code_unwind_for_return(). By default, we'll return whatever |
| | 178 | * our enclosing statement does. |
| | 179 | */ |
| | 180 | virtual int will_gen_code_unwind_for_return() const |
| | 181 | { |
| | 182 | /* |
| | 183 | * return what the enclosing statement does, or false if we're |
| | 184 | * the outermost statement |
| | 185 | */ |
| | 186 | return (enclosing_ != 0 |
| | 187 | ? enclosing_->will_gen_code_unwind_for_return() |
| | 188 | : FALSE); |
| | 189 | } |
| | 190 | |
| | 191 | /* |
| | 192 | * Generate the code necessary to unwind the stack for executing a |
| | 193 | * 'goto' to the given label statement. We first determine if the |
| | 194 | * target label is contained within this statement; if it is, |
| | 195 | * there's nothing we need to do, because we're transferring control |
| | 196 | * within the same enclosing statement. |
| | 197 | * |
| | 198 | * If control is being transferred outside of this statement (i.e., |
| | 199 | * the label is not contained within this statement), we must |
| | 200 | * generate the necessary code to leave the block; for example, a |
| | 201 | * 'try' block must generate a call to its 'finally' block. We must |
| | 202 | * then invoke this same function on our enclosing statement to let |
| | 203 | * it do the same work. |
| | 204 | */ |
| | 205 | void gen_code_unwind_for_goto(class CTPNStmGoto *goto_stm, |
| | 206 | class CTPNStmLabel *target); |
| | 207 | |
| | 208 | /* |
| | 209 | * Generate code for transferring control out of this statement. We |
| | 210 | * invoke this from gen_code_unwind_for_goto() when we determine |
| | 211 | * that the 'goto' target is not enclosed within this statement. By |
| | 212 | * default we do nothing; statements such as 'try' that must do work |
| | 213 | * on transferring control must override this to generate the |
| | 214 | * appropriate code. |
| | 215 | */ |
| | 216 | virtual void gen_code_for_transfer_out() { } |
| | 217 | |
| | 218 | /* |
| | 219 | * Check to see if we are allowed to transfer in to this block via |
| | 220 | * 'goto' statements. If so, simply return TRUE. If we don't allow |
| | 221 | * this type of transfer, we should log an appropriate error, then |
| | 222 | * return FALSE. Note that the function should both log an error |
| | 223 | * and return FALSE if the transfer isn't allowed; the return value |
| | 224 | * allows the caller to ensure that only one error is displayed for |
| | 225 | * this type of problem even if the target label is nested within |
| | 226 | * several levels of blocks that don't allow transfers in. |
| | 227 | * |
| | 228 | * By default, we'll simply return TRUE, since most block types |
| | 229 | * allow this type of transfer. |
| | 230 | */ |
| | 231 | virtual int check_enter_by_goto(class CTPNStmGoto * /*goto_stm*/, |
| | 232 | class CTPNStmLabel * /*target*/) |
| | 233 | { return TRUE; } |
| | 234 | |
| | 235 | protected: |
| | 236 | /* |
| | 237 | * generate code for a break - this can be used as a service routine |
| | 238 | * by loop/switch statements |
| | 239 | */ |
| | 240 | int gen_code_break_loop(CTcCodeLabel *code_label, |
| | 241 | const textchar_t *lbl, size_t lbl_len); |
| | 242 | |
| | 243 | /* |
| | 244 | * generate code for a continue - this can be used as a service |
| | 245 | * routine by loop/switch statements |
| | 246 | */ |
| | 247 | int gen_code_continue_loop(CTcCodeLabel *code_label, |
| | 248 | const textchar_t *lbl, size_t lbl_len); |
| | 249 | |
| | 250 | |
| | 251 | /* the block enclosing this block */ |
| | 252 | CTPNStmEnclosing *enclosing_; |
| | 253 | }; |
| | 254 | |
| | 255 | #endif /* TCT3INT_H */ |
| | 256 | |