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