~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

« back to all changes in this revision

Viewing changes to tads/tads3/tcprs.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Sylvain Beucler
  • Date: 2009-09-11 20:09:43 UTC
  • Revision ID: james.westby@ubuntu.com-20090911200943-idgzoyupq6650zpn
Tags: upstream-2009-08-25
ImportĀ upstreamĀ versionĀ 2009-08-25

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifdef RCSID
 
2
static char RCSid[] =
 
3
"$Header: d:/cvsroot/tads/tads3/TCPRS.CPP,v 1.5 1999/07/11 00:46:53 MJRoberts Exp $";
 
4
#endif
 
5
 
 
6
/* 
 
7
 *   Copyright (c) 1999, 2002 Michael J. Roberts.  All Rights Reserved.
 
8
 *   
 
9
 *   Please see the accompanying license file, LICENSE.TXT, for information
 
10
 *   on using and copying this software.  
 
11
 */
 
12
/*
 
13
Name
 
14
  tcprs.cpp - TADS 3 Compiler Parser
 
15
Function
 
16
  This parser module contains code required for any parser usage, both
 
17
  for a full compiler and for a debugger.
 
18
Notes
 
19
  
 
20
Modified
 
21
  04/30/99 MJRoberts  - Creation
 
22
*/
 
23
 
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
#include <stdio.h>
 
27
#include <assert.h>
 
28
 
 
29
#include "os.h"
 
30
#include "t3std.h"
 
31
#include "tcprs.h"
 
32
#include "tctarg.h"
 
33
#include "tcgen.h"
 
34
#include "vmhash.h"
 
35
#include "tcmain.h"
 
36
#include "vmfile.h"
 
37
#include "tctok.h"
 
38
 
 
39
 
 
40
/* ------------------------------------------------------------------------ */
 
41
/*
 
42
 *   Expression Operator parser objects.  These objects are linked
 
43
 *   together in a network that defines the order of precedence for
 
44
 *   expression operators.
 
45
 *   
 
46
 *   These objects use static storage.  This is acceptable, even though
 
47
 *   these objects aren't all "const" qualified, because the compiler uses
 
48
 *   a single global parser object; since there's only the one parser,
 
49
 *   there only needs to be a single network of these objects.  
 
50
 */
 
51
 
 
52
/* unary operator parser */
 
53
static CTcPrsOpUnary S_op_unary;
 
54
 
 
55
/* factor group */
 
56
static const CTcPrsOpMul S_op_mul;
 
57
static const CTcPrsOpDiv S_op_div;
 
58
static const CTcPrsOpMod S_op_mod;
 
59
static const CTcPrsOpBin *const
 
60
   S_grp_factor[] = { &S_op_mul, &S_op_div, &S_op_mod, 0 };
 
61
static const CTcPrsOpBinGroup S_op_factor(&S_op_unary, &S_op_unary,
 
62
                                          S_grp_factor);
 
63
 
 
64
/* term group */
 
65
static const CTcPrsOpAdd S_op_add;
 
66
static const CTcPrsOpSub S_op_sub;
 
67
static const CTcPrsOpBin *const S_grp_term[] = { &S_op_add, &S_op_sub, 0 };
 
68
static const CTcPrsOpBinGroup S_op_term(&S_op_factor, &S_op_factor,
 
69
                                        S_grp_term);
 
70
 
 
71
/* shift group */
 
72
static const CTcPrsOpShl S_op_shl;
 
73
static const CTcPrsOpShr S_op_shr;
 
74
static const CTcPrsOpBin *const S_grp_shift[] = { &S_op_shl, &S_op_shr, 0 };
 
75
static const CTcPrsOpBinGroup S_op_shift(&S_op_term, &S_op_term,
 
76
                                         S_grp_shift);
 
77
 
 
78
/* magnitude comparisons group */
 
79
static const CTcPrsOpGt S_op_gt;
 
80
static const CTcPrsOpGe S_op_ge;
 
81
static const CTcPrsOpLt S_op_lt;
 
82
static const CTcPrsOpLe S_op_le;
 
83
static const CTcPrsOpBin *const
 
84
   S_grp_relcomp[] = { &S_op_gt, &S_op_ge, &S_op_lt, &S_op_le, 0 };
 
85
static const CTcPrsOpBinGroup S_op_relcomp(&S_op_shift, &S_op_shift,
 
86
                                           S_grp_relcomp);
 
87
 
 
88
/* 
 
89
 *   Equality/inequality comparison group.  Note that the equality operator
 
90
 *   is non-const because we want the option to change the operator on the
 
91
 *   fly based on syntax mode - '==' in C-mode, '=' in TADS traditional mode.
 
92
 *   (This was a feature of tads 2, but we have since deprecated it in tads
 
93
 *   3, so this ability is actually just vestigial at this point.  No harm in
 
94
 *   keeping around the code internally for it, though, since it's pretty
 
95
 *   simple.)
 
96
 *   
 
97
 *   Note also that this is a special binary group - this one recognizes the
 
98
 *   non-keyword operators 'is in' and 'not in'.  
 
99
 */
 
100
static CTcPrsOpEq S_op_eq;
 
101
static const CTcPrsOpNe S_op_ne;
 
102
static const CTcPrsOpBin *const
 
103
   S_grp_eqcomp[] = { &S_op_eq, &S_op_ne, 0 };
 
104
static const CTcPrsOpBinGroupCompare
 
105
   S_op_eqcomp(&S_op_relcomp, &S_op_relcomp, S_grp_eqcomp);
 
106
 
 
107
/* bitwise AND operator */
 
108
static const CTcPrsOpBAnd S_op_band(&S_op_eqcomp, &S_op_eqcomp);
 
109
 
 
110
/* bitwise XOR operator */
 
111
static const CTcPrsOpBXor S_op_bxor(&S_op_band, &S_op_band);
 
112
 
 
113
/* bitwise OR operator */
 
114
static const CTcPrsOpBOr S_op_bor(&S_op_bxor, &S_op_bxor);
 
115
 
 
116
/* logical AND operator */
 
117
static const CTcPrsOpAnd S_op_and(&S_op_bor, &S_op_bor);
 
118
 
 
119
/* logical OR operator */
 
120
static const CTcPrsOpOr S_op_or(&S_op_and, &S_op_and);
 
121
 
 
122
/* conditional operator */
 
123
static const CTcPrsOpIf S_op_if;
 
124
 
 
125
/* 
 
126
 *   assignment operator - note that this is non-const, because we must be
 
127
 *   able to change the operator - '=' in C-mode, and ':=' in TADS
 
128
 *   traditional mode 
 
129
 */
 
130
static CTcPrsOpAsi S_op_asi;
 
131
 
 
132
/* comma operator */
 
133
static const CTcPrsOpComma S_op_comma(&S_op_asi, &S_op_asi);
 
134
 
 
135
 
 
136
/* ------------------------------------------------------------------------ */
 
137
/*
 
138
 *   Main Parser 
 
139
 */
 
140
 
 
141
/*
 
142
 *   initialize the parser 
 
143
 */
 
144
CTcParser::CTcParser()
 
145
{
 
146
    size_t i;
 
147
    
 
148
    /* we don't have any module information yet */
 
149
    module_name_ = 0;
 
150
    module_seqno_ = 0;
 
151
 
 
152
    /* start out in normal mode */
 
153
    pp_expr_mode_ = FALSE;
 
154
    src_group_mode_ = FALSE;
 
155
 
 
156
    /* create the global symbol table */
 
157
    global_symtab_ = new CTcPrsSymtab(0);
 
158
 
 
159
    /* no enclosing statement yet */
 
160
    enclosing_stm_ = 0;
 
161
 
 
162
    /* no source location yet */
 
163
    cur_desc_ = 0;
 
164
    cur_linenum_ = 0;
 
165
 
 
166
    /* no dictionaries yet */
 
167
    dict_cur_ = 0;
 
168
    dict_head_ = dict_tail_ = 0;
 
169
 
 
170
    /* no object file dictionary list yet */
 
171
    obj_dict_list_ = 0;
 
172
    obj_file_dict_idx_ = 0;
 
173
 
 
174
    /* no dictionary properties yet */
 
175
    dict_prop_head_ = 0;
 
176
 
 
177
    /* no grammar productions yet */
 
178
    gramprod_head_ = gramprod_tail_ = 0;
 
179
 
 
180
    /* no object file symbol list yet */
 
181
    obj_sym_list_ = 0;
 
182
    obj_file_sym_idx_ = 0;
 
183
 
 
184
    /* no object templates yet */
 
185
    template_head_ = template_tail_ = 0;
 
186
 
 
187
    /* allocate some initial template parsing space */
 
188
    template_expr_max_ = 16;
 
189
    template_expr_ = (CTcObjTemplateInst *)G_prsmem->
 
190
                     alloc(sizeof(template_expr_[0]) * template_expr_max_);
 
191
 
 
192
    /* no locals yet */
 
193
    local_cnt_ = max_local_cnt_ = 0;
 
194
 
 
195
    /* no local or goto symbol table yet */
 
196
    local_symtab_ = 0;
 
197
    enclosing_local_symtab_ = 0;
 
198
    goto_symtab_ = 0;
 
199
 
 
200
    /* no debugger local symbol table yet */
 
201
    debug_symtab_ = 0;
 
202
 
 
203
    /* not in a preprocessor constant expression */
 
204
    pp_expr_mode_ = FALSE;
 
205
 
 
206
    /* assume we're doing full compilation */
 
207
    syntax_only_ = FALSE;
 
208
 
 
209
    /* no nested top-level statements yet */
 
210
    nested_stm_head_ = 0;
 
211
    nested_stm_tail_ = 0;
 
212
 
 
213
    /* no anonymous objects yet */
 
214
    anon_obj_head_ = 0;
 
215
    anon_obj_tail_ = 0;
 
216
 
 
217
    /* no non-symbol objects yet */
 
218
    nonsym_obj_head_ = 0;
 
219
    nonsym_obj_tail_ = 0;
 
220
 
 
221
    /* allocate an initial context variable property array */
 
222
    ctx_var_props_size_ = 50;
 
223
    ctx_var_props_ = (tctarg_prop_id_t *)
 
224
                     t3malloc(ctx_var_props_size_ * sizeof(tctarg_prop_id_t));
 
225
 
 
226
    /* no context variable properties assigned yet */
 
227
    ctx_var_props_cnt_ = 0;
 
228
    ctx_var_props_used_ = 0;
 
229
 
 
230
    /* 
 
231
     *   no context variable indices assigned yet - start at one higher
 
232
     *   than the index at which we always store 'self' 
 
233
     */
 
234
    next_ctx_arr_idx_ = TCPRS_LOCAL_CTX_METHODCTX + 1;
 
235
 
 
236
    /* 'self' isn't valid yet */
 
237
    self_valid_ = FALSE;
 
238
 
 
239
    /* start at enum ID 1 (let 0 serve as an invalid value) */
 
240
    next_enum_id_ = 1;
 
241
 
 
242
    /* the '+' property is not yet defined */
 
243
    plus_prop_ = 0;
 
244
 
 
245
    /* no exported symbols yet */
 
246
    exp_head_ = exp_tail_ = 0;
 
247
 
 
248
    /* allocate an initial '+' stack */
 
249
    plus_stack_alloc_ = 32;
 
250
    plus_stack_ = (CTPNStmObject **)
 
251
                  t3malloc(plus_stack_alloc_ * sizeof(*plus_stack_));
 
252
 
 
253
    /* clear out the stack */
 
254
    for (i = 0 ; i < plus_stack_alloc_ ; ++i)
 
255
        plus_stack_[i] = 0;
 
256
 
 
257
    /* there's no current code body (function/method body) yet */
 
258
    cur_code_body_ = 0;
 
259
 
 
260
    /* nothing in the local context has been referenced yet */
 
261
    self_referenced_ = FALSE;
 
262
    local_ctx_needs_self_ = FALSE;
 
263
    full_method_ctx_referenced_ = FALSE;
 
264
    local_ctx_needs_full_method_ctx_ = FALSE;
 
265
}
 
266
 
 
267
/*
 
268
 *   Initialize.  This must be called after the code generator is set up.  
 
269
 */
 
270
void CTcParser::init()
 
271
{
 
272
    static const char construct_name[] = "construct";
 
273
    static const char finalize_name[] = "finalize";
 
274
    static const char objcall_name[] = ".objcall";
 
275
    static const char graminfo_name[] = "grammarInfo";
 
276
    static const char miscvocab_name[] = "miscVocab";
 
277
    static const char lexical_parent_name[] = "lexicalParent";
 
278
    static const char src_order_name[] = "sourceTextOrder";
 
279
    static const char src_group_name[] = "sourceTextGroup";
 
280
    static const char src_group_mod_name[] = "sourceTextGroupName";
 
281
    static const char src_group_seq_name[] = "sourceTextGroupOrder";
 
282
    tctarg_prop_id_t graminfo_prop_id;
 
283
    tctarg_prop_id_t lexpar_prop_id;
 
284
    tctarg_prop_id_t src_order_prop_id;
 
285
    tctarg_prop_id_t src_group_prop_id;
 
286
    tctarg_prop_id_t src_group_mod_prop_id;
 
287
    tctarg_prop_id_t src_group_seq_prop_id;
 
288
    CTcSymProp *sym;
 
289
 
 
290
    /* allocate and note our special property ID's */
 
291
    constructor_prop_ = G_cg->new_prop_id();
 
292
    finalize_prop_ = G_cg->new_prop_id();
 
293
    objcall_prop_ = G_cg->new_prop_id();
 
294
    graminfo_prop_id = G_cg->new_prop_id();
 
295
    miscvocab_prop_ = G_cg->new_prop_id();
 
296
    lexpar_prop_id = G_cg->new_prop_id();
 
297
    src_order_prop_id = G_cg->new_prop_id();
 
298
    src_group_prop_id = G_cg->new_prop_id();
 
299
    src_group_mod_prop_id = G_cg->new_prop_id();
 
300
    src_group_seq_prop_id = G_cg->new_prop_id();
 
301
 
 
302
    /* add a "construct" property for constructors */
 
303
    sym = new CTcSymProp(construct_name, sizeof(construct_name) - 1,
 
304
                         FALSE, (tctarg_prop_id_t)constructor_prop_);
 
305
    sym->mark_referenced();
 
306
    global_symtab_->add_entry(sym);
 
307
    constructor_sym_ = sym;
 
308
 
 
309
    /* add a "finalize" property for finalizers */
 
310
    sym = new CTcSymProp(finalize_name, sizeof(finalize_name) - 1,
 
311
                         FALSE, (tctarg_prop_id_t)finalize_prop_);
 
312
    sym->mark_referenced();
 
313
    global_symtab_->add_entry(sym);
 
314
 
 
315
    /* add an "object call" property for anonymous functions */
 
316
    sym = new CTcSymProp(objcall_name, sizeof(objcall_name) - 1,
 
317
                         FALSE, (tctarg_prop_id_t)objcall_prop_);
 
318
    sym->mark_referenced();
 
319
    global_symtab_->add_entry(sym);
 
320
 
 
321
    /* add a "grammarInfo" property for grammar production match objects */
 
322
    graminfo_prop_ = new CTcSymProp(graminfo_name, sizeof(graminfo_name) - 1,
 
323
                                    FALSE,
 
324
                                    (tctarg_prop_id_t)graminfo_prop_id);
 
325
    graminfo_prop_->mark_referenced();
 
326
    global_symtab_->add_entry(graminfo_prop_);
 
327
 
 
328
    /* add a "miscVocab" property for miscellaneous vocabulary words */
 
329
    sym = new CTcSymProp(miscvocab_name, sizeof(miscvocab_name) - 1,
 
330
                         FALSE, miscvocab_prop_);
 
331
    sym->mark_referenced();
 
332
    global_symtab_->add_entry(sym);
 
333
 
 
334
    /* add a "lexicalParent" property for a nested object's parent */
 
335
    lexical_parent_sym_ = new CTcSymProp(lexical_parent_name,
 
336
                                         sizeof(lexical_parent_name) - 1,
 
337
                                         FALSE,
 
338
                                         (tctarg_prop_id_t)lexpar_prop_id);
 
339
    lexical_parent_sym_->mark_referenced();
 
340
    global_symtab_->add_entry(lexical_parent_sym_);
 
341
 
 
342
    /* add a "sourceTextOrder" property */
 
343
    src_order_sym_ = new CTcSymProp(src_order_name,
 
344
                                    sizeof(src_order_name) - 1,
 
345
                                    FALSE,
 
346
                                    (tctarg_prop_id_t)src_order_prop_id);
 
347
    src_order_sym_->mark_referenced();
 
348
    global_symtab_->add_entry(src_order_sym_);
 
349
 
 
350
    /* start the sourceTextOrder index at 1 */
 
351
    src_order_idx_ = 1;
 
352
 
 
353
    /* add a "sourceTextGroup" property */
 
354
    src_group_sym_ = new CTcSymProp(src_group_name,
 
355
                                    sizeof(src_group_name) - 1,
 
356
                                    FALSE,
 
357
                                    (tctarg_prop_id_t)src_group_prop_id);
 
358
    src_group_sym_->mark_referenced();
 
359
    global_symtab_->add_entry(src_group_sym_);
 
360
 
 
361
    /* we haven't created the sourceTextGroup referral object yet */
 
362
    src_group_id_ = TCTARG_INVALID_OBJ;
 
363
 
 
364
    /* add a "sourceTextGroupName" property */
 
365
    src_group_mod_sym_ = new CTcSymProp(
 
366
        src_group_mod_name, sizeof(src_group_mod_name) - 1, FALSE,
 
367
        (tctarg_prop_id_t)src_group_mod_prop_id);
 
368
    src_group_mod_sym_->mark_referenced();
 
369
    global_symtab_->add_entry(src_group_mod_sym_);
 
370
 
 
371
    /* add a "sourceTextGroupOrder" property */
 
372
    src_group_seq_sym_ = new CTcSymProp(
 
373
        src_group_seq_name, sizeof(src_group_seq_name) - 1, FALSE,
 
374
        (tctarg_prop_id_t)src_group_seq_prop_id);
 
375
    src_group_seq_sym_->mark_referenced();
 
376
    global_symtab_->add_entry(src_group_seq_sym_);
 
377
}
 
378
 
 
379
 
 
380
/*
 
381
 *   destroy the parser
 
382
 */
 
383
CTcParser::~CTcParser()
 
384
{
 
385
    /*
 
386
     *   Note that we don't have to delete certain objects, because we
 
387
     *   allocated them out of the parser memory pool and will be
 
388
     *   automatically deleted when the pool is deleted.  For example, we
 
389
     *   don't have to delete any symbol tables, including the global
 
390
     *   symbol table.  
 
391
     */
 
392
 
 
393
    /* delete the module name, if it's known */
 
394
    lib_free_str(module_name_);
 
395
 
 
396
    /* delete the object file symbol fixup list, if present */
 
397
    if (obj_sym_list_ != 0)
 
398
        t3free(obj_sym_list_);
 
399
 
 
400
    /* delete the object file dictionary fixup list, if present */
 
401
    if (obj_dict_list_ != 0)
 
402
        t3free(obj_dict_list_);
 
403
 
 
404
    /* delete the context variable property list */
 
405
    if (ctx_var_props_ != 0)
 
406
        t3free(ctx_var_props_);
 
407
 
 
408
    /* delete the export list */
 
409
    while (exp_head_ != 0)
 
410
    {
 
411
        CTcPrsExport *nxt;
 
412
        
 
413
        /* remember the next entry, since we're deleting our pointer to it */
 
414
        nxt = exp_head_->get_next();
 
415
        
 
416
        /* delete this entry */
 
417
        delete exp_head_;
 
418
 
 
419
        /* move on to the next */
 
420
        exp_head_ = nxt;
 
421
    }
 
422
 
 
423
    /* delete the '+' stack */
 
424
    t3free(plus_stack_);
 
425
}
 
426
 
 
427
/* ------------------------------------------------------------------------ */
 
428
/*
 
429
 *   Set the module information 
 
430
 */
 
431
void CTcParser::set_module_info(const char *name, int seqno)
 
432
{
 
433
    /* if we have a name stored already, delete the old one */
 
434
    lib_free_str(module_name_);
 
435
 
 
436
    /* store the new name and sequence number */
 
437
    module_name_ = lib_copy_str(name);
 
438
    module_seqno_ = seqno;
 
439
}
 
440
 
 
441
/*
 
442
 *   Change the #pragma C mode.  On changing this mode, we'll change the
 
443
 *   assignment operator and equality operator tokens.  If 'mode' is true,
 
444
 *   we're in C mode; otherwise, we're in traditional TADS mode.
 
445
 *   
 
446
 *   #pragma C+: assignment is '=', equality is '=='
 
447
 *.  #pragma C-: assignment is ':=', equality is '='.  
 
448
 */
 
449
void CTcParser::set_pragma_c(int mode)
 
450
{
 
451
    /* set the assignment operator */
 
452
    S_op_asi.set_asi_op(mode ? TOKT_EQ : TOKT_ASI);
 
453
 
 
454
    /* set the equality comparison operator */
 
455
    S_op_eq.set_eq_op(mode ? TOKT_EQEQ : TOKT_EQ);
 
456
}
 
457
 
 
458
/*
 
459
 *   Parse an expression.  This parses a top-level comma expression.
 
460
 */
 
461
CTcPrsNode *CTcParser::parse_expr()
 
462
{
 
463
    /* parse a comma expression */
 
464
    return S_op_comma.parse();
 
465
}
 
466
 
 
467
/*
 
468
 *   Parse a condition expression.  Warns if the outermost operator is a
 
469
 *   simple assignment.  
 
470
 */
 
471
CTcPrsNode *CTcParser::parse_cond_expr()
 
472
{
 
473
    CTcPrsNode *cond;
 
474
 
 
475
    /* parse the expression */
 
476
    cond = parse_expr();
 
477
 
 
478
    /* 
 
479
     *   if the outermost operator is a simple assignment, display an
 
480
     *   error 
 
481
     */
 
482
    if (cond != 0 && cond->is_simple_asi() && !G_prs->get_syntax_only())
 
483
        G_tok->log_warning(TCERR_ASI_IN_COND);
 
484
 
 
485
    /* return the result */
 
486
    return cond;
 
487
}
 
488
 
 
489
/*
 
490
 *   Parse an assignment expression.  
 
491
 */
 
492
CTcPrsNode *CTcParser::parse_asi_expr()
 
493
{
 
494
    /* parse an assignment expression */
 
495
    return S_op_asi.parse();
 
496
}
 
497
 
 
498
/*
 
499
 *   Parse an expression or a double-quoted string expression 
 
500
 */
 
501
CTcPrsNode *CTcParser::parse_expr_or_dstr(int allow_comma_expr)
 
502
{
 
503
    /* 
 
504
     *   parse the appropriate kind of expression - if a comma expression is
 
505
     *   allowed, parse that, otherwise parse an assignment expression (as
 
506
     *   that's the next thing down the hierarchy from the comma operator) 
 
507
     */
 
508
    return (allow_comma_expr ? S_op_comma.parse() : S_op_asi.parse());
 
509
}
 
510
 
 
511
/*
 
512
 *   Parse a required semicolon 
 
513
 */
 
514
int CTcParser::parse_req_sem()
 
515
{
 
516
    const char eof_str[] = "<end of file>";
 
517
    
 
518
    /* check to see if we found the semicolon */
 
519
    if (G_tok->cur() == TOKT_SEM)
 
520
    {
 
521
        /* success - skip the semicolon and tell the caller to proceed */
 
522
        G_tok->next();
 
523
        return 0;
 
524
    }
 
525
 
 
526
    /* 
 
527
     *   check what we have; the type of error we want to log depends on
 
528
     *   what we find next 
 
529
     */
 
530
    switch(G_tok->cur())
 
531
    {
 
532
    case TOKT_RPAR:
 
533
        /* log the extra ')' error */
 
534
        G_tok->log_error(TCERR_EXTRA_RPAR);
 
535
 
 
536
        /* 
 
537
         *   we're probably in an expression that ended before the user
 
538
         *   thought it should; skip the extraneous material up to the
 
539
         *   next semicolon 
 
540
         */
 
541
        return skip_to_sem();
 
542
        
 
543
    case TOKT_RBRACK:
 
544
        /* log the error */
 
545
        G_tok->log_error(TCERR_EXTRA_RBRACK);
 
546
 
 
547
        /* skip up to the next semicolon */
 
548
        return skip_to_sem();
 
549
 
 
550
    case TOKT_EOF:
 
551
        /* 
 
552
         *   missing semicolon at end of file - log the missing-semicolon
 
553
         *   error and tell the caller not to proceed, since there's
 
554
         *   nothing left to parse 
 
555
         */
 
556
        G_tok->log_error(TCERR_EXPECTED_SEMI,
 
557
                         (int)sizeof(eof_str)-1, eof_str);
 
558
        return 1;
 
559
 
 
560
    default:
 
561
        /* 
 
562
         *   the source is probably just missing a semicolon; log the
 
563
         *   error, and tell the caller to proceed from the current
 
564
         *   position 
 
565
         */
 
566
        G_tok->log_error_curtok(TCERR_EXPECTED_SEMI);
 
567
        return 0;
 
568
    }
 
569
}
 
570
 
 
571
/*
 
572
 *   Skip to the next semicolon 
 
573
 */
 
574
int CTcParser::skip_to_sem()
 
575
{
 
576
    /* keep going until we find a semicolon or some other reason to stop */
 
577
    for (;;)
 
578
    {
 
579
        /* see what we have next */
 
580
        switch(G_tok->cur())
 
581
        {
 
582
        case TOKT_EOF:
 
583
            /* end of file - tell the caller not to proceed */
 
584
            return 1;
 
585
 
 
586
        case TOKT_SEM:
 
587
            /* 
 
588
             *   it's the semicolon at last - skip it and tell the caller
 
589
             *   to proceed 
 
590
             */
 
591
            G_tok->next();
 
592
            return 0;
 
593
 
 
594
        case TOKT_LBRACE:
 
595
        case TOKT_RBRACE:
 
596
            /* 
 
597
             *   Don't skip past braces - the caller probably simply left
 
598
             *   out a semicolon at the end of a statement, and we've now
 
599
             *   reached the next block start or end.  Stop here and tell
 
600
             *   the caller to proceed.  
 
601
             */
 
602
            return 0;
 
603
 
 
604
        default:
 
605
            /* skip anything else */
 
606
            G_tok->next();
 
607
            break;
 
608
        }
 
609
    }
 
610
}
 
611
 
 
612
/*
 
613
 *   Create a symbol node 
 
614
 */
 
615
CTcPrsNode *CTcParser::create_sym_node(const textchar_t *sym, size_t sym_len)
 
616
{
 
617
    CTcSymbol *entry;
 
618
    CTcPrsSymtab *symtab;
 
619
    
 
620
    /* 
 
621
     *   First, look up the symbol in local scope.  Local scope symbols
 
622
     *   can always be resolved during parsing, because the language
 
623
     *   requires that local scope items be declared before their first
 
624
     *   use. 
 
625
     */
 
626
    entry = local_symtab_->find(sym, sym_len, &symtab);
 
627
 
 
628
    /* if we found it in local scope, return a resolved symbol node */
 
629
    if (entry != 0 && symtab != global_symtab_)
 
630
        return new CTPNSymResolved(entry);
 
631
 
 
632
    /* if there's a debugger local scope, look it up there */
 
633
    if (debug_symtab_ != 0)
 
634
    {
 
635
        tcprsdbg_sym_info info;
 
636
 
 
637
        /* look it up in the debug symbol table */
 
638
        if (debug_symtab_->find_symbol(sym, sym_len, &info))
 
639
        {
 
640
            /* found it - return a debugger local variable */
 
641
            return new CTPNSymDebugLocal(&info);
 
642
        }
 
643
    }
 
644
 
 
645
    /* 
 
646
     *   We didn't find it in local scope, so the symbol cannot be resolved
 
647
     *   until code generation - return an unresolved symbol node.  Note a
 
648
     *   possible implicit self-reference, since this could be a property of
 
649
     *   'self'.  
 
650
     */
 
651
    set_self_referenced(TRUE);
 
652
    return new CTPNSym(sym, sym_len);
 
653
}
 
654
 
 
655
/*
 
656
 *   Find or add a dictionary symbol 
 
657
 */
 
658
CTcDictEntry *CTcParser::declare_dict(const char *txt, size_t len)
 
659
{
 
660
    CTcSymObj *sym;
 
661
    CTcDictEntry *entry = 0;
 
662
 
 
663
    /* look up the symbol */
 
664
    sym = (CTcSymObj *)global_symtab_->find(txt, len);
 
665
 
 
666
    /* if it's not defined, add it; otherwise, make sure it's correct */
 
667
    if (sym == 0)
 
668
    {
 
669
        /* it's not yet defined - define it as a dictionary */
 
670
        sym = new CTcSymObj(G_tok->getcur()->get_text(),
 
671
                            G_tok->getcur()->get_text_len(),
 
672
                            FALSE, G_cg->new_obj_id(), FALSE,
 
673
                            TC_META_DICT, 0);
 
674
 
 
675
        /* add it to the global symbol table */
 
676
        global_symtab_->add_entry(sym);
 
677
 
 
678
        /* create a new dictionary entry */
 
679
        entry = create_dict_entry(sym);
 
680
    }
 
681
    else
 
682
    {
 
683
        /* make sure it's an object of metaclass 'dictionary' */
 
684
        if (sym->get_type() != TC_SYM_OBJ)
 
685
        {
 
686
            /* log an error */
 
687
            G_tok->log_error_curtok(TCERR_REDEF_AS_OBJ);
 
688
            
 
689
            /* forget the symbol - it's not even an object */
 
690
            sym = 0;
 
691
        }
 
692
        else if (sym->get_metaclass() != TC_META_DICT)
 
693
        {
 
694
            /* it's an object, but not a dictionary - log an error */
 
695
            G_tok->log_error_curtok(TCERR_REDEF_AS_DICT);
 
696
 
 
697
            /* forget the symbol */
 
698
            sym = 0;
 
699
        }
 
700
 
 
701
        /* find it in our dictionary list */
 
702
        entry = get_dict_entry(sym);
 
703
 
 
704
        /* 
 
705
         *   if we didn't find the entry, we must have loaded the symbol
 
706
         *   from a symbol file - add the dictionary list entry now
 
707
         */
 
708
        if (entry == 0)
 
709
            entry = create_dict_entry(sym);
 
710
    }
 
711
 
 
712
    /* return the new dictionary object */
 
713
    return entry;
 
714
}
 
715
 
 
716
/*
 
717
 *   Find or add a grammar production symbol.  Returns the master
 
718
 *   CTcGramProdEntry object for the grammar production.  
 
719
 */
 
720
CTcGramProdEntry *CTcParser::declare_gramprod(const char *txt, size_t len)
 
721
{
 
722
    CTcSymObj *sym;
 
723
    CTcGramProdEntry *entry;
 
724
 
 
725
    /* find or define the grammar production object symbol */
 
726
    sym = find_or_def_gramprod(txt, len, &entry);
 
727
 
 
728
    /* return the entry */
 
729
    return entry;
 
730
}
 
731
 
 
732
/*
 
733
 *   Find or add a grammar production symbol.  
 
734
 */
 
735
CTcSymObj *CTcParser::find_or_def_gramprod(const char *txt, size_t len,
 
736
                                           CTcGramProdEntry **entryp)
 
737
{
 
738
    CTcSymObj *sym;
 
739
    CTcGramProdEntry *entry;
 
740
    
 
741
    /* look up the symbol */
 
742
    sym = (CTcSymObj *)global_symtab_->find(txt, len);
 
743
 
 
744
    /* if it's not defined, add it; otherwise, make sure it's correct */
 
745
    if (sym == 0)
 
746
    {
 
747
        /* it's not yet defined - define it as a grammar production */
 
748
        sym = new CTcSymObj(G_tok->getcur()->get_text(),
 
749
                            G_tok->getcur()->get_text_len(),
 
750
                            FALSE, G_cg->new_obj_id(), FALSE,
 
751
                            TC_META_GRAMPROD, 0);
 
752
 
 
753
        /* add it to the global symbol table */
 
754
        global_symtab_->add_entry(sym);
 
755
 
 
756
        /* create a new production list entry */
 
757
        entry = create_gramprod_entry(sym);
 
758
    }
 
759
    else
 
760
    {
 
761
        /* make sure it's an object of metaclass 'grammar production' */
 
762
        if (sym->get_type() != TC_SYM_OBJ)
 
763
        {
 
764
            /* log an error */
 
765
            G_tok->log_error_curtok(TCERR_REDEF_AS_OBJ);
 
766
 
 
767
            /* forget the symbol - it's not even an object */
 
768
            sym = 0;
 
769
        }
 
770
        else if (sym->get_metaclass() != TC_META_GRAMPROD)
 
771
        {
 
772
            /* it's an object, but not a production - log an error */
 
773
            G_tok->log_error_curtok(TCERR_REDEF_AS_GRAMPROD);
 
774
 
 
775
            /* forget the symbol */
 
776
            sym = 0;
 
777
        }
 
778
 
 
779
        /* 
 
780
         *   If we found the symbol, make sure it's not marked as external,
 
781
         *   since we're actually defining a rule for this production.  If
 
782
         *   the production is exported from any other modules, we'll share
 
783
         *   the production object with the other modules.  
 
784
         */
 
785
        if (sym != 0)
 
786
            sym->set_extern(FALSE);
 
787
 
 
788
        /* get the existing production object, if any */
 
789
        entry = get_gramprod_entry(sym);
 
790
 
 
791
        /* 
 
792
         *   if we didn't find the entry, we must have loaded the symbol
 
793
         *   from a symbol file - add the entry now 
 
794
         */
 
795
        if (entry == 0)
 
796
            entry = create_gramprod_entry(sym);
 
797
    }
 
798
 
 
799
    /* 
 
800
     *   if the caller is interested in knowing the associated grammar rule
 
801
     *   list entry, return it 
 
802
     */
 
803
    if (entryp != 0)
 
804
        *entryp = entry;
 
805
 
 
806
    /* return the new symbol */
 
807
    return sym;
 
808
}
 
809
 
 
810
/*
 
811
 *   Add a symbol loaded from an object file 
 
812
 */
 
813
void CTcParser::add_sym_from_obj_file(uint idx, class CTcSymbol *sym)
 
814
{
 
815
    /* 
 
816
     *   add the entry to the object file index list - adjust from the
 
817
     *   1-based index used in the file to an array index 
 
818
     */
 
819
    obj_sym_list_[idx - 1] = sym;
 
820
}
 
821
 
 
822
/*
 
823
 *   Get an object file symbol, ensuring that it's an object symbol
 
824
 */
 
825
CTcSymObj *CTcParser::get_objfile_objsym(uint idx)
 
826
{
 
827
    CTcSymObj *sym;
 
828
 
 
829
    /* get the object based on the index */
 
830
    sym = (CTcSymObj *)get_objfile_sym(idx);
 
831
 
 
832
    /* make sure it's an object - if it isn't, return null */
 
833
    if (sym == 0 || sym->get_type() != TC_SYM_OBJ)
 
834
        return 0;
 
835
 
 
836
    /* it checks out - return it */
 
837
    return sym;
 
838
}
 
839
 
 
840
 
 
841
/*
 
842
 *   Add a dictionary symbol loaded from an object file 
 
843
 */
 
844
void CTcParser::add_dict_from_obj_file(CTcSymObj *sym)
 
845
{
 
846
    CTcDictEntry *entry;
 
847
    
 
848
    /* get the current entry, if any */
 
849
    entry = get_dict_entry(sym);
 
850
 
 
851
    /* if there's no current entry, create a new one */
 
852
    if (entry == 0)
 
853
    {
 
854
        /* create the entry */
 
855
        entry = create_dict_entry(sym);
 
856
    }
 
857
 
 
858
    /* add the entry to the object file index list */
 
859
    obj_dict_list_[obj_file_dict_idx_++] = entry;
 
860
}
 
861
 
 
862
/*
 
863
 *   create a new dictionary list entry 
 
864
 */
 
865
CTcDictEntry *CTcParser::create_dict_entry(CTcSymObj *sym)
 
866
{
 
867
    CTcDictEntry *entry;
 
868
 
 
869
    /* allocate the new entry */
 
870
    entry = new (G_prsmem) CTcDictEntry(sym);
 
871
 
 
872
    /* link the new entry into our list */
 
873
    if (dict_tail_ != 0)
 
874
        dict_tail_->set_next(entry);
 
875
    else
 
876
        dict_head_ = entry;
 
877
    dict_tail_ = entry;
 
878
 
 
879
    /* 
 
880
     *   set the metaclass-specific extra data in the object symbol to
 
881
     *   point to the dictionary list entry 
 
882
     */
 
883
    sym->set_meta_extra(entry);
 
884
 
 
885
    /* return the new entry */
 
886
    return entry;
 
887
}
 
888
 
 
889
/* 
 
890
 *   find a dictionary list entry for a given object symbol 
 
891
 */
 
892
CTcDictEntry *CTcParser::get_dict_entry(CTcSymObj *obj)
 
893
{
 
894
    /* the dictionary list entry is the metaclass-specific data pointer */
 
895
    return (obj == 0 ? 0 : (CTcDictEntry *)obj->get_meta_extra());
 
896
}
 
897
 
 
898
/*
 
899
 *   Create a grammar production list entry.  This creates a
 
900
 *   CTcGramProdEntry object associated with the given grammar production
 
901
 *   symbol, and links the new entry into the master list of grammar
 
902
 *   production entries.   
 
903
 */
 
904
CTcGramProdEntry *CTcParser::create_gramprod_entry(CTcSymObj *sym)
 
905
{
 
906
    CTcGramProdEntry *entry;
 
907
 
 
908
    /* allocate the new entry */
 
909
    entry = new (G_prsmem) CTcGramProdEntry(sym);
 
910
 
 
911
    /* link the new entry into our list of anonymous match entries */
 
912
    if (gramprod_tail_ != 0)
 
913
        gramprod_tail_->set_next(entry);
 
914
    else
 
915
        gramprod_head_ = entry;
 
916
    gramprod_tail_ = entry;
 
917
 
 
918
    /* 
 
919
     *   set the metaclass-specific data in the object symbol to point to
 
920
     *   the grammar production list entry 
 
921
     */
 
922
    if (sym != 0)
 
923
        sym->set_meta_extra(entry);
 
924
 
 
925
    /* return the new entry */
 
926
    return entry;
 
927
}
 
928
 
 
929
/* 
 
930
 *   find a grammar entry for a given (GrammarProd) object symbol 
 
931
 */
 
932
CTcGramProdEntry *CTcParser::get_gramprod_entry(CTcSymObj *obj)
 
933
{
 
934
    /* the grammar entry is the metaclass-specific data pointer */
 
935
    return (obj == 0 ? 0 : (CTcGramProdEntry *)obj->get_meta_extra());
 
936
}
 
937
 
 
938
/*
 
939
 *   Add a nested top-level statement to our list 
 
940
 */
 
941
void CTcParser::add_nested_stm(CTPNStmTop *stm)
 
942
{
 
943
    /* link it into our list */
 
944
    if (nested_stm_tail_ != 0)
 
945
        nested_stm_tail_->set_next_stm_top(stm);
 
946
    else
 
947
        nested_stm_head_ = stm;
 
948
    nested_stm_tail_ = stm;
 
949
}
 
950
 
 
951
/*
 
952
 *   Add an anonymous object to our list 
 
953
 */
 
954
void CTcParser::add_anon_obj(CTcSymObj *sym)
 
955
{
 
956
    /* link it into our list */
 
957
    if (anon_obj_tail_ != 0)
 
958
        anon_obj_tail_->nxt_ = sym;
 
959
    else
 
960
        anon_obj_head_ = sym;
 
961
    anon_obj_tail_ = sym;
 
962
 
 
963
    /* it's the last one */
 
964
    sym->nxt_ = 0;
 
965
 
 
966
    /* mark the symbol as anonymous */
 
967
    sym->set_anon(TRUE);
 
968
}
 
969
 
 
970
/*
 
971
 *   Add a non-symbolic object to our list 
 
972
 */
 
973
void CTcParser::add_nonsym_obj(tctarg_obj_id_t id)
 
974
{
 
975
    tcprs_nonsym_obj *obj;
 
976
    
 
977
    /* allocate a link structure */
 
978
    obj = new (G_prsmem) tcprs_nonsym_obj(id);
 
979
    
 
980
    /* link it into our list */
 
981
    if (nonsym_obj_tail_ != 0)
 
982
        nonsym_obj_tail_->nxt_ = obj;
 
983
    else
 
984
        nonsym_obj_head_ = obj;
 
985
    nonsym_obj_tail_ = obj;
 
986
}
 
987
 
 
988
/*
 
989
 *   Basic routine to read a length-prefixed symbol.  Uses the given
 
990
 *   temporary buffer, then stores the text in tokenizer memory (which
 
991
 *   remains valid and available throughout compilation).  If the length
 
992
 *   exceeds the temporary buffer length, we'll flag the given error and
 
993
 *   return null.  The length return pointer can be null if the caller wants
 
994
 *   the results null-terminated rather than returned with a counted length.
 
995
 *   If the length pointer is given, the result will not be null-terminated.
 
996
 *   
 
997
 */
 
998
const char *CTcParser::read_len_prefix_str
 
999
   (CVmFile *fp, char *tmp_buf, size_t tmp_buf_len, size_t *ret_len,
 
1000
    int err_if_too_long)
 
1001
{
 
1002
    size_t read_len;
 
1003
    size_t alloc_len;
 
1004
    
 
1005
    /* read the length to read from the file */
 
1006
    read_len = (size_t)fp->read_uint2();
 
1007
 
 
1008
    /* if we need null termination, add a byte to the allocation length */
 
1009
    alloc_len = read_len + (ret_len == 0 ? 1 : 0);
 
1010
 
 
1011
    /* if it won't fit in the temporary buffer, it's an error */
 
1012
    if (alloc_len > tmp_buf_len)
 
1013
    {
 
1014
        /* log the error and return failure */
 
1015
        G_tcmain->log_error(0, 0, TC_SEV_ERROR, err_if_too_long);
 
1016
        return 0;
 
1017
    }
 
1018
 
 
1019
    /* read the bytes into the temporary buffer */
 
1020
    fp->read_bytes(tmp_buf, read_len);
 
1021
 
 
1022
    /* add null termination if required, or set the return length if not */
 
1023
    if (ret_len == 0)
 
1024
        tmp_buf[read_len] = '\0';
 
1025
    else
 
1026
        *ret_len = read_len;
 
1027
 
 
1028
    /* store the result in the tokenizer's text list and return the result */
 
1029
    return G_tok->store_source(tmp_buf, alloc_len);
 
1030
}
 
1031
 
 
1032
/*
 
1033
 *   Read a length prefixed string into a given buffer.  Returns zero on
 
1034
 *   success, non-zero on failure. 
 
1035
 */
 
1036
int CTcParser::read_len_prefix_str(CVmFile *fp, char *buf, size_t buf_len,
 
1037
                                   int err_if_too_long)
 
1038
{
 
1039
    size_t read_len;
 
1040
    size_t alloc_len;
 
1041
 
 
1042
    /* read the length to read from the file */
 
1043
    read_len = (size_t)fp->read_uint2();
 
1044
 
 
1045
    /* add a byte for null termination */
 
1046
    alloc_len = read_len + 1;
 
1047
 
 
1048
    /* if it won't fit in the temporary buffer, it's an error */
 
1049
    if (alloc_len > buf_len)
 
1050
    {
 
1051
        /* log the error and return failure */
 
1052
        G_tcmain->log_error(0, 0, TC_SEV_ERROR, err_if_too_long);
 
1053
        return 1;
 
1054
    }
 
1055
 
 
1056
    /* read the bytes into the caller's buffer */
 
1057
    fp->read_bytes(buf, read_len);
 
1058
 
 
1059
    /* add null termination */
 
1060
    buf[read_len] = '\0';
 
1061
 
 
1062
    /* success */
 
1063
    return 0;
 
1064
}
 
1065
 
 
1066
/* ------------------------------------------------------------------------ */
 
1067
/*
 
1068
 *   Constant Value 
 
1069
 */
 
1070
 
 
1071
/*
 
1072
 *   set a string value 
 
1073
 */
 
1074
void CTcConstVal::set_sstr(const char *val, size_t len)
 
1075
{
 
1076
    /* store the type */
 
1077
    typ_ = TC_CVT_SSTR;
 
1078
 
 
1079
    /* store a pointer to the string */
 
1080
    val_.strval_.strval_ = val;
 
1081
    val_.strval_.strval_len_ = len;
 
1082
 
 
1083
    /* for image file layout purposes, record the length of this string */
 
1084
    G_cg->note_str(len);
 
1085
}
 
1086
 
 
1087
/*
 
1088
 *   set a list value 
 
1089
 */
 
1090
void CTcConstVal::set_list(CTPNList *lst)
 
1091
{
 
1092
    /* set the type */
 
1093
    typ_ = TC_CVT_LIST;
 
1094
 
 
1095
    /* remember the list */
 
1096
    val_.listval_ = lst;
 
1097
 
 
1098
    /* for image file layout purposes, record the length of this list */
 
1099
    G_cg->note_list(lst->get_count());
 
1100
}
 
1101
 
 
1102
/*
 
1103
 *   Convert a value to a string 
 
1104
 */
 
1105
const char *CTcConstVal::cvt_to_str(char *buf, size_t bufl,
 
1106
                                    size_t *result_len)
 
1107
{
 
1108
    /* check my type */
 
1109
    switch(typ_)
 
1110
    {
 
1111
    case TC_CVT_NIL:
 
1112
        /* the result is "nil" */
 
1113
        if (bufl < 4)
 
1114
            return 0;
 
1115
 
 
1116
        strcpy(buf, "nil");
 
1117
        *result_len = 3;
 
1118
        return buf;
 
1119
 
 
1120
    case TC_CVT_TRUE:
 
1121
        /* the result is "true" */
 
1122
        if (bufl < 5)
 
1123
            return 0;
 
1124
 
 
1125
        strcpy(buf, "true");
 
1126
        *result_len = 4;
 
1127
        return buf;
 
1128
 
 
1129
    case TC_CVT_SSTR:
 
1130
        /* it's already a string */
 
1131
        *result_len = get_val_str_len();
 
1132
        return get_val_str();
 
1133
 
 
1134
    case TC_CVT_INT:
 
1135
        /* convert our signed integer value */
 
1136
        if (bufl < 12)
 
1137
            return 0;
 
1138
 
 
1139
        sprintf(buf, "%ld", get_val_int());
 
1140
        *result_len = strlen(buf);
 
1141
        return buf;
 
1142
 
 
1143
    case TC_CVT_FLOAT:
 
1144
        /* we store these as strings */
 
1145
        *result_len = get_val_float_len();
 
1146
        return get_val_float();
 
1147
 
 
1148
    default:
 
1149
        /* can't convert other types */
 
1150
        return 0;
 
1151
    }
 
1152
}
 
1153
 
 
1154
/*
 
1155
 *   Compare for equality to another constant value 
 
1156
 */
 
1157
int CTcConstVal::is_equal_to(const CTcConstVal *val) const
 
1158
{
 
1159
    CTPNListEle *ele1;
 
1160
    CTPNListEle *ele2;
 
1161
    
 
1162
    /* 
 
1163
     *   if the types are not equal, the values are not equal; otherwise,
 
1164
     *   check the various types 
 
1165
     */
 
1166
    if (typ_ != val->get_type())
 
1167
    {
 
1168
        /* the types aren't equal, so the values are not equal */
 
1169
        return FALSE;
 
1170
    }
 
1171
 
 
1172
    /* the types are the same; do the comparison based on the type */
 
1173
    switch(typ_)
 
1174
    {
 
1175
    case TC_CVT_UNK:
 
1176
        /* unknown type; unknown values can never be equal */
 
1177
        return FALSE;
 
1178
 
 
1179
    case TC_CVT_TRUE:
 
1180
    case TC_CVT_NIL:
 
1181
        /* 
 
1182
         *   nil==nil and true==true; since we know the types are the
 
1183
         *   same, the values are the same
 
1184
         */
 
1185
        return TRUE;
 
1186
 
 
1187
    case TC_CVT_INT:
 
1188
        /* compare the integers */
 
1189
        return (get_val_int() == val->get_val_int());
 
1190
 
 
1191
    case TC_CVT_SSTR:
 
1192
        /* compare the strings */
 
1193
        return (get_val_str_len() == val->get_val_str_len()
 
1194
                && memcmp(get_val_str(), val->get_val_str(),
 
1195
                          get_val_str_len()) == 0);
 
1196
            
 
1197
    case TC_CVT_LIST:
 
1198
        /* 
 
1199
         *   if the lists don't have the same number of elements, they're
 
1200
         *   not equal 
 
1201
         */
 
1202
        if (get_val_list()->get_count() != val->get_val_list()->get_count())
 
1203
            return FALSE;
 
1204
 
 
1205
        /* 
 
1206
         *   compare each element of each list; if they're all the same,
 
1207
         *   the values are the same 
 
1208
         */
 
1209
        ele1 = get_val_list()->get_head();
 
1210
        ele2 = val->get_val_list()->get_head();
 
1211
        for ( ; ele1 != 0 && ele2 != 0 ;
 
1212
              ele1 = ele1->get_next(), ele2 = ele2->get_next())
 
1213
        {
 
1214
            /* if these elements aren't equal, the lists aren't equal */
 
1215
            if (!ele1->get_expr()->get_const_val()
 
1216
                ->is_equal_to(ele2->get_expr()->get_const_val()))
 
1217
                return FALSE;
 
1218
        }
 
1219
 
 
1220
        /* we didn't find any differences, so the lists are equal */
 
1221
        return TRUE;
 
1222
 
 
1223
    case TC_CVT_OBJ:
 
1224
        /* if the object values are the same, the values match */
 
1225
        return (get_val_obj() == val->get_val_obj());
 
1226
 
 
1227
    case TC_CVT_PROP:
 
1228
        /* if the property values are the same, the values match */
 
1229
        return (get_val_prop() == val->get_val_prop());
 
1230
 
 
1231
    case TC_CVT_FUNCPTR:
 
1232
        /* 
 
1233
         *   if both symbols are the same, the values match; otherwise,
 
1234
         *   they refer to different functions 
 
1235
         */
 
1236
        return (get_val_funcptr_sym() == val->get_val_funcptr_sym());
 
1237
 
 
1238
    default:
 
1239
        /* unknown type; return unequal */
 
1240
        return FALSE;
 
1241
    }
 
1242
}
 
1243
 
 
1244
 
 
1245
/* ------------------------------------------------------------------------ */
 
1246
/*
 
1247
 *   Operator Parsers 
 
1248
 */
 
1249
 
 
1250
/* ------------------------------------------------------------------------ */
 
1251
/*
 
1252
 *   Parse a left-associative binary operator 
 
1253
 */
 
1254
CTcPrsNode *CTcPrsOpBin::parse() const
 
1255
{
 
1256
    CTcPrsNode *lhs;
 
1257
    CTcPrsNode *rhs;
 
1258
    
 
1259
    /* parse our left side - if that fails, return failure */
 
1260
    if ((lhs = left_->parse()) == 0)
 
1261
        return 0;
 
1262
 
 
1263
    /* keep going as long as we find our operator */
 
1264
    for (;;)
 
1265
    {
 
1266
        /* check my operator */
 
1267
        if (G_tok->cur() == get_op_tok())
 
1268
        {
 
1269
            CTcPrsNode *const_tree;
 
1270
 
 
1271
            /* skip the matching token */
 
1272
            G_tok->next();
 
1273
            
 
1274
            /* parse the right-hand side */
 
1275
            if ((rhs = right_->parse()) == 0)
 
1276
                return 0;
 
1277
 
 
1278
            /* try folding our subnodes into a constant value, if possible */
 
1279
            const_tree = eval_constant(lhs, rhs);
 
1280
 
 
1281
            /* 
 
1282
             *   if we couldn't calculate a constant value, build the tree
 
1283
             *   normally 
 
1284
             */
 
1285
            if (const_tree == 0)
 
1286
            {
 
1287
                /* 
 
1288
                 *   Build my tree, then proceed to parse any additional
 
1289
                 *   occurrences of our operator, with the result of
 
1290
                 *   applying this occurrence of the operator as the
 
1291
                 *   left-hand side of the new operator.  
 
1292
                 */
 
1293
                lhs = build_tree(lhs, rhs);
 
1294
            }
 
1295
            else
 
1296
            {
 
1297
                /* we got a constant value - use it as the result directly */
 
1298
                lhs = const_tree;
 
1299
            }
 
1300
        }
 
1301
        else
 
1302
        {
 
1303
            /* 
 
1304
             *   it's not my operator - return what we thought might have
 
1305
             *   been our left-hand side 
 
1306
             */
 
1307
            return lhs;
 
1308
        }
 
1309
    }
 
1310
}
 
1311
 
 
1312
/* ------------------------------------------------------------------------ */
 
1313
/*
 
1314
 *   Parse a group of left-associative binary operators at the same
 
1315
 *   precedence level 
 
1316
 */
 
1317
CTcPrsNode *CTcPrsOpBinGroup::parse() const
 
1318
{
 
1319
    CTcPrsNode *lhs;
 
1320
 
 
1321
    /* parse our left side - if that fails, return failure */
 
1322
    if ((lhs = left_->parse()) == 0)
 
1323
        return 0;
 
1324
 
 
1325
    /* keep going as long as we find one of our operators */
 
1326
    while (find_and_apply_op(&lhs)) ;
 
1327
 
 
1328
    /* return the expression tree */
 
1329
    return lhs;
 
1330
}
 
1331
 
 
1332
/*
 
1333
 *   Find an apply one of our operators to the already-parsed left-hand
 
1334
 *   side.  Returns true if we found an operator, false if not.  
 
1335
 */
 
1336
int CTcPrsOpBinGroup::find_and_apply_op(CTcPrsNode **lhs) const
 
1337
{
 
1338
    const CTcPrsOpBin *const *op;
 
1339
    CTcPrsNode *rhs;
 
1340
 
 
1341
    /* check each operator at this precedence level */
 
1342
    for (op = ops_ ; *op != 0 ; ++op)
 
1343
    {
 
1344
        /* check this operator's token */
 
1345
        if (G_tok->cur() == (*op)->get_op_tok())
 
1346
        {
 
1347
            CTcPrsNode *const_tree;
 
1348
 
 
1349
            /* skip the operator token */
 
1350
            G_tok->next();
 
1351
 
 
1352
            /* parse the right-hand side */
 
1353
            if ((rhs = right_->parse()) == 0)
 
1354
            {
 
1355
                /* error - cancel the entire expression */
 
1356
                *lhs = 0;
 
1357
                return FALSE;
 
1358
            }
 
1359
 
 
1360
            /* try folding our subnodes into a constant value */
 
1361
            const_tree = (*op)->eval_constant(*lhs, rhs);
 
1362
 
 
1363
            /* 
 
1364
             *   if we couldn't calculate a constant value, build the tree
 
1365
             *   normally 
 
1366
             */
 
1367
            if (const_tree == 0)
 
1368
            {
 
1369
                /* 
 
1370
                 *   build my tree, replacing the original left-hand side
 
1371
                 *   with the new expression 
 
1372
                 */
 
1373
                *lhs = (*op)->build_tree(*lhs, rhs);
 
1374
            }
 
1375
            else
 
1376
            {
 
1377
                /* we got a constant value - use it as the result */
 
1378
                *lhs = const_tree;
 
1379
            }
 
1380
 
 
1381
            /*
 
1382
             *   Tell the caller to proceed to parse any additional
 
1383
             *   occurrences of our operator - this will apply the next
 
1384
             *   occurrence of the operator as the left-hand side of the
 
1385
             *   new operator.  
 
1386
             */
 
1387
            return TRUE;
 
1388
        }
 
1389
    }
 
1390
 
 
1391
    /* 
 
1392
     *   if we got here, we didn't find an operator - tell the caller that
 
1393
     *   we've reached the end of this operator's possible span
 
1394
     */
 
1395
    return FALSE;
 
1396
}
 
1397
 
 
1398
 
 
1399
/* ------------------------------------------------------------------------ */
 
1400
/*
 
1401
 *   Comparison operator group 
 
1402
 */
 
1403
CTcPrsNode *CTcPrsOpBinGroupCompare::parse() const
 
1404
{
 
1405
    CTcPrsNode *lhs;
 
1406
 
 
1407
    /* parse our left side - if that fails, return failure */
 
1408
    if ((lhs = left_->parse()) == 0)
 
1409
        return 0;
 
1410
 
 
1411
    /* keep going as long as we find one of our operators */
 
1412
    for (;;)
 
1413
    {
 
1414
        CTPNArglist *rhs;
 
1415
        
 
1416
        /* 
 
1417
         *   try one of our regular operators - if we find it, go back for
 
1418
         *   another round to see if there's another operator following
 
1419
         *   the next expression
 
1420
         */
 
1421
        if (find_and_apply_op(&lhs))
 
1422
            continue;
 
1423
 
 
1424
        /* 
 
1425
         *   check for the 'is in' operator - 'is' and 'in' aren't
 
1426
         *   keywords, so we must check for symbol tokens with the text of
 
1427
         *   these context-sensitive keywords 
 
1428
         */
 
1429
        if (G_tok->cur() == TOKT_SYM
 
1430
            && G_tok->getcur()->text_matches("is", 2))
 
1431
        {
 
1432
            /* we have 'is' - get the next token and check if it's 'in' */
 
1433
            if (G_tok->next() == TOKT_SYM
 
1434
                && G_tok->getcur()->text_matches("in", 2))
 
1435
            {
 
1436
                /* scan the expression list */
 
1437
                rhs = parse_inlist();
 
1438
                if (rhs == 0)
 
1439
                    return 0;
 
1440
 
 
1441
                /* build the node */
 
1442
                lhs = new CTPNIsIn(lhs, rhs);
 
1443
 
 
1444
                /* 
 
1445
                 *   we've applied the 'is in' operator - go back for
 
1446
                 *   another operator from the comparison group 
 
1447
                 */
 
1448
                continue;
 
1449
            }
 
1450
            else
 
1451
            {
 
1452
                /* it's not 'is in' - throw back the token and keep looking */
 
1453
                G_tok->unget();
 
1454
            }
 
1455
        }
 
1456
 
 
1457
        /*
 
1458
         *   Check for the 'not in' operator 
 
1459
         */
 
1460
        if (G_tok->cur() == TOKT_SYM
 
1461
            && G_tok->getcur()->text_matches("not", 3))
 
1462
        {
 
1463
            /* we have 'is' - get the next token and check if it's 'in' */
 
1464
            if (G_tok->next() == TOKT_SYM
 
1465
                && G_tok->getcur()->text_matches("in", 2))
 
1466
            {
 
1467
                /* scan the expression list */
 
1468
                rhs = parse_inlist();
 
1469
                if (rhs == 0)
 
1470
                    return 0;
 
1471
 
 
1472
                /* build the node */
 
1473
                lhs = new CTPNNotIn(lhs, rhs);
 
1474
 
 
1475
                /* 
 
1476
                 *   we've applied the 'is in' operator - go back for
 
1477
                 *   another operator from the comparison group 
 
1478
                 */
 
1479
                continue;
 
1480
            }
 
1481
            else
 
1482
            {
 
1483
                /* it's not 'is in' - throw back the token and keep looking */
 
1484
                G_tok->unget();
 
1485
            }
 
1486
        }
 
1487
 
 
1488
        /* we didn't find any of our operators - we're done */
 
1489
        break;
 
1490
    }
 
1491
 
 
1492
    /* return the expression */
 
1493
    return lhs;
 
1494
}
 
1495
 
 
1496
/*
 
1497
 *   parse the list for the right-hand side of an 'is in' or 'not in'
 
1498
 *   expression 
 
1499
 */
 
1500
CTPNArglist *CTcPrsOpBinGroupCompare::parse_inlist() const
 
1501
{
 
1502
    int argc;
 
1503
    CTPNArg *arg_head;
 
1504
    CTPNArg *arg_tail;
 
1505
 
 
1506
    /* skip the second keyword token, and check for an open paren */
 
1507
    if (G_tok->next() == TOKT_LPAR)
 
1508
    {
 
1509
        /* skip the paren */
 
1510
        G_tok->next();
 
1511
    }
 
1512
    else
 
1513
    {
 
1514
        /* 
 
1515
         *   log an error, and keep going on the assumption that it was
 
1516
         *   merely omitted and the rest of the list is well-formed 
 
1517
         */
 
1518
        G_tok->log_error_curtok(TCERR_IN_REQ_LPAR);
 
1519
    }
 
1520
 
 
1521
    /* keep going until we find the close paren */
 
1522
    for (argc = 0, arg_head = arg_tail = 0 ;; )
 
1523
    {
 
1524
        CTcPrsNode *expr;
 
1525
        CTPNArg *arg_cur;
 
1526
 
 
1527
        /* if this is the close paren, we're done */
 
1528
        if (G_tok->cur() == TOKT_RPAR)
 
1529
            break;
 
1530
 
 
1531
        /* parse this expression */
 
1532
        expr = S_op_asi.parse();
 
1533
        if (expr == 0)
 
1534
            return 0;
 
1535
 
 
1536
        /* count the argument */
 
1537
        ++argc;
 
1538
 
 
1539
        /* create a new argument node */
 
1540
        arg_cur = new CTPNArg(expr);
 
1541
 
 
1542
        /* 
 
1543
         *   link the new node at the end of our list (this preserves the
 
1544
         *   order of the original list) 
 
1545
         */
 
1546
        if (arg_tail != 0)
 
1547
            arg_tail->set_next_arg(arg_cur);
 
1548
        else
 
1549
            arg_head = arg_cur;
 
1550
        arg_tail = arg_cur;
 
1551
 
 
1552
        /* we need to be looking at a comma or right paren */
 
1553
        if (G_tok->cur() == TOKT_RPAR)
 
1554
        {
 
1555
            /* that's the end of the list */
 
1556
            break;
 
1557
        }
 
1558
        else if (G_tok->cur() == TOKT_COMMA)
 
1559
        {
 
1560
            /* skip the comma and parse the next argument */
 
1561
            G_tok->next();
 
1562
        }
 
1563
        else
 
1564
        {
 
1565
            /* 
 
1566
             *   If we're at the end of the file, there's no point
 
1567
             *   proceding, so return failure.  If we've reached something
 
1568
             *   that looks like a statement separator (semicolon, curly
 
1569
             *   brace), also return failure, since the problem is clearly
 
1570
             *   a missing right paren.  Otherwise, assume that a comma
 
1571
             *   was missing and continue as though we have another
 
1572
             *   argument.  
 
1573
             */
 
1574
            switch(G_tok->cur())
 
1575
            {
 
1576
            default:
 
1577
                /* log an error */
 
1578
                G_tok->log_error_curtok(TCERR_EXPECTED_IN_COMMA);
 
1579
 
 
1580
                /* 
 
1581
                 *   if we're at the end of file, return what we have so
 
1582
                 *   far; otherwise continue, assuming that they merely
 
1583
                 *   left out a comma between two argument expressions 
 
1584
                 */
 
1585
                if (G_tok->cur() == TOKT_EOF)
 
1586
                    return new CTPNArglist(argc, arg_head);
 
1587
                break;
 
1588
 
 
1589
            case TOKT_SEM:
 
1590
            case TOKT_LBRACE:
 
1591
            case TOKT_RBRACE:
 
1592
            case TOKT_DSTR_MID:
 
1593
            case TOKT_DSTR_END:
 
1594
                /* 
 
1595
                 *   we're apparently at the end of the statement; flag
 
1596
                 *   the error as a missing right paren, and return what
 
1597
                 *   we have so far 
 
1598
                 */
 
1599
                G_tok->log_error_curtok(TCERR_EXPECTED_IN_RPAR);
 
1600
                return new CTPNArglist(argc, arg_head);
 
1601
            }
 
1602
        }
 
1603
    }
 
1604
 
 
1605
    /* skip the closing paren */
 
1606
    G_tok->next();
 
1607
 
 
1608
    /* create and return the argument list descriptor */
 
1609
    return new CTPNArglist(argc, arg_head);
 
1610
}
 
1611
 
 
1612
/* ------------------------------------------------------------------------ */
 
1613
/*
 
1614
 *   Comma Operator 
 
1615
 */
 
1616
 
 
1617
/*
 
1618
 *   try to evaluate a constant expression 
 
1619
 */
 
1620
CTcPrsNode *CTcPrsOpComma::eval_constant(CTcPrsNode *left,
 
1621
                                         CTcPrsNode *right) const
 
1622
{
 
1623
    /* 
 
1624
     *   if both sides are constants, the result is the constant on the
 
1625
     *   right side; we can't simply fold down to a right-side constant if
 
1626
     *   the left side is not constant, though, because we must still
 
1627
     *   evaluate the left side at run-time for any possible side effects 
 
1628
     */
 
1629
    if (left->is_const() && right->is_const())
 
1630
    {
 
1631
        /* both are constants - simply return the right constant value */
 
1632
        return right;
 
1633
    }
 
1634
    else
 
1635
    {
 
1636
        /* 
 
1637
         *   one or the other is non-constant, so we can't fold the
 
1638
         *   expression - return null to so indicate 
 
1639
         */
 
1640
        return 0;
 
1641
    }
 
1642
}
 
1643
 
 
1644
/*
 
1645
 *   build a subtree for the comma operator 
 
1646
 */
 
1647
CTcPrsNode *CTcPrsOpComma::build_tree(CTcPrsNode *left,
 
1648
                                      CTcPrsNode *right) const
 
1649
{
 
1650
    return new CTPNComma(left, right);
 
1651
}
 
1652
 
 
1653
/* ------------------------------------------------------------------------ */
 
1654
/*
 
1655
 *   logical OR operator 
 
1656
 */
 
1657
 
 
1658
/*
 
1659
 *   try to evaluate a constant expression 
 
1660
 */
 
1661
CTcPrsNode *CTcPrsOpOr::eval_constant(CTcPrsNode *left,
 
1662
                                      CTcPrsNode *right) const
 
1663
{
 
1664
    /* check for constants */
 
1665
    if (left->is_const())
 
1666
    {
 
1667
        CTcPrsNode *ret;
 
1668
        
 
1669
        /* 
 
1670
         *   Check for constants.  If the first expression is constant,
 
1671
         *   the result will always be either 'true' (if the first
 
1672
         *   expression's constant value is true), or the value of the
 
1673
         *   second expression (if the first expression's constant value
 
1674
         *   is 'nil').
 
1675
         *   
 
1676
         *   Note that it doesn't matter whether or not the right side is
 
1677
         *   a constant.  If the left is true, the right will never be
 
1678
         *   executed because of the short-circuit logic; if the left is
 
1679
         *   nil, the result will always be the result of the right value.
 
1680
         */
 
1681
        if (left->get_const_val()->get_val_bool())
 
1682
        {
 
1683
            /* 
 
1684
             *   the left is true, so the result is always true, and the
 
1685
             *   right never gets executed 
 
1686
             */
 
1687
            ret = left;
 
1688
        }
 
1689
        else
 
1690
        {
 
1691
            /* the left is nil, so the result is the right value */
 
1692
            ret = right;
 
1693
        }
 
1694
 
 
1695
        /* ensure the result is a boolean value */
 
1696
        if (ret->is_const())
 
1697
        {
 
1698
            /* make it a true/nil constant value */
 
1699
            ret->get_const_val()
 
1700
                ->set_bool(ret->get_const_val()->get_val_bool());
 
1701
        }
 
1702
        else
 
1703
        {
 
1704
            /* boolean-ize the value at run-time as needed */
 
1705
            ret = new CTPNBoolize(ret);
 
1706
        }
 
1707
 
 
1708
        /* return the result */
 
1709
        return ret;
 
1710
    }
 
1711
    else
 
1712
    {
 
1713
        /* 
 
1714
         *   one or the other is non-constant, so we can't fold the
 
1715
         *   expression - return null to so indicate 
 
1716
         */
 
1717
        return 0;
 
1718
    }
 
1719
}
 
1720
 
 
1721
/*
 
1722
 *   build the subtree
 
1723
 */
 
1724
CTcPrsNode *CTcPrsOpOr::build_tree(CTcPrsNode *left,
 
1725
                                   CTcPrsNode *right) const
 
1726
{
 
1727
    return new CTPNOr(left, right);
 
1728
}
 
1729
 
 
1730
/* ------------------------------------------------------------------------ */
 
1731
/*
 
1732
 *   logical AND operator 
 
1733
 */
 
1734
 
 
1735
/*
 
1736
 *   try to evaluate a constant expression 
 
1737
 */
 
1738
CTcPrsNode *CTcPrsOpAnd::eval_constant(CTcPrsNode *left,
 
1739
                                       CTcPrsNode *right) const
 
1740
{
 
1741
    /* 
 
1742
     *   Check for constants.  If the first expression is constant, the
 
1743
     *   result will always be either 'nil' (if the first expression's
 
1744
     *   constant value is nil), or the value of the second expression (if
 
1745
     *   the first expression's constant value is 'true').
 
1746
     *   
 
1747
     *   Note that it doesn't matter whether or not the right side is a
 
1748
     *   constant.  If the left is nil, the right will never be executed
 
1749
     *   because of the short-circuit logic; if the left is true, the
 
1750
     *   result will always be the result of the right value.  
 
1751
     */
 
1752
    if (left->is_const())
 
1753
    {
 
1754
        CTcPrsNode *ret;
 
1755
        
 
1756
        /*
 
1757
         *   The left value is a constant, so the result is always know.
 
1758
         *   If the left value is nil, the result is nil; otherwise, it's
 
1759
         *   the right half.  
 
1760
         */
 
1761
        if (left->get_const_val()->get_val_bool())
 
1762
        {
 
1763
            /* the left side is true - the result is the right side */
 
1764
            ret = right;
 
1765
        }
 
1766
        else
 
1767
        {
 
1768
            /* 
 
1769
             *   The left side is nil - the result is nil, and the right
 
1770
             *   side never gets executed.
 
1771
             */
 
1772
            ret = left;
 
1773
        }
 
1774
 
 
1775
        /* ensure the result is a boolean value */
 
1776
        if (ret->is_const())
 
1777
        {
 
1778
            /* make it a true/nil constant value */
 
1779
            ret->get_const_val()
 
1780
                ->set_bool(ret->get_const_val()->get_val_bool());
 
1781
        }
 
1782
        else
 
1783
        {
 
1784
            /* boolean-ize the value at run-time as needed */
 
1785
            ret = new CTPNBoolize(ret);
 
1786
        }
 
1787
 
 
1788
        /* return the result */
 
1789
        return ret;
 
1790
    }
 
1791
    else
 
1792
    {
 
1793
        /* 
 
1794
         *   one or the other is non-constant, so we can't fold the
 
1795
         *   expression - return null to so indicate 
 
1796
         */
 
1797
        return 0;
 
1798
    }
 
1799
}
 
1800
 
 
1801
/*
 
1802
 *   build the subtree 
 
1803
 */
 
1804
CTcPrsNode *CTcPrsOpAnd::build_tree(CTcPrsNode *left,
 
1805
                                    CTcPrsNode *right) const
 
1806
{
 
1807
    return new CTPNAnd(left, right);
 
1808
}
 
1809
 
 
1810
/* ------------------------------------------------------------------------ */
 
1811
/*
 
1812
 *   Generic Comparison Operator parser base class 
 
1813
 */
 
1814
 
 
1815
/*
 
1816
 *   evaluate a constant expression 
 
1817
 */
 
1818
CTcPrsNode *CTcPrsOpRel::eval_constant(CTcPrsNode *left,
 
1819
                                       CTcPrsNode *right) const
 
1820
{
 
1821
    /* check for constants */
 
1822
    if (left->is_const() && right->is_const())
 
1823
    {
 
1824
        tc_constval_type_t typ1, typ2;
 
1825
        int sense;
 
1826
 
 
1827
        /* get the types */
 
1828
        typ1 = left->get_const_val()->get_type();
 
1829
        typ2 = right->get_const_val()->get_type();
 
1830
 
 
1831
        /* determine what we're comparing */
 
1832
        if (typ1 == TC_CVT_INT && typ2 == TC_CVT_INT)
 
1833
        {
 
1834
            long val1, val2;
 
1835
 
 
1836
            /* get the values */
 
1837
            val1 = left->get_const_val()->get_val_int();
 
1838
            val2 = right->get_const_val()->get_val_int();
 
1839
 
 
1840
            /* calculate the sense of the integer comparison */
 
1841
            sense = (val1 < val2 ? -1 : val1 == val2 ? 0 : 1);
 
1842
        }
 
1843
        else if (typ1 == TC_CVT_SSTR && typ2 == TC_CVT_SSTR)
 
1844
        {
 
1845
            /* compare the string values */
 
1846
            sense = strcmp(left->get_const_val()->get_val_str(),
 
1847
                           right->get_const_val()->get_val_str());
 
1848
        }
 
1849
        else if (typ1 == TC_CVT_FLOAT || typ2 == TC_CVT_FLOAT)
 
1850
        {
 
1851
            /* we can't compare floats at compile time, but it's legal */
 
1852
            return 0;
 
1853
        }
 
1854
        else
 
1855
        {
 
1856
            /* these types are incomparable */
 
1857
            G_tok->log_error(TCERR_CONST_BAD_COMPARE,
 
1858
                             G_tok->get_op_text(get_op_tok()));
 
1859
            return 0;
 
1860
        }
 
1861
 
 
1862
        /* set the result in the left value */
 
1863
        left->get_const_val()->set_bool(get_bool_val(sense));
 
1864
 
 
1865
        /* return the updated left value */
 
1866
        return left;
 
1867
    }
 
1868
    else
 
1869
    {
 
1870
        /* 
 
1871
         *   one or the other is non-constant, so we can't fold the
 
1872
         *   expression - return null to so indicate 
 
1873
         */
 
1874
        return 0;
 
1875
    }
 
1876
}
 
1877
 
 
1878
 
 
1879
/* ------------------------------------------------------------------------ */
 
1880
/*
 
1881
 *   greater-than operator 
 
1882
 */
 
1883
 
 
1884
/*
 
1885
 *   build the subtree 
 
1886
 */
 
1887
CTcPrsNode *CTcPrsOpGt::build_tree(CTcPrsNode *left,
 
1888
                                   CTcPrsNode *right) const
 
1889
{
 
1890
    return new CTPNGt(left, right);
 
1891
}
 
1892
 
 
1893
/* ------------------------------------------------------------------------ */
 
1894
/*
 
1895
 *   less-than operator 
 
1896
 */
 
1897
 
 
1898
/*
 
1899
 *   build the subtree 
 
1900
 */
 
1901
CTcPrsNode *CTcPrsOpLt::build_tree(CTcPrsNode *left,
 
1902
                                   CTcPrsNode *right) const
 
1903
{
 
1904
    return new CTPNLt(left, right);
 
1905
}
 
1906
 
 
1907
/* ------------------------------------------------------------------------ */
 
1908
/*
 
1909
 *   greater-or-equal operator 
 
1910
 */
 
1911
 
 
1912
/*
 
1913
 *   build the subtree 
 
1914
 */
 
1915
CTcPrsNode *CTcPrsOpGe::build_tree(CTcPrsNode *left,
 
1916
                                   CTcPrsNode *right) const
 
1917
{
 
1918
    return new CTPNGe(left, right);
 
1919
}
 
1920
 
 
1921
/* ------------------------------------------------------------------------ */
 
1922
/*
 
1923
 *   less-or-equal operator 
 
1924
 */
 
1925
 
 
1926
/*
 
1927
 *   build the subtree 
 
1928
 */
 
1929
CTcPrsNode *CTcPrsOpLe::build_tree(CTcPrsNode *left,
 
1930
                                   CTcPrsNode *right) const
 
1931
{
 
1932
    return new CTPNLe(left, right);
 
1933
}
 
1934
 
 
1935
/* ------------------------------------------------------------------------ */
 
1936
/*
 
1937
 *   General equality/inequality operators base class 
 
1938
 */
 
1939
 
 
1940
/*
 
1941
 *   evaluate a constant expression 
 
1942
 */
 
1943
CTcPrsNode *CTcPrsOpEqComp::eval_constant(CTcPrsNode *left,
 
1944
                                          CTcPrsNode *right) const
 
1945
{
 
1946
    int ops_equal;
 
1947
 
 
1948
    /* check for constants */
 
1949
    if (left->is_const() && right->is_const())
 
1950
    {
 
1951
        /* both sides are constants - determine if they're equal */
 
1952
        ops_equal = left->get_const_val()
 
1953
                    ->is_equal_to(right->get_const_val());
 
1954
 
 
1955
        /* set the result in the left value */
 
1956
        left->get_const_val()->set_bool(get_bool_val(ops_equal));
 
1957
 
 
1958
        /* return the updated left value */
 
1959
        return left;
 
1960
    }
 
1961
    else if (left->is_addr() && right->is_addr())
 
1962
    {
 
1963
        CTcConstVal cval;
 
1964
        int comparable;
 
1965
        
 
1966
        /* 
 
1967
         *   both sides are addresses - if they're both addresses of the
 
1968
         *   same subexpression, then the values are comparable as
 
1969
         *   compile-time constants 
 
1970
         */
 
1971
        ops_equal = ((CTPNAddr *)left)
 
1972
                    ->is_addr_eq((CTPNAddr *)right, &comparable);
 
1973
 
 
1974
        /* if they're not comparable, we can't fold this as a constant */
 
1975
        if (!comparable)
 
1976
            return 0;
 
1977
 
 
1978
        /* generate the appropriate boolean result for the comparison */
 
1979
        cval.set_bool(get_bool_val(ops_equal));
 
1980
 
 
1981
        /* return a new constant node with the result */
 
1982
        return new CTPNConst(&cval);
 
1983
    }
 
1984
    else
 
1985
    {
 
1986
        /* 
 
1987
         *   one or the other is non-constant, so we can't fold the
 
1988
         *   expression - return null to so indicate 
 
1989
         */
 
1990
        return 0;
 
1991
    }
 
1992
}
 
1993
 
 
1994
 
 
1995
/* ------------------------------------------------------------------------ */
 
1996
/*
 
1997
 *   equality operator 
 
1998
 */
 
1999
 
 
2000
/*
 
2001
 *   build the subtree 
 
2002
 */
 
2003
CTcPrsNode *CTcPrsOpEq::build_tree(CTcPrsNode *left,
 
2004
                                   CTcPrsNode *right) const
 
2005
{
 
2006
    return new CTPNEq(left, right);
 
2007
}
 
2008
 
 
2009
/* ------------------------------------------------------------------------ */
 
2010
/*
 
2011
 *   inequality operator 
 
2012
 */
 
2013
 
 
2014
/*
 
2015
 *   build the subtree
 
2016
 */
 
2017
CTcPrsNode *CTcPrsOpNe::build_tree(CTcPrsNode *left,
 
2018
                                   CTcPrsNode *right) const
 
2019
{
 
2020
    return new CTPNNe(left, right);
 
2021
}
 
2022
 
 
2023
/* ------------------------------------------------------------------------ */
 
2024
/*
 
2025
 *   'is in' operator 
 
2026
 */
 
2027
 
 
2028
/*
 
2029
 *   construct 
 
2030
 */
 
2031
CTPNIsInBase::CTPNIsInBase(CTcPrsNode *lhs, class CTPNArglist *rhs)
 
2032
    : CTPNBin(lhs, rhs)
 
2033
{
 
2034
    /* presume we don't have a constant value */
 
2035
    const_true_ = FALSE;
 
2036
}
 
2037
 
 
2038
/*
 
2039
 *   fold constants 
 
2040
 */
 
2041
CTcPrsNode *CTPNIsInBase::fold_binop()
 
2042
{
 
2043
    CTPNArglist *lst;
 
2044
    CTPNArg *arg;
 
2045
    CTPNArg *prv;
 
2046
    CTPNArg *nxt;
 
2047
    
 
2048
    /* if the left-hand side isn't constant, there's nothing to do */
 
2049
    if (!left_->is_const())
 
2050
        return this;
 
2051
 
 
2052
    /* the right side is always an argument list */
 
2053
    lst = (CTPNArglist *)right_;
 
2054
 
 
2055
    /* look for the value in the arguments */
 
2056
    for (prv = 0, arg = lst->get_arg_list_head() ; arg != 0 ; arg = nxt)
 
2057
    {
 
2058
        /* remember the next argument, in case we eliminate this one */
 
2059
        nxt = arg->get_next_arg();
 
2060
        
 
2061
        /* check to see if this argument is a constant */
 
2062
        if (arg->is_const())
 
2063
        {
 
2064
            /*
 
2065
             *   This one's a constant, so check to see if we found the
 
2066
             *   left side value.  If the left side equals this value,
 
2067
             *   note that we found the value.
 
2068
             */
 
2069
            if (left_->get_const_val()->is_equal_to(arg->get_const_val()))
 
2070
            {
 
2071
                /*
 
2072
                 *   The values are equal, so the result of the expression
 
2073
                 *   is definitely 'true'.  
 
2074
                 */
 
2075
                const_true_ = TRUE;
 
2076
 
 
2077
                /*
 
2078
                 *   Because the 'is in' operator only evaluates operands
 
2079
                 *   from the 'in' list until it finds one that matches,
 
2080
                 *   any remaining operands will simply never be
 
2081
                 *   evaluated.  We can thus discard the rest of the
 
2082
                 *   argument list.  
 
2083
                 */
 
2084
                nxt = 0;
 
2085
            }
 
2086
 
 
2087
            /*
 
2088
             *   We now know whether the left side equals this constant
 
2089
             *   list element.  This is never going to change because both
 
2090
             *   values are constant, so there's no point in making this
 
2091
             *   same comparison over and over again at run-time.  We can
 
2092
             *   thus eliminate this argument from the list.  
 
2093
             */
 
2094
            lst->set_argc(lst->get_argc() - 1);
 
2095
            if (prv == 0)
 
2096
                lst->set_arg_list_head(nxt);
 
2097
            else
 
2098
                prv->set_next_arg(nxt);
 
2099
        }
 
2100
    }
 
2101
 
 
2102
    /*
 
2103
     *   If the argument list is now completely empty, the result of the
 
2104
     *   expression is a constant.  
 
2105
     */
 
2106
    if (lst->get_arg_list_head() == 0)
 
2107
    {
 
2108
        /* set the left operand's value to our result */
 
2109
        left_->get_const_val()->set_bool(const_true_);
 
2110
        
 
2111
        /* return the constant value in place of the entire expression */
 
2112
        return left_;
 
2113
    }
 
2114
 
 
2115
    /* we're not a constant, to return myself unchanged */
 
2116
    return this;
 
2117
}
 
2118
 
 
2119
/* ------------------------------------------------------------------------ */
 
2120
/*
 
2121
 *   'not in' operator 
 
2122
 */
 
2123
 
 
2124
/*
 
2125
 *   construct 
 
2126
 */
 
2127
CTPNNotInBase::CTPNNotInBase(CTcPrsNode *lhs, class CTPNArglist *rhs)
 
2128
    : CTPNBin(lhs, rhs)
 
2129
{
 
2130
    /* presume we don't have a constant value */
 
2131
    const_false_ = FALSE;
 
2132
}
 
2133
 
 
2134
/*
 
2135
 *   fold constants for binary operator 
 
2136
 */
 
2137
CTcPrsNode *CTPNNotInBase::fold_binop()
 
2138
{
 
2139
    CTPNArglist *lst;
 
2140
    CTPNArg *arg;
 
2141
    CTPNArg *prv;
 
2142
    CTPNArg *nxt;
 
2143
 
 
2144
    /* if the left-hand side isn't constant, there's nothing to do */
 
2145
    if (!left_->is_const())
 
2146
        return this;
 
2147
 
 
2148
    /* the right side is always an argument list */
 
2149
    lst = (CTPNArglist *)right_;
 
2150
 
 
2151
    /* look for the value in the arguments */
 
2152
    for (prv = 0, arg = lst->get_arg_list_head() ; arg != 0 ; arg = nxt)
 
2153
    {
 
2154
        /* remember the next argument, in case we eliminate this one */
 
2155
        nxt = arg->get_next_arg();
 
2156
 
 
2157
        /* check to see if this argument is a constant */
 
2158
        if (arg->is_const())
 
2159
        {
 
2160
            /*
 
2161
             *   This one's a constant, so check to see if we found the
 
2162
             *   left side value.  If the left side equals this value,
 
2163
             *   note that we found the value.
 
2164
             */
 
2165
            if (left_->get_const_val()->is_equal_to(arg->get_const_val()))
 
2166
            {
 
2167
                /*
 
2168
                 *   The values are equal, so the result of the expression
 
2169
                 *   is definitely 'nil'.  
 
2170
                 */
 
2171
                const_false_ = TRUE;
 
2172
 
 
2173
                /*
 
2174
                 *   Because the 'not in' operator only evaluates operands
 
2175
                 *   from the 'in' list until it finds one that matches,
 
2176
                 *   any remaining operands will simply never be
 
2177
                 *   evaluated.  We can thus discard the rest of the
 
2178
                 *   argument list.  
 
2179
                 */
 
2180
                nxt = 0;
 
2181
            }
 
2182
 
 
2183
            /*
 
2184
             *   We now know whether the left side equals this constant
 
2185
             *   list element.  This is never going to change because both
 
2186
             *   values are constant, so there's no point in making this
 
2187
             *   same comparison over and over again at run-time.  We can
 
2188
             *   thus eliminate this argument from the list.  
 
2189
             */
 
2190
            lst->set_argc(lst->get_argc() - 1);
 
2191
            if (prv == 0)
 
2192
                lst->set_arg_list_head(nxt);
 
2193
            else
 
2194
                prv->set_next_arg(nxt);
 
2195
        }
 
2196
    }
 
2197
 
 
2198
    /*
 
2199
     *   If the argument list is now completely empty, the result of the
 
2200
     *   expression is a constant.  
 
2201
     */
 
2202
    if (lst->get_arg_list_head() == 0)
 
2203
    {
 
2204
        /* set the left operand's value to our result */
 
2205
        left_->get_const_val()->set_bool(!const_false_);
 
2206
        
 
2207
        /* return the constant value in place of the entire expression */
 
2208
        return left_;
 
2209
    }
 
2210
 
 
2211
    /* we're not a constant, to return myself unchanged */
 
2212
    return this;
 
2213
}
 
2214
 
 
2215
/* ------------------------------------------------------------------------ */
 
2216
/*
 
2217
 *   General arithmetic operator base class
 
2218
 */
 
2219
 
 
2220
/*
 
2221
 *   evaluate constant value 
 
2222
 */
 
2223
CTcPrsNode *CTcPrsOpArith::eval_constant(CTcPrsNode *left,
 
2224
                                         CTcPrsNode *right) const
 
2225
{
 
2226
    /* check for constants */
 
2227
    if (left->is_const() && right->is_const())
 
2228
    {
 
2229
        /* require that both values are integers or floats */
 
2230
        if (left->get_const_val()->get_type() == TC_CVT_FLOAT
 
2231
            || right->get_const_val()->get_type() == TC_CVT_FLOAT)
 
2232
        {
 
2233
            /* can't do it at compile time, but it's legal */
 
2234
            return 0;
 
2235
        }
 
2236
        else if (left->get_const_val()->get_type() != TC_CVT_INT
 
2237
            || right->get_const_val()->get_type() != TC_CVT_INT)
 
2238
        {
 
2239
            /* incompatible types - log an error */
 
2240
            G_tok->log_error(TCERR_CONST_BINARY_REQ_NUM,
 
2241
                             G_tok->get_op_text(get_op_tok()));
 
2242
            return 0;
 
2243
        }
 
2244
        else
 
2245
        {
 
2246
            long result;
 
2247
            
 
2248
            /* calculate the result */
 
2249
            result = calc_result(left->get_const_val()->get_val_int(),
 
2250
                                 right->get_const_val()->get_val_int());
 
2251
 
 
2252
            /* assign the result back to the left operand */
 
2253
            left->get_const_val()->set_int(result);
 
2254
        }
 
2255
 
 
2256
        /* return the updated left value */
 
2257
        return left;
 
2258
    }
 
2259
    else
 
2260
    {
 
2261
        /* 
 
2262
         *   one or the other is non-constant, so we can't fold the
 
2263
         *   expression - return null to so indicate 
 
2264
         */
 
2265
        return 0;
 
2266
    }
 
2267
}
 
2268
 
 
2269
/* ------------------------------------------------------------------------ */
 
2270
/*
 
2271
 *   bitwise OR operator 
 
2272
 */
 
2273
 
 
2274
/*
 
2275
 *   build the subtree 
 
2276
 */
 
2277
CTcPrsNode *CTcPrsOpBOr::build_tree(CTcPrsNode *left,
 
2278
                                    CTcPrsNode *right) const
 
2279
{
 
2280
    return new CTPNBOr(left, right);
 
2281
}
 
2282
 
 
2283
/* ------------------------------------------------------------------------ */
 
2284
/*
 
2285
 *   bitwise AND operator 
 
2286
 */
 
2287
 
 
2288
/*
 
2289
 *   build the subtree 
 
2290
 */
 
2291
CTcPrsNode *CTcPrsOpBAnd::build_tree(CTcPrsNode *left,
 
2292
                                     CTcPrsNode *right) const
 
2293
{
 
2294
    return new CTPNBAnd(left, right);
 
2295
}
 
2296
 
 
2297
/* ------------------------------------------------------------------------ */
 
2298
/*
 
2299
 *   bitwise XOR operator 
 
2300
 */
 
2301
 
 
2302
/*
 
2303
 *   build the subtree 
 
2304
 */
 
2305
CTcPrsNode *CTcPrsOpBXor::build_tree(CTcPrsNode *left,
 
2306
                                     CTcPrsNode *right) const
 
2307
{
 
2308
    return new CTPNBXor(left, right);
 
2309
}
 
2310
 
 
2311
 
 
2312
/* ------------------------------------------------------------------------ */
 
2313
/*
 
2314
 *   shift left operator 
 
2315
 */
 
2316
 
 
2317
/*
 
2318
 *   build the subtree 
 
2319
 */
 
2320
CTcPrsNode *CTcPrsOpShl::build_tree(CTcPrsNode *left,
 
2321
                                    CTcPrsNode *right) const
 
2322
{
 
2323
    return new CTPNShl(left, right);
 
2324
}
 
2325
 
 
2326
/* ------------------------------------------------------------------------ */
 
2327
/*
 
2328
 *   shift right operator 
 
2329
 */
 
2330
 
 
2331
/*
 
2332
 *   build the subtree 
 
2333
 */
 
2334
CTcPrsNode *CTcPrsOpShr::build_tree(CTcPrsNode *left,
 
2335
                                    CTcPrsNode *right) const
 
2336
{
 
2337
    return new CTPNShr(left, right);
 
2338
}
 
2339
 
 
2340
/* ------------------------------------------------------------------------ */
 
2341
/*
 
2342
 *   multiplication operator 
 
2343
 */
 
2344
 
 
2345
/*
 
2346
 *   build the subtree 
 
2347
 */
 
2348
CTcPrsNode *CTcPrsOpMul::build_tree(CTcPrsNode *left,
 
2349
                                    CTcPrsNode *right) const
 
2350
{
 
2351
    return new CTPNMul(left, right);
 
2352
}
 
2353
 
 
2354
/* ------------------------------------------------------------------------ */
 
2355
/*
 
2356
 *   division operator 
 
2357
 */
 
2358
 
 
2359
/*
 
2360
 *   build the subtree 
 
2361
 */
 
2362
CTcPrsNode *CTcPrsOpDiv::build_tree(CTcPrsNode *left,
 
2363
                                    CTcPrsNode *right) const
 
2364
{
 
2365
    return new CTPNDiv(left, right);
 
2366
}
 
2367
 
 
2368
/*
 
2369
 *   evaluate constant result 
 
2370
 */
 
2371
long CTcPrsOpDiv::calc_result(long a, long b) const
 
2372
{
 
2373
    /* check for divide-by-zero */
 
2374
    if (b == 0)
 
2375
    {
 
2376
        /* log a divide-by-zero error */
 
2377
        G_tok->log_error(TCERR_CONST_DIV_ZERO);
 
2378
 
 
2379
        /* the result isn't really meaningful, but return something anyway */
 
2380
        return 1;
 
2381
    }
 
2382
    else
 
2383
    {
 
2384
        /* return the result */
 
2385
        return a / b;
 
2386
    }
 
2387
}
 
2388
/* ------------------------------------------------------------------------ */
 
2389
/*
 
2390
 *   modulo operator 
 
2391
 */
 
2392
 
 
2393
/*
 
2394
 *   build the subtree 
 
2395
 */
 
2396
CTcPrsNode *CTcPrsOpMod::build_tree(CTcPrsNode *left,
 
2397
                                    CTcPrsNode *right) const
 
2398
{
 
2399
    return new CTPNMod(left, right);
 
2400
}
 
2401
 
 
2402
/*
 
2403
 *   evaluate constant result 
 
2404
 */
 
2405
long CTcPrsOpMod::calc_result(long a, long b) const
 
2406
{
 
2407
    /* check for divide-by-zero */
 
2408
    if (b == 0)
 
2409
    {
 
2410
        /* log a divide-by-zero error */
 
2411
        G_tok->log_error(TCERR_CONST_DIV_ZERO);
 
2412
 
 
2413
        /* the result isn't really meaningful, but return something anyway */
 
2414
        return 1;
 
2415
    }
 
2416
    else
 
2417
    {
 
2418
        /* return the result */
 
2419
        return a % b;
 
2420
    }
 
2421
}
 
2422
 
 
2423
/* ------------------------------------------------------------------------ */
 
2424
/*
 
2425
 *   subtraction operator 
 
2426
 */
 
2427
 
 
2428
/*
 
2429
 *   build the subtree 
 
2430
 */
 
2431
CTcPrsNode *CTcPrsOpSub::build_tree(CTcPrsNode *left,
 
2432
                                    CTcPrsNode *right) const
 
2433
{
 
2434
    return new CTPNSub(left, right);
 
2435
}
 
2436
 
 
2437
/*
 
2438
 *   evaluate a constant value 
 
2439
 */
 
2440
CTcPrsNode *CTcPrsOpSub::eval_constant(CTcPrsNode *left,
 
2441
                                       CTcPrsNode *right) const
 
2442
{
 
2443
    if (left->is_const() && right->is_const())
 
2444
    {
 
2445
        tc_constval_type_t typ1, typ2;
 
2446
 
 
2447
        /* get the types */
 
2448
        typ1 = left->get_const_val()->get_type();
 
2449
        typ2 = right->get_const_val()->get_type();
 
2450
 
 
2451
        /* check our types */
 
2452
        if (typ1 == TC_CVT_INT && typ2 == TC_CVT_INT)
 
2453
        {
 
2454
            /* calculate the integer sum */
 
2455
            left->get_const_val()
 
2456
                ->set_int(left->get_const_val()->get_val_int()
 
2457
                          - right->get_const_val()->get_val_int());
 
2458
        }
 
2459
        else if (typ1 == TC_CVT_FLOAT || typ2 == TC_CVT_FLOAT)
 
2460
        {
 
2461
            /* can't fold float constants at compile time */
 
2462
            return 0;
 
2463
        }
 
2464
        else if (typ1 == TC_CVT_LIST)
 
2465
        {
 
2466
            CTPNList *lst;
 
2467
 
 
2468
            /* get the original list */
 
2469
            lst = left->get_const_val()->get_val_list();
 
2470
 
 
2471
            /* 
 
2472
             *   if the right side is a list, remove each element of that
 
2473
             *   list from the list on the left; otherwise, remove the
 
2474
             *   value on the right from the list on the left 
 
2475
             */
 
2476
            if (typ2 == TC_CVT_LIST)
 
2477
            {
 
2478
                /* remove each element of the rhs list from the lhs list */
 
2479
                CTPNListEle *ele;
 
2480
 
 
2481
                /* scan the list, adding each element */
 
2482
                for (ele = right->get_const_val()
 
2483
                           ->get_val_list()->get_head() ;
 
2484
                     ele != 0 ; ele = ele->get_next())
 
2485
                {
 
2486
                    /* add this element's underlying expression value */
 
2487
                    lst->remove_element(ele->get_expr()->get_const_val());
 
2488
                }
 
2489
            }
 
2490
            else
 
2491
            {
 
2492
                /* remove the rhs value from the lhs list */
 
2493
                lst->remove_element(right->get_const_val());
 
2494
            }
 
2495
        }
 
2496
        else
 
2497
        {
 
2498
            /* these types are incompatible - log an error */
 
2499
            G_tok->log_error(TCERR_CONST_BINMINUS_INCOMPAT);
 
2500
            return 0;
 
2501
        }
 
2502
 
 
2503
        /* return the updated left side */
 
2504
        return left;
 
2505
    }
 
2506
    else
 
2507
    {
 
2508
        /* they're not constant - we can't generate a constant result */
 
2509
        return 0;
 
2510
    }
 
2511
}
 
2512
 
 
2513
/* ------------------------------------------------------------------------ */
 
2514
/*
 
2515
 *   addition operator 
 
2516
 */
 
2517
 
 
2518
/*
 
2519
 *   evaluate constant value 
 
2520
 */
 
2521
CTcPrsNode *CTcPrsOpAdd::eval_constant(CTcPrsNode *left,
 
2522
                                       CTcPrsNode *right) const
 
2523
{
 
2524
    /* check for constants */
 
2525
    if (left->is_const() && right->is_const())
 
2526
    {
 
2527
        tc_constval_type_t typ1, typ2;
 
2528
 
 
2529
        /* get the types */
 
2530
        typ1 = left->get_const_val()->get_type();
 
2531
        typ2 = right->get_const_val()->get_type();
 
2532
        
 
2533
        /* check our types */
 
2534
        if (typ1 == TC_CVT_INT && typ2 == TC_CVT_INT)
 
2535
        {
 
2536
            /* calculate the integer sum */
 
2537
            left->get_const_val()
 
2538
                ->set_int(left->get_const_val()->get_val_int()
 
2539
                          + right->get_const_val()->get_val_int());
 
2540
        }
 
2541
        else if (typ1 == TC_CVT_FLOAT || typ2 == TC_CVT_FLOAT)
 
2542
        {
 
2543
            /* can't fold float constants at compile time */
 
2544
            return 0;
 
2545
        }
 
2546
        else if (typ1 == TC_CVT_LIST)
 
2547
        {
 
2548
            CTPNList *lst;
 
2549
 
 
2550
            /* get the original list */
 
2551
            lst = left->get_const_val()->get_val_list();
 
2552
 
 
2553
            /* 
 
2554
             *   if the right side is also a list, concatenate it onto the
 
2555
             *   left list; otherwise, just add the right side as a new
 
2556
             *   element to the existing list 
 
2557
             */
 
2558
            if (typ2 == TC_CVT_LIST)
 
2559
            {
 
2560
                CTPNListEle *ele;
 
2561
                
 
2562
                /* scan the list, adding each element */
 
2563
                for (ele = right->get_const_val()
 
2564
                           ->get_val_list()->get_head() ;
 
2565
                     ele != 0 ; ele = ele->get_next())
 
2566
                {
 
2567
                    /* add this element's underlying expression value */
 
2568
                    lst->add_element(ele->get_expr());
 
2569
                }
 
2570
            }
 
2571
            else
 
2572
            {
 
2573
                /* add a new list element for the right side */
 
2574
                lst->add_element(right);
 
2575
            }
 
2576
 
 
2577
            /* 
 
2578
             *   this list is longer than the original(s); tell the parser
 
2579
             *   about it in case it's the longest list yet 
 
2580
             */
 
2581
            G_cg->note_list(lst->get_count());
 
2582
        }
 
2583
        else if (typ1 == TC_CVT_SSTR || typ2 == TC_CVT_SSTR)
 
2584
        {
 
2585
            char buf1[128];
 
2586
            char buf2[128];
 
2587
            const char *str1, *str2;
 
2588
            size_t len1, len2;
 
2589
            char *new_str;
 
2590
 
 
2591
            /* if the second value is a list, we can't make a constant */
 
2592
            if (typ2 == TC_CVT_LIST)
 
2593
                return 0;
 
2594
            
 
2595
            /* convert both values to strings if they're not already */
 
2596
            str1 = left->get_const_val()
 
2597
                   ->cvt_to_str(buf1, sizeof(buf1), &len1);
 
2598
            str2 = right->get_const_val()
 
2599
                   ->cvt_to_str(buf2, sizeof(buf2), &len2);
 
2600
 
 
2601
            /* 
 
2602
             *   if we couldn't convert one or the other, leave the result
 
2603
             *   non-constant 
 
2604
             */
 
2605
            if (str1 == 0 || str2 == 0)
 
2606
                return 0;
 
2607
            
 
2608
            /* 
 
2609
             *   allocate space in the node pool for the concatenation of
 
2610
             *   the two strings - if that fails, don't bother with the
 
2611
             *   concatenation 
 
2612
             */
 
2613
            new_str = (char *)G_prsmem->alloc(len1 + len2 + 1);
 
2614
            if (new_str == 0)
 
2615
                return 0;
 
2616
 
 
2617
            /* copy the two string values into the new space */
 
2618
            memcpy(new_str, str1, len1);
 
2619
            memcpy(new_str + len1, str2, len2);
 
2620
            new_str[len1 + len2] = '\0';
 
2621
 
 
2622
            /* set the new value in the left node */
 
2623
            left->get_const_val()->set_sstr(new_str, len1 + len2);
 
2624
        }
 
2625
        else
 
2626
        {
 
2627
            /* these types are incompatible - log an error */
 
2628
            G_tok->log_error(TCERR_CONST_BINPLUS_INCOMPAT);
 
2629
            return 0;
 
2630
        }
 
2631
 
 
2632
        /* return the updated left value */
 
2633
        return left;
 
2634
    }
 
2635
    else
 
2636
    {
 
2637
        /* the values aren't constant, so the result isn't constant */
 
2638
        return 0;
 
2639
    }
 
2640
}
 
2641
 
 
2642
 
 
2643
/*
 
2644
 *   build the subtree 
 
2645
 */
 
2646
CTcPrsNode *CTcPrsOpAdd::build_tree(CTcPrsNode *left,
 
2647
                                    CTcPrsNode *right) const
 
2648
{
 
2649
    return new CTPNAdd(left, right);
 
2650
}
 
2651
 
 
2652
/* ------------------------------------------------------------------------ */
 
2653
/*
 
2654
 *   Assignment Operator Group 
 
2655
 */
 
2656
 
 
2657
/*
 
2658
 *   parse an assignment expression 
 
2659
 */
 
2660
CTcPrsNode *CTcPrsOpAsi::parse() const
 
2661
{
 
2662
    CTcPrsNode *lhs;
 
2663
    CTcPrsNode *rhs;
 
2664
    tc_toktyp_t curtyp;
 
2665
    
 
2666
    /* start by parsing a conditional subexpression */
 
2667
    lhs = S_op_if.parse();
 
2668
    if (lhs == 0)
 
2669
        return 0;
 
2670
 
 
2671
    /* get the next operator */
 
2672
    curtyp = G_tok->cur();
 
2673
 
 
2674
    /* check to see if it's an assignment operator of some kind */
 
2675
    switch(curtyp)
 
2676
    {
 
2677
    case TOKT_PLUSEQ:
 
2678
    case TOKT_MINEQ:
 
2679
    case TOKT_TIMESEQ:
 
2680
    case TOKT_DIVEQ:
 
2681
    case TOKT_MODEQ:
 
2682
    case TOKT_ANDEQ:
 
2683
    case TOKT_OREQ:
 
2684
    case TOKT_XOREQ:
 
2685
    case TOKT_SHLEQ:
 
2686
    case TOKT_SHREQ:
 
2687
        /* it's an assignment operator - process it */
 
2688
        break;
 
2689
        
 
2690
    default:
 
2691
        /* check against the current simple-assignment operator */
 
2692
        if (curtyp == asi_op_)
 
2693
        {
 
2694
            /* it's an assignment operator - process it */
 
2695
            break;
 
2696
        }
 
2697
        else
 
2698
        {
 
2699
            /* 
 
2700
             *   it's not an assignment - return the original
 
2701
             *   subexpression with no further elaboration 
 
2702
             */
 
2703
            return lhs;
 
2704
        }
 
2705
    }
 
2706
 
 
2707
    /* check for a valid lvalue */
 
2708
    if (!lhs->check_lvalue())
 
2709
    {
 
2710
        /* log an error but continue parsing */
 
2711
        G_tok->log_error(TCERR_INVALID_LVALUE,
 
2712
                         G_tok->get_op_text(G_tok->cur()));
 
2713
    }
 
2714
 
 
2715
    /* skip the assignment operator */
 
2716
    G_tok->next();
 
2717
    
 
2718
    /* 
 
2719
     *   Recursively parse an assignment subexpression.  Do this
 
2720
     *   recursively rather than iteratively, because assignment operators
 
2721
     *   group right-to-left.  By recursively parsing an assignment, our
 
2722
     *   right-hand side will contain all remaining assignment expressions
 
2723
     *   incorporated into it.  
 
2724
     */
 
2725
    rhs = parse();
 
2726
    if (rhs == 0)
 
2727
        return 0;
 
2728
 
 
2729
    /* build and return the result based on the operator type */
 
2730
    switch(curtyp)
 
2731
    {
 
2732
    case TOKT_PLUSEQ:
 
2733
        lhs = new CTPNAddAsi(lhs, rhs);
 
2734
        break;
 
2735
        
 
2736
    case TOKT_MINEQ:
 
2737
        lhs = new CTPNSubAsi(lhs, rhs);
 
2738
        break;
 
2739
        
 
2740
    case TOKT_TIMESEQ:
 
2741
        lhs = new CTPNMulAsi(lhs, rhs);
 
2742
        break;
 
2743
 
 
2744
    case TOKT_DIVEQ:
 
2745
        lhs = new CTPNDivAsi(lhs, rhs);
 
2746
        break;
 
2747
 
 
2748
    case TOKT_MODEQ:
 
2749
        lhs = new CTPNModAsi(lhs, rhs);
 
2750
        break;
 
2751
 
 
2752
    case TOKT_ANDEQ:
 
2753
        lhs = new CTPNBAndAsi(lhs, rhs);
 
2754
        break;
 
2755
 
 
2756
    case TOKT_OREQ:
 
2757
        lhs = new CTPNBOrAsi(lhs, rhs);
 
2758
        break;
 
2759
 
 
2760
    case TOKT_XOREQ:
 
2761
        lhs = new CTPNBXorAsi(lhs, rhs);
 
2762
        break;
 
2763
 
 
2764
    case TOKT_SHLEQ:
 
2765
        lhs = new CTPNShlAsi(lhs, rhs);
 
2766
        break;
 
2767
 
 
2768
    case TOKT_SHREQ:
 
2769
        lhs = new CTPNShrAsi(lhs, rhs);
 
2770
        break;
 
2771
 
 
2772
    default:
 
2773
        /* plain assignment operator */
 
2774
        lhs = new CTPNAsi(lhs, rhs);
 
2775
        break;
 
2776
    }
 
2777
 
 
2778
    /* return the result */
 
2779
    return lhs;
 
2780
}
 
2781
 
 
2782
/* ------------------------------------------------------------------------ */
 
2783
/*
 
2784
 *   Tertiary Conditional Operator 
 
2785
 */
 
2786
 
 
2787
CTcPrsNode *CTcPrsOpIf::parse() const
 
2788
{
 
2789
    CTcPrsNode *first;
 
2790
    CTcPrsNode *second;
 
2791
    CTcPrsNode *third;
 
2792
 
 
2793
    /* parse the conditional part */
 
2794
    first = S_op_or.parse();
 
2795
    if (first == 0)
 
2796
        return 0;
 
2797
 
 
2798
    /* if we're not looking at the '?' operator, we're done */
 
2799
    if (G_tok->cur() != TOKT_QUESTION)
 
2800
        return first;
 
2801
 
 
2802
    /* skip the '?' operator */
 
2803
    G_tok->next();
 
2804
 
 
2805
    /* 
 
2806
     *   parse the second part, which can be any expression, including a
 
2807
     *   double-quoted string expression or a comma expression (even though
 
2808
     *   the '?:' operator overall has higher precedence than ',', we can't
 
2809
     *   steal away operands from a ',' before our ':' because that would
 
2810
     *   leave the ':' with nothing to go with) 
 
2811
     */
 
2812
    second = G_prs->parse_expr_or_dstr(TRUE);
 
2813
    if (second == 0)
 
2814
        return 0;
 
2815
    
 
2816
    /* make sure we have the ':' after the second part */
 
2817
    if (G_tok->cur() != TOKT_COLON)
 
2818
    {
 
2819
        /* 
 
2820
         *   log the error, but continue parsing as though we found the
 
2821
         *   ':' - if the ':' is simply missing, this will allow us to
 
2822
         *   recover and continue parsing the rest of the expression 
 
2823
         */
 
2824
        G_tok->log_error(TCERR_QUEST_WITHOUT_COLON);
 
2825
 
 
2826
        /* if we're at the end of file, there's no point in continuing */
 
2827
        if (G_tok->cur() == TOKT_EOF)
 
2828
            return 0;
 
2829
    }
 
2830
    
 
2831
    /* skip the ':' */
 
2832
    G_tok->next();
 
2833
    
 
2834
    /* 
 
2835
     *   parse the third part, which can be any other expression, including a
 
2836
     *   double-quoted string expression - but not a comma expression, since
 
2837
     *   we have higher precedence than ',' 
 
2838
     */
 
2839
    third = G_prs->parse_expr_or_dstr(FALSE);
 
2840
    if (third == 0)
 
2841
        return 0;
 
2842
        
 
2843
    /* 
 
2844
     *   If the condition is constant, we can choose the second or third
 
2845
     *   expression directly.  It doesn't matter whether or not the second
 
2846
     *   and/or third parts are themselves constant, because a constant
 
2847
     *   condition means that we'll always execute only one of the
 
2848
     *   alternatives.  
 
2849
     */
 
2850
    if (first->is_const())
 
2851
    {
 
2852
        /* 
 
2853
         *   evaluate the conditional value as a true/false value, and
 
2854
         *   return the second part's constant if the condition is true,
 
2855
         *   or the third part's constant if the condition is false 
 
2856
         */
 
2857
        return (first->get_const_val()->get_val_bool()
 
2858
                ? second : third);
 
2859
    }
 
2860
    else
 
2861
    {
 
2862
        /* it's not a constant value - return a new conditional node */
 
2863
        return new CTPNIf(first, second, third);
 
2864
    }
 
2865
}
 
2866
 
 
2867
/* ------------------------------------------------------------------------ */
 
2868
/*
 
2869
 *   Unary Operator Parser
 
2870
 */
 
2871
 
 
2872
CTcPrsNode *CTcPrsOpUnary::parse() const
 
2873
{
 
2874
    CTcPrsNode *sub;
 
2875
    tc_toktyp_t op;
 
2876
    
 
2877
    /* get the current token, which may be a prefix operator */
 
2878
    op = G_tok->cur();
 
2879
 
 
2880
    /* check for prefix operators */
 
2881
    switch(op)
 
2882
    {
 
2883
    case TOKT_AND:
 
2884
        /* skip the '&' */
 
2885
        G_tok->next();
 
2886
        
 
2887
        /* parse the address expression */
 
2888
        return parse_addr();
 
2889
 
 
2890
    case TOKT_NOT:
 
2891
    case TOKT_BNOT:
 
2892
    case TOKT_PLUS:
 
2893
    case TOKT_MINUS:
 
2894
    case TOKT_INC:
 
2895
    case TOKT_DEC:
 
2896
    case TOKT_DELETE:
 
2897
        /* skip the operator */
 
2898
        G_tok->next();
 
2899
 
 
2900
        /* 
 
2901
         *   recursively parse the unary expression to which to apply the
 
2902
         *   operator 
 
2903
         */
 
2904
        sub = parse();
 
2905
        if (sub == 0)
 
2906
            return 0;
 
2907
 
 
2908
        /* apply the operator */
 
2909
        switch(op)
 
2910
        {
 
2911
        case TOKT_NOT:
 
2912
            /* apply the NOT operator */
 
2913
            return parse_not(sub);
 
2914
 
 
2915
        case TOKT_BNOT:
 
2916
            /* apply the bitwise NOT operator */
 
2917
            return parse_bnot(sub);
 
2918
 
 
2919
        case TOKT_PLUS:
 
2920
            /* apply the unary positive operator */
 
2921
            return parse_pos(sub);
 
2922
 
 
2923
        case TOKT_MINUS:
 
2924
            /* apply the unary negation operator */
 
2925
            return parse_neg(sub);
 
2926
 
 
2927
        case TOKT_INC:
 
2928
            /* apply the pre-increment operator */
 
2929
            return parse_inc(TRUE, sub);
 
2930
 
 
2931
        case TOKT_DEC:
 
2932
            /* apply the pre-decrement operator */
 
2933
            return parse_dec(TRUE, sub);
 
2934
 
 
2935
        case TOKT_DELETE:
 
2936
            /* apply the deletion operator */
 
2937
            return parse_delete(sub);
 
2938
 
 
2939
        default:
 
2940
            break;
 
2941
        }
 
2942
 
 
2943
    default:
 
2944
        /* it's not a unary prefix operator - parse a postfix expression */
 
2945
        return parse_postfix(TRUE, TRUE);
 
2946
    }
 
2947
}
 
2948
 
 
2949
/*
 
2950
 *   parse a unary NOT expression 
 
2951
 */
 
2952
CTcPrsNode *CTcPrsOpUnary::parse_not(CTcPrsNode *subexpr)
 
2953
{
 
2954
    CTcPrsNode *ret;
 
2955
 
 
2956
    /* try folding a constant value */
 
2957
    ret = eval_const_not(subexpr);
 
2958
 
 
2959
    /* 
 
2960
     *   if we got a constant result, return it; otherwise, create a NOT
 
2961
     *   node for code generation 
 
2962
     */
 
2963
    if (ret != 0)
 
2964
        return ret;
 
2965
    else
 
2966
        return new CTPNNot(subexpr);
 
2967
}
 
2968
 
 
2969
/*
 
2970
 *   evaluate a constant NOT expression 
 
2971
 */
 
2972
CTcPrsNode *CTcPrsOpUnary::eval_const_not(CTcPrsNode *subexpr)
 
2973
{
 
2974
    /* 
 
2975
     *   if the underlying expression is a constant value, apply the
 
2976
     *   operator 
 
2977
     */
 
2978
    if (subexpr->is_const())
 
2979
    {
 
2980
        /* set the new value */
 
2981
        subexpr->get_const_val()
 
2982
            ->set_bool(!subexpr->get_const_val()->get_val_bool());
 
2983
 
 
2984
        /* return the modified constant value */
 
2985
        return subexpr;
 
2986
    }
 
2987
 
 
2988
    /* the result is not constant */
 
2989
    return 0;
 
2990
}
 
2991
 
 
2992
/*
 
2993
 *   parse a unary bitwise NOT expression 
 
2994
 */
 
2995
CTcPrsNode *CTcPrsOpUnary::parse_bnot(CTcPrsNode *subexpr)
 
2996
{
 
2997
    /* 
 
2998
     *   if the underlying expression is a constant value, apply the
 
2999
     *   operator 
 
3000
     */
 
3001
    if (subexpr->is_const())
 
3002
    {
 
3003
        /* we need an integer - log an error if it's not */
 
3004
        if (subexpr->get_const_val()->get_type() != TC_CVT_INT)
 
3005
            G_tok->log_error(TCERR_CONST_UNARY_REQ_NUM,
 
3006
                             G_tok->get_op_text(TOKT_BNOT));
 
3007
        else
 
3008
            subexpr->get_const_val()
 
3009
                ->set_int(~subexpr->get_const_val()->get_val_int());
 
3010
 
 
3011
        /* return the updated value */
 
3012
        return subexpr;
 
3013
    }
 
3014
    
 
3015
    /* create the bitwise NOT node */
 
3016
    return new CTPNBNot(subexpr);
 
3017
}
 
3018
 
 
3019
/*
 
3020
 *   parse a unary address expression 
 
3021
 */
 
3022
CTcPrsNode *CTcPrsOpUnary::parse_addr() const
 
3023
{
 
3024
    CTcPrsNode *subexpr;
 
3025
 
 
3026
    /* 
 
3027
     *   if it's a simple symbol, create an unresolved symbol node for it;
 
3028
     *   otherwise parse the entire expression 
 
3029
     */
 
3030
    if (G_tok->cur() == TOKT_SYM)
 
3031
    {
 
3032
        const CTcToken *tok;
 
3033
        
 
3034
        /* 
 
3035
         *   create an unresolved symbol node - we'll resolve this during
 
3036
         *   code generation 
 
3037
         */
 
3038
        tok = G_tok->getcur();
 
3039
        subexpr = new CTPNSym(tok->get_text(), tok->get_text_len());
 
3040
 
 
3041
        /*
 
3042
         *   The address operator implies that the symbol is a property, so
 
3043
         *   define the property symbol and mark it as referenced if we
 
3044
         *   haven't already.  
 
3045
         */
 
3046
        G_prs->get_global_symtab()->find_or_def_prop_explicit(
 
3047
            tok->get_text(), tok->get_text_len(), FALSE);
 
3048
 
 
3049
        /* skip the symbol */
 
3050
        G_tok->next();
 
3051
    }
 
3052
    else
 
3053
    {
 
3054
        /* parse an expression */
 
3055
        subexpr = parse();
 
3056
        if (subexpr == 0)
 
3057
            return 0;
 
3058
    }
 
3059
 
 
3060
    /*
 
3061
     *   The underlying expression must be something that has an address;
 
3062
     *   if it's not, it's an error.  
 
3063
     */
 
3064
    if (!subexpr->has_addr())
 
3065
    {
 
3066
        /* 
 
3067
         *   can't take the address of the subexpression - log an error,
 
3068
         *   but continue parsing the expression anyway 
 
3069
         */
 
3070
        G_tok->log_error(TCERR_NO_ADDRESS);
 
3071
    }
 
3072
    
 
3073
    /* create the address node */
 
3074
    return new CTPNAddr(subexpr);
 
3075
}
 
3076
 
 
3077
/*
 
3078
 *   parse a unary arithmetic positive expression 
 
3079
 */
 
3080
CTcPrsNode *CTcPrsOpUnary::parse_pos(CTcPrsNode *subexpr)
 
3081
{
 
3082
    /* 
 
3083
     *   if the underlying expression is a constant value, apply the
 
3084
     *   operator 
 
3085
     */
 
3086
    if (subexpr->is_const())
 
3087
    {
 
3088
        /* if it's a float, a unary '+' has no effect at all */
 
3089
        if (subexpr->get_const_val()->get_type() == TC_CVT_FLOAT)
 
3090
            return subexpr;
 
3091
 
 
3092
        /* we need an integer - log an error if it's not */
 
3093
        if (subexpr->get_const_val()->get_type() != TC_CVT_INT)
 
3094
            G_tok->log_error(TCERR_CONST_UNARY_REQ_NUM,
 
3095
                             G_tok->get_op_text(TOKT_PLUS));
 
3096
 
 
3097
        /* 
 
3098
         *   positive-ing a value doesn't change the value, so return the
 
3099
         *   original constant 
 
3100
         */
 
3101
        return subexpr;
 
3102
    }
 
3103
    
 
3104
    /* create the unary positive node */
 
3105
    return new CTPNPos(subexpr);
 
3106
}
 
3107
 
 
3108
/*
 
3109
 *   parse a unary arithmetic negation expression 
 
3110
 */
 
3111
CTcPrsNode *CTcPrsOpUnary::parse_neg(CTcPrsNode *subexpr)
 
3112
{
 
3113
    /* 
 
3114
     *   if the underlying expression is a constant value, apply the
 
3115
     *   operator 
 
3116
     */
 
3117
    if (subexpr->is_const())
 
3118
    {
 
3119
        /* we need an integer or float */
 
3120
        if (subexpr->get_const_val()->get_type() == TC_CVT_INT)
 
3121
        {
 
3122
            /* set the value negative in the subexpression */
 
3123
            subexpr->get_const_val()
 
3124
                ->set_int(-(subexpr->get_const_val()->get_val_int()));
 
3125
        }
 
3126
        else if (subexpr->get_const_val()->get_type() == TC_CVT_FLOAT)
 
3127
        {
 
3128
            CTcConstVal *cval = subexpr->get_const_val();
 
3129
            char *new_txt;
 
3130
            
 
3131
            /* allocate a buffer for a copy of the float text plus a '-' */
 
3132
            new_txt = (char *)G_prsmem->alloc(cval->get_val_float_len() + 1);
 
3133
 
 
3134
            /* insert the minus sign */
 
3135
            new_txt[0] = '-';
 
3136
 
 
3137
            /* add the original string */
 
3138
            memcpy(new_txt + 1, cval->get_val_float(),
 
3139
                   cval->get_val_float_len());
 
3140
 
 
3141
            /* update the subexpression's constant value to the new text */
 
3142
            cval->set_float(new_txt, cval->get_val_float_len() + 1);
 
3143
        }
 
3144
        else
 
3145
        {
 
3146
            /* log the error */
 
3147
            G_tok->log_error(TCERR_CONST_UNARY_REQ_NUM,
 
3148
                             G_tok->get_op_text(TOKT_MINUS));
 
3149
        }
 
3150
 
 
3151
        /* return the modified constant value */
 
3152
        return subexpr;
 
3153
    }
 
3154
 
 
3155
    /* create the unary negation node */
 
3156
    return new CTPNNeg(subexpr);
 
3157
}
 
3158
 
 
3159
 
 
3160
/*
 
3161
 *   parse a pre-increment expression 
 
3162
 */
 
3163
CTcPrsNode *CTcPrsOpUnary::parse_inc(int pre, CTcPrsNode *subexpr)
 
3164
{
 
3165
    /* require an lvalue */
 
3166
    if (!subexpr->check_lvalue())
 
3167
    {
 
3168
        /* log an error, but continue parsing */
 
3169
        G_tok->log_error(TCERR_INVALID_UNARY_LVALUE,
 
3170
                         G_tok->get_op_text(TOKT_INC));
 
3171
    }
 
3172
 
 
3173
    /* apply the increment operator */
 
3174
    if (pre)
 
3175
        return new CTPNPreInc(subexpr);
 
3176
    else
 
3177
        return new CTPNPostInc(subexpr);
 
3178
}
 
3179
 
 
3180
/*
 
3181
 *   parse a pre-decrement expression 
 
3182
 */
 
3183
CTcPrsNode *CTcPrsOpUnary::parse_dec(int pre, CTcPrsNode *subexpr)
 
3184
{
 
3185
    /* require an lvalue */
 
3186
    if (!subexpr->check_lvalue())
 
3187
    {
 
3188
        /* log an error, but continue parsing */
 
3189
        G_tok->log_error(TCERR_INVALID_UNARY_LVALUE,
 
3190
                         G_tok->get_op_text(TOKT_INC));
 
3191
    }
 
3192
 
 
3193
    /* apply the pre-increment operator */
 
3194
    if (pre)
 
3195
        return new CTPNPreDec(subexpr);
 
3196
    else
 
3197
        return new CTPNPostDec(subexpr);
 
3198
}
 
3199
 
 
3200
/*
 
3201
 *   parse a unary allocation expression 
 
3202
 */
 
3203
CTcPrsNode *CTcPrsOpUnary::parse_new(CTcPrsNode *subexpr, int is_transient)
 
3204
{
 
3205
    /* create the allocation node */
 
3206
    return new CTPNNew(subexpr, is_transient);
 
3207
}
 
3208
 
 
3209
/*
 
3210
 *   parse a unary deletion expression 
 
3211
 */
 
3212
CTcPrsNode *CTcPrsOpUnary::parse_delete(CTcPrsNode *subexpr)
 
3213
{
 
3214
    /* the delete operator is obsolete in TADS 3 - warn about it */
 
3215
    if (!G_prs->get_syntax_only())
 
3216
        G_tok->log_warning(TCERR_DELETE_OBSOLETE);
 
3217
 
 
3218
    /* create the deletion node */
 
3219
    return new CTPNDelete(subexpr);
 
3220
}
 
3221
 
 
3222
/*
 
3223
 *   parse a postfix expression 
 
3224
 */
 
3225
CTcPrsNode *CTcPrsOpUnary::parse_postfix(int allow_member_expr,
 
3226
                                         int allow_call_expr)
 
3227
{
 
3228
    CTcPrsNode *sub;
 
3229
    
 
3230
    /* parse a primary expression */
 
3231
    sub = parse_primary();
 
3232
    if (sub == 0)
 
3233
        return 0;
 
3234
 
 
3235
    /* keep going as long as we find postfix operators */
 
3236
    for (;;)
 
3237
    {
 
3238
        tc_toktyp_t op;
 
3239
        
 
3240
        /* check for a postfix operator */
 
3241
        op = G_tok->cur();
 
3242
        switch(op)
 
3243
        {
 
3244
        case TOKT_LPAR:
 
3245
            /* left paren - function or method call */
 
3246
            if (allow_call_expr)
 
3247
            {
 
3248
                /* parse the call expression */
 
3249
                sub = parse_call(sub);
 
3250
            }
 
3251
            else
 
3252
            {
 
3253
                /* call expressions aren't allowed - stop here */
 
3254
                return sub;
 
3255
            }
 
3256
            break;
 
3257
 
 
3258
        case TOKT_LBRACK:
 
3259
            /* left square bracket - subscript */
 
3260
            sub = parse_subscript(sub);
 
3261
            break;
 
3262
 
 
3263
        case TOKT_DOT:
 
3264
            /* 
 
3265
             *   Dot - member selection.  If a member expression is allowed
 
3266
             *   by the caller, parse it; otherwise, just return the
 
3267
             *   expression up to this point.  
 
3268
             */
 
3269
            if (allow_member_expr)
 
3270
            {
 
3271
                /* 
 
3272
                 *   it's allowed - parse it and continue to look for other
 
3273
                 *   postfix expressions following the member expression 
 
3274
                 */
 
3275
                sub = parse_member(sub);
 
3276
            }
 
3277
            else
 
3278
            {
 
3279
                /* 
 
3280
                 *   member expressions aren't allowed - stop here,
 
3281
                 *   returning the expression up to this point 
 
3282
                 */
 
3283
                return sub;
 
3284
            }
 
3285
            break;
 
3286
 
 
3287
        case TOKT_INC:
 
3288
            /* post-increment */
 
3289
            G_tok->next();
 
3290
            sub = parse_inc(FALSE, sub);
 
3291
            break;
 
3292
 
 
3293
        case TOKT_DEC:
 
3294
            /* post-decrement */
 
3295
            G_tok->next();
 
3296
            sub = parse_dec(FALSE, sub);
 
3297
            break;
 
3298
            
 
3299
        default:
 
3300
            /* it's not a postfix operator - return the result */
 
3301
            return sub;
 
3302
        }
 
3303
 
 
3304
        /* if the last parse failed, return failure */
 
3305
        if (sub == 0)
 
3306
            return 0;
 
3307
    }
 
3308
}
 
3309
 
 
3310
/*
 
3311
 *   Parse an argument list 
 
3312
 */
 
3313
CTPNArglist *CTcPrsOpUnary::parse_arg_list()
 
3314
{
 
3315
    int argc;
 
3316
    CTPNArg *arg_head;
 
3317
 
 
3318
    /* skip the open paren */
 
3319
    G_tok->next();
 
3320
 
 
3321
    /* keep going until we find the close paren */
 
3322
    for (argc = 0, arg_head = 0 ;; )
 
3323
    {
 
3324
        CTcPrsNode *expr;
 
3325
        CTPNArg *arg_cur;
 
3326
 
 
3327
        /* if this is the close paren, we're done */
 
3328
        if (G_tok->cur() == TOKT_RPAR)
 
3329
            break;
 
3330
 
 
3331
        /* parse this actual parameter expression */
 
3332
        expr = S_op_asi.parse();
 
3333
        if (expr == 0)
 
3334
            return 0;
 
3335
 
 
3336
        /* count the argument */
 
3337
        ++argc;
 
3338
 
 
3339
        /* create a new argument node */
 
3340
        arg_cur = new CTPNArg(expr);
 
3341
 
 
3342
        /* check to see if the argument is followed by an ellipsis */
 
3343
        if (G_tok->cur() == TOKT_ELLIPSIS)
 
3344
        {
 
3345
            /* skip the ellipsis */
 
3346
            G_tok->next();
 
3347
 
 
3348
            /* mark the argument as a list-to-varargs parameter */
 
3349
            arg_cur->set_varargs(TRUE);
 
3350
        }
 
3351
 
 
3352
        /* 
 
3353
         *   Link the new node in at the beginning of our list - this will
 
3354
         *   ensure that the list is built in reverse order, which is the
 
3355
         *   order in which we push the arguments onto the stack.
 
3356
         */
 
3357
        arg_cur->set_next_arg(arg_head);
 
3358
        arg_head = arg_cur;
 
3359
 
 
3360
        /* we need to be looking at a comma, right paren, or ellipsis */
 
3361
        if (G_tok->cur() == TOKT_RPAR)
 
3362
        {
 
3363
            /* that's the end of the list */
 
3364
            break;
 
3365
        }
 
3366
        else if (G_tok->cur() == TOKT_COMMA)
 
3367
        {
 
3368
            /* skip the comma and parse the next argument */
 
3369
            G_tok->next();
 
3370
        }
 
3371
        else
 
3372
        {
 
3373
            /* 
 
3374
             *   If we're at the end of the file, there's no point
 
3375
             *   proceding, so return failure.  If we've reached something
 
3376
             *   that looks like a statement separator (semicolon, curly
 
3377
             *   brace), also return failure, since the problem is clearly
 
3378
             *   a missing right paren.  Otherwise, assume that a comma
 
3379
             *   was missing and continue as though we have another
 
3380
             *   argument.
 
3381
             */
 
3382
            switch(G_tok->cur())
 
3383
            {
 
3384
            default:
 
3385
                /* log an error */
 
3386
                G_tok->log_error_curtok(TCERR_EXPECTED_ARG_COMMA);
 
3387
 
 
3388
                /* 
 
3389
                 *   if we're at the end of file, return what we have so
 
3390
                 *   far; otherwise continue, assuming that they merely
 
3391
                 *   left out a comma between two argument expressions 
 
3392
                 */
 
3393
                if (G_tok->cur() == TOKT_EOF)
 
3394
                    return new CTPNArglist(argc, arg_head);
 
3395
                break;
 
3396
 
 
3397
            case TOKT_SEM:
 
3398
            case TOKT_LBRACE:
 
3399
            case TOKT_RBRACE:
 
3400
            case TOKT_DSTR_MID:
 
3401
            case TOKT_DSTR_END:
 
3402
                /* 
 
3403
                 *   we're apparently at the end of the statement; flag
 
3404
                 *   the error as a missing right paren, and return what
 
3405
                 *   we have so far 
 
3406
                 */
 
3407
                G_tok->log_error_curtok(TCERR_EXPECTED_ARG_RPAR);
 
3408
                return new CTPNArglist(argc, arg_head);
 
3409
            }
 
3410
        }
 
3411
    }
 
3412
 
 
3413
    /* skip the closing paren */
 
3414
    G_tok->next();
 
3415
 
 
3416
    /* create and return the argument list descriptor */
 
3417
    return new CTPNArglist(argc, arg_head);
 
3418
}
 
3419
 
 
3420
/*
 
3421
 *   Parse a function call expression
 
3422
 */
 
3423
CTcPrsNode *CTcPrsOpUnary::parse_call(CTcPrsNode *lhs)
 
3424
{
 
3425
    CTPNArglist *arglist;
 
3426
    
 
3427
    /* parse the argument list */
 
3428
    arglist = parse_arg_list();
 
3429
    if (arglist == 0)
 
3430
        return 0;
 
3431
 
 
3432
    /* build and return the function call node */
 
3433
    return new CTPNCall(lhs, arglist);
 
3434
}
 
3435
 
 
3436
/*
 
3437
 *   Parse a subscript expression 
 
3438
 */
 
3439
CTcPrsNode *CTcPrsOpUnary::parse_subscript(CTcPrsNode *lhs)
 
3440
{
 
3441
    CTcPrsNode *subscript;
 
3442
    CTcPrsNode *cval;
 
3443
    
 
3444
    /* skip the '[' */
 
3445
    G_tok->next();
 
3446
 
 
3447
    /* parse the expression within the brackets */
 
3448
    subscript = S_op_comma.parse();
 
3449
    if (subscript == 0)
 
3450
        return 0;
 
3451
 
 
3452
    /* check for the matching ']' */
 
3453
    if (G_tok->cur() == TOKT_RBRACK)
 
3454
    {
 
3455
        /* got it - skip it */
 
3456
        G_tok->next();
 
3457
    }
 
3458
    else
 
3459
    {
 
3460
        /* log an error, and forgive the missing ']' */
 
3461
        G_tok->log_error_curtok(TCERR_EXPECTED_SUB_RBRACK);
 
3462
    }
 
3463
 
 
3464
    /* try folding constants */
 
3465
    cval = eval_const_subscript(lhs, subscript);
 
3466
 
 
3467
    /* 
 
3468
     *   if that worked, use the result; otherwise, build an expression
 
3469
     *   node to generate code for the subscript operator
 
3470
     */
 
3471
    if (cval != 0)
 
3472
        return cval;
 
3473
    else
 
3474
        return new CTPNSubscript(lhs, subscript);
 
3475
}
 
3476
 
 
3477
/*
 
3478
 *   Evaluate a constant subscript value 
 
3479
 */
 
3480
CTcPrsNode *CTcPrsOpUnary::eval_const_subscript(CTcPrsNode *lhs,
 
3481
                                                CTcPrsNode *subscript)
 
3482
{
 
3483
    /* 
 
3484
     *   if we're subscripting a constant list by a constant index value,
 
3485
     *   we can evaluate a constant result 
 
3486
     */
 
3487
    if (lhs->is_const() && subscript->is_const())
 
3488
    {
 
3489
        long idx;
 
3490
        CTcPrsNode *ele;
 
3491
 
 
3492
        /* 
 
3493
         *   make sure the index value is an integer and the value being
 
3494
         *   indexed is a list; if either type is wrong, the indexing
 
3495
         *   expression is invalid 
 
3496
         */
 
3497
        if (subscript->get_const_val()->get_type() != TC_CVT_INT)
 
3498
        {
 
3499
            /* we can't use a non-integer expression as a list index */
 
3500
            G_tok->log_error(TCERR_CONST_IDX_NOT_INT);
 
3501
        }
 
3502
        else if (lhs->get_const_val()->get_type() != TC_CVT_LIST)
 
3503
        {
 
3504
            /* we can't index any constant type other than list */
 
3505
            G_tok->log_error(TCERR_CONST_IDX_INV_TYPE);
 
3506
        }
 
3507
        else
 
3508
        {
 
3509
            /* get the index value */
 
3510
            idx = subscript->get_const_val()->get_val_int();
 
3511
 
 
3512
            /* ask the list to look up the item by index */
 
3513
            ele = lhs->get_const_val()->get_val_list()->get_const_ele(idx);
 
3514
 
 
3515
            /* if we got a valid result, return it */
 
3516
            if (ele != 0)
 
3517
                return ele;
 
3518
        }
 
3519
    }
 
3520
 
 
3521
    /* we couldn't fold it to a constant expression */
 
3522
    return 0;
 
3523
}
 
3524
 
 
3525
/*
 
3526
 *   Parse a member selection ('.') expression.  If no '.' is actually
 
3527
 *   present, then '.targetprop' is implied.  
 
3528
 */
 
3529
CTcPrsNode *CTcPrsOpUnary::parse_member(CTcPrsNode *lhs)
 
3530
{
 
3531
    CTcPrsNode *rhs;
 
3532
    int rhs_is_expr;
 
3533
 
 
3534
    /*
 
3535
     *   If a '.' is present, skip it; otherwise, '.targetprop' is implied. 
 
3536
     */
 
3537
    if (G_tok->cur() == TOKT_DOT)
 
3538
    {
 
3539
        /* we have an explicit property expression - skip the '.' */
 
3540
        G_tok->next();
 
3541
 
 
3542
        /* assume the property will be a simple symbol, not an expression */
 
3543
        rhs_is_expr = FALSE;
 
3544
 
 
3545
        /* we could have a symbol or a parenthesized expression */
 
3546
        switch(G_tok->cur())
 
3547
        {
 
3548
        case TOKT_SYM:
 
3549
            /* 
 
3550
             *   It's a simple property name - create a symbol node.  Note
 
3551
             *   that we must explicitly create an unresolved symbol node,
 
3552
             *   since we want to ignore any local variable with the same
 
3553
             *   name and look only in the global symbol table for a
 
3554
             *   property; we must hence defer resolving the symbol until
 
3555
             *   code generation.  
 
3556
             */
 
3557
            rhs = new CTPNSym(G_tok->getcur()->get_text(),
 
3558
                              G_tok->getcur()->get_text_len());
 
3559
            
 
3560
            /* skip the symbol token */
 
3561
            G_tok->next();
 
3562
            
 
3563
            /* proceed to check for an argument list */
 
3564
            break;
 
3565
            
 
3566
        case TOKT_LPAR:
 
3567
            /* 
 
3568
             *   It's a parenthesized expression - parse it.  First, skip
 
3569
             *   the open paren - we don't want the sub-expression to go
 
3570
             *   beyond the close paren (if we didn't skip the open paren,
 
3571
             *   the open paren would be part of the sub-expression, hence
 
3572
             *   any postfix expression after the close paren would be
 
3573
             *   considered part of the sub-expression; this would be
 
3574
             *   invalid, since we might want to find a postfix actual
 
3575
             *   parameter list).  
 
3576
             */
 
3577
            G_tok->next();
 
3578
            
 
3579
            /* remember that it's an expression */
 
3580
            rhs_is_expr = TRUE;
 
3581
            
 
3582
            /* parse the sub-expression */
 
3583
            rhs = S_op_comma.parse();
 
3584
            if (rhs == 0)
 
3585
                return 0;
 
3586
            
 
3587
            /* require the close paren */
 
3588
            if (G_tok->cur() == TOKT_RPAR)
 
3589
            {
 
3590
                /* skip the closing paren */
 
3591
                G_tok->next();
 
3592
            }
 
3593
            else
 
3594
            {
 
3595
                /* log the error */
 
3596
                G_tok->log_error_curtok(TCERR_EXPR_MISSING_RPAR);
 
3597
                
 
3598
                /* 
 
3599
                 *   if we're at a semicolon or end of file, we must be on
 
3600
                 *   to the next statement - stop trying to parse this one
 
3601
                 *   if so; otherwise, continue on the assumption that they
 
3602
                 *   merely left out the close paren and what follows is
 
3603
                 *   more expression for us to process 
 
3604
                 */
 
3605
                if (G_tok->cur() == TOKT_SEM || G_tok->cur() == TOKT_EOF)
 
3606
                    return lhs;
 
3607
            }
 
3608
            break;
 
3609
            
 
3610
        case TOKT_TARGETPROP:
 
3611
            /* 
 
3612
             *   it's an unparenthesized "targetprop" expression - skip the
 
3613
             *   keyword 
 
3614
             */
 
3615
            G_tok->next();
 
3616
            
 
3617
            /* 
 
3618
             *   the property value is the result of evaluating
 
3619
             *   "targetprop", which is an expression 
 
3620
             */
 
3621
            rhs = new CTPNTargetprop();
 
3622
            rhs_is_expr = TRUE;
 
3623
 
 
3624
            /* note the reference to the extended method context */
 
3625
            G_prs->set_full_method_ctx_referenced(TRUE);
 
3626
 
 
3627
            /* go parse the rest */
 
3628
            break;
 
3629
            
 
3630
        default:
 
3631
            /* anything else is invalid - log an error */
 
3632
            G_tok->log_error_curtok(TCERR_INVALID_PROP_EXPR);
 
3633
            
 
3634
            /* skip the errant token so we don't loop on it */
 
3635
            G_tok->next();
 
3636
            
 
3637
            /* return what we have so far */
 
3638
            return lhs;
 
3639
        }
 
3640
    }
 
3641
    else
 
3642
    {
 
3643
        /* there's no property specified, so '.targetprop' is implied */
 
3644
        rhs = new CTPNTargetprop();
 
3645
        rhs_is_expr = TRUE;
 
3646
 
 
3647
        /* 
 
3648
         *   note the reference to the full method context (since
 
3649
         *   'targetprop' is part of the extended method context beyond
 
3650
         *   'self') 
 
3651
         */
 
3652
        G_prs->set_full_method_ctx_referenced(TRUE);
 
3653
    }
 
3654
        
 
3655
    /* check for an argument list */
 
3656
    if (G_tok->cur() == TOKT_LPAR)
 
3657
    {
 
3658
        CTPNArglist *arglist;
 
3659
        
 
3660
        /* parse the argument list */
 
3661
        arglist = parse_arg_list();
 
3662
        if (arglist == 0)
 
3663
            return 0;
 
3664
 
 
3665
        /* create and return a member-with-arguments node */
 
3666
        return new CTPNMemArg(lhs, rhs, rhs_is_expr, arglist);
 
3667
    }
 
3668
    else
 
3669
    {
 
3670
        /* 
 
3671
         *   there's no argument list - create and return a simple member
 
3672
         *   node 
 
3673
         */
 
3674
        return new CTPNMember(lhs, rhs, rhs_is_expr);
 
3675
    }
 
3676
}
 
3677
 
 
3678
/*
 
3679
 *   Parse a double-quoted string with an embedded expression.  We treat
 
3680
 *   this type of expression as though it were a comma expression. 
 
3681
 */
 
3682
CTcPrsNode *CTcPrsOpUnary::parse_dstr_embed()
 
3683
{
 
3684
    CTcPrsNode *cur;
 
3685
    
 
3686
    /* 
 
3687
     *   First, create a node for the initial part of the string.  This is
 
3688
     *   just an ordinary double-quoted string node. If the initial part of
 
3689
     *   the string is zero-length, don't create an initial node at all,
 
3690
     *   since this would just generate do-nothing code.  
 
3691
     */
 
3692
    if (G_tok->getcur()->get_text_len() != 0)
 
3693
    {
 
3694
        /* create the node for the initial part of the string */
 
3695
        cur = new CTPNDstr(G_tok->getcur()->get_text(),
 
3696
                           G_tok->getcur()->get_text_len());
 
3697
    }
 
3698
    else
 
3699
    {
 
3700
        /* 
 
3701
         *   the initial part of the string is empty, so we don't need a node
 
3702
         *   for this portion 
 
3703
         */
 
3704
        cur = 0;
 
3705
    }
 
3706
 
 
3707
    /* skip the dstring */
 
3708
    G_tok->next();
 
3709
 
 
3710
    /* keep going until we find the end of the string */
 
3711
    for (;;)
 
3712
    {
 
3713
        CTcPrsNode *sub;
 
3714
        int done;
 
3715
 
 
3716
        /* 
 
3717
         *   parse the embedded expression, which can be any ordinary
 
3718
         *   expression type, including a double-quoted string expression 
 
3719
         */
 
3720
        sub = G_prs->parse_expr_or_dstr(TRUE);
 
3721
        if (sub == 0)
 
3722
            return 0;
 
3723
 
 
3724
        /* build an embedding node for the expression */
 
3725
        sub = new CTPNDstrEmbed(sub);
 
3726
        
 
3727
 
 
3728
        /* 
 
3729
         *   after the expression, we must find either another string
 
3730
         *   segment with another embedded expression following, or the
 
3731
         *   final string segment; anything else is an error 
 
3732
         */
 
3733
    do_next_segment:
 
3734
        switch(G_tok->cur())
 
3735
        {
 
3736
        case TOKT_DSTR_MID:
 
3737
            /* 
 
3738
             *   It's a string with yet another embedded expression.
 
3739
             *   Simply continue to the next segment. 
 
3740
             */
 
3741
            done = FALSE;
 
3742
            break;
 
3743
 
 
3744
        case TOKT_DSTR_END:
 
3745
            /* 
 
3746
             *   It's the last segment of the string.  We can stop after
 
3747
             *   processing this segment. 
 
3748
             */
 
3749
            done = TRUE;
 
3750
            break;
 
3751
 
 
3752
        default:
 
3753
            /* 
 
3754
             *   anything else is invalid - we must find the end of the
 
3755
             *   string.  Log an error. 
 
3756
             */
 
3757
            G_tok->log_error_curtok(TCERR_EXPECTED_DSTR_CONT);
 
3758
 
 
3759
            /* 
 
3760
             *   if this is the end of the file, there's no point in
 
3761
             *   continuing; return what we have so far 
 
3762
             */
 
3763
            if (G_tok->cur() == TOKT_EOF)
 
3764
                return (cur != 0 ? cur : sub);
 
3765
 
 
3766
            /* tell the tokenizer to assume the missing '>>' */
 
3767
            G_tok->assume_missing_dstr_cont();
 
3768
 
 
3769
            /* go back and try it again */
 
3770
            goto do_next_segment;
 
3771
        }
 
3772
 
 
3773
        /*
 
3774
         *   Build a node representing everything so far: do this by
 
3775
         *   combining the sub-expression with everything preceding, using a
 
3776
         *   comma operator.  This isn't necessary if there's nothing
 
3777
         *   preceding the sub-expression, since this means the
 
3778
         *   sub-expression itself is everything so far.  
 
3779
         */
 
3780
        if (cur != 0)
 
3781
            cur = new CTPNComma(cur, sub);
 
3782
        else
 
3783
            cur = sub;
 
3784
 
 
3785
        /*
 
3786
         *   Combine the part so far with the next string segment, using a
 
3787
         *   comma operator.  If the next string segment is empty, there's no
 
3788
         *   need to add anything for it.  
 
3789
         */
 
3790
        if (G_tok->getcur()->get_text_len() != 0)
 
3791
        {
 
3792
            CTcPrsNode *newstr;
 
3793
 
 
3794
            /* create a node for the new string segment */
 
3795
            newstr = new CTPNDstr(G_tok->getcur()->get_text(),
 
3796
                                  G_tok->getcur()->get_text_len());
 
3797
 
 
3798
            /* combine it into the part so far with a comma operator */
 
3799
            cur = new CTPNComma(cur, newstr);
 
3800
        }
 
3801
 
 
3802
        /* skip this string part */
 
3803
        G_tok->next();
 
3804
 
 
3805
        /* if that was the last segment, this is the final result */
 
3806
        if (done)
 
3807
            return cur;
 
3808
    }
 
3809
}
 
3810
 
 
3811
/*
 
3812
 *   Parse a primary expression 
 
3813
 */
 
3814
CTcPrsNode *CTcPrsOpUnary::parse_primary()
 
3815
{
 
3816
    CTcPrsNode *sub;
 
3817
    CTcConstVal cval;
 
3818
    
 
3819
    /* keep going until we find something interesting */
 
3820
    for (;;)
 
3821
    {
 
3822
        /* determine what we have */
 
3823
        switch(G_tok->cur())
 
3824
        {
 
3825
        case TOKT_LBRACE:
 
3826
            /* short form of anonymous function */
 
3827
            return parse_anon_func(TRUE);
 
3828
 
 
3829
        case TOKT_FUNCTION:
 
3830
            /* anonymous function requires 'new' */
 
3831
            G_tok->log_error(TCERR_ANON_FUNC_REQ_NEW);
 
3832
            
 
3833
            /* 
 
3834
             *   parse it as an anonymous function anyway, even though the
 
3835
             *   syntax isn't quite correct - the rest of it might still
 
3836
             *   be okay, so we can at least continue parsing from here to
 
3837
             *   find out 
 
3838
             */
 
3839
            return parse_anon_func(FALSE);
 
3840
 
 
3841
        case TOKT_NEW:
 
3842
            /* skip the operator and check for 'function' */
 
3843
            if (G_tok->next() == TOKT_FUNCTION)
 
3844
            {
 
3845
                /* it's an anonymous function definition - go parse it */
 
3846
                sub = parse_anon_func(FALSE);
 
3847
            }
 
3848
            else
 
3849
            {
 
3850
                int trans;
 
3851
                
 
3852
                /* check for the 'transient' keyword */
 
3853
                trans = (G_tok->cur() == TOKT_TRANSIENT);
 
3854
                if (trans)
 
3855
                    G_tok->next();
 
3856
                
 
3857
                /* 
 
3858
                 *   it's an ordinary 'new' expression - parse the primary
 
3859
                 *   making up the name 
 
3860
                 */
 
3861
                sub = parse_primary();
 
3862
 
 
3863
                /* if there's an argument list, parse the argument list */
 
3864
                if (G_tok->cur() == TOKT_LPAR)
 
3865
                    sub = parse_call(sub);
 
3866
 
 
3867
                /* create the 'new' node */
 
3868
                sub = parse_new(sub, trans);
 
3869
            }
 
3870
            return sub;
 
3871
 
 
3872
        case TOKT_LPAR:
 
3873
            /* left parenthesis - skip it */
 
3874
            G_tok->next();
 
3875
            
 
3876
            /* parse the expression */
 
3877
            sub = S_op_comma.parse();
 
3878
            if (sub == 0)
 
3879
                return 0;
 
3880
            
 
3881
            /* require the matching right parenthesis */
 
3882
            if (G_tok->cur() == TOKT_RPAR)
 
3883
            {
 
3884
                /* skip the right paren */
 
3885
                G_tok->next();
 
3886
            }
 
3887
            else
 
3888
            {
 
3889
                /* 
 
3890
                 *   log an error; assume that the paren is simply
 
3891
                 *   missing, so continue with our work 
 
3892
                 */
 
3893
                G_tok->log_error_curtok(TCERR_EXPR_MISSING_RPAR);
 
3894
            }
 
3895
 
 
3896
            /* return the parenthesized expression */
 
3897
            return sub;
 
3898
 
 
3899
        case TOKT_NIL:
 
3900
            /* nil - the result is the constant value nil */
 
3901
            cval.set_nil();
 
3902
            
 
3903
        return_constant:
 
3904
            /* skip the token */
 
3905
            G_tok->next();
 
3906
            
 
3907
            /* return a constant node */
 
3908
            return new CTPNConst(&cval);
 
3909
            
 
3910
        case TOKT_TRUE:
 
3911
            /* true - the result is the constant value true */
 
3912
            cval.set_true();
 
3913
            goto return_constant;
 
3914
            
 
3915
        case TOKT_INT:
 
3916
            /* integer - the result is a constant integer value */
 
3917
            cval.set_int(G_tok->getcur()->get_int_val());
 
3918
            goto return_constant;
 
3919
 
 
3920
        case TOKT_FLOAT:
 
3921
            /* floating point number */
 
3922
            cval.set_float(G_tok->getcur()->get_text(),
 
3923
                           G_tok->getcur()->get_text_len());
 
3924
            goto return_constant;
 
3925
            
 
3926
        case TOKT_SSTR:
 
3927
        handle_sstring:
 
3928
            /* single-quoted string - the result is a constant string value */
 
3929
            cval.set_sstr(G_tok->getcur()->get_text(),
 
3930
                          G_tok->getcur()->get_text_len());
 
3931
            goto return_constant;
 
3932
            
 
3933
        case TOKT_DSTR:
 
3934
            /* 
 
3935
             *   if we're in preprocessor expression mode, treat this the
 
3936
             *   same as a single-quoted string 
 
3937
             */
 
3938
            if (G_prs->get_pp_expr_mode())
 
3939
                goto handle_sstring;
 
3940
 
 
3941
            /* 
 
3942
             *   a string implicitly references 'self', because we could run
 
3943
             *   through the default output method on the current object 
 
3944
             */
 
3945
            G_prs->set_self_referenced(TRUE);
 
3946
            
 
3947
            /* build a double-quoted string node */
 
3948
            sub = new CTPNDstr(G_tok->getcur()->get_text(),
 
3949
                               G_tok->getcur()->get_text_len());
 
3950
            
 
3951
            /* skip the string */
 
3952
            G_tok->next();
 
3953
            
 
3954
            /* return the new node */
 
3955
            return sub;
 
3956
            
 
3957
        case TOKT_DSTR_START:
 
3958
            /* a string implicitly references 'self' */
 
3959
            G_prs->set_self_referenced(TRUE);
 
3960
 
 
3961
            /* parse the embedding expression */
 
3962
            return parse_dstr_embed();
 
3963
            
 
3964
        case TOKT_LBRACK:
 
3965
            /* parse the list */
 
3966
            return parse_list();
 
3967
            
 
3968
        case TOKT_SYM:
 
3969
            /* 
 
3970
             *   symbol - the meaning of the symbol is not yet known, so
 
3971
             *   create an unresolved symbol node 
 
3972
             */
 
3973
            sub = G_prs->create_sym_node(G_tok->getcur()->get_text(),
 
3974
                                         G_tok->getcur()->get_text_len());
 
3975
            
 
3976
            /* skip the symbol token */
 
3977
            G_tok->next();
 
3978
            
 
3979
            /* return the new node */
 
3980
            return sub;
 
3981
 
 
3982
        case TOKT_SELF:
 
3983
            /* note the explicit self-reference */
 
3984
            G_prs->set_self_referenced(TRUE);
 
3985
 
 
3986
            /* generate the "self" node */
 
3987
            G_tok->next();
 
3988
            return new CTPNSelf();
 
3989
 
 
3990
        case TOKT_REPLACED:
 
3991
            /* generate the "replaced" node */
 
3992
            G_tok->next();
 
3993
            return new CTPNReplaced();
 
3994
 
 
3995
        case TOKT_TARGETPROP:
 
3996
            /* note the explicit extended method context reference */
 
3997
            G_prs->set_full_method_ctx_referenced(TRUE);
 
3998
 
 
3999
            /* generate the "targetprop" node */
 
4000
            G_tok->next();
 
4001
            return new CTPNTargetprop();
 
4002
 
 
4003
        case TOKT_TARGETOBJ:
 
4004
            /* note the explicit extended method context reference */
 
4005
            G_prs->set_full_method_ctx_referenced(TRUE);
 
4006
 
 
4007
            /* generate the "targetobj" node */
 
4008
            G_tok->next();
 
4009
            return new CTPNTargetobj();
 
4010
 
 
4011
        case TOKT_DEFININGOBJ:
 
4012
            /* note the explicit extended method context reference */
 
4013
            G_prs->set_full_method_ctx_referenced(TRUE);
 
4014
 
 
4015
            /* generate the "definingobj" node */
 
4016
            G_tok->next();
 
4017
            return new CTPNDefiningobj();
 
4018
 
 
4019
        case TOKT_ARGCOUNT:
 
4020
            /* generate the "argcount" node */
 
4021
            G_tok->next();
 
4022
            return new CTPNArgc();
 
4023
 
 
4024
        case TOKT_INHERITED:
 
4025
            /* parse the "inherited" operation */
 
4026
            return parse_inherited();
 
4027
 
 
4028
        case TOKT_DELEGATED:
 
4029
            /* parse the "delegated" operation */
 
4030
            return parse_delegated();
 
4031
            
 
4032
        case TOKT_RPAR:
 
4033
            /* extra right paren - log an error */
 
4034
            G_tok->log_error(TCERR_EXTRA_RPAR);
 
4035
 
 
4036
            /* skip it and go back for more */
 
4037
            G_tok->next();
 
4038
            break;
 
4039
 
 
4040
        case TOKT_RBRACK:
 
4041
            /* extra right square bracket - log an error */
 
4042
            G_tok->log_error(TCERR_EXTRA_RBRACK);
 
4043
 
 
4044
            /* skip it and go back for more */
 
4045
            G_tok->next();
 
4046
            break;
 
4047
 
 
4048
        case TOKT_DSTR_MID:
 
4049
        case TOKT_DSTR_END:
 
4050
        case TOKT_SEM:
 
4051
        case TOKT_RBRACE:
 
4052
            /* 
 
4053
             *   this looks like the end of the statement, but we expected
 
4054
             *   an operand - note the error and end the statement 
 
4055
             */
 
4056
            G_tok->log_error_curtok(TCERR_EXPECTED_OPERAND);
 
4057
 
 
4058
            /* 
 
4059
             *   Synthesize a constant zero as the operand value.  Do not
 
4060
             *   skip the current token, because it's almost certainly not
 
4061
             *   meant to be part of the expression; we want to stay put
 
4062
             *   so that the caller can resynchronize on this token. 
 
4063
             */
 
4064
            cval.set_int(G_tok->getcur()->get_int_val());
 
4065
            return new CTPNConst(&cval);
 
4066
 
 
4067
        default:
 
4068
            /* invalid primary expression - log the error */
 
4069
            G_tok->log_error_curtok(TCERR_BAD_PRIMARY_EXPR);
 
4070
            
 
4071
            /* 
 
4072
             *   Skip the token that's causing the problem; this will
 
4073
             *   ensure that we don't loop indefinitely trying to figure
 
4074
             *   out what this token is about, and return a constant zero
 
4075
             *   value as the primary.  
 
4076
             */
 
4077
            G_tok->next();
 
4078
 
 
4079
            /* synthesize a constant zero as the operand value */
 
4080
            cval.set_int(G_tok->getcur()->get_int_val());
 
4081
            goto return_constant;
 
4082
        }
 
4083
    }
 
4084
}
 
4085
 
 
4086
/*
 
4087
 *   Parse an "inherited" expression 
 
4088
 */
 
4089
CTcPrsNode *CTcPrsOpUnary::parse_inherited()
 
4090
{
 
4091
    CTcPrsNode *lhs;
 
4092
    
 
4093
    /* skip the "inherited" keyword and check what follows */
 
4094
    switch(G_tok->next())
 
4095
    {
 
4096
    case TOKT_SYM:
 
4097
        /* 
 
4098
         *   it's an "inherited superclass..." expression - set up the
 
4099
         *   "inherited superclass" node 
 
4100
         */
 
4101
        lhs = new CTPNInhClass(G_tok->getcur()->get_text(),
 
4102
                               G_tok->getcur()->get_text_len());
 
4103
 
 
4104
        /* skip the superclass token */
 
4105
        G_tok->next();
 
4106
 
 
4107
        /* parse the member expression portion normally */
 
4108
        break;
 
4109
 
 
4110
    case TOKT_LT:
 
4111
        /* 
 
4112
         *   '<' - this is the start of a multi-method type list.  Parse the
 
4113
         *   list: type1 ',' type2 ',' ... '>', then the argument list to the
 
4114
         *   'inherited' call.  
 
4115
         */
 
4116
        {
 
4117
            /* create the formal type list */
 
4118
            CTcFormalTypeList *tl = new (G_prsmem)CTcFormalTypeList();
 
4119
 
 
4120
            /* skip the '<' */
 
4121
            G_tok->next();
 
4122
 
 
4123
            /* parse each list element */
 
4124
            for (int done = FALSE ; !done ; )
 
4125
            {
 
4126
                switch (G_tok->cur())
 
4127
                {
 
4128
                case TOKT_GT:
 
4129
                    /* end of the list - skip the '>', and we're done */
 
4130
                    G_tok->next();
 
4131
                    done = TRUE;
 
4132
                    break;
 
4133
 
 
4134
                case TOKT_ELLIPSIS:
 
4135
                    /* '...' */
 
4136
                    tl->add_ellipsis();
 
4137
 
 
4138
                    /* this has to be the end of the list */
 
4139
                    if (G_tok->next() == TOKT_GT)
 
4140
                        G_tok->next();
 
4141
                    else
 
4142
                        G_tok->log_error_curtok(TCERR_MMINH_MISSING_GT);
 
4143
 
 
4144
                    /* assume the list ends here in any case */
 
4145
                    done = TRUE;
 
4146
                    break;
 
4147
 
 
4148
                case TOKT_SYM:
 
4149
                    /* a type token - add it to the list */
 
4150
                    tl->add_typed_param(G_tok->getcur());
 
4151
 
 
4152
                finish_type:
 
4153
                    /* skip the type token */
 
4154
                    switch (G_tok->next())
 
4155
                    {
 
4156
                    case TOKT_COMMA:
 
4157
                        /* another type follows */
 
4158
                        G_tok->next();
 
4159
                        break;
 
4160
 
 
4161
                    case TOKT_GT:
 
4162
                        G_tok->next();
 
4163
                        done = TRUE;
 
4164
                        break;
 
4165
 
 
4166
                    case TOKT_SYM:
 
4167
                    case TOKT_ELLIPSIS:
 
4168
                    case TOKT_TIMES:
 
4169
                        /* probably just a missing comma */
 
4170
                        G_tok->log_error_curtok(TCERR_MMINH_MISSING_COMMA);
 
4171
                        break;
 
4172
 
 
4173
                    default:
 
4174
                        /* anything else is an error */
 
4175
                        G_tok->log_error_curtok(TCERR_MMINH_MISSING_COMMA);
 
4176
                        G_tok->next();
 
4177
                        break;
 
4178
                    }
 
4179
                    break;
 
4180
 
 
4181
                case TOKT_TIMES:
 
4182
                    /* '*' indicates an untyped parameter */
 
4183
                    tl->add_untyped_param();
 
4184
                    goto finish_type;
 
4185
 
 
4186
                case TOKT_LPAR:
 
4187
                    /* probably a missing '>' */
 
4188
                    G_tok->log_error_curtok(TCERR_MMINH_MISSING_GT);
 
4189
                    done = TRUE;
 
4190
                    break;
 
4191
 
 
4192
                case TOKT_COMMA:
 
4193
                    /* probably a missing type */
 
4194
                    G_tok->log_error_curtok(TCERR_MMINH_MISSING_ARG_TYPE);
 
4195
                    G_tok->next();
 
4196
                    break;
 
4197
 
 
4198
                case TOKT_SEM:
 
4199
                case TOKT_RPAR:
 
4200
                case TOKT_EOF:
 
4201
                    /* all of these indicate a premature end of the list */
 
4202
                    G_tok->log_error_curtok(TCERR_MMINH_MISSING_ARG_TYPE);
 
4203
                    return 0;
 
4204
 
 
4205
                default:
 
4206
                    /* anything else is an error */
 
4207
                    G_tok->log_error_curtok(TCERR_MMINH_MISSING_ARG_TYPE);
 
4208
                    G_prs->skip_to_sem();
 
4209
                    return 0;
 
4210
                }
 
4211
            }
 
4212
 
 
4213
            /* the left-hand side is an "inherited" node, with the arg list */
 
4214
            lhs = new CTPNInh();
 
4215
            ((CTPNInh *)lhs)->set_typelist(tl);
 
4216
 
 
4217
            /* an inherited<> expression must have an argument list */
 
4218
            if (G_tok->cur() != TOKT_LPAR)
 
4219
            {
 
4220
                G_tok->log_error_curtok(TCERR_MMINH_MISSING_ARG_LIST);
 
4221
                G_prs->skip_to_sem();
 
4222
                return 0;
 
4223
            }
 
4224
        }
 
4225
        break;
 
4226
        
 
4227
    default:
 
4228
        /*
 
4229
         *   There's no explicit superclass name listed, so the left-hand
 
4230
         *   side of the '.' expression is the simple "inherited" node. 
 
4231
         */
 
4232
        lhs = new CTPNInh();
 
4233
 
 
4234
        /*
 
4235
         *   Since we don't have an explicit superclass, we'll need the
 
4236
         *   method context at run-time to establish the next class in
 
4237
         *   inheritance order.  Flag the need for the full method context.  
 
4238
         */
 
4239
        G_prs->set_full_method_ctx_referenced(TRUE);
 
4240
 
 
4241
        /* parse the member expression portion normally */
 
4242
        break;
 
4243
    }
 
4244
 
 
4245
    /* parse and return the member expression */
 
4246
    return parse_member(lhs);
 
4247
}
 
4248
 
 
4249
/*
 
4250
 *   Parse a "delegated" expression 
 
4251
 */
 
4252
CTcPrsNode *CTcPrsOpUnary::parse_delegated()
 
4253
{
 
4254
    CTcPrsNode *lhs;
 
4255
    CTcPrsNode *target;
 
4256
 
 
4257
    /* 'delegated' always references 'self' */
 
4258
    G_prs->set_self_referenced(TRUE);
 
4259
 
 
4260
    /* skip the "delegated" keyword */
 
4261
    G_tok->next();
 
4262
 
 
4263
    /* 
 
4264
     *   Parse a postfix expression giving the delegatee.  Don't allow
 
4265
     *   nested member subexpressions (unless they're enclosed in
 
4266
     *   parentheses, of course) - our implicit '.' postfix takes
 
4267
     *   precedence.  Also, don't allow call subexpressions (unless enclosed
 
4268
     *   in parens), since a postfix argument list binds to the 'delegated'
 
4269
     *   expression, not to a subexpression involving a function/method
 
4270
     *   call.  
 
4271
     */
 
4272
    target = parse_postfix(FALSE, FALSE);
 
4273
 
 
4274
    /* set up the "delegated" node */
 
4275
    lhs = new CTPNDelegated(target);
 
4276
 
 
4277
    /* return the rest as a normal member expression */
 
4278
    return parse_member(lhs);
 
4279
}
 
4280
 
 
4281
/*
 
4282
 *   Parse a list 
 
4283
 */
 
4284
CTcPrsNode *CTcPrsOpUnary::parse_list()
 
4285
{
 
4286
    CTPNList *lst;
 
4287
    CTcPrsNode *ele;
 
4288
    
 
4289
    /* skip the opening '[' */
 
4290
    G_tok->next();
 
4291
 
 
4292
    /* 
 
4293
     *   create the list expression -- we'll add elements to the list as
 
4294
     *   we parse the elements
 
4295
     */
 
4296
    lst = new CTPNList();
 
4297
 
 
4298
    /* scan all list elements */
 
4299
    for (;;)
 
4300
    {
 
4301
        /* check what we have */
 
4302
        switch(G_tok->cur())
 
4303
        {
 
4304
        case TOKT_RBRACK:
 
4305
            /* 
 
4306
             *   that's the end of the list - skip the closing bracket and
 
4307
             *   return the finished list 
 
4308
             */
 
4309
            G_tok->next();
 
4310
            goto done;
 
4311
            
 
4312
        case TOKT_EOF:
 
4313
        case TOKT_RBRACE:
 
4314
        case TOKT_SEM:
 
4315
        case TOKT_DSTR_MID:
 
4316
        case TOKT_DSTR_END:
 
4317
            /* 
 
4318
             *   these would all seem to imply that the closing ']' was
 
4319
             *   missing from the list; flag the error and end the list
 
4320
             *   now 
 
4321
             */
 
4322
            G_tok->log_error_curtok(TCERR_LIST_MISSING_RBRACK);
 
4323
            goto done;
 
4324
 
 
4325
        case TOKT_RPAR:
 
4326
            /* 
 
4327
             *   extra right paren - log an error, but then skip the paren
 
4328
             *   and try to keep parsing
 
4329
             */
 
4330
            G_tok->log_error(TCERR_LIST_EXTRA_RPAR);
 
4331
            G_tok->next();
 
4332
            break;
 
4333
 
 
4334
        default:
 
4335
            /* it must be the next element expression */
 
4336
            break;
 
4337
        }
 
4338
 
 
4339
        /* 
 
4340
         *   Attempt to parse another list element expression.  Parse just
 
4341
         *   below a comma expression, because commas can be used to
 
4342
         *   separate list elements.  
 
4343
         */
 
4344
        ele = S_op_asi.parse();
 
4345
        if (ele == 0)
 
4346
            return 0;
 
4347
        
 
4348
        /* add the element to the list */
 
4349
        lst->add_element(ele);
 
4350
 
 
4351
        /* check what follows the element */
 
4352
        switch(G_tok->cur())
 
4353
        {
 
4354
        case TOKT_COMMA:
 
4355
            /* skip the comma introducing the next element */
 
4356
            G_tok->next();
 
4357
 
 
4358
            /* if a close bracket follows, we seem to have an extra comma */
 
4359
            if (G_tok->cur() == TOKT_RBRACK)
 
4360
            {
 
4361
                /* 
 
4362
                 *   log an error about the missing element, then end the
 
4363
                 *   list here 
 
4364
                 */
 
4365
                G_tok->log_error_curtok(TCERR_LIST_EXPECT_ELEMENT);
 
4366
                goto done;
 
4367
            }
 
4368
            break;
 
4369
 
 
4370
        case TOKT_RBRACK:
 
4371
            /* 
 
4372
             *   we're done with the list - skip the bracket and return
 
4373
             *   the finished list 
 
4374
             */
 
4375
            G_tok->next();
 
4376
            goto done;
 
4377
 
 
4378
        case TOKT_EOF:
 
4379
        case TOKT_LBRACE:
 
4380
        case TOKT_RBRACE:
 
4381
        case TOKT_SEM:
 
4382
        case TOKT_DSTR_MID:
 
4383
        case TOKT_DSTR_END:
 
4384
            /* 
 
4385
             *   these would all seem to imply that the closing ']' was
 
4386
             *   missing from the list; flag the error and end the list
 
4387
             *   now 
 
4388
             */
 
4389
            G_tok->log_error_curtok(TCERR_LIST_MISSING_RBRACK);
 
4390
            goto done;
 
4391
 
 
4392
        default:
 
4393
            /* 
 
4394
             *   Anything else is an error - note that we expected a
 
4395
             *   comma, then proceed with parsing from the current token
 
4396
             *   as though we had found the comma (in all likelihood, the
 
4397
             *   comma was accidentally omitted).  If we've reached the
 
4398
             *   end of the file, return what we have so far, since it's
 
4399
             *   pointless to keep looping.  
 
4400
             */
 
4401
            G_tok->log_error_curtok(TCERR_LIST_EXPECT_COMMA);
 
4402
 
 
4403
            /* give up on end of file, otherwise keep going */
 
4404
            if (G_tok->cur() == TOKT_EOF)
 
4405
                goto done;
 
4406
            break;
 
4407
        }
 
4408
    }
 
4409
 
 
4410
done:
 
4411
    /* tell the parser to note this list, in case it's the longest yet */
 
4412
    G_cg->note_list(lst->get_count());
 
4413
 
 
4414
    /* return the list */
 
4415
    return lst;
 
4416
}
 
4417
 
 
4418
 
 
4419
/* ------------------------------------------------------------------------ */
 
4420
/*
 
4421
 *   Parse Allocation Object 
 
4422
 */
 
4423
 
 
4424
/*
 
4425
 *   memory allocator for parse nodes
 
4426
 */
 
4427
void *CTcPrsAllocObj::operator new(size_t siz)
 
4428
{
 
4429
    /* allocate the space out of the node pool */
 
4430
    return G_prsmem->alloc(siz);
 
4431
}
 
4432
 
 
4433
 
 
4434
/* ------------------------------------------------------------------------ */
 
4435
/*
 
4436
 *   Parse Tree space manager 
 
4437
 */
 
4438
 
 
4439
/*
 
4440
 *   create 
 
4441
 */
 
4442
CTcPrsMem::CTcPrsMem()
 
4443
{
 
4444
    /* we have no blocks yet */
 
4445
    head_ = tail_ = 0;
 
4446
 
 
4447
    /* allocate our first block */
 
4448
    alloc_block();
 
4449
}
 
4450
 
 
4451
CTcPrsMem::~CTcPrsMem()
 
4452
{
 
4453
    /* delete all objects in our pool */
 
4454
    delete_all();
 
4455
}
 
4456
 
 
4457
/*
 
4458
 *   Save state, for later resetting 
 
4459
 */
 
4460
void CTcPrsMem::save_state(tcprsmem_state_t *state)
 
4461
{
 
4462
    /* save the pool information in the state structure */
 
4463
    state->tail = tail_;
 
4464
    state->free_ptr = free_ptr_;
 
4465
    state->rem = rem_;
 
4466
}
 
4467
 
 
4468
/*
 
4469
 *   Reset to initial state 
 
4470
 */
 
4471
void CTcPrsMem::reset()
 
4472
{
 
4473
    /* delete all blocks */
 
4474
    delete_all();
 
4475
 
 
4476
    /* re-allocate the initial block */
 
4477
    alloc_block();
 
4478
}
 
4479
 
 
4480
/*
 
4481
 *   Reset.  This deletes all objects allocated out of the parser pool
 
4482
 *   since the state was saved.  
 
4483
 */
 
4484
void CTcPrsMem::reset(const tcprsmem_state_t *state)
 
4485
{
 
4486
    tcprsmem_blk_t *cur;
 
4487
    
 
4488
    /* 
 
4489
     *   delete all of the blocks that were allocated after the last block
 
4490
     *   that existed when the state was saved 
 
4491
     */
 
4492
    for (cur = state->tail->next_ ; cur != 0 ; )
 
4493
    {
 
4494
        tcprsmem_blk_t *nxt;
 
4495
 
 
4496
        /* remember the next block */
 
4497
        nxt = cur->next_;
 
4498
 
 
4499
        /* delete this block */
 
4500
        t3free(cur);
 
4501
 
 
4502
        /* move on to the next one */
 
4503
        cur = nxt;
 
4504
    }
 
4505
 
 
4506
    /* re-establish the saved last block */
 
4507
    tail_ = state->tail;
 
4508
 
 
4509
    /* make sure the list is terminated at the last block */
 
4510
    tail_->next_ = 0;
 
4511
 
 
4512
    /* re-establish the saved allocation point in the last block */
 
4513
    free_ptr_ = state->free_ptr;
 
4514
    rem_ = state->rem;
 
4515
}
 
4516
 
 
4517
/*
 
4518
 *   Delete all parser memory.  This deletes all objects allocated out of
 
4519
 *   parser memory, so the caller must be sure that all of these objects
 
4520
 *   are unreferenced.  
 
4521
 */
 
4522
void CTcPrsMem::delete_all()
 
4523
{
 
4524
    /* free all blocks */
 
4525
    while (head_ != 0)
 
4526
    {
 
4527
        tcprsmem_blk_t *nxt;
 
4528
 
 
4529
        /* remember the next block after this one */
 
4530
        nxt = head_->next_;
 
4531
 
 
4532
        /* free this block */
 
4533
        t3free(head_);
 
4534
 
 
4535
        /* move on to the next one */
 
4536
        head_ = nxt;
 
4537
    }
 
4538
 
 
4539
    /* there's no tail now */
 
4540
    tail_ = 0;
 
4541
}
 
4542
 
 
4543
/*
 
4544
 *   allocate a block 
 
4545
 */
 
4546
void CTcPrsMem::alloc_block()
 
4547
{
 
4548
    tcprsmem_blk_t *blk;
 
4549
 
 
4550
    /* 
 
4551
     *   block size - pick a size that's large enough that we won't be
 
4552
     *   unduly inefficient (in terms of having tons of blocks), but still
 
4553
     *   friendly to 16-bit platforms (i.e., under 64k) 
 
4554
     */
 
4555
    const size_t BLOCK_SIZE = 65000;
 
4556
 
 
4557
    /* allocate space for the block */
 
4558
    blk = (tcprsmem_blk_t *)t3malloc(sizeof(tcprsmem_blk_t) + BLOCK_SIZE - 1);
 
4559
 
 
4560
    /* if that failed, throw an error */
 
4561
    if (blk == 0)
 
4562
        err_throw(TCERR_NO_MEM_PRS_TREE);
 
4563
 
 
4564
    /* link in the block at the end of our list */
 
4565
    blk->next_ = 0;
 
4566
    if (tail_ != 0)
 
4567
        tail_->next_ = blk;
 
4568
    else
 
4569
        head_ = blk;
 
4570
 
 
4571
    /* the block is now the last block in the list */
 
4572
    tail_ = blk;
 
4573
 
 
4574
    /* 
 
4575
     *   Set up to allocate out of our block.  Make sure the free pointer
 
4576
     *   starts out on a worst-case alignment boundary; normally, the C++
 
4577
     *   compiler will properly align our "buf_" structure member on a
 
4578
     *   worst-case boundary, so this calculation won't actually change
 
4579
     *   anything, but this will help ensure portability even to weird
 
4580
     *   compilers.  
 
4581
     */
 
4582
    free_ptr_ = (char *)osrndpt((unsigned char *)blk->buf_);
 
4583
 
 
4584
    /* 
 
4585
     *   get the amount of space remaining in the block (in the unlikely
 
4586
     *   event that worst-case alignment actually moved the free pointer
 
4587
     *   above the start of the buffer, we'll have lost a little space in
 
4588
     *   the buffer for the alignment offset) 
 
4589
     */
 
4590
    rem_ = BLOCK_SIZE - (free_ptr_ - blk->buf_);
 
4591
}
 
4592
 
 
4593
/*
 
4594
 *   Allocate space 
 
4595
 */
 
4596
void *CTcPrsMem::alloc(size_t siz)
 
4597
{
 
4598
    char *ret;
 
4599
    size_t space_used;
 
4600
 
 
4601
    /* if there's not enough space available, allocate a new block */
 
4602
    if (siz > rem_)
 
4603
    {
 
4604
        /* allocate a new block */
 
4605
        alloc_block();
 
4606
 
 
4607
        /* 
 
4608
         *   if there's still not enough room, the request must exceed the
 
4609
         *   largest block we can allocate 
 
4610
         */
 
4611
        if (siz > rem_)
 
4612
            G_tok->throw_internal_error(TCERR_PRS_BLK_TOO_BIG, (ulong)siz);
 
4613
    }
 
4614
 
 
4615
    /* return the free pointer */
 
4616
    ret = free_ptr_;
 
4617
 
 
4618
    /* advance the free pointer past the space, rounding for alignment */
 
4619
    free_ptr_ = (char *)osrndpt((unsigned char *)free_ptr_ + siz);
 
4620
 
 
4621
    /* deduct the amount of space we consumed from the available space */
 
4622
    space_used = free_ptr_ - ret;
 
4623
    if (space_used > rem_)
 
4624
        rem_ = 0;
 
4625
    else
 
4626
        rem_ -= space_used;
 
4627
 
 
4628
    /* return the allocated space */
 
4629
    return ret;
 
4630
}
 
4631
 
 
4632
/* ------------------------------------------------------------------------ */
 
4633
/*
 
4634
 *   parse node base class 
 
4635
 */
 
4636
 
 
4637
/*
 
4638
 *   By default, an expression cannot be used as a debugger expression 
 
4639
 */
 
4640
CTcPrsNode *CTcPrsNodeBase::adjust_for_debug(const tcpn_debug_info *info)
 
4641
{
 
4642
    err_throw(VMERR_INVAL_DBG_EXPR);
 
4643
    AFTER_ERR_THROW(return 0;)
 
4644
}
 
4645
 
 
4646
 
 
4647
/* ------------------------------------------------------------------------ */
 
4648
/*
 
4649
 *   constant node 
 
4650
 */
 
4651
 
 
4652
/*
 
4653
 *   adjust for debugger use 
 
4654
 */
 
4655
CTcPrsNode *CTPNConstBase::adjust_for_debug(const tcpn_debug_info *info)
 
4656
{
 
4657
    /* convert to a debugger-constant */
 
4658
    return new CTPNDebugConst(&val_);
 
4659
}
 
4660
 
 
4661
 
 
4662
/* ------------------------------------------------------------------------ */
 
4663
/*
 
4664
 *   List parse node 
 
4665
 */
 
4666
 
 
4667
/*
 
4668
 *   add an element to a list 
 
4669
 */
 
4670
void CTPNListBase::add_element(CTcPrsNode *expr)
 
4671
{
 
4672
    CTPNListEle *ele;
 
4673
    
 
4674
    /* create a list element object for the new element */
 
4675
    ele = new CTPNListEle(expr);
 
4676
 
 
4677
    /* count the new entry */
 
4678
    ++cnt_;
 
4679
 
 
4680
    /* add the element to our linked list */
 
4681
    ele->set_prev(tail_);
 
4682
    if (tail_ != 0)
 
4683
        tail_->set_next(ele);
 
4684
    else
 
4685
        head_ = ele;
 
4686
    tail_ = ele;
 
4687
 
 
4688
    /* 
 
4689
     *   if the new element does not have a constant value, the list no
 
4690
     *   longer has a constant value (if it did before) 
 
4691
     */
 
4692
    if (!expr->is_const())
 
4693
        is_const_ = FALSE;
 
4694
}
 
4695
 
 
4696
/*
 
4697
 *   remove each occurrence of a given constant value from the list
 
4698
 */
 
4699
void CTPNListBase::remove_element(const CTcConstVal *val)
 
4700
{
 
4701
    CTPNListEle *cur;
 
4702
    
 
4703
    /* scan the list */
 
4704
    for (cur = head_ ; cur != 0 ; cur = cur->get_next())
 
4705
    {
 
4706
        /* 
 
4707
         *   if this element is constant, compare it to the value to be
 
4708
         *   removed; if it matches, remove it 
 
4709
         */
 
4710
        if (cur->get_expr()->is_const()
 
4711
            && cur->get_expr()->get_const_val()->is_equal_to(val))
 
4712
        {
 
4713
            /* set the previous element's forward pointer */
 
4714
            if (cur->get_prev() == 0)
 
4715
                head_ = cur->get_next();
 
4716
            else
 
4717
                cur->get_prev()->set_next(cur->get_next());
 
4718
 
 
4719
            /* set the next element's back pointer */
 
4720
            if (cur->get_next() == 0)
 
4721
                tail_ = cur->get_prev();
 
4722
            else
 
4723
                cur->get_next()->set_prev(cur->get_prev());
 
4724
 
 
4725
            /* decrement our element counter */
 
4726
            --cnt_;
 
4727
        }
 
4728
    }
 
4729
}
 
4730
 
 
4731
/*
 
4732
 *   Get the constant value of the element at the given index.  Logs an
 
4733
 *   error and returns null if there's no such element. 
 
4734
 */
 
4735
CTcPrsNode *CTPNListBase::get_const_ele(int index)
 
4736
{
 
4737
    CTPNListEle *ele;
 
4738
    
 
4739
    /* if the index is negative, it's out of range */
 
4740
    if (index < 1)
 
4741
    {
 
4742
        /* log the error and return failure */
 
4743
        G_tok->log_error(TCERR_CONST_IDX_RANGE);
 
4744
        return 0;
 
4745
    }
 
4746
 
 
4747
    /* scan the list for the given element */
 
4748
    for (ele = head_ ; ele != 0 && index > 1 ;
 
4749
         ele = ele->get_next(), --index) ;
 
4750
 
 
4751
    /* if we ran out of elements, the index is out of range */
 
4752
    if (ele == 0 || index != 1)
 
4753
    {
 
4754
        G_tok->log_error(TCERR_CONST_IDX_RANGE);
 
4755
        return 0;
 
4756
    }
 
4757
 
 
4758
    /* return the element's constant value */
 
4759
    return ele->get_expr();
 
4760
}
 
4761
 
 
4762
/*
 
4763
 *   Fold constants 
 
4764
 */
 
4765
CTcPrsNode *CTPNListBase::fold_constants(CTcPrsSymtab *symtab)
 
4766
{
 
4767
    CTPNListEle *cur;
 
4768
    int all_const;
 
4769
 
 
4770
    /* 
 
4771
     *   if the list is already constant, there's nothing extra we need to
 
4772
     *   do 
 
4773
     */
 
4774
    if (is_const_)
 
4775
        return this;
 
4776
 
 
4777
    /* presume the result will be all constants */
 
4778
    all_const = TRUE;
 
4779
    
 
4780
    /* run through my list and fold each element */
 
4781
    for (cur = head_ ; cur != 0 ; cur = cur->get_next())
 
4782
    {
 
4783
        /* fold this element */
 
4784
        cur->fold_constants(symtab);
 
4785
 
 
4786
        /* 
 
4787
         *   if this element is not a constant, the whole list cannot be
 
4788
         *   constant 
 
4789
         */
 
4790
        if (!cur->get_expr()->is_const())
 
4791
            all_const = FALSE;
 
4792
    }
 
4793
 
 
4794
    /* if every element was a constant, the overall list is constant */
 
4795
    if (all_const)
 
4796
        is_const_ = TRUE;
 
4797
 
 
4798
    /* return myself */
 
4799
    return this;
 
4800
}
 
4801
 
 
4802
/*
 
4803
 *   Adjust for debugging 
 
4804
 */
 
4805
CTcPrsNode *CTPNListBase::adjust_for_debug(const tcpn_debug_info *info)
 
4806
{
 
4807
    CTPNListEle *cur;
 
4808
 
 
4809
    /* run through my list and adjust each element */
 
4810
    for (cur = head_ ; cur != 0 ; cur = cur->get_next())
 
4811
    {
 
4812
        /* adjust this element */
 
4813
        cur->adjust_for_debug(info);
 
4814
    }
 
4815
 
 
4816
    /* 
 
4817
     *   force the list to be non-constant - in debugger mode, we have to
 
4818
     *   build the value we push as a dynamic object, never as an actual
 
4819
     *   constant, to ensure that the generated code can be deleted
 
4820
     *   immediately after being executed 
 
4821
     */
 
4822
    is_const_ = FALSE;
 
4823
 
 
4824
    /* return myself */
 
4825
    return this;
 
4826
}
 
4827
 
 
4828
/* ------------------------------------------------------------------------ */
 
4829
/*
 
4830
 *   conditional operator node base class 
 
4831
 */
 
4832
 
 
4833
/*
 
4834
 *   fold constants 
 
4835
 */
 
4836
CTcPrsNode *CTPNIfBase::fold_constants(CTcPrsSymtab *symtab)
 
4837
{
 
4838
    /* fold constants in the subnodes */
 
4839
    first_ = first_->fold_constants(symtab);
 
4840
    second_ = second_->fold_constants(symtab);
 
4841
    third_ = third_->fold_constants(symtab);
 
4842
 
 
4843
    /* 
 
4844
     *   if the first is now a constant, we can fold this entire
 
4845
     *   expression node by choosing the second or third based on its
 
4846
     *   value; otherwise, return myself unchanged 
 
4847
     */
 
4848
    if (first_->is_const())
 
4849
    {
 
4850
        /* 
 
4851
         *   the condition is a constant - the result is the 'then' or
 
4852
         *   'else' part, based on the condition's value 
 
4853
         */
 
4854
        return (first_->get_const_val()->get_val_bool()
 
4855
                ? second_ : third_);
 
4856
    }
 
4857
    else
 
4858
    {
 
4859
        /* we can't fold this node any further - return it unchanged */
 
4860
        return this;
 
4861
    }
 
4862
}
 
4863
 
 
4864
 
 
4865
/* ------------------------------------------------------------------------ */
 
4866
/*
 
4867
 *   Double-quoted string node - base class 
 
4868
 */
 
4869
 
 
4870
/* 
 
4871
 *   create a double-quoted string node 
 
4872
 */
 
4873
CTPNDstrBase::CTPNDstrBase(const char *str, size_t len)
 
4874
{
 
4875
    /* remember the string */
 
4876
    str_ = str;
 
4877
    len_ = len;
 
4878
 
 
4879
    /* 
 
4880
     *   note the length in the parser, in case it's the longest string
 
4881
     *   we've seen so far 
 
4882
     */
 
4883
    G_cg->note_str(len);
 
4884
}
 
4885
 
 
4886
/*
 
4887
 *   adjust for debugger use 
 
4888
 */
 
4889
CTcPrsNode *CTPNDstrBase::adjust_for_debug(const tcpn_debug_info *info)
 
4890
{
 
4891
    /* 
 
4892
     *   don't allow dstring evaluation in speculative mode, since we
 
4893
     *   can't execute anything with side effects in this mode 
 
4894
     */
 
4895
    if (info->speculative)
 
4896
        err_throw(VMERR_BAD_SPEC_EVAL);
 
4897
 
 
4898
    /* return a debugger dstring node */
 
4899
    return new CTPNDebugDstr(str_, len_);
 
4900
}
 
4901
 
 
4902
/* ------------------------------------------------------------------------ */
 
4903
/*
 
4904
 *   Address-of parse node 
 
4905
 */
 
4906
 
 
4907
/*
 
4908
 *   fold constants 
 
4909
 */
 
4910
CTcPrsNode *CTPNAddrBase::fold_constants(CTcPrsSymtab *symtab)
 
4911
{
 
4912
    CTcPrsNode *ret;
 
4913
 
 
4914
    /* ask the symbol to generate a constant expression for its address */
 
4915
    ret = get_sub_expr()->fold_addr_const(symtab);
 
4916
 
 
4917
    /* 
 
4918
     *   if we got a constant value, return it; otherwise, return myself
 
4919
     *   unchanged 
 
4920
     */
 
4921
    return (ret != 0 ? ret : this);
 
4922
}
 
4923
 
 
4924
/*
 
4925
 *   determine if my address equals that of another node 
 
4926
 */
 
4927
int CTPNAddrBase::is_addr_eq(const CTPNAddr *node, int *comparable) const
 
4928
{
 
4929
    /* 
 
4930
     *   If both sides are symbols, the addresses are equal if and only if
 
4931
     *   the symbols are identical.  One symbol has exactly one meaning in
 
4932
     *   a given context, and no two symbols can have the same meaning.
 
4933
     *   (It's important that we be able to state this for all symbols,
 
4934
     *   because we can't necessarily know during parsing the meaning of a
 
4935
     *   given symbol, since the symbol could be a forward reference.)  
 
4936
     */
 
4937
    if (get_sub_expr()->get_sym_text() != 0
 
4938
        && node->get_sub_expr()->get_sym_text() != 0)
 
4939
    {
 
4940
        CTcPrsNode *sym1;
 
4941
        CTcPrsNode *sym2;
 
4942
 
 
4943
        /* they're both symbols, so they're comparable */
 
4944
        *comparable = TRUE;
 
4945
 
 
4946
        /* they're the same if both symbols have the same text */
 
4947
        sym1 = get_sub_expr();
 
4948
        sym2 = node->get_sub_expr();
 
4949
        return (sym1->get_sym_text_len() == sym2->get_sym_text_len()
 
4950
                && memcmp(sym1->get_sym_text(), sym2->get_sym_text(),
 
4951
                          sym1->get_sym_text_len()) == 0);
 
4952
    }
 
4953
 
 
4954
    /* they're not comparable */
 
4955
    *comparable = FALSE;
 
4956
    return FALSE;
 
4957
}
 
4958
 
 
4959
/* ------------------------------------------------------------------------ */
 
4960
/*
 
4961
 *   Symbol parse node base class 
 
4962
 */
 
4963
 
 
4964
/*
 
4965
 *   fold constants 
 
4966
 */
 
4967
CTcPrsNode *CTPNSymBase::fold_constants(CTcPrsSymtab *symtab)
 
4968
{
 
4969
    CTcSymbol *sym;
 
4970
    CTcPrsNode *ret;
 
4971
 
 
4972
    /*
 
4973
     *   Look up my symbol.  At this stage, don't assume a definition;
 
4974
     *   merely look to see if it's already known.  We don't have enough
 
4975
     *   information to determine how we should define the symbol, so
 
4976
     *   leave it undefined until code generation if it's not already
 
4977
     *   known.  
 
4978
     */
 
4979
    sym = symtab->find(get_sym_text(), get_sym_text_len());
 
4980
    if (sym != 0)
 
4981
    {
 
4982
        /* ask the symbol to do the folding */
 
4983
        ret = sym->fold_constant();
 
4984
 
 
4985
        /* if that succeeded, return it; otherwise, return unchanged */
 
4986
        return (ret != 0 ? ret : this);
 
4987
    }
 
4988
    else
 
4989
    {
 
4990
        /* not defined - return myself unchanged */
 
4991
        return this;
 
4992
    }
 
4993
}
 
4994
 
 
4995
/*
 
4996
 *   Fold my address to a constant node.  If I have no address value, I'll
 
4997
 *   simply return myself unchanged.  Note that it's an error if I have no
 
4998
 *   constant value, but we'll count on the code generator to report the
 
4999
 *   error, and simply ignore it for now.  
 
5000
 */
 
5001
CTcPrsNode *CTPNSymBase::fold_addr_const(CTcPrsSymtab *symtab)
 
5002
{
 
5003
    CTcSymbol *sym;
 
5004
 
 
5005
    /* look up my symbol; if we don't find it, don't define it */
 
5006
    sym = symtab->find(get_sym_text(), get_sym_text_len());
 
5007
    if (sym != 0)
 
5008
    {
 
5009
        /* we got a symbol - ask it to do the folding */
 
5010
        return sym->fold_addr_const();
 
5011
    }
 
5012
    else
 
5013
    {
 
5014
        /* undefined symbol - there's no constant address value */
 
5015
        return 0;
 
5016
    }
 
5017
}
 
5018
 
 
5019
/*
 
5020
 *   Determine if I have a return value when called 
 
5021
 */
 
5022
int CTPNSymBase::has_return_value_on_call() const
 
5023
{
 
5024
    CTcSymbol *sym;
 
5025
    
 
5026
    /* try resolving my symbol */
 
5027
    sym = G_prs->get_global_symtab()->find(sym_, len_);
 
5028
 
 
5029
    /* 
 
5030
     *   if we found a symbol, let it resolve the call; otherwise, assume
 
5031
     *   that we do have a return value 
 
5032
     */
 
5033
    if (sym != 0)
 
5034
        return sym->has_return_value_on_call();
 
5035
    else
 
5036
        return TRUE;
 
5037
}
 
5038
 
 
5039
/*
 
5040
 *   Determine if I am a valid lvalue 
 
5041
 */
 
5042
int CTPNSymBase::check_lvalue_resolved(class CTcPrsSymtab *symtab) const
 
5043
{
 
5044
    CTcSymbol *sym;
 
5045
 
 
5046
    /* look up the symbol in the given scope */
 
5047
    sym = symtab->find(get_sym_text(), get_sym_text_len());
 
5048
    if (sym != 0)
 
5049
    {
 
5050
        /* ask the symbol what it thinks */
 
5051
        return sym->check_lvalue();
 
5052
    }
 
5053
    else
 
5054
    {
 
5055
        /* it's undefined - can't be an lvalue */
 
5056
        return FALSE;
 
5057
    }
 
5058
}
 
5059
 
 
5060
/*
 
5061
 *   Adjust for debugger use 
 
5062
 */
 
5063
CTcPrsNode *CTPNSymBase::adjust_for_debug(const tcpn_debug_info *)
 
5064
{
 
5065
    /* 
 
5066
     *   If this symbol isn't defined in the global symbol table, we can't
 
5067
     *   evaluate this expression in the debugger - new symbols can never
 
5068
     *   be defined in the debugger, so there's no point in trying to hold
 
5069
     *   a forward reference as we normally would for an undefined symbol.
 
5070
     *   We need look only in the global symbol table because local
 
5071
     *   symbols will already have been resolved.  
 
5072
     */
 
5073
    if (G_prs->get_global_symtab()->find(sym_, len_) == 0)
 
5074
    {
 
5075
        /* log the error, to generate an appropriate message */
 
5076
        G_tok->log_error(TCERR_UNDEF_SYM, (int)len_, sym_);
 
5077
        
 
5078
        /* throw the error as well */
 
5079
        err_throw_a(TCERR_UNDEF_SYM, 2,
 
5080
                    ERR_TYPE_INT, (int)len_, ERR_TYPE_TEXTCHAR, sym_);
 
5081
    }
 
5082
    
 
5083
    /* return myself unchanged */
 
5084
    return this;
 
5085
}
 
5086
 
 
5087
 
 
5088
/* ------------------------------------------------------------------------ */
 
5089
/*
 
5090
 *   Resolved Symbol parse node base class 
 
5091
 */
 
5092
 
 
5093
/*
 
5094
 *   fold constants 
 
5095
 */
 
5096
CTcPrsNode *CTPNSymResolvedBase::fold_constants(CTcPrsSymtab *symtab)
 
5097
{
 
5098
    CTcPrsNode *ret;
 
5099
 
 
5100
    /* ask the symbol to generate the folded constant value */
 
5101
    ret = sym_->fold_constant();
 
5102
 
 
5103
    /* if that succeeded, return it; otherwise, return myself unchanged */
 
5104
    return (ret != 0 ? ret : this);
 
5105
}
 
5106
 
 
5107
/*
 
5108
 *   Fold my address to a constant node.  If I have no address value, I'll
 
5109
 *   simply return myself unchanged.  Note that it's an error if I have no
 
5110
 *   constant value, but we'll count on the code generator to report the
 
5111
 *   error, and simply ignore it for now.  
 
5112
 */
 
5113
CTcPrsNode *CTPNSymResolvedBase::fold_addr_const(CTcPrsSymtab *symtab)
 
5114
{
 
5115
    /* ask my symbol to generate the folded constant value */
 
5116
    return sym_->fold_addr_const();
 
5117
}
 
5118
 
 
5119
 
 
5120
/* ------------------------------------------------------------------------ */
 
5121
/*
 
5122
 *   Debugger local variable resolved symbol 
 
5123
 */
 
5124
 
 
5125
/*
 
5126
 *   construction 
 
5127
 */
 
5128
CTPNSymDebugLocalBase::CTPNSymDebugLocalBase(const tcprsdbg_sym_info *info)
 
5129
{
 
5130
    /* save the type information */
 
5131
    switch(info->sym_type)
 
5132
    {
 
5133
    case TC_SYM_LOCAL:
 
5134
        var_id_ = info->var_id;
 
5135
        ctx_arr_idx_ = info->ctx_arr_idx;
 
5136
        frame_idx_ = info->frame_idx;
 
5137
        is_param_ = FALSE;
 
5138
        break;
 
5139
 
 
5140
    case TC_SYM_PARAM:
 
5141
        var_id_ = info->var_id;
 
5142
        ctx_arr_idx_ = 0;
 
5143
        frame_idx_ = info->frame_idx;
 
5144
        is_param_ = TRUE;
 
5145
        break;
 
5146
 
 
5147
    default:
 
5148
        /* other types are invalid */
 
5149
        assert(FALSE);
 
5150
        break;
 
5151
    }
 
5152
}
 
5153
 
 
5154
/* ------------------------------------------------------------------------ */
 
5155
/*
 
5156
 *   Argument List parse node base class 
 
5157
 */
 
5158
 
 
5159
/*
 
5160
 *   fold constants 
 
5161
 */
 
5162
CTcPrsNode *CTPNArglistBase::fold_constants(CTcPrsSymtab *symtab)
 
5163
{
 
5164
    CTPNArg *cur;
 
5165
    
 
5166
    /* fold each list element */
 
5167
    for (cur = get_arg_list_head() ; cur != 0 ; cur = cur->get_next_arg())
 
5168
        cur->fold_constants(symtab);
 
5169
 
 
5170
    /* return myself with no further folding */
 
5171
    return this;
 
5172
}
 
5173
 
 
5174
/*
 
5175
 *   adjust for debugger use 
 
5176
 */
 
5177
CTcPrsNode *CTPNArglistBase::adjust_for_debug(const tcpn_debug_info *info)
 
5178
{
 
5179
    CTPNArg *arg;
 
5180
    
 
5181
    /* adjust each argument list member */
 
5182
    for (arg = list_ ; arg != 0 ; arg = arg->get_next_arg())
 
5183
    {
 
5184
        /* 
 
5185
         *   adjust this argument; assume the argument node itself isn't
 
5186
         *   affected 
 
5187
         */
 
5188
        arg->adjust_for_debug(info);
 
5189
    }
 
5190
 
 
5191
    /* return myself otherwise unchanged */
 
5192
    return this;
 
5193
}
 
5194
 
 
5195
/* ------------------------------------------------------------------------ */
 
5196
/*
 
5197
 *   Argument List Entry parse node base class 
 
5198
 */
 
5199
 
 
5200
/*
 
5201
 *   fold constants 
 
5202
 */
 
5203
CTcPrsNode *CTPNArgBase::fold_constants(CTcPrsSymtab *symtab)
 
5204
{
 
5205
    /* fold my argument expression */
 
5206
    arg_expr_ = arg_expr_->fold_constants(symtab);
 
5207
 
 
5208
    /* return myself unchanged */
 
5209
    return this;
 
5210
}
 
5211
 
 
5212
/* ------------------------------------------------------------------------ */
 
5213
/*
 
5214
 *   Member with no arguments 
 
5215
 */
 
5216
 
 
5217
/*
 
5218
 *   adjust for debugger use
 
5219
 */
 
5220
CTcPrsNode *CTPNMemberBase::adjust_for_debug(const tcpn_debug_info *info)
 
5221
{
 
5222
    /* adjust the object and property expressions */
 
5223
    obj_expr_ = obj_expr_->adjust_for_debug(info);
 
5224
    prop_expr_ = prop_expr_->adjust_for_debug(info);
 
5225
 
 
5226
    /* return myself otherwise unchanged */
 
5227
    return this;
 
5228
}
 
5229
 
 
5230
/* ------------------------------------------------------------------------ */
 
5231
/*
 
5232
 *   Member with Arguments parse node base class 
 
5233
 */
 
5234
 
 
5235
/*
 
5236
 *   fold constants 
 
5237
 */
 
5238
CTcPrsNode *CTPNMemArgBase::fold_constants(CTcPrsSymtab *symtab)
 
5239
{
 
5240
    /* fold constants in the object and property expressions */
 
5241
    obj_expr_ = obj_expr_->fold_constants(symtab);
 
5242
    prop_expr_ = prop_expr_->fold_constants(symtab);
 
5243
 
 
5244
    /* 
 
5245
     *   fold constants in the argument list; an argument list node never
 
5246
     *   changes to a new node type during constant folding, so we don't
 
5247
     *   need to update the member 
 
5248
     */
 
5249
    arglist_->fold_constants(symtab);
 
5250
 
 
5251
    /* return myself with no further evaluation */
 
5252
    return this;
 
5253
}
 
5254
 
 
5255
/* 
 
5256
 *   adjust for debugger use 
 
5257
 */
 
5258
CTcPrsNode *CTPNMemArgBase::adjust_for_debug(const tcpn_debug_info *info)
 
5259
{
 
5260
    /* don't allow in speculative mode due to possible side effects */
 
5261
    if (info->speculative)
 
5262
        err_throw(VMERR_BAD_SPEC_EVAL);
 
5263
 
 
5264
    /* 
 
5265
     *   adjust my object expression, property expression, and argument
 
5266
     *   list 
 
5267
     */
 
5268
    obj_expr_ = obj_expr_->adjust_for_debug(info);
 
5269
    prop_expr_ = prop_expr_->adjust_for_debug(info);
 
5270
    arglist_->adjust_for_debug(info);
 
5271
 
 
5272
    /* return myself otherwise unchanged */
 
5273
    return this;
 
5274
}
 
5275
 
 
5276
 
 
5277
/* ------------------------------------------------------------------------ */
 
5278
/*
 
5279
 *   Function/Method Call parse node base class 
 
5280
 */
 
5281
 
 
5282
/*
 
5283
 *   fold constants 
 
5284
 */
 
5285
CTcPrsNode *CTPNCallBase::fold_constants(CTcPrsSymtab *symtab)
 
5286
{
 
5287
    /* fold my function expression */
 
5288
    func_ = func_->fold_constants(symtab);
 
5289
 
 
5290
    /* fold my argument list */
 
5291
    arglist_->fold_constants(symtab);
 
5292
 
 
5293
    /* return myself unchanged */
 
5294
    return this;
 
5295
}
 
5296
 
 
5297
/*
 
5298
 *   adjust for debugger use 
 
5299
 */
 
5300
CTcPrsNode *CTPNCallBase::adjust_for_debug(const tcpn_debug_info *info)
 
5301
{
 
5302
    /* don't allow in speculative mode because of side effects */
 
5303
    if (info->speculative)
 
5304
        err_throw(VMERR_BAD_SPEC_EVAL);
 
5305
 
 
5306
    /* adjust the function expression */
 
5307
    func_ = func_->adjust_for_debug(info);
 
5308
    
 
5309
    /* adjust the argument list (assume it doesn't change) */
 
5310
    arglist_->adjust_for_debug(info);
 
5311
    
 
5312
    /* return myself otherwise unchanged */
 
5313
    return this;
 
5314
}
 
5315
 
 
5316
/* ------------------------------------------------------------------------ */
 
5317
/*
 
5318
 *   Parser Symbol Table implementation 
 
5319
 */
 
5320
 
 
5321
/* static hash function */
 
5322
CVmHashFunc *CTcPrsSymtab::hash_func_ = 0;
 
5323
 
 
5324
/*
 
5325
 *   allocate parser symbol tables out of the parser memory pool 
 
5326
 */
 
5327
void *CTcPrsSymtab::operator new(size_t siz)
 
5328
{
 
5329
    return G_prsmem->alloc(siz);
 
5330
}
 
5331
 
 
5332
/*
 
5333
 *   static initialization 
 
5334
 */
 
5335
void CTcPrsSymtab::s_init()
 
5336
{
 
5337
    /* create our static hash function */
 
5338
    if (hash_func_ == 0)
 
5339
        hash_func_ = new CVmHashFuncCS();
 
5340
}
 
5341
 
 
5342
/*
 
5343
 *   static termination 
 
5344
 */
 
5345
void CTcPrsSymtab::s_terminate()
 
5346
{
 
5347
    /* delete our static hash function */
 
5348
    if (hash_func_ != 0)
 
5349
    {
 
5350
        delete hash_func_;
 
5351
        hash_func_ = 0;
 
5352
    }
 
5353
}
 
5354
 
 
5355
/*
 
5356
 *   initialize 
 
5357
 */
 
5358
CTcPrsSymtab::CTcPrsSymtab(CTcPrsSymtab *parent_scope)
 
5359
{
 
5360
    size_t hash_table_size;
 
5361
    
 
5362
    /* 
 
5363
     *   Create the hash table.  If we're at global scope (parent_scope ==
 
5364
     *   0), create a large hash table, since we'll probably add lots of
 
5365
     *   symbols; otherwise, it's just a local table, which probably won't
 
5366
     *   have many entries, so create a small table.
 
5367
     *   
 
5368
     *   Note that we always use the static hash function object, hence
 
5369
     *   the table doesn't own the object.  
 
5370
     */
 
5371
    hash_table_size = (parent_scope == 0 ? 512 : 32);
 
5372
    hashtab_ = new (G_prsmem)
 
5373
               CVmHashTable(hash_table_size, hash_func_, FALSE,
 
5374
                            new (G_prsmem) CVmHashEntry *[hash_table_size]);
 
5375
 
 
5376
    /* remember the parent scope */
 
5377
    parent_ = parent_scope;
 
5378
 
 
5379
    /* we're not in a debugger frame list yet */
 
5380
    list_index_ = 0;
 
5381
    list_next_ = 0;
 
5382
}
 
5383
 
 
5384
/*
 
5385
 *   delete 
 
5386
 */
 
5387
CTcPrsSymtab::~CTcPrsSymtab()
 
5388
{
 
5389
    /* delete our underlying hash table */
 
5390
    delete hashtab_;
 
5391
}
 
5392
 
 
5393
/*
 
5394
 *   Find a symbol, marking it as referenced if we find it.   
 
5395
 */
 
5396
CTcSymbol *CTcPrsSymtab::find(const textchar_t *sym, size_t len,
 
5397
                              CTcPrsSymtab **symtab)
 
5398
{
 
5399
    CTcSymbol *entry;
 
5400
 
 
5401
    /* find the symbol */
 
5402
    entry = find_noref(sym, len, symtab);
 
5403
 
 
5404
    /* if we found an entry, mark it as referenced */
 
5405
    if (entry != 0)
 
5406
        entry->mark_referenced();
 
5407
 
 
5408
    /* return the result */
 
5409
    return entry;
 
5410
}
 
5411
 
 
5412
/*
 
5413
 *   Find a symbol.  This base version does not affect the 'referenced'
 
5414
 *   status of the symbol we look up.  
 
5415
 */
 
5416
CTcSymbol *CTcPrsSymtab::find_noref(const textchar_t *sym, size_t len,
 
5417
                                    CTcPrsSymtab **symtab)
 
5418
{
 
5419
    CTcPrsSymtab *curtab;
 
5420
 
 
5421
    /*
 
5422
     *   Look for the symbol.  Start in the current symbol table, and work
 
5423
     *   outwards to the outermost enclosing table.  
 
5424
     */
 
5425
    for (curtab = this ; curtab != 0 ; curtab = curtab->get_parent())
 
5426
    {
 
5427
        CTcSymbol *entry;
 
5428
 
 
5429
        /* look for the symbol in this table */
 
5430
        if ((entry = curtab->find_direct(sym, len)) != 0)
 
5431
        {
 
5432
            /* 
 
5433
             *   found it - if the caller wants to know about the symbol
 
5434
             *   table in which we actually found the symbol, return that
 
5435
             *   information 
 
5436
             */
 
5437
            if (symtab != 0)
 
5438
                *symtab = curtab;
 
5439
 
 
5440
            /* return the symbol table entry we found */
 
5441
            return entry;
 
5442
        }
 
5443
    }
 
5444
 
 
5445
    /* we didn't find the symbol - return failure */
 
5446
    return 0;
 
5447
}
 
5448
 
 
5449
/*
 
5450
 *   Find a symbol directly in this table 
 
5451
 */
 
5452
CTcSymbol *CTcPrsSymtab::find_direct(const textchar_t *sym, size_t len)
 
5453
{
 
5454
    /* return the entry from our hash table */
 
5455
    return (CTcSymbol *)get_hashtab()->find(sym, len);
 
5456
}
 
5457
 
 
5458
/*
 
5459
 *   Add a formal parameter symbol 
 
5460
 */
 
5461
void CTcPrsSymtab::add_formal(const textchar_t *sym, size_t len,
 
5462
                              int formal_num, int copy_str)
 
5463
{
 
5464
    CTcSymLocal *lcl;
 
5465
    
 
5466
    /* 
 
5467
     *   Make sure it's not already defined in our own symbol table - if
 
5468
     *   it is, log an error and ignore the redundant definition.  (We
 
5469
     *   only care about our own scope, not enclosing scopes, since it's
 
5470
     *   perfectly fine to hide variables in enclosing scopes.)  
 
5471
     */
 
5472
    if (get_hashtab()->find(sym, len) != 0)
 
5473
    {
 
5474
        /* log an error */
 
5475
        G_tok->log_error(TCERR_FORMAL_REDEF, (int)len, sym);
 
5476
 
 
5477
        /* don't add the symbol again */
 
5478
        return;
 
5479
    }
 
5480
 
 
5481
    /* create the symbol entry */
 
5482
    lcl = new CTcSymLocal(sym, len, copy_str, TRUE, formal_num);
 
5483
 
 
5484
    /* add it to the table */
 
5485
    get_hashtab()->add(lcl);
 
5486
}
 
5487
 
 
5488
/*
 
5489
 *   Add a symbol to the table 
 
5490
 */
 
5491
void CTcPrsSymtab::add_entry(CTcSymbol *sym)
 
5492
{
 
5493
    /* add it to the table */
 
5494
    get_hashtab()->add(sym);
 
5495
}
 
5496
 
 
5497
/*
 
5498
 *   remove a symbol from the table 
 
5499
 */
 
5500
void CTcPrsSymtab::remove_entry(CTcSymbol *sym)
 
5501
{
 
5502
    /* remove it from the underyling hash table */
 
5503
    get_hashtab()->remove(sym);
 
5504
}
 
5505
 
 
5506
/*
 
5507
 *   Add a local variable symbol 
 
5508
 */
 
5509
CTcSymLocal *CTcPrsSymtab::add_local(const textchar_t *sym, size_t len,
 
5510
                                     int local_num, int copy_str,
 
5511
                                     int init_assigned, int init_referenced)
 
5512
{
 
5513
    CTcSymLocal *lcl;
 
5514
 
 
5515
    /* 
 
5516
     *   make sure the symbol isn't already defined in this scope; if it
 
5517
     *   is, log an error 
 
5518
     */
 
5519
    if (get_hashtab()->find(sym, len) != 0)
 
5520
    {
 
5521
        /* log the error */
 
5522
        G_tok->log_error(TCERR_LOCAL_REDEF, (int)len, sym);
 
5523
 
 
5524
        /* don't create the symbol again - return the original definition */
 
5525
        return 0;
 
5526
    }
 
5527
 
 
5528
    /* create the symbol entry */
 
5529
    lcl = new CTcSymLocal(sym, len, copy_str, FALSE, local_num);
 
5530
 
 
5531
    /* 
 
5532
     *   if the symbol is initially to be marked as referenced or
 
5533
     *   assigned, mark it now 
 
5534
     */
 
5535
    if (init_assigned)
 
5536
        lcl->set_val_assigned(TRUE);
 
5537
    if (init_referenced)
 
5538
        lcl->set_val_used(TRUE);
 
5539
    
 
5540
    /* add it to the table */
 
5541
    get_hashtab()->add(lcl);
 
5542
 
 
5543
    /* return the new local */
 
5544
    return lcl;
 
5545
}
 
5546
 
 
5547
/*
 
5548
 *   Add a code label ('goto') symbol
 
5549
 */
 
5550
CTcSymLabel *CTcPrsSymtab::add_code_label(const textchar_t *sym, size_t len,
 
5551
                                          int copy_str)
 
5552
{
 
5553
    CTcSymLabel *lbl;
 
5554
 
 
5555
    /* 
 
5556
     *   make sure the symbol isn't already defined in this scope; if it
 
5557
     *   is, log an error 
 
5558
     */
 
5559
    if (get_hashtab()->find(sym, len) != 0)
 
5560
    {
 
5561
        /* log the error */
 
5562
        G_tok->log_error(TCERR_CODE_LABEL_REDEF, (int)len, sym);
 
5563
 
 
5564
        /* don't create the symbol again - return the original definition */
 
5565
        return 0;
 
5566
    }
 
5567
 
 
5568
    /* create the symbol entry */
 
5569
    lbl = new CTcSymLabel(sym, len, copy_str);
 
5570
 
 
5571
    /* add it to the table */
 
5572
    get_hashtab()->add(lbl);
 
5573
 
 
5574
    /* return the new label */
 
5575
    return lbl;
 
5576
}
 
5577
 
 
5578
 
 
5579
/* 
 
5580
 *   Find a symbol; if the symbol isn't defined, add a new entry according
 
5581
 *   to the action flag.  Because we add a symbol entry if the symbol
 
5582
 *   isn't defined, this *always* returns a valid symbol object.  
 
5583
 */
 
5584
CTcSymbol *CTcPrsSymtab::find_or_def(const textchar_t *sym, size_t len,
 
5585
                                     int copy_str, tcprs_undef_action action)
 
5586
{
 
5587
    CTcSymbol *entry;
 
5588
    CTcPrsSymtab *curtab;
 
5589
 
 
5590
    /*
 
5591
     *   Look for the symbol.  Start in the current symbol table, and work
 
5592
     *   outwards to the outermost enclosing table. 
 
5593
     */
 
5594
    for (curtab = this ; ; curtab = curtab->get_parent())
 
5595
    {
 
5596
        /* look for the symbol in this table */
 
5597
        entry = (CTcSymbol *)curtab->get_hashtab()->find(sym, len);
 
5598
        if (entry != 0)
 
5599
        {
 
5600
            /* mark the entry as referenced */
 
5601
            entry->mark_referenced();
 
5602
 
 
5603
            /* found it - return the symbol */
 
5604
            return entry;
 
5605
        }
 
5606
 
 
5607
        /* 
 
5608
         *   If there's no parent symbol table, the symbol is undefined.
 
5609
         *   Add a new symbol according to the action parameter.  Note
 
5610
         *   that we always add the new symbol at global scope, hence we
 
5611
         *   add it to 'curtab', not 'this'.  
 
5612
         */
 
5613
        if (curtab->get_parent() == 0)
 
5614
        {
 
5615
            /* check which action we're being asked to perform */
 
5616
            switch(action)
 
5617
            {
 
5618
            case TCPRS_UNDEF_ADD_UNDEF:
 
5619
                /* add an "undefined" entry - log an error */
 
5620
                G_tok->log_error(TCERR_UNDEF_SYM, (int)len, sym);
 
5621
 
 
5622
                /* create a new symbol of type undefined */
 
5623
                entry = new CTcSymUndef(sym, len, copy_str);
 
5624
 
 
5625
                /* finish up */
 
5626
                goto add_entry;
 
5627
 
 
5628
            case TCPRS_UNDEF_ADD_PROP:
 
5629
                /* add a new "property" entry - log a warning */
 
5630
                G_tok->log_warning(TCERR_ASSUME_SYM_PROP, (int)len, sym);
 
5631
 
 
5632
                /* create a new symbol of type property */
 
5633
                entry = new CTcSymProp(sym, len, copy_str,
 
5634
                                       G_cg->new_prop_id());
 
5635
 
 
5636
                /* finish up */
 
5637
                goto add_entry;
 
5638
 
 
5639
            case TCPRS_UNDEF_ADD_PROP_NO_WARNING:
 
5640
                /* add a new property entry with no warning */
 
5641
                entry = new CTcSymProp(sym, len, copy_str,
 
5642
                                       G_cg->new_prop_id());
 
5643
 
 
5644
                /* finish up */
 
5645
                goto add_entry;
 
5646
 
 
5647
            add_entry:
 
5648
                /* add the new entry to the global table */
 
5649
                add_to_global_symtab(curtab, entry);
 
5650
 
 
5651
                /* return the new entry */
 
5652
                return entry;
 
5653
            }
 
5654
        }
 
5655
    }
 
5656
}
 
5657
 
 
5658
/*
 
5659
 *   Enumerate the entries in a symbol table 
 
5660
 */
 
5661
void CTcPrsSymtab::enum_entries(void (*func)(void *, CTcSymbol *),
 
5662
                                void *ctx)
 
5663
{
 
5664
    /* 
 
5665
     *   Ask the hash table to perform the enumeration.  We know that all
 
5666
     *   of our entries in the symbol table are CTcSymbol objects, so we
 
5667
     *   can coerce the callback function to the appropriate type without
 
5668
     *   danger. 
 
5669
     */
 
5670
    get_hashtab()->enum_entries((void (*)(void *, CVmHashEntry *))func, ctx);
 
5671
}
 
5672
 
 
5673
/*
 
5674
 *   Scan the symbol table for unreferenced local variables 
 
5675
 */
 
5676
void CTcPrsSymtab::check_unreferenced_locals()
 
5677
{
 
5678
    /* skip the check if we're only parsing for syntax */
 
5679
    if (!G_prs->get_syntax_only())
 
5680
    {
 
5681
        /* run the symbols through our unreferenced local check callback */
 
5682
        enum_entries(&unref_local_cb, this);
 
5683
    }
 
5684
}
 
5685
 
 
5686
/*
 
5687
 *   Enumeration callback to check for unreferenced locals 
 
5688
 */
 
5689
void CTcPrsSymtab::unref_local_cb(void *, CTcSymbol *sym)
 
5690
{
 
5691
    /* check the symbol */
 
5692
    sym->check_local_references();
 
5693
}
 
5694
 
 
5695
/* ------------------------------------------------------------------------ */
 
5696
/*
 
5697
 *   Comma node 
 
5698
 */
 
5699
 
 
5700
/*
 
5701
 *   fold constants 
 
5702
 */
 
5703
CTcPrsNode *CTPNCommaBase::fold_binop()
 
5704
{
 
5705
    /* use the normal addition folder */
 
5706
    return S_op_comma.eval_constant(left_, right_);
 
5707
}
 
5708
 
 
5709
 
 
5710
/* ------------------------------------------------------------------------ */
 
5711
/*
 
5712
 *   Addition parse node 
 
5713
 */
 
5714
 
 
5715
/* 
 
5716
 *   Fold constants.  We override the default fold_constants() for
 
5717
 *   addition nodes because addition constancy can be affected by symbol
 
5718
 *   resolution.  In particular, if we resolve symbols in a list, the list
 
5719
 *   could turn constant, which could in turn make the result of an
 
5720
 *   addition operator with the list as an operand turn constant.  
 
5721
 */
 
5722
CTcPrsNode *CTPNAddBase::fold_binop()
 
5723
{
 
5724
    /* use the normal addition folder */
 
5725
    return S_op_add.eval_constant(left_, right_);
 
5726
}
 
5727
 
 
5728
/* ------------------------------------------------------------------------ */
 
5729
/*
 
5730
 *   Subtraction parse node 
 
5731
 */
 
5732
 
 
5733
/* 
 
5734
 *   Fold constants.  We override the default fold_constants() for the
 
5735
 *   subtraction node because subtraction constancy can be affected by
 
5736
 *   symbol resolution.  In particular, if we resolve symbols in a list,
 
5737
 *   the list could turn constant, which could in turn make the result of
 
5738
 *   a subtraction operator with the list as an operand turn constant.  
 
5739
 */
 
5740
CTcPrsNode *CTPNSubBase::fold_binop()
 
5741
{
 
5742
    /* use the normal addition folder */
 
5743
    return S_op_sub.eval_constant(left_, right_);
 
5744
}
 
5745
 
 
5746
/* ------------------------------------------------------------------------ */
 
5747
/*
 
5748
 *   Equality Comparison parse node 
 
5749
 */
 
5750
 
 
5751
/*
 
5752
 *   fold constants 
 
5753
 */
 
5754
CTcPrsNode *CTPNEqBase::fold_binop()
 
5755
{
 
5756
    /* use the normal addition folder */
 
5757
    return S_op_eq.eval_constant(left_, right_);
 
5758
}
 
5759
 
 
5760
/* ------------------------------------------------------------------------ */
 
5761
/*
 
5762
 *   Inequality Comparison parse node 
 
5763
 */
 
5764
 
 
5765
/*
 
5766
 *   fold constants 
 
5767
 */
 
5768
CTcPrsNode *CTPNNeBase::fold_binop()
 
5769
{
 
5770
    /* use the normal addition folder */
 
5771
    return S_op_ne.eval_constant(left_, right_);
 
5772
}
 
5773
 
 
5774
/* ------------------------------------------------------------------------ */
 
5775
/*
 
5776
 *   Logical AND parse node 
 
5777
 */
 
5778
 
 
5779
/*
 
5780
 *   fold constants 
 
5781
 */
 
5782
CTcPrsNode *CTPNAndBase::fold_binop()
 
5783
{
 
5784
    /* use the normal addition folder */
 
5785
    return S_op_and.eval_constant(left_, right_);
 
5786
}
 
5787
 
 
5788
/* ------------------------------------------------------------------------ */
 
5789
/*
 
5790
 *   Logical OR parse node 
 
5791
 */
 
5792
 
 
5793
/*
 
5794
 *   fold constants 
 
5795
 */
 
5796
CTcPrsNode *CTPNOrBase::fold_binop()
 
5797
{
 
5798
    /* use the normal addition folder */
 
5799
    return S_op_or.eval_constant(left_, right_);
 
5800
}
 
5801
 
 
5802
/* ------------------------------------------------------------------------ */
 
5803
/*
 
5804
 *   NOT parse node 
 
5805
 */
 
5806
 
 
5807
/*
 
5808
 *   fold constants 
 
5809
 */
 
5810
CTcPrsNode *CTPNNotBase::fold_unop()
 
5811
{
 
5812
    /* use the normal addition folder */
 
5813
    return S_op_unary.eval_const_not(sub_);
 
5814
}
 
5815
 
 
5816
 
 
5817
/* ------------------------------------------------------------------------ */
 
5818
/*
 
5819
 *   Subscript parse node
 
5820
 */
 
5821
 
 
5822
/* 
 
5823
 *   Fold constants.  We override the default fold_constants() for
 
5824
 *   subscript nodes because subscript constancy can be affected by symbol
 
5825
 *   resolution.  In particular, if we resolve symbols in a list, the list
 
5826
 *   could turn constant, which could in turn make the result of a
 
5827
 *   subscript operator with the list as an operand turn constant.  
 
5828
 */
 
5829
/* ------------------------------------------------------------------------ */
 
5830
/*
 
5831
 *   Equality Comparison parse node 
 
5832
 */
 
5833
 
 
5834
/*
 
5835
 *   fold constants 
 
5836
 */
 
5837
CTcPrsNode *CTPNSubscriptBase::fold_binop()
 
5838
{
 
5839
    /* use the normal addition folder */
 
5840
    return S_op_unary.eval_const_subscript(left_, right_);
 
5841
}
 
5842
 
 
5843
 
 
5844
/* ------------------------------------------------------------------------ */
 
5845
/*
 
5846
 *   Parser Symbol Table Entry base class 
 
5847
 */
 
5848
 
 
5849
/*
 
5850
 *   Allocate symbol objects from the parse pool, since these objects have
 
5851
 *   all of the lifespan characteristics of pool objects.  
 
5852
 */
 
5853
void *CTcSymbolBase::operator new(size_t siz)
 
5854
{
 
5855
    return G_prsmem->alloc(siz);
 
5856
}
 
5857
 
 
5858
/*
 
5859
 *   Write to a symbol file.  
 
5860
 */
 
5861
int CTcSymbolBase::write_to_sym_file(CVmFile *fp)
 
5862
{
 
5863
    /* do the basic writing */
 
5864
    return write_to_file_gen(fp);
 
5865
}
 
5866
 
 
5867
/*
 
5868
 *   Write to a file.  This is a generic base routine that can be used for
 
5869
 *   writing to a symbol or object file. 
 
5870
 */
 
5871
int CTcSymbolBase::write_to_file_gen(CVmFile *fp)
 
5872
{
 
5873
    /* write my type */
 
5874
    fp->write_int2((int)get_type());
 
5875
 
 
5876
    /* write my name */
 
5877
    return write_name_to_file(fp);
 
5878
}
 
5879
 
 
5880
/*
 
5881
 *   Write the symbol name to a file 
 
5882
 */
 
5883
int CTcSymbolBase::write_name_to_file(CVmFile *fp)
 
5884
{
 
5885
    /* write the length of my symbol name, followed by the symbol name */
 
5886
    fp->write_int2((int)get_sym_len());
 
5887
 
 
5888
    /* write the symbol string */
 
5889
    fp->write_bytes(get_sym(), get_sym_len());
 
5890
 
 
5891
    /* we wrote the symbol */
 
5892
    return TRUE;
 
5893
}
 
5894
 
 
5895
/*
 
5896
 *   Read a symbol from a symbol file 
 
5897
 */
 
5898
CTcSymbol *CTcSymbolBase::read_from_sym_file(CVmFile *fp)
 
5899
{
 
5900
    tc_symtype_t typ;
 
5901
    
 
5902
    /* 
 
5903
     *   read the type - this is the one thing we know is always present
 
5904
     *   for every symbol (the rest of the data might vary per subclass) 
 
5905
     */
 
5906
    typ = (tc_symtype_t)fp->read_uint2();
 
5907
 
 
5908
    /* create the object based on the type */
 
5909
    switch(typ)
 
5910
    {
 
5911
    case TC_SYM_FUNC:
 
5912
        return CTcSymFunc::read_from_sym_file(fp);
 
5913
 
 
5914
    case TC_SYM_OBJ:
 
5915
        return CTcSymObj::read_from_sym_file(fp);
 
5916
 
 
5917
    case TC_SYM_PROP:
 
5918
        return CTcSymProp::read_from_sym_file(fp);
 
5919
 
 
5920
    case TC_SYM_ENUM:
 
5921
        return CTcSymEnum::read_from_sym_file(fp);
 
5922
 
 
5923
    default:
 
5924
        /* other types should not be in a symbol file */
 
5925
        G_tcmain->log_error(0, 0, TC_SEV_ERROR, TCERR_SYMEXP_INV_TYPE);
 
5926
        return 0;
 
5927
    }
 
5928
}
 
5929
 
 
5930
/*
 
5931
 *   Read the basic information from the symbol file 
 
5932
 */
 
5933
const char *CTcSymbolBase::base_read_from_sym_file(CVmFile *fp)
 
5934
{
 
5935
    char buf[TOK_SYM_MAX_LEN + 1];
 
5936
 
 
5937
    /* read, null-terminate, and return the string */
 
5938
    return CTcParser::read_len_prefix_str(fp, buf, sizeof(buf), 0,
 
5939
                                          TCERR_SYMEXP_SYM_TOO_LONG);
 
5940
}
 
5941
 
 
5942
/*
 
5943
 *   Write to an object file.  
 
5944
 */
 
5945
int CTcSymbolBase::write_to_obj_file(CVmFile *fp)
 
5946
{
 
5947
    /* do the basic writing */
 
5948
    return write_to_file_gen(fp);
 
5949
}
 
5950
 
 
5951
 
 
5952
/* ------------------------------------------------------------------------ */
 
5953
/*
 
5954
 *   function symbol entry base 
 
5955
 */
 
5956
 
 
5957
/*
 
5958
 *   fold function name into a function address
 
5959
 */
 
5960
CTcPrsNode *CTcSymFuncBase::fold_constant()
 
5961
{
 
5962
    CTcConstVal cval;
 
5963
 
 
5964
    /* set up the function pointer constant */
 
5965
    cval.set_funcptr((CTcSymFunc *)this);
 
5966
 
 
5967
    /* return a constant node with the function pointer */
 
5968
    return new CTPNConst(&cval);
 
5969
}
 
5970
 
 
5971
/*
 
5972
 *   Write to a symbol file 
 
5973
 */
 
5974
int CTcSymFuncBase::write_to_sym_file(CVmFile *fp)
 
5975
{
 
5976
    char buf[5];
 
5977
    CTcSymFunc *cur;
 
5978
    int ext_modify;
 
5979
 
 
5980
    /* scan for the bottom of our modify stack */
 
5981
    for (cur = get_mod_base() ; cur != 0 && cur->get_mod_base() != 0 ;
 
5982
         cur = cur->get_mod_base()) ;
 
5983
 
 
5984
    /* we modify an external if the bottom of our modify stack is external */
 
5985
    ext_modify = (cur != 0 && cur->is_extern());
 
5986
 
 
5987
    /* 
 
5988
     *   If we're external, don't bother writing to the file - if we're
 
5989
     *   importing a function, we don't want to export it as well.  Note that
 
5990
     *   a function that is replacing or modifying an external function is
 
5991
     *   fundamentally external itself, because the function must be defined
 
5992
     *   in another file to be replaceable/modifiable.
 
5993
     *   
 
5994
     *   As an exception, if this is a multi-method base symbol, and a
 
5995
     *   multi-method with this name is defined in this file, export it even
 
5996
     *   though it's technically an extern symbol.  We don't export most
 
5997
     *   extern symbols because we count on the definer to export them, but
 
5998
     *   in the case of multi-method base symbols, there is no definer - the
 
5999
     *   base symbol is basically a placeholder to be filled in by the
 
6000
     *   linker.  So *someone* has to export these.  The logical place to
 
6001
     *   export them is from any file that defines a multi-method based on
 
6002
     *   the base symbol.  
 
6003
     */
 
6004
    if ((is_extern_ || ext_replace_ || ext_modify) && !mm_def_)
 
6005
        return FALSE;
 
6006
    
 
6007
    /* inherit default */
 
6008
    CTcSymbol::write_to_sym_file(fp);
 
6009
 
 
6010
    /* write our argument count, varargs flag, and return value flag */
 
6011
    oswp2(buf, argc_);
 
6012
    buf[2] = (varargs_ != 0);
 
6013
    buf[3] = (has_retval_ != 0);
 
6014
    buf[4] = (is_multimethod_ ? 1 : 0)
 
6015
             | (is_multimethod_base_ ? 2 : 0);
 
6016
    fp->write_bytes(buf, 5);
 
6017
 
 
6018
    /* we wrote the symbol */
 
6019
    return TRUE;
 
6020
}
 
6021
 
 
6022
/*
 
6023
 *   add an absolute fixup to my list 
 
6024
 */
 
6025
void CTcSymFuncBase::add_abs_fixup(CTcDataStream *ds, ulong ofs)
 
6026
{
 
6027
    /* ask the code body to add the fixup */
 
6028
    CTcAbsFixup::add_abs_fixup(&fixups_, ds, ofs);
 
6029
}
 
6030
 
 
6031
/*
 
6032
 *   add an absolute fixup at the current stream offset 
 
6033
 */
 
6034
void CTcSymFuncBase::add_abs_fixup(CTcDataStream *ds)
 
6035
{
 
6036
    /* ask the code body to add the fixup */
 
6037
    CTcAbsFixup::add_abs_fixup(&fixups_, ds, ds->get_ofs());
 
6038
}
 
6039
 
 
6040
/*
 
6041
 *   Read from a symbol file
 
6042
 */
 
6043
CTcSymbol *CTcSymFuncBase::read_from_sym_file(CVmFile *fp)
 
6044
{
 
6045
    char symbuf[4096];
 
6046
    const char *sym;
 
6047
    char info[5];
 
6048
    int argc;
 
6049
    int varargs;
 
6050
    int has_retval;
 
6051
    int is_multimethod, is_multimethod_base;
 
6052
 
 
6053
    /* 
 
6054
     *   Read the symbol name.  Use a custom reader instead of the base
 
6055
     *   reader, because function symbols can be quite long, due to
 
6056
     *   multimethod name decoration. 
 
6057
     */
 
6058
    if ((sym = CTcParser::read_len_prefix_str(
 
6059
        fp, symbuf, sizeof(symbuf), 0, TCERR_SYMEXP_SYM_TOO_LONG)) == 0)
 
6060
        return 0;
 
6061
 
 
6062
    /* read the argument count, varargs flag, and return value flag */
 
6063
    fp->read_bytes(info, 5);
 
6064
    argc = osrp2(info);
 
6065
    varargs = (info[2] != 0);
 
6066
    has_retval = (info[3] != 0);
 
6067
    is_multimethod = ((info[4] & 1) != 0);
 
6068
    is_multimethod_base = ((info[4] & 2) != 0);
 
6069
 
 
6070
    /* create and return the new symbol */
 
6071
    return new CTcSymFunc(sym, strlen(sym), FALSE, argc,
 
6072
                          varargs, has_retval,
 
6073
                          is_multimethod, is_multimethod_base, TRUE);
 
6074
}
 
6075
 
 
6076
/*
 
6077
 *   Write to an object file 
 
6078
 */
 
6079
int CTcSymFuncBase::write_to_obj_file(CVmFile *fp)
 
6080
{
 
6081
    char buf[10];
 
6082
    CTcSymFunc *cur;
 
6083
    CTcSymFunc *last_mod;
 
6084
    int mod_body_cnt;
 
6085
    int ext_modify;
 
6086
 
 
6087
    /* 
 
6088
     *   If it's external, and we have no fixups, don't bother writing it to
 
6089
     *   the object file.  If there are no fixups, we don't have any
 
6090
     *   references to the function, hence there's no need to include it in
 
6091
     *   the object file.  
 
6092
     */
 
6093
    if (is_extern_ && fixups_ == 0)
 
6094
        return FALSE;
 
6095
 
 
6096
    /*
 
6097
     *   If we have a modified base function, scan down the chain of modified
 
6098
     *   bases until we reach the last one.  If it's external, we need to
 
6099
     *   note this, and we need to store the fixup list for the external
 
6100
     *   symbol so that we can explicitly link it to the imported symbol at
 
6101
     *   link time.  
 
6102
     */
 
6103
    for (mod_body_cnt = 0, last_mod = 0, cur = get_mod_base() ; cur != 0 ;
 
6104
         last_mod = cur, cur = cur->get_mod_base())
 
6105
    {
 
6106
        /* if this one has an associated code body, count it */
 
6107
        if (cur->get_code_body() != 0 && !cur->get_code_body()->is_replaced())
 
6108
            ++mod_body_cnt;
 
6109
    }
 
6110
 
 
6111
    /* we modify an external if the last in the modify chain is external */
 
6112
    ext_modify = (last_mod != 0 && last_mod->is_extern());
 
6113
 
 
6114
    /* inherit default */
 
6115
    CTcSymbol::write_to_obj_file(fp);
 
6116
 
 
6117
    /* 
 
6118
     *   write our argument count, varargs flag, return value, extern flags,
 
6119
     *   and the number of our modified base functions with code bodies 
 
6120
     */
 
6121
    oswp2(buf, argc_);
 
6122
    buf[2] = (varargs_ != 0);
 
6123
    buf[3] = (has_retval_ != 0);
 
6124
    buf[4] = (is_extern_ != 0);
 
6125
    buf[5] = (ext_replace_ != 0);
 
6126
    buf[6] = (ext_modify != 0);
 
6127
    buf[7] = (is_multimethod_ ? 1 : 0)
 
6128
             | (is_multimethod_base_ ? 2 : 0);
 
6129
    oswp2(buf + 8, mod_body_cnt);
 
6130
    fp->write_bytes(buf, 10);
 
6131
 
 
6132
    /* if we modify an external, save its fixup list */
 
6133
    if (ext_modify)
 
6134
        CTcAbsFixup::write_fixup_list_to_object_file(fp, last_mod->fixups_);
 
6135
 
 
6136
    /* write the code stream offsets of the modified base function bodies */
 
6137
    for (cur = get_mod_base() ; cur != 0 ; cur = cur->get_mod_base())
 
6138
    {
 
6139
        /* if this one has a code body, write its code stream offset */
 
6140
        if (cur->get_code_body() != 0)
 
6141
            fp->write_int4(cur->get_anchor()->get_ofs());
 
6142
    }
 
6143
 
 
6144
    /* 
 
6145
     *   If we're defined as external, write our fixup list.  Since this
 
6146
     *   is an external symbol, it will have no anchor in the code stream,
 
6147
     *   hence we need to write our fixup list with the symbol and not
 
6148
     *   with the anchor.  
 
6149
     */
 
6150
    if (is_extern_)
 
6151
        CTcAbsFixup::write_fixup_list_to_object_file(fp, fixups_);
 
6152
 
 
6153
    /* we wrote the symbol */
 
6154
    return TRUE;
 
6155
}
 
6156
 
 
6157
/* ------------------------------------------------------------------------ */
 
6158
/*
 
6159
 *   local variable symbol entry base 
 
6160
 */
 
6161
 
 
6162
/*
 
6163
 *   initialize 
 
6164
 */
 
6165
CTcSymLocalBase::CTcSymLocalBase(const char *str, size_t len, int copy,
 
6166
                                 int is_param, int var_num)
 
6167
    : CTcSymbol(str, len, copy, (is_param ? TC_SYM_PARAM : TC_SYM_LOCAL))
 
6168
{
 
6169
    /* remember the information */
 
6170
    var_num_ = var_num;
 
6171
    is_param_ = is_param;
 
6172
 
 
6173
    /* presume it's a regular stack variable (not a context local) */
 
6174
    is_ctx_local_ = FALSE;
 
6175
    ctx_orig_ = 0;
 
6176
    ctx_var_num_ = 0;
 
6177
    ctx_level_ = 0;
 
6178
    ctx_var_num_set_ = FALSE;
 
6179
 
 
6180
    /* so far, the value isn't used anywhere */
 
6181
    val_used_ = FALSE;
 
6182
    val_assigned_ = FALSE;
 
6183
 
 
6184
    /* the symbol has not been referenced so far */
 
6185
    referenced_ = FALSE;
 
6186
 
 
6187
    /* remember where the symbol is defined in the source file */
 
6188
    G_tok->get_last_pos(&src_desc_, &src_linenum_);
 
6189
}
 
6190
 
 
6191
/*
 
6192
 *   Mark the value of the variable as used 
 
6193
 */
 
6194
void CTcSymLocalBase::set_val_used(int f)
 
6195
{
 
6196
    /* note the new status */
 
6197
    val_used_ = f;
 
6198
 
 
6199
    /* if we have now assigned the value, propagate to the original */
 
6200
    if (f && ctx_orig_ != 0)
 
6201
        ctx_orig_->set_val_used(TRUE);
 
6202
}
 
6203
 
 
6204
/*
 
6205
 *   Mark the value of the variable as assigned
 
6206
 */
 
6207
void CTcSymLocalBase::set_val_assigned(int f)
 
6208
{
 
6209
    /* note the new status */
 
6210
    val_assigned_ = f;
 
6211
 
 
6212
    /* if we have now assigned the value, propagate to the original */
 
6213
    if (f && ctx_orig_ != 0)
 
6214
        ctx_orig_->set_val_assigned(TRUE);
 
6215
}
 
6216
 
 
6217
/*
 
6218
 *   Check for references to this local 
 
6219
 */
 
6220
void CTcSymLocalBase::check_local_references()
 
6221
{
 
6222
    int err;
 
6223
    tc_severity_t sev = TC_SEV_WARNING;
 
6224
    
 
6225
    /* 
 
6226
     *   if this isn't an original, but is simply a copy of a variable
 
6227
     *   inherited from an enclosing scope (such as into an anonymous
 
6228
     *   function), don't bother even checking for errors - we'll let the
 
6229
     *   original symbol take care of reporting its own errors 
 
6230
     */
 
6231
    if (ctx_orig_ != 0)
 
6232
        return;
 
6233
 
 
6234
    /* 
 
6235
     *   if it's unreferenced or unassigned (or both), log an error; note
 
6236
     *   that a formal parameter is always assigned, since the value is
 
6237
     *   assigned by the caller 
 
6238
     */
 
6239
    if (!get_val_used() && (!get_val_assigned() && !is_param()))
 
6240
    {
 
6241
        /* the variable is never used at all */
 
6242
        err = TCERR_UNREFERENCED_LOCAL;
 
6243
    }
 
6244
    else if (!get_val_used())
 
6245
    {
 
6246
        if (is_param() || is_list_param())
 
6247
        {
 
6248
            /* 
 
6249
             *   it's a parameter, or a local that actually contains a
 
6250
             *   varargs parameter list - generate only a pedantic error 
 
6251
             */
 
6252
            sev = TC_SEV_PEDANTIC;
 
6253
            err = TCERR_UNREFERENCED_PARAM;
 
6254
        }
 
6255
        else
 
6256
        {
 
6257
            /* this local is assigned a value that's never used */
 
6258
            err = TCERR_UNUSED_LOCAL_ASSIGNMENT;
 
6259
        }
 
6260
    }
 
6261
    else if (!get_val_assigned() && !is_param())
 
6262
    {
 
6263
        /* it's used but never assigned */
 
6264
        err = TCERR_UNASSIGNED_LOCAL;
 
6265
    }
 
6266
    else
 
6267
    {
 
6268
        /* no error */
 
6269
        return;
 
6270
    }
 
6271
 
 
6272
    /* 
 
6273
     *   display the warning message, showing the error location as the
 
6274
     *   source line where the local was defined 
 
6275
     */
 
6276
    G_tcmain->log_error(get_src_desc(), get_src_linenum(),
 
6277
                        sev, err, (int)get_sym_len(), get_sym());
 
6278
}
 
6279
 
 
6280
/*
 
6281
 *   create a new context variable copy of this symbol 
 
6282
 */
 
6283
CTcSymbol *CTcSymLocalBase::new_ctx_var() const
 
6284
{
 
6285
    CTcSymLocal *lcl;
 
6286
    
 
6287
    /* create a new local with the same name */
 
6288
    lcl = new CTcSymLocal(get_sym(), get_sym_len(), FALSE, FALSE, 0);
 
6289
 
 
6290
    /* refer the copy back to the original (i.e., me) */
 
6291
    lcl->set_ctx_orig((CTcSymLocal *)this);
 
6292
 
 
6293
    /* set up the context variable information */
 
6294
    if (!is_ctx_local_)
 
6295
    {
 
6296
        /* 
 
6297
         *   The original is a true local - we're at the first context
 
6298
         *   level, and we don't yet have a property assigned, since we
 
6299
         *   don't know if this variable is actually going to be
 
6300
         *   referenced. 
 
6301
         */
 
6302
        lcl->set_ctx_level(1);
 
6303
    }
 
6304
    else
 
6305
    {
 
6306
        /* 
 
6307
         *   The original was already a context variable - we're at one
 
6308
         *   higher context level in this function, and we use the same
 
6309
         *   context property as the original did.  
 
6310
         */
 
6311
        lcl->set_ctx_level(ctx_level_ + 1);
 
6312
    }
 
6313
 
 
6314
    /* return the new symbol */
 
6315
    return lcl;
 
6316
}
 
6317
 
 
6318
/*
 
6319
 *   Apply context variable conversion 
 
6320
 */
 
6321
int CTcSymLocalBase::apply_ctx_var_conv(CTcPrsSymtab *symtab,
 
6322
                                        CTPNCodeBody *code_body)
 
6323
{
 
6324
    /* 
 
6325
     *   if this symbol isn't referenced, simply delete it from the table,
 
6326
     *   so that it doesn't get entered in the debug records; and there's
 
6327
     *   no need to propagate it back to the enclosing scope as a context
 
6328
     *   variable, since it's not referenced from this enclosed scope 
 
6329
     */
 
6330
    if (!referenced_)
 
6331
    {
 
6332
        /* remove the symbol from the table */
 
6333
        symtab->remove_entry(this);
 
6334
 
 
6335
        /* this variable doesn't need to be converted */
 
6336
        return FALSE;
 
6337
    }
 
6338
 
 
6339
    /* 
 
6340
     *   convert the symbol in the enclosing scope to a context local, if
 
6341
     *   it's not already 
 
6342
     */
 
6343
    if (ctx_orig_ != 0)
 
6344
    {
 
6345
        /* convert the original to a context symbol */
 
6346
        ctx_orig_->convert_to_ctx_var(get_val_used(), get_val_assigned());
 
6347
 
 
6348
        /* 
 
6349
         *   ask the code body for the context object's local variable for
 
6350
         *   our recursion level 
 
6351
         */
 
6352
        ctx_var_num_ = code_body->get_or_add_ctx_var_for_level(ctx_level_);
 
6353
 
 
6354
        /* note that we've set our context variable ID */
 
6355
        ctx_var_num_set_ = TRUE;
 
6356
 
 
6357
        /* this variable was converted */
 
6358
        return TRUE;
 
6359
    }
 
6360
 
 
6361
    /* this variable wasn't converted */
 
6362
    return FALSE;
 
6363
}
 
6364
 
 
6365
/*
 
6366
 *   convert this variable to a context variable 
 
6367
 */
 
6368
void CTcSymLocalBase::convert_to_ctx_var(int val_used, int val_assigned)
 
6369
{
 
6370
    /* if I'm not already a context local, mark me as a context local */
 
6371
    if (!is_ctx_local_)
 
6372
    {
 
6373
        /* mark myself as a context local */
 
6374
        is_ctx_local_ = TRUE;
 
6375
 
 
6376
        /* 
 
6377
         *   we haven't yet assigned our local context variable, since
 
6378
         *   we're still processing the inner scope at this point; just
 
6379
         *   store placeholders for now so we know to come back and fix
 
6380
         *   this up 
 
6381
         */
 
6382
        ctx_var_num_ = 0;
 
6383
        ctx_arr_idx_ = 0;
 
6384
    }
 
6385
 
 
6386
    /* note that I've been referenced */
 
6387
    mark_referenced();
 
6388
 
 
6389
    /* propagate the value-used and value-assigned flags */
 
6390
    if (val_used)
 
6391
        set_val_used(TRUE);
 
6392
    if (val_assigned)
 
6393
        set_val_assigned(TRUE);
 
6394
        
 
6395
    /* propagate the conversion to the original symbol */
 
6396
    if (ctx_orig_ != 0)
 
6397
        ctx_orig_->convert_to_ctx_var(val_used, val_assigned);
 
6398
}
 
6399
 
 
6400
/*
 
6401
 *   finish the context variable conversion 
 
6402
 */
 
6403
void CTcSymLocalBase::finish_ctx_var_conv()
 
6404
{
 
6405
    /* 
 
6406
     *   If this isn't already marked as a context variable, there's
 
6407
     *   nothing to do - this variable must not have been referenced from
 
6408
     *   an anonymous function yet, and hence can be kept in the stack.
 
6409
     *   
 
6410
     *   Similarly, if my context local variable number has been assigned
 
6411
     *   already, there's nothing to do - we must have been set to refer
 
6412
     *   back to a context variable in an enclosing scope (this can happen
 
6413
     *   in a nested anonymous function).
 
6414
     */
 
6415
    if (!is_ctx_local_ || ctx_var_num_set_)
 
6416
        return;
 
6417
 
 
6418
    /* 
 
6419
     *   tell the parser to create a local context for this scope, if it
 
6420
     *   hasn't already 
 
6421
     */
 
6422
    G_prs->init_local_ctx();
 
6423
 
 
6424
    /* use the local context variable specified by the parser */
 
6425
    ctx_var_num_ = G_prs->get_local_ctx_var();
 
6426
    ctx_var_num_set_ = TRUE;
 
6427
 
 
6428
    /* assign our array index */
 
6429
    if (ctx_arr_idx_ == 0)
 
6430
        ctx_arr_idx_ = G_prs->alloc_ctx_arr_idx();
 
6431
}
 
6432
 
 
6433
/*
 
6434
 *   Get my context variable array index 
 
6435
 */
 
6436
int CTcSymLocalBase::get_ctx_arr_idx() const
 
6437
{
 
6438
    /* 
 
6439
     *   if I'm based on an original symbol from another scope, use the
 
6440
     *   same property ID as the original symbol 
 
6441
     */
 
6442
    if (ctx_orig_ != 0)
 
6443
        return ctx_orig_->get_ctx_arr_idx();
 
6444
 
 
6445
    /* return my context property */
 
6446
    return ctx_arr_idx_;
 
6447
}
 
6448
 
 
6449
/* ------------------------------------------------------------------------ */
 
6450
/*
 
6451
 *   object symbol entry base 
 
6452
 */
 
6453
 
 
6454
/*
 
6455
 *   fold the symbol as a constant 
 
6456
 */
 
6457
CTcPrsNode *CTcSymObjBase::fold_constant()
 
6458
{
 
6459
    CTcConstVal cval;
 
6460
 
 
6461
    /* set up the object constant */
 
6462
    cval.set_obj(get_obj_id(), get_metaclass());
 
6463
 
 
6464
    /* return a constant node */
 
6465
    return new CTPNConst(&cval);
 
6466
}
 
6467
 
 
6468
/*
 
6469
 *   Write to a symbol file 
 
6470
 */
 
6471
int CTcSymObjBase::write_to_sym_file(CVmFile *fp)
 
6472
{
 
6473
    int result;
 
6474
    
 
6475
    /* 
 
6476
     *   If we're external, don't bother writing to the file - if we're
 
6477
     *   importing an object, we don't want to export it as well.  If it's
 
6478
     *   modified, don't write it either, because modified symbols cannot
 
6479
     *   be referenced directly by name (the symbol for a modified object
 
6480
     *   is a fake symbol anyway).  In addition, don't write the symbol if
 
6481
     *   it's a 'modify' or 'replace' definition that applies to an
 
6482
     *   external base object - instead, we'll pick up the symbol from the
 
6483
     *   other symbol file with the original definition.  
 
6484
     */
 
6485
    if (is_extern_ || modified_ || ext_modify_ || ext_replace_)
 
6486
        return FALSE;
 
6487
 
 
6488
    /* inherit default */
 
6489
    result =  CTcSymbol::write_to_sym_file(fp);
 
6490
 
 
6491
    /* if that was successful, write additional object-type-specific data */
 
6492
    if (result)
 
6493
    {
 
6494
        /* write the metaclass ID */
 
6495
        fp->write_int2((int)metaclass_);
 
6496
 
 
6497
        /* if it's of metaclass tads-object, write superclass information */
 
6498
        if (metaclass_ == TC_META_TADSOBJ)
 
6499
        {
 
6500
            char c;
 
6501
            size_t cnt;
 
6502
            CTPNSuperclass *sc;
 
6503
 
 
6504
            /* 
 
6505
             *   set up our flags: indicate whether or not we're explicitly
 
6506
             *   based on the root object class, and if we're a 'class'
 
6507
             *   object 
 
6508
             */
 
6509
            c = ((sc_is_root() ? 1 : 0)
 
6510
                 | (is_class() ? 2 : 0)
 
6511
                 | (is_transient() ? 4 : 0));
 
6512
            fp->write_bytes(&c, 1);
 
6513
 
 
6514
            /* count the declared superclasses */
 
6515
            for (cnt = 0, sc = sc_name_head_ ; sc != 0 ;
 
6516
                 sc = sc->nxt_, ++cnt) ;
 
6517
 
 
6518
            /* 
 
6519
             *   write the number of declared superclasses followed by the
 
6520
             *   names of the superclasses 
 
6521
             */
 
6522
            fp->write_int2(cnt);
 
6523
            for (sc = sc_name_head_ ; sc != 0 ; sc = sc->nxt_)
 
6524
            {
 
6525
                /* write the counted-length identifier */
 
6526
                fp->write_int2(sc->get_sym_len());
 
6527
                fp->write_bytes(sc->get_sym_txt(), sc->get_sym_len());
 
6528
            }
 
6529
        }
 
6530
    }
 
6531
 
 
6532
    /* return the result */
 
6533
    return result;
 
6534
}
 
6535
 
 
6536
/*
 
6537
 *   Read from a symbol file 
 
6538
 */
 
6539
CTcSymbol *CTcSymObjBase::read_from_sym_file(CVmFile *fp)
 
6540
{
 
6541
    const char *txt;
 
6542
    tc_metaclass_t meta;
 
6543
    CTcSymObj *sym;
 
6544
    char c;
 
6545
    size_t cnt;
 
6546
    size_t i;
 
6547
 
 
6548
    /* read the symbol name */
 
6549
    if ((txt = base_read_from_sym_file(fp)) == 0)
 
6550
        return 0;
 
6551
 
 
6552
    /* read the metaclass ID */
 
6553
    meta = (tc_metaclass_t)fp->read_uint2();
 
6554
 
 
6555
    /* 
 
6556
     *   If it's a dictionary object, check to see if it's already defined -
 
6557
     *   a dictionary object can be exported from multiple modules without
 
6558
     *   error, since dictionaries are shared across modules.
 
6559
     *   
 
6560
     *   The same applies to grammar productions, since a grammar production
 
6561
     *   can be implicitly created in multiple files.  
 
6562
     */
 
6563
    if (meta == TC_META_DICT || meta == TC_META_GRAMPROD)
 
6564
    {
 
6565
        CTcSymbol *old_sym;
 
6566
 
 
6567
        /* look for a previous instance of the symbol */
 
6568
        old_sym = G_prs->get_global_symtab()->find(txt, strlen(txt));
 
6569
        if (old_sym != 0
 
6570
            && old_sym->get_type() == TC_SYM_OBJ
 
6571
            && ((CTcSymObj *)old_sym)->get_metaclass() == meta)
 
6572
        {
 
6573
            /* 
 
6574
             *   the dictionary is already in the symbol table - return the
 
6575
             *   existing one, since there's no conflict with importing the
 
6576
             *   dictionary from multiple places 
 
6577
             */
 
6578
            return old_sym;
 
6579
        }
 
6580
    }
 
6581
 
 
6582
    /* create the new symbol */
 
6583
    sym = new CTcSymObj(txt, strlen(txt), FALSE, G_cg->new_obj_id(),
 
6584
                        TRUE, meta, 0);
 
6585
 
 
6586
    /* if the metaclass is tads-object, read additional information */
 
6587
    if (meta == TC_META_TADSOBJ)
 
6588
    {
 
6589
        /* read the root-object-superclass flag and the class-object flag */
 
6590
        fp->read_bytes(&c, 1);
 
6591
        sym->set_sc_is_root((c & 1) != 0);
 
6592
        sym->set_is_class((c & 2) != 0);
 
6593
        if ((c & 4) != 0)
 
6594
            sym->set_transient();
 
6595
 
 
6596
        /* read the number of superclasses, and read the superclass names */
 
6597
        cnt = fp->read_uint2();
 
6598
        for (i = 0 ; i < cnt ; ++i)
 
6599
        {
 
6600
            char buf[TOK_SYM_MAX_LEN + 1];
 
6601
            const char *sc_txt;
 
6602
            size_t sc_len;
 
6603
 
 
6604
            /* read the symbol */
 
6605
            sc_txt = CTcParser::read_len_prefix_str(
 
6606
                fp, buf, sizeof(buf), &sc_len, TCERR_SYMEXP_SYM_TOO_LONG);
 
6607
 
 
6608
            /* add the superclass list entry to the symbol */
 
6609
            sym->add_sc_name_entry(sc_txt, sc_len);
 
6610
        }
 
6611
    }
 
6612
 
 
6613
    /* return the symbol */
 
6614
    return sym;
 
6615
}
 
6616
 
 
6617
/*
 
6618
 *   Add a superclass name entry.  
 
6619
 */
 
6620
void CTcSymObjBase::add_sc_name_entry(const char *txt, size_t len)
 
6621
{
 
6622
    CTPNSuperclass *entry;
 
6623
 
 
6624
    /* create the entry object */
 
6625
    entry = new CTPNSuperclass(txt, len);
 
6626
 
 
6627
    /* link it into our list */
 
6628
    if (sc_name_tail_ != 0)
 
6629
        sc_name_tail_->nxt_ = entry;
 
6630
    else
 
6631
        sc_name_head_ = entry;
 
6632
    sc_name_tail_ = entry;
 
6633
}
 
6634
 
 
6635
/*
 
6636
 *   Check to see if I have a given superclass.  
 
6637
 */
 
6638
int CTcSymObjBase::has_superclass(class CTcSymObj *sc_sym) const
 
6639
{
 
6640
    CTPNSuperclass *entry;
 
6641
 
 
6642
    /* 
 
6643
     *   Scan my direct superclasses.  For each one, check to see if my
 
6644
     *   superclass matches the given superclass, or if my superclass
 
6645
     *   inherits from the given superclass.  
 
6646
     */
 
6647
    for (entry = sc_name_head_ ; entry != 0 ; entry = entry->nxt_)
 
6648
    {
 
6649
        CTcSymObj *entry_sym;
 
6650
 
 
6651
        /* look up this symbol */
 
6652
        entry_sym = (CTcSymObj *)G_prs->get_global_symtab()->find(
 
6653
            entry->get_sym_txt(), entry->get_sym_len());
 
6654
 
 
6655
        /* 
 
6656
         *   if the entry's symbol doesn't exist or isn't an object symbol,
 
6657
         *   skip it 
 
6658
         */
 
6659
        if (entry_sym == 0 || entry_sym->get_type() != TC_SYM_OBJ)
 
6660
            continue;
 
6661
 
 
6662
        /* 
 
6663
         *   if it matches the given superclass, we've found the given
 
6664
         *   superclass among our direct superclasses, so we definitely have
 
6665
         *   the given superclass 
 
6666
         */
 
6667
        if (entry_sym == sc_sym)
 
6668
            return TRUE;
 
6669
 
 
6670
        /* 
 
6671
         *   ask the symbol if the given class is among its direct or
 
6672
         *   indirect superclasses - if it's a superclass of my superclass,
 
6673
         *   it's also my superclass 
 
6674
         */
 
6675
        if (entry_sym->has_superclass(sc_sym))
 
6676
            return TRUE;
 
6677
    }
 
6678
 
 
6679
    /* 
 
6680
     *   we didn't find the given class anywhere among our superclasses or
 
6681
     *   their superclasses, so it must not be a superclass of ours 
 
6682
     */
 
6683
    return FALSE;
 
6684
}
 
6685
 
 
6686
/*
 
6687
 *   Synthesize a placeholder symbol for a modified object.
 
6688
 *   
 
6689
 *   The new symbol is not for use by the source code; we add it merely as
 
6690
 *   a placeholder.  Build its name starting with a space so that it can
 
6691
 *   never be reached from source code, and use the object number to
 
6692
 *   ensure it's unique within the file.  
 
6693
 */
 
6694
CTcSymObj *CTcSymObjBase::synthesize_modified_obj_sym(int anon)
 
6695
{
 
6696
    char nm[TOK_SYM_MAX_LEN + 1];
 
6697
    const char *stored_nm;
 
6698
    tc_obj_id mod_id;
 
6699
    CTcSymObj *mod_sym;
 
6700
    size_t len;
 
6701
    
 
6702
    /* create a new ID for the modified object */
 
6703
    mod_id = G_cg->new_obj_id();
 
6704
 
 
6705
    /* build the name */
 
6706
    if (anon)
 
6707
    {
 
6708
        /* it's anonymous - we don't need a real name */
 
6709
        stored_nm = ".anon";
 
6710
        len = strlen(nm);
 
6711
    }
 
6712
    else
 
6713
    {
 
6714
        /* synthesize a name */
 
6715
        synthesize_modified_obj_name(nm, mod_id);
 
6716
        len = strlen(nm);
 
6717
 
 
6718
        /* store it in tokenizer memory */
 
6719
        stored_nm = G_tok->store_source(nm, len);
 
6720
    }
 
6721
 
 
6722
    /* create the object */
 
6723
    mod_sym = new CTcSymObj(stored_nm, len, FALSE, mod_id, FALSE,
 
6724
                            TC_META_TADSOBJ, 0);
 
6725
 
 
6726
    /* mark it as modified */
 
6727
    mod_sym->set_modified(TRUE);
 
6728
    
 
6729
    /* add it to the symbol table, if it has a name */
 
6730
    if (!anon)
 
6731
        G_prs->get_global_symtab()->add_entry(mod_sym);
 
6732
    else
 
6733
        G_prs->add_anon_obj(mod_sym);
 
6734
 
 
6735
    /* return the new symbol */
 
6736
    return mod_sym;
 
6737
}
 
6738
 
 
6739
/*
 
6740
 *   Build the name of a synthesized placeholder symbol for a given object
 
6741
 *   number.  The buffer should be TOK_SYM_MAX_LEN + 1 bytes long.  
 
6742
 */
 
6743
void CTcSymObjBase::
 
6744
   synthesize_modified_obj_name(char *buf, tctarg_obj_id_t obj_id)
 
6745
{
 
6746
    /* 
 
6747
     *   Build the fake name, based on the object ID to ensure uniqueness
 
6748
     *   and so that we can look it up based on the object ID.  Start it
 
6749
     *   with a space so that no source token can ever refer to it.  
 
6750
     */
 
6751
    sprintf(buf, " %lx", (ulong)obj_id);
 
6752
}
 
6753
 
 
6754
/*
 
6755
 *   Add a deleted property entry 
 
6756
 */
 
6757
void CTcSymObjBase::add_del_prop_to_list(CTcObjPropDel **list_head,
 
6758
                                         CTcSymProp *prop_sym)
 
6759
{
 
6760
    CTcObjPropDel *entry;
 
6761
 
 
6762
    /* create the new entry */
 
6763
    entry = new CTcObjPropDel(prop_sym);
 
6764
 
 
6765
    /* link it into my list */
 
6766
    entry->nxt_ = *list_head;
 
6767
    *list_head = entry;
 
6768
}
 
6769
 
 
6770
/*
 
6771
 *   Add a self-reference fixup 
 
6772
 */
 
6773
void CTcSymObjBase::add_self_ref_fixup(CTcDataStream *stream, ulong ofs)
 
6774
{
 
6775
    /* add a fixup to our list */
 
6776
    CTcIdFixup::add_fixup(&fixups_, stream, ofs, obj_id_);
 
6777
}
 
6778
 
 
6779
/*
 
6780
 *   Write to a object file 
 
6781
 */
 
6782
int CTcSymObjBase::write_to_obj_file(CVmFile *fp)
 
6783
{
 
6784
    /* 
 
6785
     *   If the object is external and has never been referenced, don't
 
6786
     *   bother writing it.
 
6787
     *   
 
6788
     *   In addition, if the object is marked as modified, don't write it.
 
6789
     *   We write modified base objects specially, because we must control
 
6790
     *   the order in which a modified base object is written relative its
 
6791
     *   modifying object.
 
6792
     */
 
6793
    if ((is_extern_ && !ref_) || modified_)
 
6794
        return FALSE;
 
6795
 
 
6796
    /* if the object has already been written, don't write it again */
 
6797
    if (written_to_obj_)
 
6798
    {
 
6799
        /* 
 
6800
         *   if we've never been counted in the object file before, we
 
6801
         *   must have been written indirectly in the course of writing
 
6802
         *   another symbol - in this case, return true to indicate that
 
6803
         *   we are in the file, even though we're not actually writing
 
6804
         *   anything now 
 
6805
         */
 
6806
        if (!counted_in_obj_)
 
6807
        {
 
6808
            /* we've now been counted in the object file */
 
6809
            counted_in_obj_ = TRUE;
 
6810
 
 
6811
            /* indicate that we have been written */
 
6812
            return TRUE;
 
6813
        }
 
6814
        else
 
6815
        {
 
6816
            /* we've already been written and counted - don't write again */
 
6817
            return FALSE;
 
6818
        }
 
6819
    }
 
6820
 
 
6821
    /* do the main part of the writing */
 
6822
    return write_to_obj_file_main(fp);
 
6823
}
 
6824
 
 
6825
/*
 
6826
 *   Write the object symbol to an object file.  This main routine does
 
6827
 *   most of the actual work, once we've decided that we're actually going
 
6828
 *   to write the symbol.  
 
6829
 */
 
6830
int CTcSymObjBase::write_to_obj_file_main(CVmFile *fp)
 
6831
{
 
6832
    char buf[32];
 
6833
    uint cnt;
 
6834
    CTcObjPropDel *delprop;
 
6835
 
 
6836
    /* take the next object file index */
 
6837
    set_obj_file_idx(G_prs->get_next_obj_file_sym_idx());
 
6838
 
 
6839
    /* 
 
6840
     *   if I have a dictionary object, make sure it's in the object file
 
6841
     *   before I am - we need to be able to reference the object during
 
6842
     *   load, so it has to be written before me 
 
6843
     */
 
6844
    if (dict_ != 0)
 
6845
        dict_->write_sym_to_obj_file(fp);
 
6846
 
 
6847
    /* 
 
6848
     *   if I'm not anonymous, write the basic header information for the
 
6849
     *   symbol (don't do this for anonymous objects, since they don't
 
6850
     *   have a name to write) 
 
6851
     */
 
6852
    if (!anon_)
 
6853
        write_to_file_gen(fp);
 
6854
 
 
6855
    /* 
 
6856
     *   write my object ID, so that we can translate from the local
 
6857
     *   numbering system in the object file to the new numbering system
 
6858
     *   in the image file 
 
6859
     */
 
6860
    oswp4(buf, obj_id_);
 
6861
 
 
6862
    /* write the flags */
 
6863
    buf[4] = (is_extern_ != 0);
 
6864
    buf[5] = (ext_replace_ != 0);
 
6865
    buf[6] = (modified_ != 0);
 
6866
    buf[7] = (mod_base_sym_ != 0);
 
6867
    buf[8] = (ext_modify_ != 0);
 
6868
    buf[9] = (obj_stm_ != 0 && obj_stm_->is_class());
 
6869
    buf[10] = (transient_ != 0);
 
6870
 
 
6871
    /* add the metaclass type */
 
6872
    oswp2(buf + 11, (int)metaclass_);
 
6873
 
 
6874
    /* add the dictionary's object file index, if we have one */
 
6875
    if (dict_ != 0)
 
6876
        oswp2(buf + 13, dict_->get_obj_idx());
 
6877
    else
 
6878
        oswp2(buf + 13, 0);
 
6879
 
 
6880
    /* 
 
6881
     *   add my object file index (we store this to eliminate any
 
6882
     *   dependency on the load order - this allows us to write other
 
6883
     *   symbols recursively without worrying about exactly where the
 
6884
     *   recursion occurs relative to assigning the file index) 
 
6885
     */
 
6886
    oswp2(buf + 15, get_obj_file_idx());
 
6887
 
 
6888
    /* write the data to the file */
 
6889
    fp->write_bytes(buf, 17);
 
6890
 
 
6891
    /* if we're not external, write our stream address */
 
6892
    if (!is_extern_)
 
6893
        fp->write_int4(stream_ofs_);
 
6894
 
 
6895
    /* if we're modifying another object, store some extra information */
 
6896
    if (mod_base_sym_ != 0)
 
6897
    {
 
6898
        /* 
 
6899
         *   Write our list of properties to be deleted from base objects
 
6900
         *   at link time.  First, count the properties in the list.  
 
6901
         */
 
6902
        for (cnt = 0, delprop = first_del_prop_ ; delprop != 0 ;
 
6903
             ++cnt, delprop = delprop->nxt_) ;
 
6904
 
 
6905
        /* write the count */
 
6906
        fp->write_int2(cnt);
 
6907
 
 
6908
        /* write the deleted property list */
 
6909
        for (delprop = first_del_prop_ ; delprop != 0 ;
 
6910
             delprop = delprop->nxt_)
 
6911
        {
 
6912
            /* 
 
6913
             *   write out this property symbol (we write the symbol
 
6914
             *   rather than the ID, because when we load the object file,
 
6915
             *   we'll need to adjust the ID to new global numbering
 
6916
             *   system in the image file; the easiest way to do this is
 
6917
             *   to write the symbol and look it up at load time) 
 
6918
             */
 
6919
            fp->write_int2(delprop->prop_sym_->get_sym_len());
 
6920
            fp->write_bytes(delprop->prop_sym_->get_sym(),
 
6921
                            delprop->prop_sym_->get_sym_len());
 
6922
        }
 
6923
    }
 
6924
 
 
6925
    /* write our self-reference fixup list */
 
6926
    CTcIdFixup::write_to_object_file(fp, fixups_);
 
6927
 
 
6928
    /*
 
6929
     *   If this is a modifying object, we must write the entire chain of
 
6930
     *   modified base objects immediately after this object.  When we're
 
6931
     *   reading the symbol table, this ensures that we can read each
 
6932
     *   modified base object recursively as we read its modifiers, which
 
6933
     *   is necessary so that we can build up the same modification chain
 
6934
     *   on loading the object file.  
 
6935
     */
 
6936
    if (mod_base_sym_ != 0)
 
6937
    {
 
6938
        /* write the main part of the definition */
 
6939
        mod_base_sym_->write_to_obj_file_main(fp);
 
6940
    }
 
6941
 
 
6942
    /* mark the object as written to the file */
 
6943
    written_to_obj_ = TRUE;
 
6944
 
 
6945
    /* written */
 
6946
    return TRUE;
 
6947
}
 
6948
 
 
6949
/*
 
6950
 *   Write cross-references to the object file 
 
6951
 */
 
6952
int CTcSymObjBase::write_refs_to_obj_file(CVmFile *fp)
 
6953
{
 
6954
    CTPNSuperclass *sc;
 
6955
    uint cnt;
 
6956
    long cnt_pos;
 
6957
    long end_pos;
 
6958
    CTcVocabEntry *voc;
 
6959
 
 
6960
    /* 
 
6961
     *   if this symbol wasn't written to the object file in the first
 
6962
     *   place, we obviously don't want to include any extra data for it 
 
6963
     */
 
6964
    if (!written_to_obj_)
 
6965
        return FALSE;
 
6966
    
 
6967
    /* write my symbol index */
 
6968
    fp->write_int4(get_obj_file_idx());
 
6969
 
 
6970
    /* write a placeholder superclass count */
 
6971
    cnt_pos = fp->get_pos();
 
6972
    fp->write_int2(0);
 
6973
 
 
6974
    /* write my superclass list */
 
6975
    for (sc = (obj_stm_ != 0 ? obj_stm_->get_first_sc() : 0), cnt = 0 ;
 
6976
         sc != 0 ; sc = sc->nxt_)
 
6977
    {
 
6978
        CTcSymObj *sym;
 
6979
        
 
6980
        /* look up this superclass symbol */
 
6981
        sym = (CTcSymObj *)sc->get_sym();
 
6982
        if (sym != 0 && sym->get_type() == TC_SYM_OBJ)
 
6983
        {
 
6984
            /* write the superclass symbol index */
 
6985
            fp->write_int4(sym->get_obj_file_idx());
 
6986
 
 
6987
            /* count it */
 
6988
            ++cnt;
 
6989
        }
 
6990
    }
 
6991
 
 
6992
    /* go back and write the superclass count */
 
6993
    end_pos = fp->get_pos();
 
6994
    fp->set_pos(cnt_pos);
 
6995
    fp->write_int2(cnt);
 
6996
    fp->set_pos(end_pos);
 
6997
 
 
6998
    /* count my vocabulary words */
 
6999
    for (cnt = 0, voc = vocab_ ; voc != 0 ; ++cnt, voc = voc->nxt_) ;
 
7000
 
 
7001
    /* write my vocabulary words */
 
7002
    fp->write_int2(cnt);
 
7003
    for (voc = vocab_ ; voc != 0 ; voc = voc->nxt_)
 
7004
    {
 
7005
        /* write the text of the word */
 
7006
        fp->write_int2(voc->len_);
 
7007
        fp->write_bytes(voc->txt_, voc->len_);
 
7008
 
 
7009
        /* write the property ID */
 
7010
        fp->write_int2(voc->prop_);
 
7011
    }
 
7012
 
 
7013
    /* indicate that we wrote the symbol */
 
7014
    return TRUE;
 
7015
}
 
7016
 
 
7017
/*
 
7018
 *   Load references from the object file 
 
7019
 */
 
7020
void CTcSymObjBase::load_refs_from_obj_file(CVmFile *fp, const char *,
 
7021
                                            tctarg_obj_id_t *,
 
7022
                                            tctarg_prop_id_t *prop_xlat)
 
7023
{
 
7024
    uint i;
 
7025
    uint cnt;
 
7026
    CTcObjScEntry *sc_tail;
 
7027
    
 
7028
    /* read the superclass count */
 
7029
    cnt = fp->read_uint2();
 
7030
 
 
7031
    /* read the superclass list */
 
7032
    for (sc_tail = 0, i = 0 ; i < cnt ; ++i)
 
7033
    {
 
7034
        ulong idx;
 
7035
        CTcSymObj *sym;
 
7036
        CTcObjScEntry *sc;
 
7037
 
 
7038
        /* read the next index */
 
7039
        idx = fp->read_uint4();
 
7040
 
 
7041
        /* get the symbol */
 
7042
        sym = (CTcSymObj *)G_prs->get_objfile_sym(idx);
 
7043
        if (sym->get_type() != TC_SYM_OBJ)
 
7044
            sym = 0;
 
7045
 
 
7046
        /* create a new list entry */
 
7047
        sc = new (G_prsmem) CTcObjScEntry(sym);
 
7048
 
 
7049
        /* link it in at the end of the my superclass list */
 
7050
        if (sc_tail != 0)
 
7051
            sc_tail->nxt_ = sc;
 
7052
        else
 
7053
            sc_ = sc;
 
7054
 
 
7055
        /* this is now the last entry in my superclass list */
 
7056
        sc_tail = sc;
 
7057
    }
 
7058
 
 
7059
    /* load the vocabulary words */
 
7060
    cnt = fp->read_uint2();
 
7061
    for (i = 0 ; i < cnt ; ++i)
 
7062
    {
 
7063
        size_t len;
 
7064
        char *txt;
 
7065
        tctarg_prop_id_t prop;
 
7066
        
 
7067
        /* read the length of this word's text */
 
7068
        len = fp->read_uint2();
 
7069
 
 
7070
        /* allocate parser memory for the word's text */
 
7071
        txt = (char *)G_prsmem->alloc(len);
 
7072
 
 
7073
        /* read the word into the allocated text buffer */
 
7074
        fp->read_bytes(txt, len);
 
7075
 
 
7076
        /* read the property */
 
7077
        prop = (tctarg_prop_id_t)fp->read_uint2();
 
7078
 
 
7079
        /* translate the property to the new numbering system */
 
7080
        prop = prop_xlat[prop];
 
7081
 
 
7082
        /* add the word to our vocabulary */
 
7083
        add_vocab_word(txt, len, prop);
 
7084
    }
 
7085
}
 
7086
 
 
7087
/*
 
7088
 *   Add a word to my vocabulary 
 
7089
 */
 
7090
void CTcSymObjBase::add_vocab_word(const char *txt, size_t len,
 
7091
                                   tctarg_prop_id_t prop)
 
7092
{
 
7093
    CTcVocabEntry *entry;
 
7094
    
 
7095
    /* create a new vocabulary entry */
 
7096
    entry = new (G_prsmem) CTcVocabEntry(txt, len, prop);
 
7097
 
 
7098
    /* link it into my list */
 
7099
    entry->nxt_ = vocab_;
 
7100
    vocab_ = entry;
 
7101
}
 
7102
 
 
7103
/*
 
7104
 *   Delete a vocabulary property from my list (for 'replace') 
 
7105
 */
 
7106
void CTcSymObjBase::delete_vocab_prop(tctarg_prop_id_t prop)
 
7107
{
 
7108
    CTcVocabEntry *entry;
 
7109
    CTcVocabEntry *prv;
 
7110
    CTcVocabEntry *nxt;
 
7111
    
 
7112
    /* scan my list and delete each word defined for the given property */
 
7113
    for (prv = 0, entry = vocab_ ; entry != 0 ; entry = nxt)
 
7114
    {
 
7115
        /* remember the next entry */
 
7116
        nxt = entry->nxt_;
 
7117
        
 
7118
        /* if this entry is for the given property, unlink it */
 
7119
        if (entry->prop_ == prop)
 
7120
        {
 
7121
            /* 
 
7122
             *   it matches - unlink it from the list (note that we don't
 
7123
             *   have to delete the entry, because it's allocated in
 
7124
             *   parser memory and thus will be deleted when the parser is
 
7125
             *   deleted) 
 
7126
             */
 
7127
            if (prv != 0)
 
7128
                prv->nxt_ = nxt;
 
7129
            else
 
7130
                vocab_ = nxt;
 
7131
 
 
7132
            /* 
 
7133
             *   this entry is no longer in any list (we don't really have
 
7134
             *   to clear the 'next' pointer here, since nothing points to
 
7135
             *   'entry' any more, but doing so will make it obvious that
 
7136
             *   the entry was removed from the list, which could be handy
 
7137
             *   during debugging from time to time) 
 
7138
             */
 
7139
            entry->nxt_ = 0;
 
7140
        }
 
7141
        else
 
7142
        {
 
7143
            /* 
 
7144
             *   this entry is still in the list, so it's now the previous
 
7145
             *   entry for our scan 
 
7146
             */
 
7147
            prv = entry;
 
7148
        }
 
7149
    }
 
7150
}
 
7151
 
 
7152
/*
 
7153
 *   Build my dictionary 
 
7154
 */
 
7155
void CTcSymObjBase::build_dictionary()
 
7156
{
 
7157
    CTcVocabEntry *entry;
 
7158
 
 
7159
    /* if I don't have a dictionary, there's nothing to do */
 
7160
    if (dict_ == 0)
 
7161
        return;
 
7162
 
 
7163
    /* 
 
7164
     *   if I'm a class, there's nothing to do, since vocabulary defined
 
7165
     *   in a class is only entered in the dictionary for the instances of
 
7166
     *   the class, not for the class itself 
 
7167
     */
 
7168
    if (is_class_)
 
7169
        return;
 
7170
 
 
7171
    /* add inherited words from my superclasses to my list */
 
7172
    inherit_vocab();
 
7173
 
 
7174
    /* add each of my words to the dictionary */
 
7175
    for (entry = vocab_ ; entry != 0 ; entry = entry->nxt_)
 
7176
    {
 
7177
        /* add this word to my dictionary */
 
7178
        dict_->add_word(entry->txt_, entry->len_, FALSE,
 
7179
                        obj_id_, entry->prop_);
 
7180
    }
 
7181
}
 
7182
 
 
7183
/*
 
7184
 *   Add my words to the dictionary, associating the words with the given
 
7185
 *   object.  This can be used to add my own words to the dictionary or to
 
7186
 *   add my words to a subclass's dictionary.  
 
7187
 */
 
7188
void CTcSymObjBase::inherit_vocab()
 
7189
{
 
7190
    CTcObjScEntry *sc;
 
7191
 
 
7192
    /* 
 
7193
     *   if I've already inherited my superclass vocabulary, there's
 
7194
     *   nothing more we need to do 
 
7195
     */
 
7196
    if (vocab_inherited_)
 
7197
        return;
 
7198
 
 
7199
    /* make a note that I've inherited my superclass vocabulary */
 
7200
    vocab_inherited_ = TRUE;
 
7201
 
 
7202
    /* inherit words from each superclass */
 
7203
    for (sc = sc_ ; sc != 0 ; sc = sc->nxt_)
 
7204
    {
 
7205
        /* make sure this superclass has built its inherited list */
 
7206
        sc->sym_->inherit_vocab();
 
7207
        
 
7208
        /* add this superclass's words to my list */
 
7209
        sc->sym_->add_vocab_to_subclass((CTcSymObj *)this);
 
7210
    }
 
7211
}
 
7212
 
 
7213
/*
 
7214
 *   Add my vocabulary words to the given subclass's vocabulary list 
 
7215
 */
 
7216
void CTcSymObjBase::add_vocab_to_subclass(CTcSymObj *sub)
 
7217
{
 
7218
    CTcVocabEntry *entry;
 
7219
 
 
7220
    /* add each of my words to the subclass */
 
7221
    for (entry = vocab_ ; entry != 0 ; entry = entry->nxt_)
 
7222
    {
 
7223
        /* add this word to my dictionary */
 
7224
        sub->add_vocab_word(entry->txt_, entry->len_, entry->prop_);
 
7225
    }
 
7226
}
 
7227
 
 
7228
/*
 
7229
 *   Set my base 'modify' object.  This tells us the object that we're
 
7230
 *   modifying. 
 
7231
 */
 
7232
void CTcSymObjBase::set_mod_base_sym(CTcSymObj *sym)
 
7233
{
 
7234
    /* remember the object I'm modifying */
 
7235
    mod_base_sym_ = sym;
 
7236
 
 
7237
    /* 
 
7238
     *   set the other object's link back to me, so it knows that I'm the
 
7239
     *   object that's modifying it 
 
7240
     */
 
7241
    if (sym != 0)
 
7242
        sym->set_modifying_sym((CTcSymObj *)this);
 
7243
}
 
7244
 
 
7245
/*
 
7246
 *   Get the appropriate stream for a given metaclass 
 
7247
 */
 
7248
CTcDataStream *CTcSymObjBase::get_stream_from_meta(tc_metaclass_t meta)
 
7249
{
 
7250
    switch(meta)
 
7251
    {
 
7252
    case TC_META_TADSOBJ:
 
7253
        /* it's the regular object stream */
 
7254
        return G_os;
 
7255
 
 
7256
    case TC_META_ICMOD:
 
7257
        /* intrinsic class modifier stream */
 
7258
        return G_icmod_stream;
 
7259
 
 
7260
    default:
 
7261
        /* other metaclasses have no stream */
 
7262
        return 0;
 
7263
    }
 
7264
}
 
7265
 
 
7266
/*
 
7267
 *   Add a class-specific template 
 
7268
 */
 
7269
void CTcSymObjBase::add_template(CTcObjTemplate *tpl)
 
7270
{
 
7271
    /* link it in at the tail of our list */
 
7272
    if (template_tail_ != 0)
 
7273
        template_tail_->nxt_ = tpl;
 
7274
    else
 
7275
        template_head_ = tpl;
 
7276
    template_tail_ = tpl;
 
7277
}
 
7278
 
 
7279
/*
 
7280
 *   Create a grammar rule list object 
 
7281
 */
 
7282
CTcGramProdEntry *CTcSymObjBase::create_grammar_entry(
 
7283
    const char *prod_sym, size_t prod_sym_len)
 
7284
{
 
7285
    CTcSymObj *sym;
 
7286
 
 
7287
    /* look up the grammar production symbol */
 
7288
    sym = G_prs->find_or_def_gramprod(prod_sym, prod_sym_len, 0);
 
7289
 
 
7290
    /* create a new grammar list associated with the production */
 
7291
    grammar_entry_ = new (G_prsmem) CTcGramProdEntry(sym);
 
7292
 
 
7293
    /* return the new grammar list */
 
7294
    return grammar_entry_;
 
7295
}
 
7296
 
 
7297
 
 
7298
/* ------------------------------------------------------------------------ */
 
7299
/*
 
7300
 *   metaclass symbol   
 
7301
 */
 
7302
 
 
7303
/*
 
7304
 *   add a property 
 
7305
 */
 
7306
void CTcSymMetaclassBase::add_prop(const char *txt, size_t len,
 
7307
                                   const char *obj_fname, int is_static)
 
7308
{
 
7309
    CTcSymProp *prop_sym;
 
7310
 
 
7311
    /* see if this property is already defined */
 
7312
    prop_sym = (CTcSymProp *)G_prs->get_global_symtab()->find(txt, len);
 
7313
    if (prop_sym != 0)
 
7314
    {
 
7315
        /* it's already defined - make sure it's a property */
 
7316
        if (prop_sym->get_type() != TC_SYM_PROP)
 
7317
        {
 
7318
            /* 
 
7319
             *   it's something other than a property - log the
 
7320
             *   appropriate type of error, depending on whether we're
 
7321
             *   loading this from an object file or from source code 
 
7322
             */
 
7323
            if (obj_fname == 0)
 
7324
            {
 
7325
                /* creating from source - note the code location */
 
7326
                G_tok->log_error_curtok(TCERR_REDEF_AS_PROP);
 
7327
            }
 
7328
            else
 
7329
            {
 
7330
                /* loading from an object file */
 
7331
                G_tcmain->log_error(0, 0, TC_SEV_ERROR,
 
7332
                                    TCERR_OBJFILE_REDEF_SYM_TYPE,
 
7333
                                    (int)len, txt, "property", obj_fname);
 
7334
            }
 
7335
 
 
7336
            /* forget the symbol - it's not a property */
 
7337
            prop_sym = 0;
 
7338
        }
 
7339
    }
 
7340
    else
 
7341
    {
 
7342
        /* add the property definition */
 
7343
        prop_sym = new CTcSymProp(txt, len, FALSE, G_cg->new_prop_id());
 
7344
        G_prs->get_global_symtab()->add_entry(prop_sym);
 
7345
    }
 
7346
 
 
7347
    /* 
 
7348
     *   if we found a valid property symbol, add it to the metaclass
 
7349
     *   property list 
 
7350
     */
 
7351
    if (prop_sym != 0)
 
7352
    {
 
7353
        /* 
 
7354
         *   mark the symbol as referenced - even if we don't directly
 
7355
         *   make use of it, the metaclass table references this symbol 
 
7356
         */
 
7357
        prop_sym->mark_referenced();
 
7358
        
 
7359
        /* add the property to the metaclass list */
 
7360
        add_prop(prop_sym, is_static);
 
7361
    }
 
7362
}
 
7363
 
 
7364
/*
 
7365
 *   add a property 
 
7366
 */
 
7367
void CTcSymMetaclassBase::add_prop(class CTcSymProp *prop, int is_static)
 
7368
{
 
7369
    CTcSymMetaProp *entry;
 
7370
 
 
7371
    /* create a new list entry for the property */
 
7372
    entry = new (G_prsmem) CTcSymMetaProp(prop, is_static);
 
7373
    
 
7374
    /* link it at the end of our list */
 
7375
    if (prop_tail_ != 0)
 
7376
        prop_tail_->nxt_ = entry;
 
7377
    else
 
7378
        prop_head_ = entry;
 
7379
    prop_tail_ = entry;
 
7380
 
 
7381
    /* count the addition */
 
7382
    ++prop_cnt_;
 
7383
}
 
7384
 
 
7385
/* 
 
7386
 *   write some additional data to the object file 
 
7387
 */
 
7388
int CTcSymMetaclassBase::write_to_obj_file(class CVmFile *fp)
 
7389
{
 
7390
    CTcSymMetaProp *cur;
 
7391
    char buf[16];
 
7392
    
 
7393
    /* inherit default */
 
7394
    CTcSymbol::write_to_obj_file(fp);
 
7395
 
 
7396
    /* write my metaclass index, class object ID, and property count */
 
7397
    fp->write_int2(meta_idx_);
 
7398
    fp->write_int4(class_obj_);
 
7399
    fp->write_int2(prop_cnt_);
 
7400
 
 
7401
    /* write my property symbol list */
 
7402
    for (cur = prop_head_ ; cur != 0 ; cur = cur->nxt_)
 
7403
    {
 
7404
        /* write this symbol name */
 
7405
        fp->write_int2(cur->prop_->get_sym_len());
 
7406
        fp->write_bytes(cur->prop_->get_sym(), cur->prop_->get_sym_len());
 
7407
 
 
7408
        /* set up the flags */
 
7409
        buf[0] = 0;
 
7410
        if (cur->is_static_)
 
7411
            buf[0] |= 1;
 
7412
 
 
7413
        /* write the flags */
 
7414
        fp->write_bytes(buf, 1);
 
7415
    }
 
7416
 
 
7417
    /* write our modifying object flag */
 
7418
    buf[0] = (mod_obj_ != 0);
 
7419
    fp->write_bytes(buf, 1);
 
7420
 
 
7421
    /* if we have a modifier object chain, write it out */
 
7422
    if (mod_obj_ != 0)
 
7423
        mod_obj_->write_to_obj_file_as_modified(fp);
 
7424
 
 
7425
    /* written */
 
7426
    return TRUE;
 
7427
}
 
7428
 
 
7429
/*
 
7430
 *   get the nth property in our table
 
7431
 */
 
7432
CTcSymMetaProp *CTcSymMetaclassBase::get_nth_prop(int n) const
 
7433
{
 
7434
    CTcSymMetaProp *prop;
 
7435
    
 
7436
    /* traverse the list to the desired index */
 
7437
    for (prop = prop_head_ ; prop != 0 && n != 0 ; prop = prop->nxt_, --n) ;
 
7438
 
 
7439
    /* return the property */
 
7440
    return prop;
 
7441
}
 
7442
 
 
7443
 
 
7444
/* ------------------------------------------------------------------------ */
 
7445
/*
 
7446
 *   property symbol entry base 
 
7447
 */
 
7448
 
 
7449
/*
 
7450
 *   fold an address constant 
 
7451
 */
 
7452
CTcPrsNode *CTcSymPropBase::fold_addr_const()
 
7453
{
 
7454
    CTcConstVal cval;
 
7455
 
 
7456
    /* set up the property pointer constant */
 
7457
    cval.set_prop(get_prop());
 
7458
 
 
7459
    /* return a constant node */
 
7460
    return new CTPNConst(&cval);
 
7461
}
 
7462
 
 
7463
/*
 
7464
 *   Read from a symbol file 
 
7465
 */
 
7466
CTcSymbol *CTcSymPropBase::read_from_sym_file(CVmFile *fp)
 
7467
{
 
7468
    const char *sym;
 
7469
    CTcSymbol *old_entry;
 
7470
 
 
7471
    /* read the symbol name */
 
7472
    if ((sym = base_read_from_sym_file(fp)) == 0)
 
7473
        return 0;
 
7474
 
 
7475
    /* 
 
7476
     *   If this property is already defined, this is a harmless
 
7477
     *   redefinition - every symbol file can define the same property
 
7478
     *   without any problem.  Indicate the harmless redefinition by
 
7479
     *   returning the original symbol.  
 
7480
     */
 
7481
    old_entry = G_prs->get_global_symtab()->find(sym, strlen(sym));
 
7482
    if (old_entry != 0 && old_entry->get_type() == TC_SYM_PROP)
 
7483
        return old_entry;
 
7484
 
 
7485
    /* create and return the new symbol */
 
7486
    return new CTcSymProp(sym, strlen(sym), FALSE, G_cg->new_prop_id());
 
7487
}
 
7488
 
 
7489
/*
 
7490
 *   Write to an object file 
 
7491
 */
 
7492
int CTcSymPropBase::write_to_obj_file(CVmFile *fp)
 
7493
{
 
7494
    /* 
 
7495
     *   If the property has never been referenced, don't bother writing
 
7496
     *   it.  We must have picked up the definition from an external
 
7497
     *   symbol set we loaded but have no references of our own to the
 
7498
     *   property.  
 
7499
     */
 
7500
    if (!ref_)
 
7501
        return FALSE;
 
7502
 
 
7503
    /* inherit default */
 
7504
    CTcSymbol::write_to_obj_file(fp);
 
7505
 
 
7506
    /* 
 
7507
     *   write my local property ID value - when we load the object file,
 
7508
     *   we'll need to figure out the translation from our original
 
7509
     *   numbering system to the new numbering system used in the image
 
7510
     *   file 
 
7511
     */
 
7512
    fp->write_int4((ulong)prop_);
 
7513
 
 
7514
    /* written */
 
7515
    return TRUE;
 
7516
}
 
7517
 
 
7518
 
 
7519
/* ------------------------------------------------------------------------ */
 
7520
/*
 
7521
 *   Enumerator symbol base
 
7522
 */
 
7523
 
 
7524
/*
 
7525
 *   fold the symbol as a constant 
 
7526
 */
 
7527
CTcPrsNode *CTcSymEnumBase::fold_constant()
 
7528
{
 
7529
    CTcConstVal cval;
 
7530
 
 
7531
    /* set up the enumerator constant */
 
7532
    cval.set_enum(get_enum_id());
 
7533
 
 
7534
    /* return a constant node */
 
7535
    return new CTPNConst(&cval);
 
7536
}
 
7537
 
 
7538
 
 
7539
/*
 
7540
 *   Write to a symbol file 
 
7541
 */
 
7542
int CTcSymEnumBase::write_to_sym_file(CVmFile *fp)
 
7543
{
 
7544
    int result;
 
7545
    char buf[32];
 
7546
 
 
7547
    /* inherit default */
 
7548
    result =  CTcSymbol::write_to_sym_file(fp);
 
7549
 
 
7550
    /* write the 'token' flag */
 
7551
    if (result)
 
7552
    {
 
7553
        /* clear the flags */
 
7554
        buf[0] = 0;
 
7555
 
 
7556
        /* set the 'token' flag if appropriate */
 
7557
        if (is_token_)
 
7558
            buf[0] |= 1;
 
7559
 
 
7560
        /* write the flags */
 
7561
        fp->write_bytes(buf, 1);
 
7562
    }
 
7563
 
 
7564
    /* return the result */
 
7565
    return result;
 
7566
}
 
7567
 
 
7568
/*
 
7569
 *   Read from a symbol file 
 
7570
 */
 
7571
CTcSymbol *CTcSymEnumBase::read_from_sym_file(CVmFile *fp)
 
7572
{
 
7573
    const char *sym;
 
7574
    CTcSymEnum *old_entry;
 
7575
    char buf[32];
 
7576
    int is_token;
 
7577
 
 
7578
    /* read the symbol name */
 
7579
    if ((sym = base_read_from_sym_file(fp)) == 0)
 
7580
        return 0;
 
7581
 
 
7582
    /* read the 'token' flag */
 
7583
    fp->read_bytes(buf, 1);
 
7584
    is_token = ((buf[0] & 1) != 0);
 
7585
 
 
7586
    /* 
 
7587
     *   If this enumerator is already defined, this is a harmless
 
7588
     *   redefinition - every symbol file can define the same enumerator
 
7589
     *   without any problem.  Indicate the harmless redefinition by
 
7590
     *   returning the original symbol.  
 
7591
     */
 
7592
    old_entry = (CTcSymEnum *)
 
7593
                G_prs->get_global_symtab()->find(sym, strlen(sym));
 
7594
    if (old_entry != 0 && old_entry->get_type() == TC_SYM_ENUM)
 
7595
    {
 
7596
        /* if this is a 'token' enum, mark the old entry as such */
 
7597
        if (is_token)
 
7598
            old_entry->set_is_token(TRUE);
 
7599
        
 
7600
        /* return the original entry */
 
7601
        return old_entry;
 
7602
    }
 
7603
 
 
7604
    /* create and return the new symbol */
 
7605
    return new CTcSymEnum(sym, strlen(sym), FALSE,
 
7606
                          G_prs->new_enum_id(), is_token);
 
7607
}
 
7608
 
 
7609
/*
 
7610
 *   Write to an object file 
 
7611
 */
 
7612
int CTcSymEnumBase::write_to_obj_file(CVmFile *fp)
 
7613
{
 
7614
    char buf[32];
 
7615
    
 
7616
    /* 
 
7617
     *   If the enumerator has never been referenced, don't bother writing
 
7618
     *   it.  We must have picked up the definition from an external
 
7619
     *   symbol set we loaded but have no references of our own to the
 
7620
     *   enumerator.  
 
7621
     */
 
7622
    if (!ref_)
 
7623
        return FALSE;
 
7624
 
 
7625
    /* inherit default */
 
7626
    CTcSymbol::write_to_obj_file(fp);
 
7627
 
 
7628
    /* 
 
7629
     *   write my local enumerator ID value - when we load the object file,
 
7630
     *   we'll need to figure out the translation from our original
 
7631
     *   numbering system to the new numbering system used in the image
 
7632
     *   file 
 
7633
     */
 
7634
    fp->write_int4((ulong)enum_id_);
 
7635
 
 
7636
    /* clear the flags */
 
7637
    buf[0] = 0;
 
7638
 
 
7639
    /* set the 'token' flag if appropriate */
 
7640
    if (is_token_)
 
7641
        buf[0] |= 1;
 
7642
 
 
7643
    /* write the flags */
 
7644
    fp->write_bytes(buf, 1);
 
7645
 
 
7646
    /* written */
 
7647
    return TRUE;
 
7648
}
 
7649
 
 
7650
 
 
7651
/* ------------------------------------------------------------------------ */
 
7652
/*
 
7653
 *   Built-in function symbol base
 
7654
 */
 
7655
 
 
7656
/*
 
7657
 *   Write to a object file 
 
7658
 */
 
7659
int CTcSymBifBase::write_to_obj_file(CVmFile *fp)
 
7660
{
 
7661
    char buf[10];
 
7662
 
 
7663
    /* inherit default */
 
7664
    CTcSymbol::write_to_obj_file(fp);
 
7665
 
 
7666
    /* write the varargs and return value flags */
 
7667
    buf[0] = (varargs_ != 0);
 
7668
    buf[1] = (has_retval_ != 0);
 
7669
 
 
7670
    /* write the argument count information */
 
7671
    oswp2(buf+2, min_argc_);
 
7672
    oswp2(buf+4, max_argc_);
 
7673
 
 
7674
    /* 
 
7675
     *   write the function set ID and index - these are required to match
 
7676
     *   those used in all other object files that make up a single image
 
7677
     *   file 
 
7678
     */
 
7679
    oswp2(buf+6, func_set_id_);
 
7680
    oswp2(buf+8, func_idx_);
 
7681
    fp->write_bytes(buf, 10);
 
7682
 
 
7683
    /* written */
 
7684
    return TRUE;
 
7685
}
 
7686
 
 
7687
/* ------------------------------------------------------------------------ */
 
7688
/*
 
7689
 *   Parser dictionary hash table entry 
 
7690
 */
 
7691
 
 
7692
/*
 
7693
 *   add an item to my list of object associations
 
7694
 */
 
7695
void CVmHashEntryPrsDict::add_item(tc_obj_id obj, tc_prop_id prop)
 
7696
{
 
7697
    CTcPrsDictItem *item;
 
7698
 
 
7699
    /* search my list for an existing association to the same obj/prop */
 
7700
    for (item = list_ ; item != 0 ; item = item->nxt_)
 
7701
    {
 
7702
        /* if it matches, we don't need to add this one again */
 
7703
        if (item->obj_ == obj && item->prop_ == prop)
 
7704
            return;
 
7705
    }
 
7706
 
 
7707
    /* not found - create a new item */
 
7708
    item = new (G_prsmem) CTcPrsDictItem(obj, prop);
 
7709
    
 
7710
    /* link it into my list */
 
7711
    item->nxt_ = list_;
 
7712
    list_ = item;
 
7713
}
 
7714
 
 
7715
/* ------------------------------------------------------------------------ */
 
7716
/*
 
7717
 *   Dictionary entry - each dictionary object gets one of these objects
 
7718
 *   to track it 
 
7719
 */
 
7720
 
 
7721
/*
 
7722
 *   construction 
 
7723
 */
 
7724
CTcDictEntry::CTcDictEntry(CTcSymObj *sym)
 
7725
{
 
7726
    const size_t hash_table_size = 128;
 
7727
    
 
7728
    /* remember my object symbol and word truncation length */
 
7729
    sym_ = sym;
 
7730
 
 
7731
    /* no object file index yet */
 
7732
    obj_idx_ = 0;
 
7733
 
 
7734
    /* not in a list yet */
 
7735
    nxt_ = 0;
 
7736
 
 
7737
    /* create my hash table */
 
7738
    hashtab_ = new (G_prsmem)
 
7739
               CVmHashTable(hash_table_size,
 
7740
                            new (G_prsmem) CVmHashFuncCI(), TRUE,
 
7741
                            new (G_prsmem) CVmHashEntry *[hash_table_size]);
 
7742
}
 
7743
 
 
7744
/*
 
7745
 *   Add a word to the table 
 
7746
 */
 
7747
void CTcDictEntry::add_word(const char *txt, size_t len, int copy,
 
7748
                            tc_obj_id obj, tc_prop_id prop)
 
7749
{
 
7750
    CVmHashEntryPrsDict *entry;
 
7751
        
 
7752
    /* search for an existing entry */
 
7753
    entry = (CVmHashEntryPrsDict *)hashtab_->find(txt, len);
 
7754
 
 
7755
    /* if there's no entry, create a new one */
 
7756
    if (entry == 0)
 
7757
    {
 
7758
        /* create a new item */
 
7759
        entry = new (G_prsmem) CVmHashEntryPrsDict(txt, len, copy);
 
7760
 
 
7761
        /* add it to the table */
 
7762
        hashtab_->add(entry);
 
7763
    }
 
7764
 
 
7765
    /* add this object/property association to the word's hash table entry */
 
7766
    entry->add_item(obj, prop);
 
7767
}
 
7768
 
 
7769
/*
 
7770
 *   Write my symbol to an object file 
 
7771
 */
 
7772
void CTcDictEntry::write_sym_to_obj_file(CVmFile *fp)
 
7773
{
 
7774
    /* if I already have a non-zero index value, I've already been written */
 
7775
    if (obj_idx_ != 0)
 
7776
        return;
 
7777
 
 
7778
    /* assign myself an object file dictionary index */
 
7779
    obj_idx_ = G_prs->get_next_obj_file_dict_idx();
 
7780
 
 
7781
    /* write my symbol to the object file */
 
7782
    sym_->write_to_obj_file(fp);
 
7783
}
 
7784
 
 
7785
/* ------------------------------------------------------------------------ */
 
7786
/*
 
7787
 *   Grammar production list entry 
 
7788
 */
 
7789
CTcGramProdEntry::CTcGramProdEntry(CTcSymObj *prod_sym)
 
7790
{
 
7791
    /* remember my object symbol */
 
7792
    prod_sym_ = prod_sym;
 
7793
 
 
7794
    /* not in a list yet */
 
7795
    nxt_ = 0;
 
7796
 
 
7797
    /* no alternatives yet */
 
7798
    alt_head_ = alt_tail_ = 0;
 
7799
 
 
7800
    /* not explicitly declared yet */
 
7801
    is_declared_ = FALSE;
 
7802
}
 
7803
 
 
7804
/*
 
7805
 *   Add an alternative 
 
7806
 */
 
7807
void CTcGramProdEntry::add_alt(CTcGramProdAlt *alt)
 
7808
{
 
7809
    /* link it at the end of my list */
 
7810
    if (alt_tail_ != 0)
 
7811
        alt_tail_->set_next(alt);
 
7812
    else
 
7813
        alt_head_ = alt;
 
7814
    alt_tail_ = alt;
 
7815
 
 
7816
    /* this is now the last element in our list */
 
7817
    alt->set_next(0);
 
7818
}
 
7819
 
 
7820
/*
 
7821
 *   Move my alternatives to a new owner 
 
7822
 */
 
7823
void CTcGramProdEntry::move_alts_to(CTcGramProdEntry *new_entry)
 
7824
{
 
7825
    CTcGramProdAlt *alt;
 
7826
    CTcGramProdAlt *nxt;
 
7827
 
 
7828
    /* move each of my alternatives */
 
7829
    for (alt = alt_head_ ; alt != 0 ; alt = nxt)
 
7830
    {
 
7831
        /* remember the next alternative, since we're unlinking this one */
 
7832
        nxt = alt->get_next();
 
7833
 
 
7834
        /* unlink this one from the list */
 
7835
        alt->set_next(0);
 
7836
 
 
7837
        /* link this one into the new owner's list */
 
7838
        new_entry->add_alt(alt);
 
7839
    }
 
7840
 
 
7841
    /* there's nothing left in our list */
 
7842
    alt_head_ = alt_tail_ = 0;
 
7843
}
 
7844
 
 
7845
/*
 
7846
 *   Write to an object file 
 
7847
 */
 
7848
void CTcGramProdEntry::write_to_obj_file(CVmFile *fp)
 
7849
{
 
7850
    ulong cnt;
 
7851
    CTcGramProdAlt *alt;
 
7852
    ulong flags;
 
7853
 
 
7854
    /* write the object file index of my production object symbol */
 
7855
    fp->write_int4(prod_sym_ == 0 ? 0 : prod_sym_->get_obj_file_idx());
 
7856
 
 
7857
    /* set up the flags */
 
7858
    flags = 0;
 
7859
    if (is_declared_)
 
7860
        flags |= 1;
 
7861
 
 
7862
    /* write the flags */
 
7863
    fp->write_int4(flags);
 
7864
 
 
7865
    /* count my alternatives */
 
7866
    for (cnt = 0, alt = alt_head_ ; alt != 0 ;
 
7867
         ++cnt, alt = alt->get_next()) ;
 
7868
 
 
7869
    /* write the count */
 
7870
    fp->write_int4(cnt);
 
7871
 
 
7872
    /* write each alternative */
 
7873
    for (alt = alt_head_ ; alt != 0 ; alt = alt->get_next())
 
7874
        alt->write_to_obj_file(fp);
 
7875
}
 
7876
 
 
7877
/* ------------------------------------------------------------------------ */
 
7878
/*
 
7879
 *   Grammar production alternative 
 
7880
 */
 
7881
CTcGramProdAlt::CTcGramProdAlt(CTcSymObj *obj_sym, CTcDictEntry *dict)
 
7882
{
 
7883
    /* remember the associated processor object */
 
7884
    obj_sym_ = obj_sym;
 
7885
 
 
7886
    /* remember the default dictionary currently in effect */
 
7887
    dict_ = dict;
 
7888
    
 
7889
    /* nothing in our token list yet */
 
7890
    tok_head_ = tok_tail_ = 0;
 
7891
 
 
7892
    /* we don't have a score or badness yet */
 
7893
    score_ = 0;
 
7894
    badness_ = 0;
 
7895
 
 
7896
    /* we're not in a list yet */
 
7897
    nxt_ = 0;
 
7898
}
 
7899
 
 
7900
void CTcGramProdAlt::add_tok(CTcGramProdTok *tok)
 
7901
{
 
7902
    /* link the token at the end of my list */
 
7903
    if (tok_tail_ != 0)
 
7904
        tok_tail_->set_next(tok);
 
7905
    else
 
7906
        tok_head_ = tok;
 
7907
    tok_tail_ = tok;
 
7908
 
 
7909
    /* there's nothing after this token */
 
7910
    tok->set_next(0);
 
7911
}
 
7912
 
 
7913
/*
 
7914
 *   Write to an object file 
 
7915
 */
 
7916
void CTcGramProdAlt::write_to_obj_file(CVmFile *fp)
 
7917
{
 
7918
    ulong cnt;
 
7919
    CTcGramProdTok *tok;
 
7920
    
 
7921
    /* write my score and badness */
 
7922
    fp->write_int2(score_);
 
7923
    fp->write_int2(badness_);
 
7924
 
 
7925
    /* write the index of my processor object symbol */
 
7926
    fp->write_int4(obj_sym_ == 0 ? 0 : obj_sym_->get_obj_file_idx());
 
7927
 
 
7928
    /* write the dictionary index */
 
7929
    fp->write_int4(dict_ == 0 ? 0 : dict_->get_obj_idx());
 
7930
 
 
7931
    /* count my tokens */
 
7932
    for (cnt = 0, tok = tok_head_ ; tok != 0 ;
 
7933
         ++cnt, tok = tok->get_next()) ;
 
7934
 
 
7935
    /* write my token count */
 
7936
    fp->write_int4(cnt);
 
7937
 
 
7938
    /* write the tokens */
 
7939
    for (tok = tok_head_ ; tok != 0 ; tok = tok->get_next())
 
7940
        tok->write_to_obj_file(fp);
 
7941
}
 
7942
 
 
7943
/* ------------------------------------------------------------------------ */
 
7944
/*
 
7945
 *   Grammar production token object 
 
7946
 */
 
7947
 
 
7948
/*
 
7949
 *   write to an object file 
 
7950
 */
 
7951
void CTcGramProdTok::write_to_obj_file(CVmFile *fp)
 
7952
{
 
7953
    size_t i;
 
7954
 
 
7955
    /* write my type */
 
7956
    fp->write_int2((int)typ_);
 
7957
 
 
7958
    /* write my data */
 
7959
    switch(typ_)
 
7960
    {
 
7961
    case TCGRAM_PROD:
 
7962
        /* write my object's object file index */
 
7963
        fp->write_int4(val_.obj_ != 0
 
7964
                       ? val_.obj_->get_obj_file_idx() : 0);
 
7965
        break;
 
7966
 
 
7967
    case TCGRAM_TOKEN_TYPE:
 
7968
        /* write my enum token ID */
 
7969
        fp->write_int4(val_.enum_id_);
 
7970
        break;
 
7971
 
 
7972
    case TCGRAM_PART_OF_SPEECH:
 
7973
        /* write my property ID */
 
7974
        fp->write_int2(val_.prop_);
 
7975
        break;
 
7976
 
 
7977
    case TCGRAM_LITERAL:
 
7978
        /* write my string */
 
7979
        fp->write_int2(val_.str_.len_);
 
7980
        fp->write_bytes(val_.str_.txt_, val_.str_.len_);
 
7981
        break;
 
7982
 
 
7983
    case TCGRAM_STAR:
 
7984
        /* no additional value data */
 
7985
        break;
 
7986
 
 
7987
    case TCGRAM_PART_OF_SPEECH_LIST:
 
7988
        /* write the length */
 
7989
        fp->write_int2(val_.prop_list_.len_);
 
7990
 
 
7991
        /* write each element */
 
7992
        for (i = 0 ; i < val_.prop_list_.len_ ; ++i)
 
7993
            fp->write_int2(val_.prop_list_.arr_[i]);
 
7994
 
 
7995
        /* done */
 
7996
        break;
 
7997
 
 
7998
    case TCGRAM_UNKNOWN:
 
7999
        /* no value - there's nothing extra to write */
 
8000
        break;
 
8001
    }
 
8002
 
 
8003
    /* write my property association */
 
8004
    fp->write_int2(prop_assoc_);
 
8005
}
 
8006
 
 
8007
/*
 
8008
 *   Initialize with a part-of-speech list 
 
8009
 */
 
8010
void CTcGramProdTok::set_match_part_list()
 
8011
{
 
8012
    const size_t init_alo = 10;
 
8013
 
 
8014
    /* remember the type */
 
8015
    typ_ = TCGRAM_PART_OF_SPEECH_LIST;
 
8016
 
 
8017
    /* we have nothing in the list yet */
 
8018
    val_.prop_list_.len_ = 0;
 
8019
 
 
8020
    /* set the initial allocation size */
 
8021
    val_.prop_list_.alo_ = init_alo;
 
8022
 
 
8023
    /* allocate the initial list */
 
8024
    val_.prop_list_.arr_ = (tctarg_prop_id_t *)G_prsmem->alloc(
 
8025
        init_alo * sizeof(val_.prop_list_.arr_[0]));
 
8026
}
 
8027
 
 
8028
/*
 
8029
 *   Add a property to our part-of-speech match list 
 
8030
 */
 
8031
void CTcGramProdTok::add_match_part_ele(tctarg_prop_id_t prop)
 
8032
{
 
8033
    /* if necessary, re-allocate the array at a larger size */
 
8034
    if (val_.prop_list_.len_ == val_.prop_list_.alo_)
 
8035
    {
 
8036
        tctarg_prop_id_t *oldp;
 
8037
 
 
8038
        /* bump up the size a bit */
 
8039
        val_.prop_list_.alo_ += 10;
 
8040
 
 
8041
        /* remember the current list long enough to copy it */
 
8042
        oldp = val_.prop_list_.arr_;
 
8043
 
 
8044
        /* reallocate it */
 
8045
        val_.prop_list_.arr_ = (tctarg_prop_id_t *)G_prsmem->alloc(
 
8046
            val_.prop_list_.alo_ * sizeof(val_.prop_list_.arr_[0]));
 
8047
 
 
8048
        /* copy the old list into the new one */
 
8049
        memcpy(val_.prop_list_.arr_, oldp,
 
8050
               val_.prop_list_.len_ * sizeof(val_.prop_list_.arr_[0]));
 
8051
    }
 
8052
 
 
8053
    /* 
 
8054
     *   we now know we have space for the new element, so add it, bumping up
 
8055
     *   the length counter to account for the addition 
 
8056
     */
 
8057
    val_.prop_list_.arr_[val_.prop_list_.len_++] = prop;
 
8058
}
 
8059
 
 
8060
/* ------------------------------------------------------------------------ */
 
8061
/*
 
8062
 *   Code Body Parse Node 
 
8063
 */
 
8064
 
 
8065
/*
 
8066
 *   instantiate 
 
8067
 */
 
8068
CTPNCodeBodyBase::CTPNCodeBodyBase(CTcPrsSymtab *lcltab,
 
8069
                                   CTcPrsSymtab *gototab, CTPNStm *stm,
 
8070
                                   int argc, int varargs,
 
8071
                                   int varargs_list,
 
8072
                                   CTcSymLocal *varargs_list_local,
 
8073
                                   int local_cnt, int self_valid,
 
8074
                                   CTcCodeBodyRef *enclosing_code_body)
 
8075
{
 
8076
    /* remember the data in the code body */
 
8077
    lcltab_ = lcltab;
 
8078
    gototab_ = gototab;
 
8079
    stm_ = stm;
 
8080
    argc_ = argc;
 
8081
    varargs_ = varargs;
 
8082
    varargs_list_ = varargs_list;
 
8083
    varargs_list_local_ = varargs_list_local;
 
8084
    local_cnt_ = local_cnt;
 
8085
    self_valid_ = self_valid;
 
8086
    self_referenced_ = FALSE;
 
8087
    full_method_ctx_referenced_ = FALSE;
 
8088
 
 
8089
    /* remember the enclosing code body */
 
8090
    enclosing_code_body_ = enclosing_code_body;
 
8091
 
 
8092
    /* presume we won't need a local context object */
 
8093
    has_local_ctx_ = FALSE;
 
8094
    local_ctx_arr_size_ = 0;
 
8095
    ctx_head_ = ctx_tail_ = 0;
 
8096
    local_ctx_needs_self_ = FALSE;
 
8097
    local_ctx_needs_full_method_ctx_ = FALSE;
 
8098
 
 
8099
    /* presume we have an internal fixup list */
 
8100
    fixup_owner_sym_ = 0;
 
8101
    fixup_list_anchor_ = &internal_fixups_;
 
8102
 
 
8103
    /* no internal fixups yet */
 
8104
    internal_fixups_ = 0;
 
8105
 
 
8106
    /* we haven't been replaced yet */
 
8107
    replaced_ = FALSE;
 
8108
 
 
8109
    /* 
 
8110
     *   remember the source location of the closing brace, which should
 
8111
     *   be the current location when we're instantiated 
 
8112
     */
 
8113
    end_desc_ = G_tok->get_last_desc();
 
8114
    end_linenum_ = G_tok->get_last_linenum();
 
8115
}
 
8116
 
 
8117
 
 
8118
/*
 
8119
 *   fold constants 
 
8120
 */
 
8121
CTcPrsNode *CTPNCodeBodyBase::fold_constants(class CTcPrsSymtab *)
 
8122
{
 
8123
    /* 
 
8124
     *   fold constants in our compound statement, in the scope of our
 
8125
     *   local symbol table 
 
8126
     */
 
8127
    if (stm_ != 0)
 
8128
        stm_->fold_constants(lcltab_);
 
8129
 
 
8130
    /* we are not directly changed by this operation */
 
8131
    return this;
 
8132
}
 
8133
 
 
8134
/*
 
8135
 *   Check for unreferenced labels 
 
8136
 */
 
8137
void CTPNCodeBodyBase::check_unreferenced_labels()
 
8138
{
 
8139
    /* 
 
8140
     *   enumerate our labels - skip this check if we're only parsing the
 
8141
     *   program for syntax 
 
8142
     */
 
8143
    if (gototab_ != 0 && !G_prs->get_syntax_only())
 
8144
        gototab_->enum_entries(&unref_label_cb, this);
 
8145
}
 
8146
 
 
8147
/*
 
8148
 *   Callback for enumerating labels for checking for unreferenced labels 
 
8149
 */
 
8150
void CTPNCodeBodyBase::unref_label_cb(void *, CTcSymbol *sym)
 
8151
{
 
8152
    /* if it's a label, check it out */
 
8153
    if (sym->get_type() == TC_SYM_LABEL)
 
8154
    {
 
8155
        CTcSymLabel *lbl = (CTcSymLabel *)sym;
 
8156
 
 
8157
        /* 
 
8158
         *   get its underlying statement, and make sure it has a
 
8159
         *   control-flow flag for goto, continue, or break 
 
8160
         */
 
8161
        if (lbl->get_stm() != 0)
 
8162
        {
 
8163
            ulong flags;
 
8164
 
 
8165
            /* 
 
8166
             *   get the explicit control flow flags for this statement --
 
8167
             *   these flags indicate the use of the label in a goto,
 
8168
             *   break, or continue statement 
 
8169
             */
 
8170
            flags = lbl->get_stm()->get_explicit_control_flow_flags();
 
8171
 
 
8172
            /* 
 
8173
             *   if the flags aren't set for at least one of the explicit
 
8174
             *   label uses, the label is unreferenced 
 
8175
             */
 
8176
            if ((flags & (TCPRS_FLOW_GOTO | TCPRS_FLOW_BREAK
 
8177
                          | TCPRS_FLOW_CONT)) == 0)
 
8178
                lbl->get_stm()->log_warning(TCERR_UNREFERENCED_LABEL,
 
8179
                                            (int)lbl->get_sym_len(),
 
8180
                                            lbl->get_sym());
 
8181
        }
 
8182
    }
 
8183
}
 
8184
 
 
8185
/*
 
8186
 *   add an absolute fixup to my list 
 
8187
 */
 
8188
void CTPNCodeBodyBase::add_abs_fixup(CTcDataStream *ds, ulong ofs)
 
8189
{
 
8190
    /* ask the code body to add the fixup */
 
8191
    CTcAbsFixup::add_abs_fixup(fixup_list_anchor_, ds, ofs);
 
8192
}
 
8193
 
 
8194
/*
 
8195
 *   add an absolute fixup at the current stream offset 
 
8196
 */
 
8197
void CTPNCodeBodyBase::add_abs_fixup(CTcDataStream *ds)
 
8198
{
 
8199
    /* ask the code body to add the fixup */
 
8200
    CTcAbsFixup::add_abs_fixup(fixup_list_anchor_, ds, ds->get_ofs());
 
8201
}
 
8202
 
 
8203
/*
 
8204
 *   Get the context variable for a given level 
 
8205
 */
 
8206
int CTPNCodeBodyBase::get_or_add_ctx_var_for_level(int level)
 
8207
{
 
8208
    CTcCodeBodyCtx *ctx;
 
8209
    
 
8210
    /* scan our list to see if the level is already assigned */
 
8211
    for (ctx = ctx_head_ ; ctx != 0 ; ctx = ctx->nxt_)
 
8212
    {
 
8213
        /* if we've already set up this level, return its variable */
 
8214
        if (ctx->level_ == level)
 
8215
            return ctx->var_num_;
 
8216
    }
 
8217
 
 
8218
    /* we didn't find it - allocate a new level structure */
 
8219
    ctx = new (G_prsmem) CTcCodeBodyCtx();
 
8220
 
 
8221
    /* set up its level and allocate a new variable and property for it */
 
8222
    ctx->level_ = level;
 
8223
    ctx->var_num_ = G_prs->alloc_ctx_holder_var();
 
8224
 
 
8225
    /* 
 
8226
     *   allocating a new variable probably increased the maximum local
 
8227
     *   variable count - update our information from the parser 
 
8228
     */
 
8229
    local_cnt_ = G_prs->get_max_local_cnt();
 
8230
 
 
8231
    /* link it into our list */
 
8232
    ctx->prv_ = ctx_tail_;
 
8233
    ctx->nxt_ = 0;
 
8234
    if (ctx_tail_ != 0)
 
8235
        ctx_tail_->nxt_ = ctx;
 
8236
    else
 
8237
        ctx_head_ = ctx;
 
8238
    ctx_tail_ = ctx;
 
8239
 
 
8240
    /* return the variable for the new level */
 
8241
    return ctx->var_num_;
 
8242
}
 
8243
 
 
8244
/*
 
8245
 *   Find a local context for a given level 
 
8246
 */
 
8247
int CTPNCodeBodyBase::get_ctx_var_for_level(int level, int *varnum)
 
8248
{
 
8249
    CTcCodeBodyCtx *ctx;
 
8250
 
 
8251
    /* if they want level zero, it's our local context */
 
8252
    if (level == 0)
 
8253
    {
 
8254
        /* set the variable ID to our local context variable */
 
8255
        *varnum = local_ctx_var_;
 
8256
 
 
8257
        /* return true only if we actually have a local context */
 
8258
        return has_local_ctx_;
 
8259
    }
 
8260
 
 
8261
    /* scan our list to see if the level is already assigned */
 
8262
    for (ctx = ctx_head_ ; ctx != 0 ; ctx = ctx->nxt_)
 
8263
    {
 
8264
        /* if we've already set up this level, return its variable */
 
8265
        if (ctx->level_ == level)
 
8266
        {
 
8267
            /* set the caller's variable number */
 
8268
            *varnum = ctx->var_num_;
 
8269
 
 
8270
            /* indicate that we found it */
 
8271
            return TRUE;
 
8272
        }
 
8273
    }
 
8274
 
 
8275
    /* didn't find it */
 
8276
    return FALSE;
 
8277
}
 
8278
 
 
8279
/*
 
8280
 *   Get the immediately enclosing code body 
 
8281
 */
 
8282
CTPNCodeBody *CTPNCodeBodyBase::get_enclosing() const
 
8283
{
 
8284
    /* 
 
8285
     *   if we have no enclosing code body reference, we have no enclosing
 
8286
     *   code body 
 
8287
     */
 
8288
    if (enclosing_code_body_ == 0)
 
8289
        return 0;
 
8290
 
 
8291
    /* get the code body from my enclosing code body reference object */
 
8292
    return enclosing_code_body_->ptr;
 
8293
}
 
8294
 
 
8295
/*
 
8296
 *   Get the outermost enclosing code body 
 
8297
 */
 
8298
CTPNCodeBody *CTPNCodeBodyBase::get_outermost_enclosing() const
 
8299
{
 
8300
    CTPNCodeBody *cur;
 
8301
    CTPNCodeBody *nxt;
 
8302
 
 
8303
    /* 
 
8304
     *   scan each enclosing code body until we find one without an enclosing
 
8305
     *   code body 
 
8306
     */
 
8307
    for (cur = 0, nxt = get_enclosing() ; nxt != 0 ;
 
8308
         cur = nxt, nxt = nxt->get_enclosing()) ;
 
8309
 
 
8310
    /* return what we found */
 
8311
    return cur;
 
8312
}
 
8313
 
 
8314
/*
 
8315
 *   Get the base function symbol for a code body defining a modified
 
8316
 *   function (i.e., 'modify <funcname>...').  This is the function to which
 
8317
 *   'replaced' refers within this code body and within nested code bodies.  
 
8318
 */
 
8319
class CTcSymFunc *CTPNCodeBodyBase::get_replaced_func() const
 
8320
{
 
8321
    CTcSymFunc *b;
 
8322
    CTPNCodeBody *enc;
 
8323
 
 
8324
    /* if we have an associated function symbol, it's the base function */
 
8325
    if ((b = get_func_sym()) != 0)
 
8326
        return b->get_mod_base();
 
8327
 
 
8328
    /* 
 
8329
     *   if we have an enclosing code body, then 'replaced' here means the
 
8330
     *   same thing it does there, since we don't explicitly replace anything
 
8331
     *   here 
 
8332
     */
 
8333
    if ((enc = get_enclosing()) != 0)
 
8334
        return enc->get_replaced_func();
 
8335
 
 
8336
    /* if we haven't found anything yet, we don't have a base function */
 
8337
    return 0;
 
8338
}
 
8339
 
 
8340
/* ------------------------------------------------------------------------ */
 
8341
/*
 
8342
 *   Generic statement node 
 
8343
 */
 
8344
 
 
8345
/* 
 
8346
 *   initialize at the tokenizer's current source file position 
 
8347
 */
 
8348
CTPNStmBase::CTPNStmBase()
 
8349
{
 
8350
    /* get the current source location from the parser */
 
8351
    init(G_prs->get_cur_desc(), G_prs->get_cur_linenum());
 
8352
}
 
8353
 
 
8354
/* 
 
8355
 *   log an error at this statement's source file position 
 
8356
 */
 
8357
void CTPNStmBase::log_error(int errnum, ...) const
 
8358
{
 
8359
    va_list marker;
 
8360
 
 
8361
    /* display the message */
 
8362
    va_start(marker, errnum);
 
8363
    G_tcmain->v_log_error(file_, linenum_, TC_SEV_ERROR, errnum, marker);
 
8364
    va_end(marker);
 
8365
}
 
8366
 
 
8367
/* 
 
8368
 *   log a warning at this statement's source file position 
 
8369
 */
 
8370
void CTPNStmBase::log_warning(int errnum, ...) const
 
8371
{
 
8372
    va_list marker;
 
8373
 
 
8374
    /* display the message */
 
8375
    va_start(marker, errnum);
 
8376
    G_tcmain->v_log_error(file_, linenum_, TC_SEV_WARNING, errnum, marker);
 
8377
    va_end(marker);
 
8378
}
 
8379
 
 
8380
/*
 
8381
 *   Generate code for a sub-statement 
 
8382
 */
 
8383
void CTPNStmBase::gen_code_substm(CTPNStm *substm)
 
8384
{
 
8385
    /* set the error reporting location to refer to the sub-statement */
 
8386
    G_tok->set_line_info(substm->get_source_desc(),
 
8387
                         substm->get_source_linenum());
 
8388
 
 
8389
    /* generate code for the sub-statement */
 
8390
    substm->gen_code(TRUE, TRUE);
 
8391
 
 
8392
    /* restore the error reporting location to the main statement */
 
8393
    G_tok->set_line_info(get_source_desc(), get_source_linenum());
 
8394
}
 
8395
 
 
8396
/* ------------------------------------------------------------------------ */
 
8397
/*
 
8398
 *   Object Definition Statement 
 
8399
 */
 
8400
 
 
8401
/*
 
8402
 *   fold constants 
 
8403
 */
 
8404
CTcPrsNode *CTPNStmObjectBase::fold_constants(CTcPrsSymtab *symtab)
 
8405
{
 
8406
    CTPNObjProp *prop;
 
8407
 
 
8408
    /* fold constants in each of our property list entries */
 
8409
    for (prop = first_prop_ ; prop != 0 ; prop = prop->nxt_)
 
8410
        prop->fold_constants(symtab);
 
8411
 
 
8412
    /* we're not changed directly by this */
 
8413
    return this;
 
8414
}
 
8415
 
 
8416
/* ------------------------------------------------------------------------ */
 
8417
/*
 
8418
 *   superclass record
 
8419
 */
 
8420
 
 
8421
/* 
 
8422
 *   get my symbol 
 
8423
 */
 
8424
CTcSymbol *CTPNSuperclass::get_sym() const
 
8425
{
 
8426
    /* if we know the symbol already, return it directly */
 
8427
    if (sym_ != 0)
 
8428
        return sym_;
 
8429
 
 
8430
    /* look up my symbol by name in the global symbol table */
 
8431
    return G_prs->get_global_symtab()->find(sym_txt_, sym_len_);
 
8432
}
 
8433
 
 
8434
/*
 
8435
 *   am I a subclass of the given class?  
 
8436
 */
 
8437
int CTPNSuperclass::is_subclass_of(const CTPNSuperclass *other) const
 
8438
{
 
8439
    CTcSymObj *sym;
 
8440
    CTPNSuperclass *sc;
 
8441
 
 
8442
    /* 
 
8443
     *   if my name matches, we're a subclass (we are a subclass of
 
8444
     *   ourselves) 
 
8445
     */
 
8446
    if (other->sym_len_ == sym_len_
 
8447
        && memcmp(other->sym_txt_, sym_txt_, sym_len_) == 0)
 
8448
        return TRUE;
 
8449
 
 
8450
    /* 
 
8451
     *   We're a subclass if any of our superclasses are subclasses of the
 
8452
     *   given object.  Get my object symbol, and make sure it's really a
 
8453
     *   tads-object - if it's not, we're definitely not a subclass of
 
8454
     *   anything.  
 
8455
     */
 
8456
    sym = (CTcSymObj *)get_sym();
 
8457
    if (sym == 0
 
8458
        || sym->get_type() != TC_SYM_OBJ
 
8459
        || sym->get_metaclass() != TC_META_TADSOBJ)
 
8460
        return FALSE;
 
8461
 
 
8462
    /* scan our symbol's superclass list for a match */
 
8463
    for (sc = sym->get_sc_name_head() ; sc != 0 ; sc = sc->nxt_)
 
8464
    {
 
8465
        /* 
 
8466
         *   if this one's a subclass of the given class, we're a subclass
 
8467
         *   as well, since we're a subclass of this superclass 
 
8468
         */
 
8469
        if (sc->is_subclass_of(other))
 
8470
            return TRUE;
 
8471
    }
 
8472
 
 
8473
    /* 
 
8474
     *   we didn't find any superclass that's a subclass of the given
 
8475
     *   class, so we're not a subclass of the given class 
 
8476
     */
 
8477
    return FALSE;
 
8478
}
 
8479
 
 
8480
 
 
8481
/* ------------------------------------------------------------------------ */
 
8482
/*
 
8483
 *   'return' statement 
 
8484
 */
 
8485
 
 
8486
/*
 
8487
 *   fold constants 
 
8488
 */
 
8489
CTcPrsNode *CTPNStmReturnBase::fold_constants(CTcPrsSymtab *symtab)
 
8490
{
 
8491
    /* set our location for any errors that occur */
 
8492
    G_tok->set_line_info(get_source_desc(), get_source_linenum());
 
8493
 
 
8494
    /* fold constants in the expression, if we have one */
 
8495
    if (expr_ != 0)
 
8496
        expr_ = expr_->fold_constants(symtab);
 
8497
 
 
8498
    /* we are not directly changed by this operation */
 
8499
    return this;
 
8500
}
 
8501
 
 
8502
/* ------------------------------------------------------------------------ */
 
8503
/*
 
8504
 *   Formal type list 
 
8505
 */
 
8506
 
 
8507
/* 
 
8508
 *   add a typed parameter to the list - 'tok' is the symbol giving the type
 
8509
 *   name 
 
8510
 */
 
8511
void CTcFormalTypeList::add_typed_param(const CTcToken *tok)
 
8512
{
 
8513
    add(new (G_prsmem) CTcFormalTypeEle(tok->get_text(), tok->get_text_len()));
 
8514
}
 
8515
 
 
8516
/* add an untyped parameter to the list */
 
8517
void CTcFormalTypeList::add_untyped_param()
 
8518
{
 
8519
    add(new (G_prsmem) CTcFormalTypeEle());
 
8520
}
 
8521
 
 
8522
/* add a list element */
 
8523
void CTcFormalTypeList::add(CTcFormalTypeEle *ele)
 
8524
{
 
8525
    /* link it into our list */
 
8526
    if (tail_ != 0)
 
8527
        tail_->nxt_ = ele;
 
8528
    else
 
8529
        head_ = ele;
 
8530
    tail_ = ele;
 
8531
    ele->nxt_ = 0;
 
8532
}
 
8533
 
 
8534
/* 
 
8535
 *   create a decorated name token for the multi-method defined by the given
 
8536
 *   function name and our type list 
 
8537
 */
 
8538
void CTcFormalTypeList::decorate_name(CTcToken *decorated_name,
 
8539
                                      const CTcToken *func_base_name)
 
8540
{
 
8541
    CTcFormalTypeEle *ele;
 
8542
    size_t len;
 
8543
    const char *p;
 
8544
    
 
8545
    /* figure out how much space we need for the decorated name */
 
8546
    for (len = func_base_name->get_text_len() + 1, ele = head_ ;
 
8547
         ele != 0 ; ele = ele->nxt_)
 
8548
    {
 
8549
        /* add this type name's length, if there's a name */
 
8550
        if (ele->name_ != 0)
 
8551
            len += ele->name_len_;
 
8552
 
 
8553
        /* add a semicolon after the type */
 
8554
        len += 1;
 
8555
    }
 
8556
 
 
8557
    /* add "...;" if it's varargs */
 
8558
    if (varargs_)
 
8559
        len += 4;
 
8560
 
 
8561
    /* allocate space for the name */
 
8562
    G_tok->reserve_source(len);
 
8563
 
 
8564
    /* start with the function name */
 
8565
    p = G_tok->store_source_partial(func_base_name->get_text(),
 
8566
                                    func_base_name->get_text_len());
 
8567
 
 
8568
    /* add a "*" separator for the multi-method indicator */
 
8569
    G_tok->store_source_partial("*", 1);
 
8570
 
 
8571
    /* add each type name */
 
8572
    for (ele = head_ ; ele != 0 ; ele = ele->nxt_)
 
8573
    {
 
8574
        /* add the type, if it has one (if not, leave the type empty) */
 
8575
        if (ele->name_ != 0)
 
8576
            G_tok->store_source_partial(ele->name_, ele->name_len_);
 
8577
 
 
8578
        /* add a semicolon to terminate the parameter name */
 
8579
        G_tok->store_source_partial(";", 1);
 
8580
    }
 
8581
 
 
8582
    /* add the varargs indicator ("...;"), if applicable */
 
8583
    if (varargs_)
 
8584
        G_tok->store_source_partial("...;", 4);
 
8585
 
 
8586
    /* null-terminate it */
 
8587
    G_tok->store_source_partial("\0", 1);
 
8588
 
 
8589
    /* set the decorated token name */
 
8590
    decorated_name->settyp(TOKT_SYM);
 
8591
    decorated_name->set_text(p, len);
 
8592
}
 
8593
 
 
8594
/* formal list element - construction */
 
8595
CTcFormalTypeEle::CTcFormalTypeEle(const char *name, size_t len)
 
8596
{
 
8597
    name_ = new (G_prsmem) char[len + 1];
 
8598
    memcpy(name_, name, len);
 
8599
    name_len_ = len;
 
8600
}