| | 1 | #ifdef RCSID |
| | 2 | static char RCSid[] = |
| | 3 | "$Header: d:/cvsroot/tads/tads3/TCMAIN.CPP,v 1.4 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 | tcmain.cpp - TADS 3 Compiler - main compiler driver |
| | 15 | Function |
| | 16 | |
| | 17 | Notes |
| | 18 | |
| | 19 | Modified |
| | 20 | 04/22/99 MJRoberts - Creation |
| | 21 | */ |
| | 22 | |
| | 23 | #include "t3std.h" |
| | 24 | #include "vmerr.h" |
| | 25 | #include "tcglob.h" |
| | 26 | #include "tcmain.h" |
| | 27 | #include "tcerr.h" |
| | 28 | #include "tctok.h" |
| | 29 | #include "utf8.h" |
| | 30 | #include "charmap.h" |
| | 31 | #include "tchost.h" |
| | 32 | #include "tcprs.h" |
| | 33 | #include "tcgen.h" |
| | 34 | #include "tctarg.h" |
| | 35 | #include "charmap.h" |
| | 36 | #include "resload.h" |
| | 37 | #include "tcunas.h" |
| | 38 | |
| | 39 | |
| | 40 | /* ------------------------------------------------------------------------ */ |
| | 41 | /* |
| | 42 | * statics |
| | 43 | */ |
| | 44 | |
| | 45 | /* references to the error subsystem */ |
| | 46 | int CTcMain::err_refs_ = 0; |
| | 47 | |
| | 48 | /* flag: we have failed to load external messages */ |
| | 49 | int CTcMain::err_no_extern_messages_ = FALSE; |
| | 50 | |
| | 51 | /* console output character mapper */ |
| | 52 | CCharmapToLocal *CTcMain::console_mapper_ = 0; |
| | 53 | |
| | 54 | |
| | 55 | /* ------------------------------------------------------------------------ */ |
| | 56 | /* |
| | 57 | * Initialize the error subsystem for the compiler |
| | 58 | */ |
| | 59 | void CTcMain::tc_err_init(size_t param_stack_size, |
| | 60 | CResLoader *res_loader) |
| | 61 | { |
| | 62 | /* initialize the error stack */ |
| | 63 | err_init(1024); |
| | 64 | |
| | 65 | /* if this is the first initializer, set things up */ |
| | 66 | if (err_refs_ == 0) |
| | 67 | { |
| | 68 | /* if we haven't loaded external compiler messages, load them */ |
| | 69 | if (!err_no_extern_messages_ |
| | 70 | && tc_messages == &tc_messages_english[0]) |
| | 71 | { |
| | 72 | osfildef *fp; |
| | 73 | |
| | 74 | /* try finding a message file */ |
| | 75 | fp = res_loader->open_res_file("t3make.msg", 0, "XMSG"); |
| | 76 | if (fp != 0) |
| | 77 | { |
| | 78 | /* try loading it */ |
| | 79 | err_load_message_file(fp, &tc_messages, &tc_message_count, |
| | 80 | &tc_messages_english[0], |
| | 81 | tc_message_count_english); |
| | 82 | |
| | 83 | /* done with the file */ |
| | 84 | osfcls(fp); |
| | 85 | } |
| | 86 | else |
| | 87 | { |
| | 88 | /* note the failure, so we don't try again */ |
| | 89 | err_no_extern_messages_ = FALSE; |
| | 90 | } |
| | 91 | } |
| | 92 | } |
| | 93 | |
| | 94 | /* count the reference depth */ |
| | 95 | ++err_refs_; |
| | 96 | } |
| | 97 | |
| | 98 | /* |
| | 99 | * terminate the error subsystem for the compiler |
| | 100 | */ |
| | 101 | void CTcMain::tc_err_term() |
| | 102 | { |
| | 103 | /* reduce the reference count */ |
| | 104 | --err_refs_; |
| | 105 | |
| | 106 | /* delete the error stack */ |
| | 107 | err_terminate(); |
| | 108 | |
| | 109 | /* if this is the last reference, clean things up */ |
| | 110 | if (err_refs_ == 0) |
| | 111 | { |
| | 112 | /* if we loaded an external message file, unload it */ |
| | 113 | err_delete_message_array(&tc_messages, &tc_message_count, |
| | 114 | &tc_messages_english[0], |
| | 115 | tc_message_count_english); |
| | 116 | } |
| | 117 | } |
| | 118 | |
| | 119 | /* ------------------------------------------------------------------------ */ |
| | 120 | /* |
| | 121 | * Initialize the compiler |
| | 122 | */ |
| | 123 | void CTcMain::init(CTcHostIfc *hostifc, CResLoader *res_loader, |
| | 124 | const char *default_charset) |
| | 125 | { |
| | 126 | /* initialize the error subsystem */ |
| | 127 | tc_err_init(1024, res_loader); |
| | 128 | |
| | 129 | /* remember the host interface */ |
| | 130 | G_hostifc = hostifc; |
| | 131 | |
| | 132 | /* perform static initializations on the parser symbol table class */ |
| | 133 | CTcPrsSymtab::s_init(); |
| | 134 | |
| | 135 | /* create the compiler main object */ |
| | 136 | G_tcmain = new CTcMain(res_loader, default_charset); |
| | 137 | } |
| | 138 | |
| | 139 | /* |
| | 140 | * Terminate the compiler |
| | 141 | */ |
| | 142 | void CTcMain::terminate() |
| | 143 | { |
| | 144 | /* delete the tokenizer */ |
| | 145 | delete G_tok; |
| | 146 | G_tok = 0; |
| | 147 | |
| | 148 | /* delete the compiler main object */ |
| | 149 | delete G_tcmain; |
| | 150 | G_tcmain = 0; |
| | 151 | |
| | 152 | /* forget any object and property fixups */ |
| | 153 | G_objfixup = 0; |
| | 154 | G_propfixup = 0; |
| | 155 | G_enumfixup = 0; |
| | 156 | |
| | 157 | /* |
| | 158 | * make sure we explicitly turn the fixup flags on again if we want |
| | 159 | * them in a future run |
| | 160 | */ |
| | 161 | G_keep_objfixups = FALSE; |
| | 162 | G_keep_propfixups = FALSE; |
| | 163 | G_keep_enumfixups = FALSE; |
| | 164 | |
| | 165 | /* perform static termination on the parser symbol table class */ |
| | 166 | CTcPrsSymtab::s_terminate(); |
| | 167 | |
| | 168 | /* forget the host interface */ |
| | 169 | G_hostifc = 0; |
| | 170 | |
| | 171 | /* terminate the error subsystem */ |
| | 172 | tc_err_term(); |
| | 173 | } |
| | 174 | |
| | 175 | /* ------------------------------------------------------------------------ */ |
| | 176 | /* |
| | 177 | * set up the compiler |
| | 178 | */ |
| | 179 | CTcMain::CTcMain(CResLoader *res_loader, const char *default_charset) |
| | 180 | { |
| | 181 | char csbuf[OSFNMAX]; |
| | 182 | |
| | 183 | /* |
| | 184 | * if the caller didn't provide a default character set, ask the OS |
| | 185 | * what we should use |
| | 186 | */ |
| | 187 | if (default_charset == 0) |
| | 188 | { |
| | 189 | /* |
| | 190 | * ask the OS what to use for file contents, since we use this |
| | 191 | * character set to translate the text we read from source files |
| | 192 | */ |
| | 193 | os_get_charmap(csbuf, OS_CHARMAP_FILECONTENTS); |
| | 194 | |
| | 195 | /* use our OS-provided character set */ |
| | 196 | default_charset = csbuf; |
| | 197 | } |
| | 198 | |
| | 199 | /* if there's no static console output character map, create one */ |
| | 200 | if (console_mapper_ == 0) |
| | 201 | { |
| | 202 | char mapname[32]; |
| | 203 | |
| | 204 | /* get the console character set name */ |
| | 205 | os_get_charmap(mapname, OS_CHARMAP_DISPLAY); |
| | 206 | |
| | 207 | /* create a resource loader for the console character map */ |
| | 208 | console_mapper_ = CCharmapToLocal::load(res_loader, mapname); |
| | 209 | |
| | 210 | /* if that failed, create an ASCII mapper */ |
| | 211 | if (console_mapper_ == 0) |
| | 212 | console_mapper_ = CCharmapToLocal::load(res_loader, "us-ascii"); |
| | 213 | } |
| | 214 | |
| | 215 | /* remember our resource loader */ |
| | 216 | res_loader_ = res_loader; |
| | 217 | |
| | 218 | /* |
| | 219 | * set default options - minimum verbosity, no numeric error codes, |
| | 220 | * show standard warnings but not pedantic warnings, not test mode |
| | 221 | */ |
| | 222 | err_options_ = TCMAIN_ERR_WARNINGS; |
| | 223 | |
| | 224 | /* we have no warning suppression list yet */ |
| | 225 | suppress_list_ = 0; |
| | 226 | suppress_cnt_ = 0; |
| | 227 | |
| | 228 | /* remember our default character set */ |
| | 229 | default_charset_ = lib_copy_str(default_charset); |
| | 230 | |
| | 231 | /* create the tokenizer */ |
| | 232 | G_tok = new CTcTokenizer(res_loader_, default_charset_); |
| | 233 | |
| | 234 | /* |
| | 235 | * Create the parser and node memory pool. Create the memory pool |
| | 236 | * first, because the parser allocates objects out of the pool. |
| | 237 | */ |
| | 238 | G_prsmem = new CTcPrsMem(); |
| | 239 | G_prs = new CTcParser(); |
| | 240 | |
| | 241 | /* create the generator data stream (for constant data) */ |
| | 242 | G_ds = new CTcDataStream(TCGEN_DATA_STREAM); |
| | 243 | |
| | 244 | /* create the primary generator code stream */ |
| | 245 | G_cs_main = new CTcCodeStream(TCGEN_CODE_STREAM); |
| | 246 | |
| | 247 | /* create the static initializer code stream */ |
| | 248 | G_cs_static = new CTcCodeStream(TCGEN_STATIC_CODE_STREAM); |
| | 249 | |
| | 250 | /* make the primary code stream active */ |
| | 251 | G_cs = G_cs_main; |
| | 252 | |
| | 253 | /* create the generator object data stream */ |
| | 254 | G_os = new CTcDataStream(TCGEN_OBJECT_STREAM); |
| | 255 | |
| | 256 | /* create the intrinsic class modifier object data stream */ |
| | 257 | G_icmod_stream = new CTcDataStream(TCGEN_ICMOD_STREAM); |
| | 258 | |
| | 259 | /* create the dictionary object data stream */ |
| | 260 | G_dict_stream = new CTcDataStream(TCGEN_DICT_STREAM); |
| | 261 | |
| | 262 | /* create the grammar-production object data stream */ |
| | 263 | G_gramprod_stream = new CTcDataStream(TCGEN_GRAMPROD_STREAM); |
| | 264 | |
| | 265 | /* create the BigNumber object data stream */ |
| | 266 | G_bignum_stream = new CTcDataStream(TCGEN_BIGNUM_STREAM); |
| | 267 | |
| | 268 | /* create the IntrinsicClass object data stream */ |
| | 269 | G_int_class_stream = new CTcDataStream(TCGEN_INTCLASS_STREAM); |
| | 270 | |
| | 271 | /* create the static initializer identifier stream */ |
| | 272 | G_static_init_id_stream = new CTcDataStream(TCGEN_STATIC_INIT_ID_STREAM); |
| | 273 | |
| | 274 | /* create the target-specific code generator */ |
| | 275 | G_cg = new CTcGenTarg(); |
| | 276 | |
| | 277 | /* initialize the parser */ |
| | 278 | G_prs->init(); |
| | 279 | |
| | 280 | /* no errors or warnings yet */ |
| | 281 | error_count_ = 0; |
| | 282 | warning_count_ = 0; |
| | 283 | first_error_ = 0; |
| | 284 | first_warning_ = 0; |
| | 285 | |
| | 286 | /* set a fairly liberal maximum error limit */ |
| | 287 | max_error_count_ = 100; |
| | 288 | |
| | 289 | /* there's no disassembly output stream yet */ |
| | 290 | G_disasm_out = 0; |
| | 291 | } |
| | 292 | |
| | 293 | |
| | 294 | /* ------------------------------------------------------------------------ */ |
| | 295 | /* |
| | 296 | * delete the compiler driver |
| | 297 | */ |
| | 298 | CTcMain::~CTcMain() |
| | 299 | { |
| | 300 | /* if there's a disassembly stream, delete it */ |
| | 301 | if (G_disasm_out != 0) |
| | 302 | delete G_disasm_out; |
| | 303 | |
| | 304 | /* delete the various data streams */ |
| | 305 | delete G_cs_main; |
| | 306 | delete G_cs_static; |
| | 307 | delete G_ds; |
| | 308 | delete G_os; |
| | 309 | delete G_icmod_stream; |
| | 310 | delete G_dict_stream; |
| | 311 | delete G_gramprod_stream; |
| | 312 | delete G_bignum_stream; |
| | 313 | delete G_int_class_stream; |
| | 314 | delete G_static_init_id_stream; |
| | 315 | |
| | 316 | /* delete the console output character map, if there is one */ |
| | 317 | if (console_mapper_ != 0) |
| | 318 | { |
| | 319 | /* release our reference on it */ |
| | 320 | console_mapper_->release_ref(); |
| | 321 | |
| | 322 | /* forget it (since it's static) */ |
| | 323 | console_mapper_ = 0; |
| | 324 | } |
| | 325 | |
| | 326 | /* delete the target-specific code generator */ |
| | 327 | delete G_cg; |
| | 328 | |
| | 329 | /* delete the parser and node memory pool */ |
| | 330 | delete G_prs; |
| | 331 | delete G_prsmem; |
| | 332 | |
| | 333 | /* delete the parser */ |
| | 334 | delete G_tok; |
| | 335 | |
| | 336 | /* delete our default character set name string */ |
| | 337 | lib_free_str(default_charset_); |
| | 338 | } |
| | 339 | |
| | 340 | |
| | 341 | /* ------------------------------------------------------------------------ */ |
| | 342 | /* |
| | 343 | * Log an error, part 1: show the message prefix. This should be called |
| | 344 | * before formatting the text of the message, and part 2 should be called |
| | 345 | * after formatting the message text. Returns a pointer to the message |
| | 346 | * template text. |
| | 347 | */ |
| | 348 | static const char *log_msg_internal_1( |
| | 349 | CTcTokFileDesc *linedesc, long linenum, |
| | 350 | int *err_counter, int *warn_counter, int *first_error, int *first_warning, |
| | 351 | unsigned long options, const int *suppress_list, size_t suppress_cnt, |
| | 352 | tc_severity_t severity, int err) |
| | 353 | { |
| | 354 | const char *msg; |
| | 355 | const char *prefix; |
| | 356 | |
| | 357 | /* |
| | 358 | * If this is a warning or a pedantic warning, and it's in the list of |
| | 359 | * suppressed messages, ignore it entirely. |
| | 360 | */ |
| | 361 | if (severity == TC_SEV_PEDANTIC || severity == TC_SEV_WARNING) |
| | 362 | { |
| | 363 | size_t rem; |
| | 364 | const int *p; |
| | 365 | |
| | 366 | /* scan the suppress list */ |
| | 367 | for (p = suppress_list, rem = suppress_cnt ; rem != 0 ; ++p, --rem) |
| | 368 | { |
| | 369 | /* check for a match */ |
| | 370 | if (*p == err) |
| | 371 | { |
| | 372 | /* it's in the suppress list - ignore the error */ |
| | 373 | return 0; |
| | 374 | } |
| | 375 | } |
| | 376 | } |
| | 377 | |
| | 378 | /* increment the appropriate counter */ |
| | 379 | switch(severity) |
| | 380 | { |
| | 381 | case TC_SEV_INFO: |
| | 382 | /* |
| | 383 | * we don't need to count informational messages, and no prefix is |
| | 384 | * required |
| | 385 | */ |
| | 386 | prefix = ""; |
| | 387 | break; |
| | 388 | |
| | 389 | case TC_SEV_PEDANTIC: |
| | 390 | /* |
| | 391 | * if we're not in "pedantic" mode, or we're not even showing |
| | 392 | * regular errors, ignore it |
| | 393 | */ |
| | 394 | if (!(options & TCMAIN_ERR_PEDANTIC) |
| | 395 | || !(options & TCMAIN_ERR_WARNINGS)) |
| | 396 | return 0; |
| | 397 | |
| | 398 | /* if this is the first warning, remember the code */ |
| | 399 | if (*warn_counter == 0 && first_warning != 0) |
| | 400 | *first_warning = err; |
| | 401 | |
| | 402 | /* count it */ |
| | 403 | ++(*warn_counter); |
| | 404 | |
| | 405 | /* set the prefix */ |
| | 406 | prefix = "warning"; |
| | 407 | break; |
| | 408 | |
| | 409 | case TC_SEV_WARNING: |
| | 410 | /* if we're suppressing warnings, ignore it */ |
| | 411 | if (!(options & TCMAIN_ERR_WARNINGS)) |
| | 412 | return 0; |
| | 413 | |
| | 414 | /* if this is the first warning, remember the code */ |
| | 415 | if (*warn_counter == 0 && first_warning != 0) |
| | 416 | *first_warning = err; |
| | 417 | |
| | 418 | /* count the warning */ |
| | 419 | ++(*warn_counter); |
| | 420 | |
| | 421 | /* use an appropriate prefix */ |
| | 422 | prefix = "warning"; |
| | 423 | break; |
| | 424 | |
| | 425 | case TC_SEV_ERROR: |
| | 426 | /* if this is the first error, remember the code */ |
| | 427 | if (*err_counter == 0 && first_error != 0) |
| | 428 | *first_error = err; |
| | 429 | |
| | 430 | /* count the error */ |
| | 431 | ++(*err_counter); |
| | 432 | |
| | 433 | /* use an appropriate prefix */ |
| | 434 | prefix = "error"; |
| | 435 | break; |
| | 436 | |
| | 437 | case TC_SEV_FATAL: |
| | 438 | /* if this is the first error, remember the code */ |
| | 439 | if (*err_counter == 0 && first_error != 0) |
| | 440 | *first_error = err; |
| | 441 | |
| | 442 | /* count this as an error */ |
| | 443 | ++(*err_counter); |
| | 444 | |
| | 445 | /* use an appropriate prefix */ |
| | 446 | prefix = "fatal error"; |
| | 447 | break; |
| | 448 | |
| | 449 | case TC_SEV_INTERNAL: |
| | 450 | /* if this is the first error, remember the code */ |
| | 451 | if (*err_counter == 0 && first_error != 0) |
| | 452 | *first_error = err; |
| | 453 | |
| | 454 | /* count this as an error */ |
| | 455 | ++(*err_counter); |
| | 456 | |
| | 457 | /* use an appropriate prefix */ |
| | 458 | prefix = "internal error"; |
| | 459 | break; |
| | 460 | } |
| | 461 | |
| | 462 | /* display the current parsing position, if available */ |
| | 463 | if (linedesc != 0) |
| | 464 | { |
| | 465 | const char *fname; |
| | 466 | char qu_buf[OSFNMAX*2 + 2]; |
| | 467 | |
| | 468 | /* get the filename from the source descriptor */ |
| | 469 | fname = linedesc->get_fname(); |
| | 470 | |
| | 471 | /* |
| | 472 | * if we're in test reporting mode, show only the root part of the |
| | 473 | * filename |
| | 474 | */ |
| | 475 | if ((options & TCMAIN_ERR_TESTMODE) != 0) |
| | 476 | fname = os_get_root_name((char *)fname); |
| | 477 | |
| | 478 | /* if they want quoted filenames, quote the filename */ |
| | 479 | if ((options & TCMAIN_ERR_FNAME_QU) != 0) |
| | 480 | { |
| | 481 | const char *src; |
| | 482 | char *dst; |
| | 483 | |
| | 484 | /* quote each character of the filename */ |
| | 485 | for (src = fname, qu_buf[0] = '"', dst = qu_buf + 1 ; |
| | 486 | *src != '\0' ; ) |
| | 487 | { |
| | 488 | /* if this is a quote character, stutter it */ |
| | 489 | if (*src == '"') |
| | 490 | *dst++ = '"'; |
| | 491 | |
| | 492 | /* add this character */ |
| | 493 | *dst++ = *src++; |
| | 494 | } |
| | 495 | |
| | 496 | /* add a closing quote and trailing null */ |
| | 497 | *dst++ = '"'; |
| | 498 | *dst = '\0'; |
| | 499 | |
| | 500 | /* use the quoted version of the filename */ |
| | 501 | fname = qu_buf; |
| | 502 | } |
| | 503 | |
| | 504 | /* show the filename and line number prefix */ |
| | 505 | G_hostifc->print_err("%s(%ld): ", fname, linenum); |
| | 506 | } |
| | 507 | |
| | 508 | /* display the error type prefix */ |
| | 509 | G_hostifc->print_err("%s", prefix); |
| | 510 | |
| | 511 | /* add the error number, if we're showing error numbers */ |
| | 512 | if ((options & TCMAIN_ERR_NUMBERS) != 0 && severity != TC_SEV_INFO) |
| | 513 | G_hostifc->print_err(" %u", (unsigned int)err); |
| | 514 | |
| | 515 | /* add a colon and a space for separation */ |
| | 516 | G_hostifc->print_err(": "); |
| | 517 | |
| | 518 | /* get the error message */ |
| | 519 | msg = tcerr_get_msg(err, (options & TCMAIN_ERR_VERBOSE) != 0); |
| | 520 | if (msg == 0) |
| | 521 | msg = "[Unable to find message text for this error code. " |
| | 522 | "This might indicate an internal problem with the compiler, " |
| | 523 | "or it might be caused by an installation problem that is " |
| | 524 | "preventing the compiler from finding an external message " |
| | 525 | "file that it requires.]"; |
| | 526 | |
| | 527 | /* return the message text, so the caller can format it with arguments */ |
| | 528 | return msg; |
| | 529 | } |
| | 530 | |
| | 531 | /* |
| | 532 | * Log an error, part 2: show the message suffix. |
| | 533 | */ |
| | 534 | static void log_msg_internal_2(unsigned long options, tc_severity_t severity) |
| | 535 | { |
| | 536 | /* |
| | 537 | * if we're in verbose mode, and this is an internal error, add the |
| | 538 | * internal error explanation text |
| | 539 | */ |
| | 540 | if (severity == TC_SEV_INTERNAL && (options & TCMAIN_ERR_VERBOSE) != 0) |
| | 541 | { |
| | 542 | const char *msg; |
| | 543 | |
| | 544 | /* get the internal error explanation text and display it */ |
| | 545 | msg = tcerr_get_msg(TCERR_INTERNAL_EXPLAN, TRUE); |
| | 546 | if (msg != 0) |
| | 547 | G_hostifc->print_err("\n%s", msg); |
| | 548 | } |
| | 549 | |
| | 550 | /* end the line */ |
| | 551 | G_hostifc->print_err((options & TCMAIN_ERR_VERBOSE) != 0 ? "\n\n" : "\n"); |
| | 552 | } |
| | 553 | |
| | 554 | /* ------------------------------------------------------------------------ */ |
| | 555 | /* |
| | 556 | * Print an error message. Word-wrap the message if we're in verbose mode. |
| | 557 | */ |
| | 558 | static void format_message(const char *msg, unsigned long options) |
| | 559 | { |
| | 560 | /* |
| | 561 | * if we're in verbose mode, word-wrap to 80 columns; otherwise just |
| | 562 | * print it as-is |
| | 563 | */ |
| | 564 | if ((options & TCMAIN_ERR_VERBOSE) != 0) |
| | 565 | { |
| | 566 | const char *p; |
| | 567 | const int line_wid = 79; |
| | 568 | |
| | 569 | /* start on a new line, to skip any prefix text */ |
| | 570 | G_hostifc->print_err("\n"); |
| | 571 | |
| | 572 | /* word-wrap to 80 columns */ |
| | 573 | for (p = msg ; *p != '\0' ; ) |
| | 574 | { |
| | 575 | const char *start; |
| | 576 | const char *sp; |
| | 577 | |
| | 578 | /* find the next word break */ |
| | 579 | for (sp = 0, start = p ; ; ) |
| | 580 | { |
| | 581 | /* if this is a space, note it */ |
| | 582 | if (*p == ' ') |
| | 583 | sp = p; |
| | 584 | |
| | 585 | /* |
| | 586 | * if we're at the end of the line, or we're over the line |
| | 587 | * width and we found a space, break here |
| | 588 | */ |
| | 589 | if (*p == '\0' || p - start >= line_wid && sp != 0) |
| | 590 | { |
| | 591 | /* if we've reached the end, print the rest */ |
| | 592 | if (*p == '\0') |
| | 593 | sp = p; |
| | 594 | |
| | 595 | /* trim off trailing spaces */ |
| | 596 | for ( ; sp > start && *(sp-1) == ' ' ; --sp) ; |
| | 597 | |
| | 598 | /* show this part */ |
| | 599 | G_hostifc->print_err("%.*s\n", sp - start, start); |
| | 600 | |
| | 601 | /* skip leading spaces */ |
| | 602 | for ( ; *sp == ' ' ; ++sp) ; |
| | 603 | |
| | 604 | /* if this is the end of the line, we're done */ |
| | 605 | if (*p == '\0') |
| | 606 | break; |
| | 607 | |
| | 608 | /* start over here */ |
| | 609 | start = p = sp; |
| | 610 | } |
| | 611 | else |
| | 612 | { |
| | 613 | /* this one fits - skip it */ |
| | 614 | ++p; |
| | 615 | } |
| | 616 | } |
| | 617 | } |
| | 618 | } |
| | 619 | else |
| | 620 | { |
| | 621 | /* display it */ |
| | 622 | G_hostifc->print_err("%s", msg); |
| | 623 | } |
| | 624 | } |
| | 625 | |
| | 626 | /* ------------------------------------------------------------------------ */ |
| | 627 | /* |
| | 628 | * log an error from an exception object |
| | 629 | */ |
| | 630 | void CTcMain::S_log_error(CTcTokFileDesc *linedesc, long linenum, |
| | 631 | int *err_counter, int *warn_counter, |
| | 632 | unsigned long options, |
| | 633 | const int *suppress_list, size_t suppress_cnt, |
| | 634 | tc_severity_t severity, CVmException *exc) |
| | 635 | { |
| | 636 | const char *msg; |
| | 637 | char msgbuf[1024]; |
| | 638 | |
| | 639 | /* show the prefix */ |
| | 640 | msg = log_msg_internal_1(linedesc, linenum, err_counter, warn_counter, |
| | 641 | 0, 0, options, suppress_list, suppress_cnt, |
| | 642 | severity, exc->get_error_code()); |
| | 643 | |
| | 644 | /* if the message is suppressed, we're done */ |
| | 645 | if (msg == 0) |
| | 646 | return; |
| | 647 | |
| | 648 | /* format the message using arguments stored in the exception */ |
| | 649 | err_format_msg(msgbuf, sizeof(msgbuf), msg, exc); |
| | 650 | |
| | 651 | /* print the error */ |
| | 652 | format_message(msgbuf, options); |
| | 653 | |
| | 654 | /* show the suffix */ |
| | 655 | log_msg_internal_2(options, severity); |
| | 656 | } |
| | 657 | |
| | 658 | /* ------------------------------------------------------------------------ */ |
| | 659 | /* |
| | 660 | * Log an error using va_list arguments |
| | 661 | */ |
| | 662 | void CTcMain::S_v_log_error(CTcTokFileDesc *linedesc, long linenum, |
| | 663 | int *err_counter, int *warn_counter, |
| | 664 | int *first_error, int *first_warning, |
| | 665 | unsigned long options, |
| | 666 | const int *suppress_list, size_t suppress_cnt, |
| | 667 | tc_severity_t severity, int err, va_list args) |
| | 668 | { |
| | 669 | const char *msg; |
| | 670 | char msgbuf[2048]; |
| | 671 | |
| | 672 | /* show the prefix */ |
| | 673 | msg = log_msg_internal_1(linedesc, linenum, err_counter, warn_counter, |
| | 674 | first_error, first_warning, options, |
| | 675 | suppress_list, suppress_cnt, severity, err); |
| | 676 | |
| | 677 | /* if the message is suppressed, we're done */ |
| | 678 | if (msg == 0) |
| | 679 | return; |
| | 680 | |
| | 681 | /* format the message using the va_list argument */ |
| | 682 | t3vsprintf(msgbuf, sizeof(msgbuf), msg, args); |
| | 683 | |
| | 684 | /* display it */ |
| | 685 | format_message(msgbuf, options); |
| | 686 | |
| | 687 | /* show the suffix */ |
| | 688 | log_msg_internal_2(options, severity); |
| | 689 | } |
| | 690 | |
| | 691 | /* ------------------------------------------------------------------------ */ |
| | 692 | /* |
| | 693 | * Check the current error count against the maximum error limit, and throw |
| | 694 | * a fatal error if we've reached the limit. |
| | 695 | */ |
| | 696 | void CTcMain::check_error_limit() |
| | 697 | { |
| | 698 | /* check the error count against the limit */ |
| | 699 | if (error_count_ > max_error_count_) |
| | 700 | { |
| | 701 | /* |
| | 702 | * raise the maximum error count a bit so that we don't encounter |
| | 703 | * another maximum error situation and loop on flagging the |
| | 704 | * too-many-errors error while trying to display a too-many-errors |
| | 705 | * error |
| | 706 | */ |
| | 707 | max_error_count_ = error_count_ + 100; |
| | 708 | |
| | 709 | /* display a message explaining the problem */ |
| | 710 | log_error(G_tok->get_last_desc(), G_tok->get_last_linenum(), |
| | 711 | TC_SEV_FATAL, TCERR_TOO_MANY_ERRORS); |
| | 712 | |
| | 713 | /* throw the generic fatal error, since we've logged this */ |
| | 714 | err_throw(TCERR_FATAL_ERROR); |
| | 715 | } |
| | 716 | } |
| | 717 | |