-
Notifications
You must be signed in to change notification settings - Fork 1
/
tct3base.h
362 lines (327 loc) · 16.1 KB
/
tct3base.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
/* $Header: d:/cvsroot/tads/tads3/TCT3BASE.H,v 1.3 1999/07/11 00:46:57 MJRoberts Exp $ */
/*
* Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved.
*
* Please see the accompanying license file, LICENSE.TXT, for information
* on using and copying this software.
*/
/*
Name
tct3base.h - base parse node classes for T3 code generator
Function
Notes
Modified
05/10/99 MJRoberts - Creation
*/
#ifndef TCT3BASE_H
#define TCT3BASE_H
#include "tcprs.h"
/* include the target-independent base classes */
#include "tcpnbase.h"
/* ------------------------------------------------------------------------ */
/*
* Base parse node class
*/
class CTcPrsNode: public CTcPrsNodeBase
{
public:
/*
* Generate code to assign into the expression as an lvalue. By
* default, we'll throw an error; a default node should never be called
* upon to generate code as an assignment target, because the
* impossibility of this condition should be detected during parsing.
* Each class that overrides check_lvalue() to return true must
* override this to generate code for an assignment.
*
* 'typ' specifies the type of assignment - this specifies the
* assignment operator being generated.
*
* 'phase' indicates what part of the assignment we're generating. For
* a simple assignment, this routine will be called only once, with
* phase set to 1. For a compound assignment, this routine will be
* called twice. The first call is phase 1. This can do one of two
* things:
*
* - Generate the entire assignment code, and return TRUE to indicate
* that the assignment has been handled. The caller will generate no
* more code. This should be used when the particular combination of
* assignment type and lvalue can be specially optimized in the
* bytecode.
*
* - Generate code to evaluate the lvalue's value, and prepare the
* stack for eventual assignment to the lvalue, and return FALSE. The
* caller in this case will then generate generic code to combine the
* lvalue and rvalue. For example, with operator '+=', the caller will
* generate the ADD instruction to compute 'lvalue + rvalue'. The
* caller will finally call the routine again with phase set to 2.
*
* During phase 2, the routine must generate code to assign the rvalue
* at top of stack to the lvalue.
*
* Returns true if the assignment type was handled, false if not.
* Simple assignment must always be handled, but composite assignments
* (such as "+=" or "*=") can refused. If the assignment isn't
* handled, the caller must perform a generic calculation to compute
* the result of the assignment (for example, for "+=", the caller must
* generate code compute the sum of the right-hand side and the
* original value of the left-hand side), then call gen_code_asi()
* again to generate a simple assignment.
*
* In general, gen_code_asi() must generate code for complex
* assignments itself only when it can take advantage of special
* opcodes that would result in more efficient generated code. When no
* special opcodes are available for the assignment, there's no need
* for special coding here.
*
* If 'ignore_error' is true, this should not generate an error if this
* node is not a suitable lvalue, but should simply return false.
*
* 'explicit' is true if this is an explicit assignment by user code,
* false if it's an assignment generated automatically by the compiler.
* Implicit assignments don't count for the purposes of unused value
* warnings. These warnings are primarily to alert the user that they
* could delete an unnecessary assignment from their code, or
* conversely that they might have forgotten to do something with the
* value that the assignment would suggest they intended to do, but
* with a compiler-generated assignment there's nothing for the user to
* delete to fix the warning.
*
* 'ctx' is the address of a 'void *' variable (a generic pointer).
* This is for the callee's use during a two-phase compound operator
* assignment, for passing itself context information between the
* phases. On phase 1, the callee can allocate a structure and store
* it at *ctx. On phase 2, the callee can then look at this structure
* to retrieve information saved from the first phase. The callee is
* responsible for deleting the structure on the second phase. For
* single-phase TC_ASI_SIMPLE calls, the caller can simply pass a null
* pointer for ctx, so the callee must not attempt to store anything
* here during a simple assignment call.
*/
virtual int gen_code_asi(int discard, int phase,
tc_asitype_t typ, const char *op,
class CTcPrsNode *rhs,
int ignore_error, int xplicit, void **ctx);
/*
* Generate code to take the address of the expression. By default,
* we'll throw an internal error; a default node should never be
* called upon to generate code to take its address, because we
* shouldn't be able to parse such a thing. Each class that
* overrides has_addr() to return true must override this to
* generate address code.
*/
virtual void gen_code_addr();
/*
* Generate an if-then-else condition test. This is called on the
* controlling expression of an if-then-else, and can also be called on
* subexpressions of short-circuit operators (|| and &&). The purpose
* of this type of code generation is to avoid pushing the result of
* the controlling expression onto the stack when this can be avoided,
* and generate a jump to the appropriate if-else branch directly.
*
* Either then_label or else_label will be non-null; the one that's
* null directly follows the condition test, so we are simply to fall
* through to that code rather than jump to it explicitly.
*/
virtual void gen_code_cond(struct CTcCodeLabel *then_label,
struct CTcCodeLabel *else_label);
/*
* Generate code to call the expression as a function or method.
* The caller will already have generated code to push the argument
* list; this routine only needs to generate code to make the call.
*
* By default, we'll assume that the result of evaluating the
* expression is a method or function pointer, so we'll generate a
* call-indirect instruction to call the result of evaluating the
* expression.
*/
virtual void gen_code_call(int discard, int argc, int varargs,
struct CTcNamedArgs *named_args);
/*
* Generate code to apply operator 'new' to the expression. By
* default, 'new' cannot be applied to an expression; nodes that
* allow operator 'new' must override this.
*/
virtual void gen_code_new(int discard, int argc,
int varargs, struct CTcNamedArgs *named_args,
int from_call, int is_transient);
/*
* Generate code to evaluate a member expression on this object
* expression, calling the property expression given. By default,
* we'll evaluate our own expression to yield the object value, then
* get the property expression (either as a constant or by
* generating code to yield a property pointer), then we'll invoke
* that code. Nodes should override this where more specific
* instructions can be generated.
*
* If 'prop_is_expr' is true, the property expression (prop_expr) is
* a parenthesized expression; otherwise, it's a simple property
* symbol. (We need this information because a symbol enclosed in
* parentheses would be otherwise indistinguishable from a plain
* symbol, but the two syntax cases differ in their behavior: a
* plain symbol is always a property name, whereas a symbol in
* parentheses can be a local variable.)
*/
virtual void gen_code_member(int discard,
class CTcPrsNode *prop_expr,
int prop_is_expr,
int argc, int varargs,
struct CTcNamedArgs *named_args);
/*
* Generate code for an object on the left side of a '.' expression.
* If possible, return the constant object rather than generating
* code. If the expression refers to "self", set (*is_self) to true
* and return VM_INVALID_OBJ; otherwise, if the expression refers to
* a constant object reference, set (*is_self) to false and return
* the constant object value; otherwise, generate code for the
* expression, set (*is_self) to false, and return VM_INVALID_OBJ to
* indicate that the value must be obtained from the generated code
* at run-time.
*
* By default, we'll use generated code to get the value.
*/
virtual vm_obj_id_t gen_code_obj_predot(int *is_self)
{
/* generate the expression */
gen_code(FALSE, FALSE);
/* tell the caller that the value is not a compile-time constant */
*is_self = FALSE;
return VM_INVALID_OBJ;
}
/*
* generic generation for a member expression after the left side
* has been generated
*/
static void s_gen_member_rhs(int discard,
class CTcPrsNode *prop_expr,
int prop_is_expr,
int argc, int varargs,
struct CTcNamedArgs *named_args);
/*
* Get the property ID of this expression. If the property ID is
* available as a constant value, this doesn't generate any code and
* simply returns the constant property ID value. If this
* expression requires run-time evaluation, we'll generate code for
* the expression and return VM_INVALID_PROP to indicate that a
* constant property ID is not available.
*
* If 'check_only' is true, this routine should only check to see
* whether a constant property value is available and return the
* appropriate indication, but should not generate any code in any
* case. Errors should also be suppressed in this case, because the
* routine will always be called again to perform the actual
* generation, at which point any errors can be logged.
*
* If 'is_expr' is true, it means that this property was given as an
* expression by being explicitly enclosed in parentheses. If
* 'is_expr' is false, it means that the property was given as a
* simple symbol name. For cases where the property expression is a
* symbol, this distinction is important because we must resolve an
* unparenthesized symbol as a property name, even if it's hidden by
* a local variable.
*/
virtual vm_prop_id_t gen_code_propid(int check_only, int is_expr);
/*
* generate a jump-ahead instruction, returning a new label which
* serves as the jump destination
*/
static struct CTcCodeLabel *gen_jump_ahead(uchar opc);
/* define the position of a code label */
static void def_label_pos(struct CTcCodeLabel *lbl);
/* allocate a new label at the current write position */
static struct CTcCodeLabel *new_label_here();
};
/* ------------------------------------------------------------------------ */
/*
* Basic T3-specific symbol class
*/
class CTcSymbol: public CTcSymbolBase
{
public:
CTcSymbol(const char *str, size_t len, int copy, tc_symtype_t typ)
: CTcSymbolBase(str, len, copy, typ) { }
/*
* get the object value for the symbol, if the symbol has an object
* value; returns VM_INVALID_OBJ if the symbol is not an object
*/
virtual vm_obj_id_t get_val_obj() const { return VM_INVALID_OBJ; }
/* generate code to evaluate the symbol */
virtual void gen_code(int discard) = 0;
/*
* Generate code to assign to the symbol. By default, we'll generate
* an error indicating that the symbol cannot be assigned into. As
* with CTcPrsNode::gen_code_asi(), this returns true if the assignment
* was generated, false if the caller must generate a generic
* assignment; simple assignment must always return true.
*
* If 'rhs' is null, the caller has already generated the value to be
* assigned, so this code doesn't need to do that. Otherwise, this
* code must generate the rvalue code. The reason that 'rhs' is passed
* down at all is that we can sometimes optimize the type of opcode we
* generate according to the type of value being assigned, especially
* when a constant value is being assigned.
*
* If 'ignore_error' is true, this should not log an error if the value
* cannot be assigned.
*
* 'xplicit' is true if this is an explicit assignment by user code,
* false if it's an assignment generated automatically by the compiler.
* Implicit assignments don't count for the purposes of unused value
* warnings. These warnings are primarily to alert the user that they
* could delete an unnecessary assignment from their code, or
* conversely that they might have forgotten to do something with the
* value that the assignment would suggest they intended to do, but
* with a compiler-generated assignment there's nothing for the user to
* delete to fix the warning.
*/
virtual int gen_code_asi(int discard, int phase,
tc_asitype_t typ, const char *op,
class CTcPrsNode *rhs,
int ignore_error, int xplicit, void **ctx);
/*
* Generate code for taking the address of the symbol. By default,
* we'll generate an error indicating that the symbol's address
* cannot be taken.
*/
virtual void gen_code_addr();
/*
* Generate code to call the symbol. By default, we can't call a
* symbol.
*/
virtual void gen_code_call(int discard, int argc, int varargs,
struct CTcNamedArgs *named_args);
/*
* generate code for operator 'new' applied to the symbol, with the
* given number of arguments; by default, we can't generate any such
* code
*/
virtual void gen_code_new(int discard, int argc,
int varargs, struct CTcNamedArgs *named_args,
int is_transient);
/* evaluate a property ID */
virtual vm_prop_id_t gen_code_propid(int check_only, int is_expr);
/* generate code for a member expression */
virtual void gen_code_member(int discard,
class CTcPrsNode *prop_expr,
int prop_is_expr,
int argc, int varargs,
struct CTcNamedArgs *named_args);
/* get the object value for a '.' expression */
virtual vm_obj_id_t gen_code_obj_predot(int *is_self);
/*
* Write the symbol to a local frame debugging record in the code
* stream. Returns true if we wrote the symbol, false if not. By
* default, we'll write nothing and return false, since most symbols
* aren't used in local symbol tables.
*/
virtual int write_to_debug_frame(int test_only) { return FALSE; }
/*
* Write the symbol to the global symbol table in the debugging
* records in an image file. Returns true if we wrote the symbol,
* false if not. By default, we'll write nothing and return false,
* since by default symbols don't go in the image file's global
* symbol table.
*/
virtual int write_to_image_file_global(class CVmImageWriter *)
{ return FALSE; }
};
#endif /* TCT3BASE_H */