cfad47cfa3/t3compiler/tads3/tcprsimg.cpp

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
#ifdef RCSID
2
static char RCSid[] =
3
"$Header: d:/cvsroot/tads/tads3/TCPRSIMG.CPP,v 1.1 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
  tcprsimg.cpp - TADS 3 Compiler Parser - image writing functions
15
Function
16
  
17
Notes
18
  
19
Modified
20
  04/30/99 MJRoberts  - Creation
21
*/
22
23
#include <stdlib.h>
24
#include <string.h>
25
#include <stdio.h>
26
#include <assert.h>
27
28
#include "os.h"
29
#include "t3std.h"
30
#include "tcprs.h"
31
#include "tctarg.h"
32
#include "tcgen.h"
33
#include "vmhash.h"
34
#include "tcmain.h"
35
#include "vmfile.h"
36
#include "tctok.h"
37
38
39
/* ------------------------------------------------------------------------ */
40
/*
41
 *   Read an object file and load the global symbol table 
42
 */
43
int CTcParser::load_object_file(class CVmFile *fp, const textchar_t *fname,
44
                                tctarg_obj_id_t *obj_xlat,
45
                                tctarg_prop_id_t *prop_xlat,
46
                                ulong *enum_xlat)
47
{
48
    ulong sym_cnt;
49
    ulong dict_cnt;
50
    ulong i;
51
    ulong anon_cnt;
52
    ulong nonsym_cnt;
53
    ulong prod_cnt;
54
    ulong exp_cnt;
55
56
    /* read the number of symbol index entries */
57
    sym_cnt = fp->read_uint4();
58
    if (sym_cnt != 0)
59
    {
60
        /* allocate space for the symbol index list */
61
        obj_sym_list_ = (CTcSymbol **)
62
                        t3malloc(sym_cnt * sizeof(obj_sym_list_[0]));
63
64
        /* the list is empty so far */
65
        obj_file_sym_idx_ = 0;
66
    }
67
68
    /* read the number of dictionary symbols */
69
    dict_cnt = fp->read_uint4();
70
71
    /* if there are any symbols, read them */
72
    if (dict_cnt != 0)
73
    {
74
        /* allocate space for the dictionary index list */
75
        obj_dict_list_ = (CTcDictEntry **)
76
                         t3malloc(dict_cnt * sizeof(obj_dict_list_[0]));
77
78
        /* nothing in the list yet */
79
        obj_file_dict_idx_ = 0;
80
    }
81
82
    /* read the number of symbols in the file */
83
    sym_cnt = fp->read_uint4();
84
85
    /* read the symbols */
86
    for (i = 0 ; i < sym_cnt ; ++i)
87
    {
88
        /* load a symbol */
89
        if (CTcSymbol::load_from_obj_file(fp, fname,
90
                                          obj_xlat, prop_xlat, enum_xlat))
91
            return 1;
92
    }
93
94
    /* read the number of anonymous object symbols */
95
    anon_cnt = fp->read_uint4();
96
97
    /* read the anonymous object symbols */
98
    for (i = 0 ; i < anon_cnt ; ++i)
99
    {
100
        /* load the next anonymous object symbol */
101
        if (CTcSymObj::load_from_obj_file(fp, fname, obj_xlat, TRUE))
102
            return 1;
103
    }
104
105
    /* read the non-symbol object ID's */
106
    nonsym_cnt = fp->read_uint4();
107
    for (i = 0 ; i < nonsym_cnt ; ++i)
108
    {
109
        tctarg_obj_id_t id;
110
111
        /* read the next non-symbol object ID */
112
        id = (tctarg_obj_id_t)fp->read_uint4();
113
114
        /* 
115
         *   allocate a new ID for the object, and set the translation
116
         *   table for the new ID - this will ensure that references to
117
         *   this non-symbol object are properly fixed up 
118
         */
119
        obj_xlat[id] = G_cg->new_obj_id();
120
    }
121
122
    /* read the number of symbol cross-reference sections in the file */
123
    sym_cnt = fp->read_uint4();
124
125
    /* read the symbol cross-references */
126
    for (i = 0 ; i < sym_cnt ; ++i)
127
    {
128
        ulong idx;
129
        CTcSymbol *sym;
130
131
        /* read the symbol index */
132
        idx = fp->read_uint4();
133
134
        /* get the symbol from the index list */
135
        sym = get_objfile_sym(idx);
136
137
        /* load the symbol's reference information */
138
        sym->load_refs_from_obj_file(fp, fname, obj_xlat, prop_xlat);
139
    }
140
141
    /* read the number of anonymous object cross-references */
142
    anon_cnt = fp->read_uint4();
143
144
    /* read the anonymous object cross-references */
145
    for (i = 0 ; i < anon_cnt ; ++i)
146
    {
147
        ulong idx;
148
        CTcSymbol *sym;
149
150
        /* read the symbol index */
151
        idx = fp->read_uint4();
152
153
        /* get the symbol from the index list */
154
        sym = get_objfile_sym(idx);
155
156
        /* load the symbol's reference information */
157
        sym->load_refs_from_obj_file(fp, fname, obj_xlat, prop_xlat);
158
    }
159
160
    /* read the master grammar rule count */
161
    prod_cnt = fp->read_uint4();
162
163
    /* read the master grammar rule list */
164
    for (i = 0 ; i < prod_cnt ; ++i)
165
    {
166
        /* read the next grammar production */
167
        CTcGramProdEntry::load_from_obj_file(fp, prop_xlat, enum_xlat, 0);
168
    }
169
170
    /* read the number of named grammar rules */
171
    prod_cnt = fp->read_uint4();
172
173
    /* read the private grammar rules */
174
    for (i = 0 ; i < prod_cnt ; ++i)
175
    {
176
        CTcSymObj *match_sym;
177
178
        /* read the match object defining the rule */
179
        match_sym = get_objfile_objsym(fp->read_uint4());
180
181
        /* read the private rule list */
182
        CTcGramProdEntry::load_from_obj_file(
183
            fp, prop_xlat, enum_xlat, match_sym);
184
    }
185
186
    /* read the export symbol list */
187
    exp_cnt = fp->read_uint4();
188
    for (i = 0 ; i < exp_cnt ; ++i)
189
    {
190
        CTcPrsExport *exp;
191
        
192
        /* read the next entry */
193
        exp = CTcPrsExport::read_from_obj_file(fp);
194
195
        /* if that failed, the whole load fails */
196
        if (exp == 0)
197
            return 1;
198
199
        /* add it to our list */
200
        add_export_to_list(exp);
201
    }
202
203
    /* done with the symbol index list - free it */
204
    if (obj_sym_list_ != 0)
205
    {
206
        /* free it and forget it */
207
        t3free(obj_sym_list_);
208
        obj_sym_list_ = 0;
209
    }
210
211
    /* done with the dictionary index list - free it */
212
    if (obj_dict_list_ != 0)
213
    {
214
        /* free the memory and forget it */
215
        t3free(obj_dict_list_);
216
        obj_dict_list_ = 0;
217
    }
218
219
    /* success */
220
    return 0;
221
}
222
223
224
/* ------------------------------------------------------------------------ */
225
/*
226
 *   Generate code and write the image file 
227
 */
228
void CTPNStmProg::build_image(class CVmFile *image_fp, uchar xor_mask,
229
                              const char tool_data[4])
230
{
231
    /* generate code */
232
    if (gen_code_for_build())
233
        return;
234
235
    /* scan the symbol table for unresolved external references */
236
    if (G_prs->check_unresolved_externs())
237
        return;
238
239
    /*
240
     *   Finally, our task of constructing the program is complete.  All
241
     *   that remains is to write the image file.  Tell the code generator
242
     *   to begin the process.  
243
     */
244
    G_cg->write_to_image(image_fp, xor_mask, tool_data);
245
}
246
247
/* ------------------------------------------------------------------------ */
248
/*
249
 *   Generate code and write the object file 
250
 */
251
void CTPNStmProg::build_object_file(class CVmFile *object_fp,
252
                                    class CTcMake *make_obj)
253
{
254
    /* generate code */
255
    if (gen_code_for_build())
256
        return;
257
258
    /*
259
     *   Finally, our task of constructing the program is complete.  All
260
     *   that remains is to write the image file.  Tell the code generator
261
     *   to begin the process.  
262
     */
263
    G_cg->write_to_object_file(object_fp, make_obj);
264
}
265
266
/* ------------------------------------------------------------------------ */
267
/*
268
 *   Generate code for a build, in preparation for writing an image file
269
 *   or an object file.
270
 */
271
int CTPNStmProg::gen_code_for_build()
272
{
273
    /* notify the tokenizer that parsing is done */
274
    G_tok->parsing_done();
275
276
    /* notify the code generator that we're finished parsing */
277
    G_cg->parsing_done();
278
279
    /* set the global symbol table in the code streams */
280
    G_cs_main->set_symtab(G_prs->get_global_symtab());
281
    G_cs_static->set_symtab(G_prs->get_global_symtab());
282
283
    /* generate code for the entire program */
284
    gen_code(TRUE, TRUE);
285
286
    /* 
287
     *   if we encountered any errors generating code, don't bother
288
     *   writing the image 
289
     */
290
    if (G_tcmain->get_error_count() != 0)
291
        return 1;
292
293
    /* return success */
294
    return 0;
295
}
296
297
/* ------------------------------------------------------------------------ */
298
/*
299
 *   Check for unresolved external symbols.  Logs an error for each
300
 *   unresolved external.  
301
 */
302
int CTcParser::check_unresolved_externs()
303
{
304
    int errcnt;
305
306
    /* generate any synthesized code */
307
    G_cg->build_synthesized_code();
308
    
309
    /* note the previous error count */
310
    errcnt = G_tcmain->get_error_count();
311
    
312
    /* enumerate the entries with our unresolved check callback */
313
    get_global_symtab()->enum_entries(&enum_sym_extref, this);
314
315
    /* 
316
     *   if the error count increased, we logged errors for unresolved
317
     *   symbols 
318
     */
319
    return (G_tcmain->get_error_count() > errcnt);
320
}
321
322
/*
323
 *   Enumeration callback - check for unresolved external references.  For
324
 *   each object or function still marked "external," we'll log an error.  
325
 */
326
void CTcParser::enum_sym_extref(void *, CTcSymbol *sym)
327
{
328
    /* if it's an external symbol, log an error */
329
    if (sym->is_unresolved_extern())
330
        G_tcmain->log_error(0, 0, TC_SEV_ERROR, TCERR_UNRESOLVED_EXTERN,
331
                            (int)sym->get_sym_len(), sym->get_sym());
332
}
333
334
335
/* ------------------------------------------------------------------------ */
336
/*
337
 *   Build dictionaries.  We go through all objects and insert their
338
 *   vocabulary words into their dictionaries.  
339
 */
340
void CTcParser::build_dictionaries()
341
{
342
    CTcDictEntry *dict;
343
    CTcSymObj *sym;
344
    
345
    /* 
346
     *   enumerate our symbols to insert dictionary words - this will
347
     *   populate each dictionary's hash table with a complete list of the
348
     *   words and object associations for the dictionary 
349
     */
350
    get_global_symtab()->enum_entries(&enum_sym_dict, this);
351
352
    /* do the same for the anonymous objects */
353
    for (sym = anon_obj_head_ ; sym != 0 ; sym = (CTcSymObj *)sym->nxt_)
354
        sym->build_dictionary();
355
356
    /* generate the object stream for each dictionary */
357
    for (dict = dict_head_ ; dict != 0 ; dict = dict->get_next())
358
    {
359
        /* generate the code (static data, actually) for this dictionary */
360
        G_cg->gen_code_for_dict(dict);
361
    }
362
}
363
364
/*
365
 *   enumeration callback - build dictionaries 
366
 */
367
void CTcParser::enum_sym_dict(void *, CTcSymbol *sym)
368
{
369
    /* tell this symbol to build its dictionary entries */
370
    sym->build_dictionary();
371
}
372
373
/* ------------------------------------------------------------------------ */
374
/*
375
 *   Build grammar productions 
376
 */
377
void CTcParser::build_grammar_productions()
378
{
379
    CTcGramProdEntry *entry;
380
381
    /* 
382
     *   First, run through the symbol table and merge all of the private
383
     *   grammar rules into the master grammar rule list.  Since we've
384
     *   finished linking, we've already applied all modify/replace
385
     *   overrides, hence each symbol table entry referring to an object
386
     *   will contain its final private grammar rule list.  So, we can
387
     *   safely merge the private lists into the master lists at this point,
388
     *   since no more modifications to private lists are possible.  
389
     */
390
    get_global_symtab()->enum_entries(&build_grammar_cb, this);
391
392
    /* 
393
     *   iterate over the master list of productions and generate the image
394
     *   data for each one 
395
     */
396
    for (entry = gramprod_head_ ; entry != 0 ; entry = entry->get_next())
397
    {
398
        /* build this entry */
399
        G_cg->gen_code_for_gramprod(entry);
400
    }
401
}
402
403
/*
404
 *   Symbol table enumeration callback - merge match object private grammar
405
 *   rules into the master grammar rule list.  
406
 */
407
void CTcParser::build_grammar_cb(void *, CTcSymbol *sym)
408
{
409
    /* if this is an object, merge its private grammar list */
410
    if (sym->get_type() == TC_SYM_OBJ)
411
        ((CTcSymObj *)sym)->merge_grammar_entry();
412
}
413
414
/* ------------------------------------------------------------------------ */
415
/*
416
 *   Apply self-reference object ID fixups.  This traverses the symbol
417
 *   table and applies each object's list of fixups.  This can be called
418
 *   once after loading all object files.  
419
 */
420
void CTcParser::apply_internal_fixups()
421
{
422
    CTcSymObj *anon_obj;
423
    
424
    /* enumerate the entries with our callback */
425
    get_global_symtab()->enum_entries(&enum_sym_internal_fixup, this);
426
427
    /* apply internal fixups to our anonymous objects */
428
    for (anon_obj = anon_obj_head_ ; anon_obj != 0 ;
429
         anon_obj = (CTcSymObj *)anon_obj->nxt_)
430
    {
431
        /* apply internal fixups to this symbol */
432
        anon_obj->apply_internal_fixups();
433
    }
434
}
435
436
/*
437
 *   Enumeration callback - apply internal ID fixups
438
 */
439
void CTcParser::enum_sym_internal_fixup(void *, CTcSymbol *sym)
440
{
441
    /* apply its self-reference fixups */
442
    sym->apply_internal_fixups();
443
}
444
445
/* ------------------------------------------------------------------------ */
446
/*
447
 *   Basic symbol class - image/object file functions 
448
 */
449
450
/*
451
 *   Read a symbol from an object file 
452
 */
453
int CTcSymbolBase::load_from_obj_file(CVmFile *fp, const textchar_t *fname,
454
                                      tctarg_obj_id_t *obj_xlat,
455
                                      tctarg_prop_id_t *prop_xlat,
456
                                      ulong *enum_xlat)
457
{
458
    tc_symtype_t typ;
459
460
    /* 
461
     *   read the type - this is the one thing we know is always present
462
     *   for every symbol (the rest of the data might vary per subclass) 
463
     */
464
    typ = (tc_symtype_t)fp->read_uint2();
465
466
    /* create the object based on the type */
467
    switch(typ)
468
    {
469
    case TC_SYM_FUNC:
470
        return CTcSymFunc::load_from_obj_file(fp, fname);
471
472
    case TC_SYM_OBJ:
473
        return CTcSymObj::load_from_obj_file(fp, fname, obj_xlat, FALSE);
474
475
    case TC_SYM_PROP:
476
        return CTcSymProp::load_from_obj_file(fp, fname, prop_xlat);
477
478
    case TC_SYM_ENUM:
479
        return CTcSymEnum::load_from_obj_file(fp, fname, enum_xlat);
480
481
    case TC_SYM_BIF:
482
        return CTcSymBif::load_from_obj_file(fp, fname);
483
484
    case TC_SYM_METACLASS:
485
        return CTcSymMetaclass::load_from_obj_file(fp, fname, obj_xlat);
486
487
    default:
488
        /* other types should not be in an object file */
489
        G_tcmain->log_error(0, 0, TC_SEV_ERROR, TCERR_OBJFILE_INV_TYPE);
490
491
        /* return an error indication */
492
        return 1;
493
    }
494
}
495
496
/*
497
 *   Log a conflict with another symbol from an object file 
498
 */
499
void CTcSymbolBase::log_objfile_conflict(const textchar_t *fname,
500
                                         tc_symtype_t new_type) const
501
{
502
    static const textchar_t *type_name[] =
503
    {
504
        "unknown", "function", "object", "property", "local",
505
        "parameter", "intrinsic function", "native function", "code label",
506
        "intrinsic class", "enum"
507
    };
508
509
    /* 
510
     *   if the types differ, log an error indicating the different types;
511
     *   otherwise, simply log an error indicating the redefinition 
512
     */
513
    if (new_type != get_type())
514
    {
515
        /* the types differ - show the two types */
516
        G_tcmain->log_error(0, 0, TC_SEV_ERROR, TCERR_OBJFILE_REDEF_SYM_TYPE,
517
                            (int)get_sym_len(), get_sym(),
518
                            type_name[get_type()], type_name[new_type],
519
                            fname);
520
    }
521
    else
522
    {
523
        /* the types are the same */
524
        G_tcmain->log_error(0, 0, TC_SEV_ERROR, TCERR_OBJFILE_REDEF_SYM,
525
                            (int)get_sym_len(), get_sym(),
526
                            type_name[new_type], fname);
527
    }
528
}
529
530
531
/* ------------------------------------------------------------------------ */
532
/*
533
 *   Function Symbol subclass - image/object file functions 
534
 */
535
536
/*
537
 *   Load from an object file 
538
 */
539
int CTcSymFuncBase::load_from_obj_file(CVmFile *fp,
540
                                       const textchar_t *fname)
541
{
542
    char txtbuf[4096];
543
    const char *txt;
544
    size_t len;
545
    char buf[10];
546
    int is_extern;
547
    int ext_replace;
548
    int ext_modify;
549
    int has_retval;
550
    int varargs;
551
    int argc;
552
    int is_multimethod, is_multimethod_base;
553
    int mod_base_cnt;
554
    CTcSymFunc *sym;
555
556
    /* 
557
     *   Read the symbol name.  Use a custom reader instead of the base
558
     *   reader, because function symbols can be quite long, due to
559
     *   multimethod name decoration.  
560
     */
561
    if ((txt = CTcParser::read_len_prefix_str(
562
        fp, txtbuf, sizeof(txtbuf), 0, TCERR_SYMEXP_SYM_TOO_LONG)) == 0)
563
        return 1;
564
    len = strlen(txt);
565
566
    /* read our extra data */
567
    fp->read_bytes(buf, 10);
568
    argc = osrp2(buf);
569
    varargs = buf[2];
570
    has_retval = buf[3];
571
    is_extern = buf[4];
572
    ext_replace = buf[5];
573
    ext_modify = buf[6];
574
    is_multimethod = (buf[7] & 1) != 0;
575
    is_multimethod_base = (buf[7] & 2) != 0;
576
    mod_base_cnt = osrp2(buf + 8);
577
578
    /* look up any existing symbol */
579
    sym = (CTcSymFunc *)G_prs->get_global_symtab()->find(txt, len);
580
581
    /* 
582
     *   If this symbol is already defined, make sure the original
583
     *   definition is a function, and make sure that it's only defined
584
     *   (not referenced as external) once.  If it's not defined, define
585
     *   it anew.  
586
     */
587
    if (sym == 0)
588
    {
589
        /* 
590
         *   It's not defined yet - create the new definition and add it
591
         *   to the symbol table.  
592
         */
593
        sym = new CTcSymFunc(txt, len, FALSE, argc, varargs, has_retval,
594
                             is_multimethod, is_multimethod_base, is_extern);
595
        G_prs->get_global_symtab()->add_entry(sym);
596
597
        /* it's an error if we're replacing a previously undefined function */
598
        if (ext_replace || ext_modify)
599
            G_tcmain->log_error(0, 0, TC_SEV_ERROR,
600
                                TCERR_OBJFILE_REPFUNC_BEFORE_ORIG,
601
                                (int)len, txt, fname);
602
    }
603
    else if (sym->get_type() != TC_SYM_FUNC
604
             || (!sym->is_extern()
605
                 && !is_extern && !ext_replace && !ext_modify))
606
    {
607
        /* 
608
         *   It's already defined, but it's not a function, or this is a
609
         *   non-extern/replaced definition and the symbol is already
610
         *   defined non-extern - log a symbol type conflict error.  
611
         */
612
        sym->log_objfile_conflict(fname, TC_SYM_FUNC);
613
614
        /* 
615
         *   proceed despite the error, since this is merely a symbol
616
         *   conflict and not a file corruption - create a fake symbol to
617
         *   hold the information, so that we can read the data and thus
618
         *   keep in sync with the file, but don't bother adding the fake
619
         *   symbol object to the symbol table 
620
         */
621
        sym = new CTcSymFunc(txt, len, FALSE, argc, varargs, has_retval,
622
                             is_multimethod, is_multimethod_base, is_extern);
623
    }
624
    else if (sym->get_argc() != argc
625
             || sym->is_varargs() != varargs
626
             || sym->has_retval() != has_retval)
627
    {
628
        /* the symbol has an incompatible definition - log the error */
629
        G_tcmain->log_error(0, 0, TC_SEV_ERROR, TCERR_OBJFILE_FUNC_INCOMPAT,
630
                            (int)len, txt, fname);
631
    }
632
    else if (sym->is_multimethod() != is_multimethod
633
             || sym->is_multimethod_base() != is_multimethod_base)
634
    {
635
        /* the multi-method status conflicts */
636
        G_tcmain->log_error(0, 0, TC_SEV_ERROR, TCERR_OBJFILE_MMFUNC_INCOMPAT,
637
                            (int)len, txt, fname);
638
    }
639
640
    /* 
641
     *   if this is a non-extern definition, we now have the object
642
     *   defined -- remove the 'extern' flag from the symbol table entry
643
     *   in this case 
644
     */
645
    if (!is_extern)
646
    {
647
        /* mark the symbol as defined */
648
        sym->set_extern(FALSE);
649
650
        /* 
651
         *   if we're replacing it, delete the original; if we're modifying
652
         *   it, chain the original into our modify list 
653
         */
654
        if (ext_replace)
655
        {
656
            int i;
657
658
            /* 
659
             *   mark the previous code anchor as obsolete so that we
660
             *   don't write its code to the image file 
661
             */
662
            if (sym->get_anchor() != 0)
663
                sym->get_anchor()->set_replaced(TRUE);
664
665
            /*
666
             *   Mark all of the modified base function code offsets as
667
             *   replaced as well.  
668
             */
669
            for (i = 0 ; i < sym->get_mod_base_offset_count() ; ++i)
670
            {
671
                CTcStreamAnchor *anchor;
672
673
                /* get the anchor for this offset */
674
                anchor = G_cs->find_anchor(sym->get_mod_base_offset(i));
675
676
                /* mark it as replaced */
677
                if (anchor != 0)
678
                    anchor->set_replaced(TRUE);
679
            }
680
681
            /*
682
             *   We can now forget everything in the modify base list, as
683
             *   everything in the list is being replaced and is thus no
684
             *   longer relevant.  
685
             */
686
            sym->clear_mod_base_offsets();
687
        }
688
        else if (ext_modify)
689
        {
690
            /*
691
             *   We're modifying an external symbol.  The anchor to the code
692
             *   stream object that we previously loaded is actually the
693
             *   anchor to the modified base object, not to the new meaning
694
             *   of the symbol, so detach the anchor from our symbol.  
695
             */
696
            sym->get_anchor()->detach_from_symbol();
697
698
            /*
699
             *   The object file has a fixup list for references to the
700
             *   external base object that we're modifying.  In other words,
701
             *   these are external references from the object file we're
702
             *   loading to the now-nameless code stream object that we're
703
             *   replacing, which is the code stream object at our anchor.
704
             *   So, load those fixups into the anchor's new internal fixup
705
             *   list.  It's important to note that these aren't references
706
             *   to this symbol - they're specifically references to the
707
             *   modified base code stream object.  
708
             */
709
            CTcAbsFixup::load_fixup_list_from_object_file(
710
                fp, fname, sym->get_anchor()->fixup_list_head_);
711
712
            /*
713
             *   Add the old code stream anchor to the list of modified base
714
             *   offsets for the function.  The function we're reading from
715
             *   the object file modifies this as a base function, so we need
716
             *   to add this to the list of modified base functions.  
717
             */
718
            sym->add_mod_base_offset(sym->get_anchor()->get_ofs());
719
720
            /* 
721
             *   Complete the dissociation from the anchor by forgetting the
722
             *   anchor in the symbol.  This will allow the code stream
723
             *   object that's associated with this symbol in the current
724
             *   file to take over the anchor duty for this symbol, which
725
             *   will ensure that all fixups that reference this symbol will
726
             *   be resolved to the new code stream object.  
727
             */
728
            sym->set_anchor(0);
729
        }
730
    }
731
732
    /* 
733
     *   Read the list of modified base function offsets.  Each entry is a
734
     *   code stream offset, so adjust each using the base code stream offset
735
     *   for this object file.  
736
     */
737
    for ( ; mod_base_cnt != 0 ; --mod_base_cnt)
738
    {
739
        int i;
740
741
        /* read them */
742
        for (i = 0 ; i < mod_base_cnt ; ++i)
743
        {
744
            /* read the offset, adjusting to the object file start position */
745
            ulong ofs = fp->read_uint4() + G_cs->get_object_file_start_ofs();
746
747
            /* append this item */
748
            sym->add_mod_base_offset(ofs);
749
        }
750
    }
751
752
    /* if it's extern, load the fixup list */
753
    if (is_extern)
754
    {
755
        /*
756
         *   This is an external reference, so we must load our fixup
757
         *   list, adding it to any fixup list that already exists with
758
         *   the symbol.  
759
         */
760
        CTcAbsFixup::
761
            load_fixup_list_from_object_file(fp, fname, &sym->fixups_);
762
    }
763
764
    /* success */
765
    return 0;
766
}
767
768
/* ------------------------------------------------------------------------ */
769
/*
770
 *   object symbol entry base - image/object file functions
771
 */
772
773
/*
774
 *   Load from an object file 
775
 */
776
int CTcSymObjBase::load_from_obj_file(CVmFile *fp,
777
                                      const textchar_t *fname,
778
                                      tctarg_obj_id_t *obj_xlat,
779
                                      int anon)
780
{
781
    /* 
782
     *   do the main loading - if it fails to return a symbol, return
783
     *   failure (i.e., non-zero) 
784
     */
785
    return (load_from_obj_file_main(fp, fname, obj_xlat, 0, 0, anon) == 0);
786
}
787
788
/*
789
 *   Load a modified base object from an object file 
790
 */
791
CTcSymObj *CTcSymObjBase::
792
   load_from_obj_file_modbase(class CVmFile *fp, const textchar_t *fname,
793
                              tctarg_obj_id_t *obj_xlat,
794
                              const textchar_t *mod_name,
795
                              size_t mod_name_len, int anon)
796
{
797
    /* skip the type prefix - we know it's an object */
798
    fp->read_uint2();
799
800
    /* load the object and return the symbol */
801
    return load_from_obj_file_main(fp, fname, obj_xlat,
802
                                   mod_name, mod_name_len, anon);
803
}
804
805
/*
806
 *   Load from an object file.  This main routine does most of the work,
807
 *   and returns the loaded symbol.
808
 *   
809
 *   'mod_name' is the primary symbol name for a stack of 'modify'
810
 *   objects.  Each of the objects in a 'modify' stack, except for the
811
 *   topmost (i.e., last defined) object, has a fake symbol name, since
812
 *   the program can't refer directly to the base object once modified.
813
 *   However, while loading, we must know the actual name for the entire
814
 *   stack, so that we can link the bottom of the stack in this object
815
 *   file to the top of the stack in another object file if the bottom of
816
 *   our stack is declared external (i.e., this object file's source code
817
 *   used 'modify' with an external object).  If we're loading a top-level
818
 *   object, not a modified object, 'mod_name' should be null.  
819
 */
820
CTcSymObj *CTcSymObjBase::
821
   load_from_obj_file_main(CVmFile *fp, const textchar_t *fname,
822
                           tctarg_obj_id_t *obj_xlat,
823
                           const textchar_t *mod_name, size_t mod_name_len,
824
                           int anon)
825
{
826
    const char *txt;
827
    size_t len;
828
    char buf[32];
829
    ulong id;
830
    int is_extern;
831
    int stream_ofs_valid;
832
    ulong stream_ofs;
833
    CTcSymObj *sym;
834
    CTcSymObj *mod_base_sym;
835
    int modify_flag;
836
    int ext_modify_flag;
837
    int ext_replace_flag;
838
    int modified_flag;
839
    int class_flag;
840
    CTcIdFixup *fixups;
841
    CTcObjPropDel *del_prop_head;
842
    tc_metaclass_t meta;
843
    uint dict_idx;
844
    int use_fake_sym;
845
    uint obj_file_idx;
846
    int trans_flag;
847
848
    /* presume we won't have to use a fake symbol */
849
    use_fake_sym = FALSE;
850
851
    /* presume we won't be able to read a stream offset */
852
    stream_ofs_valid = FALSE;
853
    
854
    /* read the symbol name information if it's not anonymous */
855
    if (!anon)
856
    {
857
        /* read the symbol name */
858
        if ((txt = base_read_from_sym_file(fp)) == 0)
859
            return 0;
860
    }
861
    else
862
    {
863
        /* use ".anon" as our symbol name placeholder */
864
        txt = ".anon";
865
    }
866
867
    /* get the symbol len */
868
    len = strlen(txt);
869
870
    /* read our extra data */
871
    fp->read_bytes(buf, 17);
872
    id = t3rp4u(buf);
873
    is_extern = buf[4];
874
    ext_replace_flag = buf[5];
875
    modified_flag = buf[6];
876
    modify_flag = buf[7];
877
    ext_modify_flag = buf[8];
878
    class_flag = buf[9];
879
    trans_flag = buf[10];
880
    meta = (tc_metaclass_t)osrp2(buf + 11);
881
    dict_idx = osrp2(buf + 13);
882
    obj_file_idx = osrp2(buf + 15);
883
884
    /* 
885
     *   if we're not external, read our stream offset, and adjust for the
886
     *   object stream base in the object file 
887
     */
888
    if (!is_extern)
889
    {
890
        CTcDataStream *stream;
891
        
892
        /* get the appropriate stream */
893
        stream = get_stream_from_meta(meta);
894
895
        /* read the relative stream offset */
896
        stream_ofs = fp->read_uint4();
897
898
        /* 
899
         *   Ensure the stream offset was actually valid.  It must be valid
900
         *   unless the object has no stream (for example, dictionary and
901
         *   grammar production objects are not generated until link time,
902
         *   hence they don't have to have - indeed, can't have - valid
903
         *   stream offsets when we're loading an object file).  
904
         */
905
        assert(stream_ofs != 0xffffffff || stream == 0);
906
907
        /* determine if it's valid */
908
        if (stream_ofs != 0xffffffff)
909
        {
910
            /* adjust it relative to this object file's stream base */
911
            stream_ofs += stream->get_object_file_start_ofs();
912
913
            /* note that it's valid */
914
            stream_ofs_valid = TRUE;
915
        }
916
        else
917
        {
918
            /* the stream offset is not valid */
919
            stream_ofs_valid = FALSE;
920
        }
921
    }
922
923
    /* we have no deleted properties yet */
924
    del_prop_head = 0;
925
926
    /* if this is a 'modify' object, read some additional data */
927
    if (modify_flag)
928
    {
929
        uint cnt;
930
931
        /* read the deleted property list */
932
        for (cnt = fp->read_uint2() ; cnt != 0 ; --cnt)
933
        {
934
            const char *prop_name;
935
            CTcSymProp *prop_sym;
936
            
937
            /* read the symbol name from the file */
938
            prop_name = base_read_from_sym_file(fp);
939
            if (prop_name == 0)
940
                return 0;
941
            
942
            /* 
943
             *   find the property symbol, or define it if it's not
944
             *   already defined as a property 
945
             */
946
            prop_sym = (CTcSymProp *)G_prs->get_global_symtab()
947
                       ->find_or_def_prop(prop_name, strlen(prop_name),
948
                                          FALSE);
949
            
950
            /* make sure it's a property */
951
            if (prop_sym->get_type() != TC_SYM_PROP)
952
            {
953
                /* it's not a property - log the conflict */
954
                prop_sym->log_objfile_conflict(fname, TC_SYM_PROP);
955
            }
956
            else
957
            {
958
                /* add the entry to my list */
959
                add_del_prop_to_list(&del_prop_head, prop_sym);
960
            }
961
        }
962
    }
963
964
    /* read the self-reference fixup list */
965
    fixups = 0;
966
    CTcIdFixup::load_object_file(fp, 0, 0, TCGEN_XLAT_OBJ,
967
                                 4, fname, &fixups);
968
969
    /* 
970
     *   if this is a 'modify' object, load the base object - this is the
971
     *   original version of the object, which this object modifies 
972
     */
973
    if (modify_flag)
974
    {
975
        /* 
976
         *   Load the base object - pass the top-level object's name
977
         *   (which is our own name if the caller didn't pass an enclosing
978
         *   top-level object to us).  Note that we must read, and can
979
         *   immediately discard, the type data in the object file - we
980
         *   know that the base symbol is going to be an object, since we
981
         *   always write it out at this specific place in the file, but
982
         *   we will have written the type information anyway; thus, we
983
         *   don't need the type information, but we must at least skip it
984
         *   in the file.  
985
         */
986
        mod_base_sym =
987
            load_from_obj_file_modbase(fp, fname, obj_xlat,
988
                                       mod_name != 0 ? mod_name : txt,
989
                                       mod_name != 0 ? mod_name_len : len,
990
                                       FALSE);
991
992
        /* if that failed, return failure */
993
        if (mod_base_sym == 0)
994
            return 0;
995
    }
996
    else
997
    {
998
        /* we have no 'modify' base symbol */
999
        mod_base_sym = 0;
1000
    }
1001
1002
    /* 
1003
     *   If this is a 'modifed extern' symbol, it's just a placeholder to
1004
     *   connect the bottom object in the stack of modified objects in
1005
     *   this file with the top object in another object file. 
1006
     */
1007
    if (is_extern && modified_flag)
1008
    {
1009
        CTcSymObj *mod_sym;
1010
1011
        /*
1012
         *   We're modifying an external object.  This must be the bottom
1013
         *   object in the stack for this object file, and serves as a
1014
         *   placeholder for the top object in a stack in another object
1015
         *   file.  We must find the object with the name of our top-level
1016
         *   object (not the fake name for this modified base object, but
1017
         *   the real name for the top-level object, because the symbol
1018
         *   we're modifying in the other file is the top object in its
1019
         *   stack, if any).  So, look up the symbol in the other file,
1020
         *   which must already be loaded.  
1021
         */
1022
        sym = (CTcSymObj *)
1023
              G_prs->get_global_symtab()->find(mod_name, mod_name_len);
1024
1025
        /* 
1026
         *   If the original base symbol wasn't an object of metaclass
1027
         *   "TADS Object", we can't modify it. 
1028
         */
1029
        if (sym != 0
1030
            && (sym->get_type() != TC_SYM_OBJ
1031
                || sym->get_metaclass() != TC_META_TADSOBJ))
1032
        {
1033
            /* log an error */
1034
            G_tcmain->log_error(0, 0, TC_SEV_ERROR,
1035
                                TCERR_OBJFILE_CANNOT_MOD_OR_REP_TYPE,
1036
                                (int)sym->get_sym_len(), sym->get_sym(),
1037
                                fname);
1038
1039
            /* forget the symbol */
1040
            sym = 0;
1041
        }
1042
        
1043
        /* create a synthesized object to hold the original definition */
1044
        mod_sym = synthesize_modified_obj_sym(FALSE);
1045
1046
        /* transfer data to the new fake symbol */
1047
        if (sym != 0)
1048
        {
1049
            /* 
1050
             *   'sym' has the original version of the object from the
1051
             *   other object file - the original object file must be
1052
             *   loaded before an object file that modifies a symbol it
1053
             *   exports, so 'sym' will definitely be present in this case
1054
             *   (it's an error - undefined external symbol - that we will
1055
             *   have already caught if it's not defined).  We want to
1056
             *   hijack 'sym' for our own use, since 'modify' replaces the
1057
             *   symbol's meaning with the new object data.
1058
             *   
1059
             *   Transfer the self-reference fixup list from the original
1060
             *   version of the object to the new synthesized object --
1061
             *   all of the self-references must now refer to the
1062
             *   renumbered object.
1063
             *   
1064
             *   This is really all we need to do to renumber the object.
1065
             *   By moving the self-fixup list to the new fake object, we
1066
             *   ensure that the original object will use its new number,
1067
             *   which leaves the original number for our use in the new,
1068
             *   modifying object (i.e., the one we're loading now).  Note
1069
             *   that we'll replace the self-fixup list for this symbol
1070
             *   with the fixup list of the modifying symbol, below.  
1071
             */
1072
            mod_sym->set_fixups(sym->get_fixups());
1073
1074
            /* 
1075
             *   Give the modified fake symbol the original pre-modified
1076
             *   object data stream.  The fake symbol owns the
1077
             *   pre-modified data stream because it's the pre-modified
1078
             *   object.  
1079
             */
1080
            mod_sym->set_stream_ofs(sym->get_stream_ofs());
1081
1082
            /* 
1083
             *   transfer the 'modify' base symbol from the original
1084
             *   version of this symbol to the new fake version 
1085
             */
1086
            mod_sym->set_mod_base_sym(sym->get_mod_base_sym());
1087
1088
            /* transfer the property deletion list */
1089
            mod_sym->set_del_prop_head(sym->get_first_del_prop());
1090
            sym->set_del_prop_head(0);
1091
1092
            /* 
1093
             *   mark the original object as a 'class' object - it might
1094
             *   have been compiled as a normal instance in its own
1095
             *   translation unit, but it's now a class because it's the
1096
             *   base class for this link-time 'modify' 
1097
             */
1098
            mod_sym->mark_compiled_as_class();
1099
1100
            /* transfer the dictionary to the base symbol */
1101
            mod_sym->set_dict(sym->get_dict());
1102
1103
            /* copy the class flag to the base symbol */
1104
            mod_sym->set_is_class(sym->is_class());
1105
1106
            /* set our class flag to the one from the original symbol */
1107
            class_flag = sym->is_class();
1108
1109
            /* 
1110
             *   transfer the superclass list from the original symbol to
1111
             *   the modified base symbol 
1112
             */
1113
            mod_sym->set_sc_head(sym->get_sc_head());
1114
            sym->set_sc_head(0);
1115
1116
            /* transfer the vocabulary list to the modified base symbol */
1117
            mod_sym->set_vocab_head(sym->get_vocab_head());
1118
            sym->set_vocab_head(0);
1119
        }
1120
1121
        /* do the remaining loading into the synthesized placeholder */
1122
        sym = mod_sym;
1123
    }
1124
    else if (modified_flag)
1125
    {
1126
        /*
1127
         *   The symbol was modified, so the name is fake.  Because the
1128
         *   name is tied to the object ID, which can change between the
1129
         *   the time of writing the object file and now, when we're
1130
         *   loading the object file, we must synthesize a new fake name
1131
         *   in the context of the loaded object file.  The name is based
1132
         *   on the object number, which is why it must be re-synthesized
1133
         *   - the object number in this scheme can be different than the
1134
         *   original object number in the object file.  
1135
         */
1136
        sym = synthesize_modified_obj_sym(FALSE);
1137
1138
        /* set the appropriate metaclass */
1139
        sym->set_metaclass(meta);
1140
    }
1141
    else if (anon)
1142
    {
1143
        /* 
1144
         *   we will definitely not find a previous entry for an anonymous
1145
         *   symbol, because there's no name to look up 
1146
         */
1147
        sym = 0;
1148
    }
1149
    else
1150
    {
1151
        /* 
1152
         *   normal object - look up a previous definition of the symbol
1153
         *   in the global symbol table 
1154
         */
1155
        sym = (CTcSymObj *)G_prs->get_global_symtab()->find(txt, len);
1156
    }
1157
1158
    /* 
1159
     *   If this symbol is already defined, make sure the original
1160
     *   definition is an object, and make sure that it's only defined
1161
     *   (not referenced as external) once.  If it's not defined, define
1162
     *   it anew.  
1163
     */
1164
    if (sym != 0 && sym->get_type() != TC_SYM_OBJ)
1165
    {
1166
        /* 
1167
         *   It's already defined, but it's not an object - log a symbol
1168
         *   type conflict error
1169
         */
1170
        sym->log_objfile_conflict(fname, TC_SYM_OBJ);
1171
1172
        /* 
1173
         *   proceed despite the error, since this is merely a symbol
1174
         *   conflict and not a file corruption - create a fake symbol to
1175
         *   hold the data of the original symbol so we can continue
1176
         *   loading 
1177
         */
1178
        sym = 0;
1179
        use_fake_sym = TRUE;
1180
    }
1181
    else if ((ext_replace_flag || ext_modify_flag)
1182
             && sym != 0 && sym->get_metaclass() != TC_META_TADSOBJ)
1183
    {
1184
        /* cannot modify or replace anything but an ordinary object */
1185
        G_tcmain->log_error(0, 0, TC_SEV_ERROR,
1186
                            TCERR_OBJFILE_CANNOT_MOD_OR_REP_TYPE,
1187
                            (int)sym->get_sym_len(), sym->get_sym(),
1188
                            fname);
1189
1190
        /* forget that we're doing a replacement */
1191
        ext_replace_flag = ext_modify_flag = FALSE;
1192
    }
1193
    else if (sym != 0
1194
             && (sym->get_metaclass() == TC_META_DICT
1195
                 || sym->get_metaclass() == TC_META_GRAMPROD))
1196
    {
1197
        /* 
1198
         *   If this is a dictionary or grammar production object, and the
1199
         *   original definition was of the same metaclass, allow the
1200
         *   multiple definitions without conflict - just treat the new
1201
         *   definition as external.  These object types don't require a
1202
         *   primary definition - every time such an object is defined,
1203
         *   it's a definition, but the same definition can appear in
1204
         *   multiple object files without conflict.  Simply act as though
1205
         *   this new declaration is extern after all in this case.
1206
         */
1207
        if (meta == sym->get_metaclass())
1208
        {
1209
            /* 
1210
             *   it's another one of the same type - allow it without
1211
             *   conflict; act as though this new definition is external 
1212
             */
1213
            if (!sym->is_extern())
1214
                is_extern = FALSE;
1215
        }
1216
        else
1217
        {
1218
            /* the other one's of a different type - log a conflict */
1219
            sym->log_objfile_conflict(fname, TC_SYM_OBJ);
1220
1221
            /* proceed with a fake symbol */
1222
            sym = 0;
1223
            use_fake_sym = TRUE;
1224
        }
1225
    }
1226
    else if ((ext_replace_flag || ext_modify_flag)
1227
             && (sym == 0 || sym->is_extern()))
1228
    {
1229
        /*
1230
         *   This symbol isn't defined yet, or is only defined as an
1231
         *   external, but the new symbol is marked as 'replace' or
1232
         *   'modify' - it's an error, because the original version of an
1233
         *   object must always be loaded before the replaced or modified
1234
         *   version 
1235
         */
1236
        G_tcmain->log_error(0, 0, TC_SEV_ERROR,
1237
                            TCERR_OBJFILE_MODREPOBJ_BEFORE_ORIG,
1238
                            (int)len, txt, fname);
1239
1240
        /* forget the symbol */
1241
        sym = 0;
1242
1243
        /* not replacing anything after all */
1244
        ext_replace_flag = ext_modify_flag = FALSE;
1245
    }
1246
    else if (sym != 0
1247
             && !sym->is_extern()
1248
             && !(is_extern || ext_modify_flag || ext_replace_flag
1249
                  || modified_flag))
1250
    {
1251
        /* 
1252
         *   the symbol was already defined, and this is a new actual
1253
         *   definition (not external, and not replace or modify) -- this
1254
         *   is an error because it means the same object is defined more
1255
         *   than once 
1256
         */
1257
        sym->log_objfile_conflict(fname, TC_SYM_OBJ);
1258
1259
        /* 
1260
         *   proceed despite the error, since this is merely a symbol
1261
         *   conflict and not a file corruption - create a fake symbol to
1262
         *   hold the data of the original symbol so we can continue
1263
         *   loading 
1264
         */
1265
        sym = 0;
1266
        use_fake_sym = TRUE;
1267
    }
1268
    else if (sym != 0 && meta != sym->get_metaclass())
1269
    {
1270
        /* 
1271
         *   the new symbol and the old symbol have different metaclasses
1272
         *   - it's a conflict 
1273
         */
1274
        sym->log_objfile_conflict(fname, TC_SYM_OBJ);
1275
1276
        /* proceed with a fake symbol */
1277
        sym = 0;
1278
        use_fake_sym = TRUE;
1279
    }
1280
1281
    /* create the object if necessary */
1282
    if (sym == 0)
1283
    {
1284
        /* 
1285
         *   The symbol isn't defined yet - create the new definition and
1286
         *   add it to the symbol table.  Allocate a new object ID for the
1287
         *   symbol in the normal fashion.  
1288
         */
1289
        sym = new CTcSymObj(txt, len, FALSE, G_cg->new_obj_id(),
1290
                            is_extern, meta, 0);
1291
1292
        /* 
1293
         *   if we're using a fake symbol, don't bother adding the symbol
1294
         *   to the symbol table, since its only function is to allow us
1295
         *   to finish reading the object file data (we won't actually try
1296
         *   to link when using a fake symbol, since this always means
1297
         *   that an error has made linking impossible; we'll proceed
1298
         *   anyway so that we catch any other errors that remain to be
1299
         *   found)
1300
         *   
1301
         *   similarly, don't add the symbol if it's anonymous 
1302
         */
1303
        if (!use_fake_sym && !anon)
1304
            G_prs->get_global_symtab()->add_entry(sym);
1305
1306
        /* if it's anonymous, add it to the anonymous symbol list */
1307
        if (anon)
1308
            G_prs->add_anon_obj(sym);
1309
    }
1310
1311
    /*
1312
     *   If we're replacing the object, tell the code generator to get rid
1313
     *   of the old object definition in the object stream -- delete the
1314
     *   definition at the symbol's old stream offset.  
1315
     */
1316
    if (ext_replace_flag)
1317
        G_cg->notify_replace_object(sym->get_stream_ofs());
1318
1319
    /* 
1320
     *   If this is a non-extern definition, we now have the object
1321
     *   defined -- remove the 'extern' flag from the symbol table entry,
1322
     *   and set the symbol's data to the data we just read.  Do not
1323
     *   transfer data to the symbol if this is an extern, since we want
1324
     *   to use the existing data from the originally loaded object.  
1325
     */
1326
    if (!is_extern)
1327
    {
1328
        /* clear the external flag */
1329
        sym->set_extern(FALSE);
1330
1331
        /* set the object's stream offset, if we read one */
1332
        if (stream_ofs_valid)
1333
            sym->set_stream_ofs(stream_ofs);
1334
1335
        /* set the base 'modify' symbol if this symbol modifies another */
1336
        if (mod_base_sym != 0)
1337
            sym->set_mod_base_sym(mod_base_sym);
1338
1339
        /* set the new symbol's fixup list */
1340
        sym->set_fixups(fixups);
1341
1342
        /* set the new symbol's deleted property list */
1343
        sym->set_del_prop_head(del_prop_head);
1344
1345
        /* 
1346
         *   set the symbol's class flag - only add the class flag,
1347
         *   because we might have already set the class flag for this
1348
         *   symbol based on the external definition 
1349
         */
1350
        if (class_flag)
1351
            sym->set_is_class(class_flag);
1352
    }
1353
1354
    /* add this symbol to the load file object index list */
1355
    G_prs->add_sym_from_obj_file(obj_file_idx, sym);
1356
1357
    /* set the dictionary, if one was specified */
1358
    if (dict_idx != 0)
1359
        sym->set_dict(G_prs->get_obj_dict(dict_idx));
1360
1361
    /* 
1362
     *   if this is a dictionary symbol, add it to the dictionary fixup
1363
     *   list 
1364
     */
1365
    if (meta == TC_META_DICT)
1366
        G_prs->add_dict_from_obj_file(sym);
1367
1368
1369
    /*
1370
     *   Set the translation table entry for the symbol.  We know the
1371
     *   original ID local to the object file, and we know the new global
1372
     *   object ID.  
1373
     */
1374
    obj_xlat[id] = sym->get_obj_id();
1375
1376
    /* success */
1377
    return sym;
1378
}
1379
1380
/*
1381
 *   Apply our self-reference fixups 
1382
 */
1383
void CTcSymObjBase::apply_internal_fixups()
1384
{
1385
    CTcIdFixup *fixup;
1386
    CTcObjPropDel *entry;
1387
    CTcSymObj *mod_base;
1388
    
1389
    /* run through our list and apply each fixup */
1390
    for (fixup = fixups_ ; fixup != 0 ; fixup = fixup->nxt_)
1391
        fixup->apply_fixup(obj_id_, 4);
1392
    
1393
    /*
1394
     *   If we're a 'modify' object, and we were based at compile-time on
1395
     *   an object external to the translation unit in which this modified
1396
     *   version of the object was defined, we'll have a property deletion
1397
     *   list to be applied at link time.  Now is the time - go through
1398
     *   our list and delete each property in each of our 'modify' base
1399
     *   classes.  Don't delete the properties in our own object,
1400
     *   obviously - just in our modified base classes.  
1401
     */
1402
    for (mod_base = mod_base_sym_ ; mod_base != 0 ;
1403
         mod_base = mod_base->get_mod_base_sym())
1404
    {
1405
        /* delete each property in our deletion list in this base class */
1406
        for (entry = first_del_prop_ ; entry != 0 ; entry = entry->nxt_)
1407
        {
1408
            /* delete this property from the base object */
1409
            mod_base->delete_prop_from_mod_base(entry->prop_sym_->get_prop());
1410
1411
            /* remove it from the base object's vocabulary list */
1412
            mod_base->delete_vocab_prop(entry->prop_sym_->get_prop());
1413
        }
1414
    }
1415
}
1416
1417
/*
1418
 *   Merge my private grammar rules into the master rule list for the
1419
 *   associated grammar production object.  
1420
 */
1421
void CTcSymObjBase::merge_grammar_entry()
1422
{
1423
    CTcSymObj *prod_sym;
1424
    CTcGramProdEntry *master_entry;
1425
1426
    /* if I don't have a grammar list, there's nothing to do */
1427
    if (grammar_entry_ == 0)
1428
        return;
1429
1430
    /* get the grammar production object my rules are associated with */
1431
    prod_sym = grammar_entry_->get_prod_sym();
1432
1433
    /* get the master list for the production */
1434
    master_entry = G_prs->get_gramprod_entry(prod_sym);
1435
1436
    /* move the alternatives from my private list to the master list */
1437
    grammar_entry_->move_alts_to(master_entry);
1438
}
1439
1440
1441
/* ------------------------------------------------------------------------ */
1442
/*
1443
 *   metaclass symbol base - image/object file functions 
1444
 */
1445
1446
/* 
1447
 *   load from an object file 
1448
 */
1449
int CTcSymMetaclassBase::
1450
   load_from_obj_file(CVmFile *fp, const textchar_t *fname,
1451
                      tctarg_obj_id_t *obj_xlat)
1452
{
1453
    const char *txt;
1454
    size_t len;
1455
    int meta_idx;
1456
    int prop_cnt;
1457
    CTcSymMetaclass *sym;
1458
    char buf[TOK_SYM_MAX_LEN + 1];
1459
    CTcSymMetaProp *prop;
1460
    int was_defined;
1461
    tctarg_obj_id_t class_obj;
1462
1463
    /* read the symbol name */
1464
    if ((txt = base_read_from_sym_file(fp)) == 0)
1465
        return 1;
1466
    len = strlen(txt);
1467
1468
    /* read the metaclass index, class object ID, and property count */
1469
    fp->read_bytes(buf, 8);
1470
    meta_idx = osrp2(buf);
1471
    class_obj = t3rp4u(buf + 2);
1472
    prop_cnt = osrp2(buf + 6);
1473
1474
    /* check for a previous definition */
1475
    sym = (CTcSymMetaclass *)G_prs->get_global_symtab()->find(txt, len);
1476
    if (sym == 0)
1477
    {
1478
        /* it's not defined yet - create the new definition */
1479
        sym = new CTcSymMetaclass(txt, len, FALSE, meta_idx,
1480
                                  G_cg->new_obj_id());
1481
        G_prs->get_global_symtab()->add_entry(sym);
1482
1483
        /* note that it wasn't yet defined */
1484
        was_defined = FALSE;
1485
1486
        /* set the metaclass symbol pointer in the dependency table */
1487
        G_cg->set_meta_sym(meta_idx, sym);
1488
    }
1489
    else if (sym->get_type() != TC_SYM_METACLASS)
1490
    {
1491
        /* log a conflict */
1492
        sym->log_objfile_conflict(fname, TC_SYM_METACLASS);
1493
1494
        /* forget the symbol */
1495
        sym = 0;
1496
        was_defined = FALSE;
1497
    }
1498
    else
1499
    {
1500
        /* if the metaclass index doesn't match, it's an error */
1501
        if (sym->get_meta_idx() != meta_idx)
1502
            G_tcmain->log_error(0, 0, TC_SEV_ERROR,
1503
                                TCERR_OBJFILE_METACLASS_IDX_CONFLICT,
1504
                                (int)len, txt, fname);
1505
1506
        /* note that it was previously defined */
1507
        was_defined = TRUE;
1508
1509
        /* start with the first property */
1510
        prop = sym->get_prop_head();
1511
    }
1512
1513
    /* set the ID translation for the class object */
1514
    if (sym != 0)
1515
        obj_xlat[class_obj] = sym->get_class_obj();
1516
1517
    /* read the property names */
1518
    for ( ; prop_cnt != 0 ; --prop_cnt)
1519
    {
1520
        int is_static;
1521
        
1522
        /* read the property symbol name */
1523
        if ((txt = base_read_from_sym_file(fp)) == 0)
1524
            return 1;
1525
        len = strlen(txt);
1526
1527
        /* read the flags */
1528
        fp->read_bytes(buf, 1);
1529
        is_static = ((buf[0] & 1) != 0);
1530
1531
        /* check what we're doing */
1532
        if (sym == 0)
1533
        {
1534
            /* 
1535
             *   we have a conflict, so we're just scanning the names to
1536
             *   keep in sync with the file - ignore it 
1537
             */
1538
        }
1539
        else if (was_defined)
1540
        {
1541
            /* 
1542
             *   the metaclass was previously defined - simply check to
1543
             *   ensure that this property matches the corresponding
1544
             *   property (by list position) in the original definition 
1545
             */
1546
            if (prop == 0)
1547
            {
1548
                /* 
1549
                 *   we're past the end of the original definition's
1550
                 *   property list - this is okay, as we can simply add
1551
                 *   the properties in the new list (which must be a more
1552
                 *   recent definition than the original one) 
1553
                 */
1554
                sym->add_prop(txt, len, fname, is_static);
1555
            }
1556
            else if (prop->prop_->get_sym_len() != len
1557
                     || memcmp(prop->prop_->get_sym(), txt, len) != 0)
1558
            {
1559
                /* this one doesn't match - it's an error */
1560
                G_tcmain->log_error(0, 0, TC_SEV_ERROR,
1561
                                    TCERR_OBJFILE_METACLASS_PROP_CONFLICT,
1562
                                    (int)len, txt,
1563
                                    (int)prop->prop_->get_sym_len(),
1564
                                    prop->prop_->get_sym(), fname);
1565
            }
1566
1567
            /* move on to the next property in the list */
1568
            if (prop != 0)
1569
                prop = prop->nxt_;
1570
        }
1571
        else
1572
        {
1573
            /* 
1574
             *   we're defining the metaclass anew - add this property to
1575
             *   the metaclass's property list 
1576
             */
1577
            sym->add_prop(txt, len, fname, is_static);
1578
        }
1579
    }
1580
1581
    /* read our modifier object flag */
1582
    fp->read_bytes(buf, 1);
1583
    if (buf[0] != 0)
1584
    {
1585
        /* laod the new object */
1586
        CTcSymObj *mod_obj;
1587
        
1588
        /* we have a modification object - load it */
1589
        mod_obj = CTcSymObj::load_from_obj_file_modbase(
1590
            fp, fname, obj_xlat, 0, 0, FALSE);
1591
1592
        /* 
1593
         *   if the metaclass already has a modification object, then the
1594
         *   bottom of the chain we just loaded modifies the top of the
1595
         *   existing chain 
1596
         */
1597
        if (sym->get_mod_obj() != 0)
1598
        {
1599
            CTcSymObj *obj;
1600
            CTcSymObj *prv;
1601
1602
            /* 
1603
             *   Set the bottom of the new chain to point to the top of
1604
             *   the existing chain.  The bottom object in each object
1605
             *   file's modification chain is always a dummy root object;
1606
             *   we'll thus find the second to last object in the new
1607
             *   chain, and replace the pointer to its dummy root
1608
             *   superclass with a pointer to the top of the
1609
             *   previously-loaded chain that we're modifying.  
1610
             */
1611
1612
            /* find the second-to-last object in the new chain */
1613
            for (prv = 0, obj = mod_obj ;
1614
                 obj != 0 && obj->get_mod_base_sym() != 0 ;
1615
                 prv = obj, obj = obj->get_mod_base_sym()) ;
1616
1617
            /* 
1618
             *   if we found the second-to-last object, set up the link
1619
             *   back into the old chain 
1620
             */
1621
            if (prv != 0)
1622
                prv->set_mod_base_sym(sym->get_mod_obj());
1623
        }
1624
1625
        /* point the metaclass to the modification object */
1626
        sym->set_mod_obj(mod_obj);
1627
    }
1628
1629
    /* return success - the file appears well-formed */
1630
    return 0;
1631
}
1632
1633
1634
/* ------------------------------------------------------------------------ */
1635
/*
1636
 *   property symbol entry base - image/object file functions
1637
 */
1638
1639
/*
1640
 *   Load from an object file 
1641
 */
1642
int CTcSymPropBase::load_from_obj_file(class CVmFile *fp,
1643
                                       const textchar_t *fname,
1644
                                       tctarg_prop_id_t *prop_xlat)
1645
{
1646
    const char *txt;
1647
    size_t len;
1648
    ulong id;
1649
    CTcSymProp *sym;
1650
1651
    /* read the symbol name information */
1652
    if ((txt = base_read_from_sym_file(fp)) == 0)
1653
        return 1;
1654
    len = strlen(txt);
1655
1656
    /* read our property ID */
1657
    id = fp->read_uint4();
1658
1659
    /* 
1660
     *   If this symbol is already defined, make sure the original
1661
     *   definition is a property.  If it's not defined, define it anew.  
1662
     */
1663
    sym = (CTcSymProp *)G_prs->get_global_symtab()->find(txt, len);
1664
    if (sym == 0)
1665
    {
1666
        /* 
1667
         *   It's not defined yet - create the new definition and add it
1668
         *   to the symbol table.  Allocate a new property ID for the
1669
         *   symbol in the normal fashion.  
1670
         */
1671
        sym = new CTcSymProp(txt, len, FALSE, G_cg->new_prop_id());
1672
        G_prs->get_global_symtab()->add_entry(sym);
1673
    }
1674
    else if (sym->get_type() != TC_SYM_PROP)
1675
    {
1676
        /* 
1677
         *   It's not already defined as a property - log a symbol type
1678
         *   conflict error 
1679
         */
1680
        sym->log_objfile_conflict(fname, TC_SYM_PROP);
1681
1682
        /* 
1683
         *   proceed despite the error, since this is merely a symbol
1684
         *   conflict and not a file corruption 
1685
         */
1686
        return 0;
1687
    }
1688
1689
    /*
1690
     *   Set the translation table entry for the symbol.  We know the
1691
     *   original ID local to the object file, and we know the new global
1692
     *   property ID.
1693
     */
1694
    prop_xlat[id] = sym->get_prop();
1695
1696
    /* success */
1697
    return 0;
1698
}
1699
                                       
1700
/* ------------------------------------------------------------------------ */
1701
/*
1702
 *   enumerator symbol entry base - image/object file functions 
1703
 */
1704
1705
/*
1706
 *   Load from an object file 
1707
 */
1708
int CTcSymEnumBase::load_from_obj_file(class CVmFile *fp,
1709
                                       const textchar_t *fname,
1710
                                       ulong *enum_xlat)
1711
{
1712
    const char *txt;
1713
    size_t len;
1714
    ulong id;
1715
    CTcSymEnum *sym;
1716
    char buf[32];
1717
    int is_token;
1718
1719
    /* read the symbol name information */
1720
    if ((txt = base_read_from_sym_file(fp)) == 0)
1721
        return 1;
1722
    len = strlen(txt);
1723
1724
    /* read our enumerator ID */
1725
    id = fp->read_uint4();
1726
1727
    /* read our flags */
1728
    fp->read_bytes(buf, 1);
1729
1730
    /* get the 'token' flag */
1731
    is_token = ((buf[0] & 1) != 0);
1732
1733
    /* 
1734
     *   If this symbol is already defined, make sure the original
1735
     *   definition is an enum.  If it's not defined, define it anew.  
1736
     */
1737
    sym = (CTcSymEnum *)G_prs->get_global_symtab()->find(txt, len);
1738
    if (sym == 0)
1739
    {
1740
        /* 
1741
         *   It's not defined yet - create the new definition and add it
1742
         *   to the symbol table.  Allocate a new enumerator ID for the
1743
         *   symbol in the normal fashion.  
1744
         */
1745
        sym = new CTcSymEnum(txt, len, FALSE, G_prs->new_enum_id(), is_token);
1746
        G_prs->get_global_symtab()->add_entry(sym);
1747
    }
1748
    else if (sym->get_type() != TC_SYM_ENUM)
1749
    {
1750
        /* 
1751
         *   It's not already defined as an enumerator - log a symbol type
1752
         *   conflict error 
1753
         */
1754
        sym->log_objfile_conflict(fname, TC_SYM_ENUM);
1755
1756
        /* 
1757
         *   proceed despite the error, since this is merely a symbol
1758
         *   conflict and not a file corruption 
1759
         */
1760
        return 0;
1761
    }
1762
1763
    /*
1764
     *   Set the translation table entry for the symbol.  We know the
1765
     *   original ID local to the object file, and we know the new global
1766
     *   enum ID.  
1767
     */
1768
    enum_xlat[id] = sym->get_enum_id();
1769
1770
    /* success */
1771
    return 0;
1772
}
1773
                                       
1774
/* ------------------------------------------------------------------------ */
1775
/*
1776
 *   Built-in function symbol base - image/object file functions
1777
 */
1778
1779
/* 
1780
 *   load from an object file 
1781
 */
1782
int CTcSymBifBase::load_from_obj_file(class CVmFile *fp,
1783
                                      const textchar_t *fname)
1784
{
1785
    const char *txt;
1786
    size_t len;
1787
    CTcSymBif *sym;
1788
    char buf[10];
1789
    int func_set_id;
1790
    int func_idx;
1791
    int has_retval;
1792
    int min_argc;
1793
    int max_argc;
1794
    int varargs;
1795
1796
    /* read the symbol name information */
1797
    if ((txt = base_read_from_sym_file(fp)) == 0)
1798
        return 1;
1799
    len = strlen(txt);
1800
1801
    /* read our additional information */
1802
    fp->read_bytes(buf, 10);
1803
    varargs = buf[0];
1804
    has_retval = buf[1];
1805
    min_argc = osrp2(buf+2);
1806
    max_argc = osrp2(buf+4);
1807
    func_set_id = osrp2(buf+6);
1808
    func_idx = osrp2(buf+8);
1809
1810
    /* 
1811
     *   If this symbol is already defined, make sure the new definition
1812
     *   matches the original definition - built-in function sets must be
1813
     *   identical in all object files loaded.  If it's not already
1814
     *   defined, add it now.  
1815
     */
1816
    sym = (CTcSymBif *)G_prs->get_global_symtab()->find(txt, len);
1817
    if (sym == 0)
1818
    {
1819
        /* 
1820
         *   it's not defined yet - create the new definition and add it
1821
         *   to the symbol table 
1822
         */
1823
        sym = new CTcSymBif(txt, len, FALSE, func_set_id, func_idx,
1824
                            has_retval, min_argc, max_argc, varargs);
1825
        G_prs->get_global_symtab()->add_entry(sym);
1826
    }
1827
    else if (sym->get_type() != TC_SYM_BIF)
1828
    {
1829
        /* log the error */
1830
        sym->log_objfile_conflict(fname, TC_SYM_BIF);
1831
    }
1832
    else if (sym->get_func_set_id() != func_set_id
1833
             || sym->get_func_idx() != func_idx
1834
             || sym->get_min_argc() != min_argc
1835
             || sym->get_max_argc() != max_argc
1836
             || sym->is_varargs() != varargs
1837
             || sym->has_retval() != has_retval)
1838
    {
1839
        /* 
1840
         *   this function is already defined but has different settings
1841
         *   -- we cannot reconcile the different usages of the function,
1842
         *   so this is an error 
1843
         */
1844
        G_tcmain->log_error(0, 0, TC_SEV_ERROR, TCERR_OBJFILE_BIF_INCOMPAT,
1845
                            (int)len, txt, fname);
1846
    }
1847
    else
1848
    {
1849
        /* 
1850
         *   everything about the symbol matches - there's no need to
1851
         *   redefine the symbol, since it's already set up exactly as we
1852
         *   need it to be 
1853
         */
1854
    }
1855
1856
    /* continue reading the file */
1857
    return 0;
1858
}
1859
1860
/* ------------------------------------------------------------------------ */
1861
/*
1862
 *   Grammar production list entry
1863
 */
1864
1865
/* 
1866
 *   load from an object file 
1867
 */
1868
void CTcGramProdEntry::load_from_obj_file(
1869
    CVmFile *fp, const tctarg_prop_id_t *prop_xlat, const ulong *enum_xlat,
1870
    CTcSymObj *private_owner)
1871
{
1872
    uint idx;
1873
    ulong cnt;
1874
    CTcSymObj *obj;
1875
    CTcGramProdEntry *prod;
1876
    ulong flags;
1877
1878
    /* 
1879
     *   read the object file index of the production object, and get the
1880
     *   production object 
1881
     */
1882
    idx = fp->read_uint4();
1883
    obj = G_prs->get_objfile_objsym(idx);
1884
1885
    /* declare the production object */
1886
    prod = G_prs->declare_gramprod(obj->get_sym(), obj->get_sym_len());
1887
1888
    /* if we have a private owner, create a private rule list */
1889
    if (private_owner != 0)
1890
        prod = private_owner->create_grammar_entry(
1891
            obj->get_sym(), obj->get_sym_len());
1892
1893
    /* read the flags */
1894
    flags = fp->read_uint4();
1895
1896
    /* set the explicitly-declared flag if appropriate */
1897
    if (flags & 1)
1898
        prod->set_declared(TRUE);
1899
1900
    /* read the alternative count */
1901
    cnt = fp->read_uint4();
1902
1903
    /* read the alternatives */
1904
    for ( ; cnt != 0 ; --cnt)
1905
    {
1906
        CTcGramProdAlt *alt;
1907
1908
        /* read an alternative */
1909
        alt = CTcGramProdAlt::load_from_obj_file(fp, prop_xlat, enum_xlat);
1910
1911
        /* add it to the production's list */
1912
        if (prod != 0)
1913
            prod->add_alt(alt);
1914
    }
1915
}
1916
1917
1918
/* ------------------------------------------------------------------------ */
1919
/*
1920
 *   Grammar production alternative
1921
 */
1922
1923
/* 
1924
 *   load from an object file 
1925
 */
1926
CTcGramProdAlt *CTcGramProdAlt::
1927
   load_from_obj_file(CVmFile *fp, const tctarg_prop_id_t *prop_xlat,
1928
                      const ulong *enum_xlat)
1929
{
1930
    uint idx;
1931
    ulong cnt;
1932
    CTcSymObj *obj;
1933
    CTcGramProdAlt *alt;
1934
    CTcDictEntry *dict;
1935
    int score;
1936
    int badness;
1937
1938
    /* read my score and badness */
1939
    score = fp->read_int2();
1940
    badness = fp->read_int2();
1941
1942
    /* read my processor object index, and get the associated object */
1943
    idx = fp->read_uint4();
1944
    obj = G_prs->get_objfile_objsym(idx);
1945
1946
    /* read my dictionary object index, and get the associated entry */
1947
    idx = fp->read_uint4();
1948
    dict = G_prs->get_obj_dict(idx);
1949
1950
    /* create the alternative object */
1951
    alt = new (G_prsmem) CTcGramProdAlt(obj, dict);
1952
1953
    /* set the score badness */
1954
    alt->set_score(score);
1955
    alt->set_badness(badness);
1956
1957
    /* read the number of tokens */
1958
    cnt = fp->read_uint4();
1959
1960
    /* read the tokens */
1961
    for ( ; cnt != 0 ; --cnt)
1962
    {
1963
        CTcGramProdTok *tok;
1964
1965
        /* read a token */
1966
        tok = CTcGramProdTok::load_from_obj_file(fp, prop_xlat, enum_xlat);
1967
1968
        /* add it to the alternative's list */
1969
        alt->add_tok(tok);
1970
    }
1971
1972
    /* return the alternative */
1973
    return alt;
1974
}
1975
1976
1977
/* ------------------------------------------------------------------------ */
1978
/*
1979
 *   Grammar production token
1980
 */
1981
1982
/* 
1983
 *   load from an object file 
1984
 */
1985
CTcGramProdTok *CTcGramProdTok::
1986
   load_from_obj_file(CVmFile *fp, const tctarg_prop_id_t *prop_xlat,
1987
                      const ulong *enum_xlat)
1988
{
1989
    CTcGramProdTok *tok;
1990
    CTcSymObj *obj;
1991
    tcgram_tok_type typ;
1992
    tctarg_prop_id_t prop;
1993
    size_t len;
1994
    char *txt;
1995
    uint idx;
1996
    ulong enum_id;
1997
    size_t i;
1998
1999
    /* create a new token */
2000
    tok = new (G_prsmem) CTcGramProdTok();
2001
2002
    /* read the type */
2003
    typ = (tcgram_tok_type)fp->read_int2();
2004
2005
    /* read the data, which depends on the type */
2006
    switch(typ)
2007
    {
2008
    case TCGRAM_PROD:
2009
        /* read the production object's object file index */
2010
        idx = fp->read_uint4();
2011
2012
        /* translate it to an object */
2013
        obj = G_prs->get_objfile_objsym(idx);
2014
2015
        /* set the production object in the token */
2016
        tok->set_match_prod(obj);
2017
        break;
2018
2019
    case TCGRAM_TOKEN_TYPE:
2020
        /* read the token ID, translating to the new enum numbering */
2021
        enum_id = enum_xlat[fp->read_uint4()];
2022
2023
        /* set the token-type match */
2024
        tok->set_match_token_type(enum_id);
2025
        break;
2026
2027
    case TCGRAM_PART_OF_SPEECH:
2028
        /* read the property ID, translating to the new numbering system */
2029
        prop = prop_xlat[fp->read_int2()];
2030
2031
        /* set the part of speech in the token */
2032
        tok->set_match_part_of_speech(prop);
2033
        break;
2034
2035
    case TCGRAM_PART_OF_SPEECH_LIST:
2036
        /* read the list length */
2037
        len = (size_t)fp->read_int2();
2038
2039
        /* set the type */
2040
        tok->set_match_part_list();
2041
2042
        /* read each element and add it to the list */
2043
        for (i = 0 ; i < len ; ++i)
2044
            tok->add_match_part_ele(prop_xlat[fp->read_int2()]);
2045
2046
        /* done */
2047
        break;
2048
2049
    case TCGRAM_LITERAL:
2050
        /* read the length of the string */
2051
        len = (size_t)fp->read_int2();
2052
2053
        /* allocate parser memory to hold the text */
2054
        txt = (char *)G_prsmem->alloc(len);
2055
2056
        /* read the text of the literal */
2057
        fp->read_bytes(txt, len);
2058
2059
        /* set the literal in the token */
2060
        tok->set_match_literal(txt, len);
2061
        break;
2062
2063
    case TCGRAM_STAR:
2064
        /* there's no additional data */
2065
        tok->set_match_star();
2066
        break;
2067
2068
    case TCGRAM_UNKNOWN:
2069
        /* no extra data to read */
2070
        break;
2071
    }
2072
2073
    /* read and set the property association */
2074
    tok->set_prop_assoc(prop_xlat[fp->read_int2()]);
2075
2076
    /* return the token */
2077
    return tok;
2078
}