1 /* $Header: d:/cvsroot/tads/tads3/TCPNINT.H,v 1.3 1999/07/11 00:46:53 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 tcpnint.h - intermediate derived parse node classes 12 Function 13 14 Notes 15 16 Modified 17 05/12/99 MJRoberts - Creation 18 */ 19 20 #ifndef TCPNINT_H 21 #define TCPNINT_H 22 23 24 25 /* ------------------------------------------------------------------------ */ 26 /* 27 * Generic unary parse node. Most unary node types don't differ at the 28 * parser level, so target node types can be subclassed directly off of 29 * this generic unary node class. 30 */ 31 class CTPNUnaryBase: public CTcPrsNode 32 { 33 public: CTPNUnaryBase(class CTcPrsNode * sub)34 CTPNUnaryBase(class CTcPrsNode *sub) 35 { 36 sub_ = sub; 37 } 38 39 /* get the subexpression */ get_sub_expr()40 class CTcPrsNode *get_sub_expr() const { return sub_; } 41 42 /* fold constants */ fold_constants(class CTcPrsSymtab * symtab)43 class CTcPrsNode *fold_constants(class CTcPrsSymtab *symtab) 44 { 45 class CTcPrsNode *ret; 46 47 /* fold constants on my subexpression */ 48 sub_ = sub_->fold_constants(symtab); 49 50 /* try folding the unary operator */ 51 ret = fold_unop(); 52 53 /* 54 * if we folded the operator, return the result; otherwise, 55 * return the original operator tree for full code generation 56 */ 57 return (ret != 0 ? ret : this); 58 } 59 60 /* adjust for debugging */ adjust_for_debug(const tcpn_debug_info * info)61 class CTcPrsNode *adjust_for_debug(const tcpn_debug_info *info) 62 { 63 /* 64 * if this expression has side effects, don't allow it to be 65 * evaluated speculatively 66 */ 67 if (info->speculative && has_side_effects()) 68 err_throw(VMERR_BAD_SPEC_EVAL); 69 70 /* adjust my subexpression */ 71 sub_ = sub_->adjust_for_debug(info); 72 73 /* return myself otherwise unchanged */ 74 return this; 75 } 76 77 protected: 78 /* fold constants for the operator */ fold_unop()79 virtual class CTcPrsNode *fold_unop() { return 0; } 80 81 /* determine if I have side effects */ has_side_effects()82 virtual int has_side_effects() const { return FALSE; } 83 84 /* our subexpression */ 85 class CTcPrsNode *sub_; 86 }; 87 88 /* 89 * Define a constructor for a CTPNUnary target subclass. Target 90 * subclasses can use this macro to define the standard CTPNUnary 91 * subclass constructor - this is simply for conciseness in those 92 * subclasses. 93 */ 94 #define CTPNUnary_ctor(scname) \ 95 scname(class CTcPrsNode *sub) \ 96 : CTPNUnary(sub) { } 97 98 99 /* 100 * define a CTPNUnary target subclass 101 */ 102 #define CTPNUnary_def(scname) \ 103 class scname: public CTPNUnary \ 104 { \ 105 public: \ 106 CTPNUnary_ctor(scname); \ 107 void gen_code(int discard, int for_condition); \ 108 }; 109 110 /* 111 * define a CTPNUnary target subclass for a unary operator with side 112 * effects 113 */ 114 #define CTPNUnary_side_def(scname) \ 115 class scname: public CTPNUnary \ 116 { \ 117 public: \ 118 CTPNUnary_ctor(scname); \ 119 void gen_code(int discard, int for_condition); \ 120 virtual int has_side_effects() const { return TRUE; } \ 121 }; 122 123 124 125 /* ------------------------------------------------------------------------ */ 126 /* 127 * Generic binary parse node. Most binary node types don't differ at 128 * the parser level, so target node types can be subclassed directly off 129 * of this generic binary node class. 130 */ 131 class CTPNBinBase: public CTcPrsNode 132 { 133 public: CTPNBinBase(class CTcPrsNode * left,class CTcPrsNode * right)134 CTPNBinBase(class CTcPrsNode *left, class CTcPrsNode *right) 135 { 136 left_ = left; 137 right_ = right; 138 } 139 140 /* fold constants */ fold_constants(class CTcPrsSymtab * symtab)141 class CTcPrsNode *fold_constants(class CTcPrsSymtab *symtab) 142 { 143 CTcPrsNode *ret; 144 145 /* fold constants on my subexpressions */ 146 left_ = left_->fold_constants(symtab); 147 right_ = right_->fold_constants(symtab); 148 149 /* try folding this operator, if we can */ 150 ret = fold_binop(); 151 152 /* 153 * if we got a folded value, return it; otherwise, return 154 * myself, unchanged except any subnode folding we did 155 */ 156 return (ret != 0 ? ret : this); 157 } 158 159 /* adjust for debugging */ adjust_for_debug(const tcpn_debug_info * info)160 class CTcPrsNode *adjust_for_debug(const tcpn_debug_info *info) 161 { 162 /* if I have side effects, don't allow speculative evaluation */ 163 if (info->speculative && has_side_effects()) 164 err_throw(VMERR_BAD_SPEC_EVAL); 165 166 /* adjust the left and right subexpressions */ 167 left_ = left_->adjust_for_debug(info); 168 right_ = right_->adjust_for_debug(info); 169 170 /* return myself otherwise unchanged */ 171 return this; 172 } 173 174 protected: 175 /* perform folding on this binary operator, if possible */ fold_binop()176 virtual class CTcPrsNode *fold_binop() { return 0; } 177 178 /* determine if I have side effects */ has_side_effects()179 virtual int has_side_effects() const { return FALSE; } 180 181 /* left and right operands */ 182 class CTcPrsNode *left_; 183 class CTcPrsNode *right_; 184 }; 185 186 /* 187 * Define a constructor for a CTPNBin target subclass. Target 188 * subclasses can use this macro to define the standard CTPNBin subclass 189 * constructor - this is simply for conciseness in those subclasses. 190 */ 191 #define CTPNBin_ctor(scname) \ 192 scname(class CTcPrsNode *left, class CTcPrsNode *right) \ 193 : CTPNBin(left, right) { } 194 195 /* 196 * Define a full general class interface for a CTPNBin target subclass. 197 * Most target subclasses will not need to add anything of their own, so 198 * they can use this generic class definition macro. 199 */ 200 #define CTPNBin_def(scname) \ 201 class scname: public CTPNBin \ 202 { \ 203 public: \ 204 CTPNBin_ctor(scname); \ 205 void gen_code(int discard, int for_condition); \ 206 }; 207 208 /* 209 * define a CTPNBin target subclass for a binary operator with side 210 * effects 211 */ 212 #define CTPNBin_side_def(scname) \ 213 class scname: public CTPNBin \ 214 { \ 215 public: \ 216 CTPNBin_ctor(scname); \ 217 void gen_code(int discard, int for_condition); \ 218 virtual int has_side_effects() const { return TRUE; } \ 219 }; 220 221 /* ------------------------------------------------------------------------ */ 222 /* 223 * Generic statement node base. 224 */ 225 class CTPNStmBase: public CTcPrsNode 226 { 227 public: 228 /* initialize at the tokenizer's current source file position */ 229 CTPNStmBase(); 230 231 /* initialize at the given source position */ CTPNStmBase(class CTcTokFileDesc * file,long linenum)232 CTPNStmBase(class CTcTokFileDesc *file, long linenum) 233 { 234 init(file, linenum); 235 } 236 237 /* set the file and line number */ set_source_pos(class CTcTokFileDesc * file,long linenum)238 void set_source_pos(class CTcTokFileDesc *file, long linenum) 239 { 240 /* remember the new line information */ 241 file_ = file; 242 linenum_ = linenum; 243 } 244 245 /* get the next statement after this one */ get_next_stm()246 class CTPNStm *get_next_stm() const { return next_stm_; } 247 248 /* set the next statement after this one */ set_next_stm(class CTPNStm * nxt)249 void set_next_stm(class CTPNStm *nxt) { next_stm_ = nxt; } 250 251 /* 252 * log an error, using the source file location of this statement as 253 * the location of the error 254 */ 255 void log_error(int errnum, ...) const; 256 257 /* 258 * log a warning, using the source file location of this statement 259 * as the location of the warning 260 */ 261 void log_warning(int errnum, ...) const; 262 263 /* get my source location information */ get_source_desc()264 class CTcTokFileDesc *get_source_desc() const { return file_; } get_source_linenum()265 long get_source_linenum() const { return linenum_; } 266 267 /* 268 * Get the ending source location - for most statements, this is 269 * identical to the normal source location information. For certain 270 * complex statements, such as compound statements, this will 271 * provide the source location where the statement's structure ends. 272 */ get_end_desc()273 virtual class CTcTokFileDesc *get_end_desc() const { return file_; } get_end_linenum()274 virtual long get_end_linenum() const { return linenum_; } 275 276 /* 277 * Determine the possible control flow routes through this 278 * statement. Set or clear each flag as appropriate. 279 * 280 *. TCPRS_FLOW_NEXT - flow continues to the next statement 281 *. TCPRS_FLOW_THROW - statement throws an exception 282 *. TCPRS_FLOW_RET_VOID - statement returns no value 283 *. TCPRS_FLOW_RET_VAL - statement returns a value 284 *. TCPRS_FLOW_GOTO - control transfers to a code label 285 *. TCPRS_FLOW_BREAK - control breaks out of the current loop/case 286 *. TCPRS_FLOW_CONT - control goes to the top of the current loop 287 * 288 * Most statements simply proceed to the next statement in all 289 * cases, so the default implementation simply sets the 'cont' flag 290 * and clears the others. 291 * 292 * This routine is not meant to evaluate dependencies on called 293 * functions or methods. Functions and methods that are called can 294 * be assumed to return, with or without a value as needed for the 295 * usage here. The possibility of VM exceptions due to run-time 296 * error conditions can be ignored; we're only interested in 297 * statements that explicitly throw exceptions. 298 */ 299 300 #define TCPRS_FLOW_NEXT 0x00000001 301 #define TCPRS_FLOW_THROW 0x00000002 302 #define TCPRS_FLOW_RET_VOID 0x00000004 303 #define TCPRS_FLOW_RET_VAL 0x00000008 304 #define TCPRS_FLOW_GOTO 0x00000010 305 #define TCPRS_FLOW_BREAK 0x00000020 306 #define TCPRS_FLOW_CONT 0x00000040 307 get_control_flow()308 virtual unsigned long get_control_flow() const 309 { 310 /* by default, a statement continues to the next statement */ 311 return TCPRS_FLOW_NEXT; 312 } 313 314 /* 315 * Determine if this statement has a code label. By default, we 316 * return false. 317 */ has_code_label()318 virtual int has_code_label() const { return FALSE; } 319 320 /* a statement has no return value */ has_return_value()321 virtual int has_return_value() const { return FALSE; } 322 323 /* add a debugging line record for this statement */ 324 void add_debug_line_rec(); 325 326 protected: 327 /* 328 * Generate code for a sub-statement (such as the 'then' part of an 329 * 'if', or a statement in a compount statement). This sets up the 330 * error reporting location to refer to the sub-statement, then 331 * generates code for the sub-statement normally. 332 */ 333 void gen_code_substm(class CTPNStm *substm); 334 335 /* add a debugging line record at the given position */ 336 void add_debug_line_rec(class CTcTokFileDesc *desc, long linenum); 337 338 /* initialize */ init(class CTcTokFileDesc * file,long linenum)339 void init(class CTcTokFileDesc *file, long linenum) 340 { 341 /* remember the file and line number containing the code */ 342 file_ = file; 343 linenum_ = linenum; 344 345 /* there's not another statement after this one yet */ 346 next_stm_ = 0; 347 } 348 349 /* next statement in execution order */ 350 class CTPNStm *next_stm_; 351 352 /* file and line number where this statement's source code appears */ 353 class CTcTokFileDesc *file_; 354 long linenum_; 355 }; 356 357 358 /* ------------------------------------------------------------------------ */ 359 /* 360 * Enclosing Statement Block object. This is a base class for 361 * statements such as "try" blocks and code labels for which we must 362 * keep a nesting list. A statement of this class has special needs for 363 * exiting, via break, continue, goto, or return, the block of code that 364 * the statement encloses 365 * 366 * NOTE: To avoid having to introduce yet another level of intermediate 367 * #include file in our target-generic/target-specific layering, we 368 * require that the target-specific intermediate include file define the 369 * base class CTPNStmEnclosing for us. It must be defined as below, 370 * with the addition of the target-specific definitions. Sorry about 371 * any confusion this causes, but inserting a fourth include layer is 372 * just going too far. 373 */ 374 // class CTPNStmEnclosing: public CTPNStm 375 // { 376 // public: 377 // CTPNStmEnclosing(CTPNStmEnclosing *enclosing) 378 // { 379 // /* remember the statement that encloses me */ 380 // enclosing_ = enclosing; 381 // } 382 // 383 // protected: 384 // /* the block enclosing this block */ 385 // CTPNStmEnclosing *enclosing_; 386 // }; 387 388 389 #endif /* TCPNINT_H */ 390 391