cfad47cfa3/t3compiler/tads3/tct3int.h

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
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