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