cfad47cfa3/t3compiler/tads3/tcprs.cpp

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