3
"$Header: d:/cvsroot/tads/tads3/TCMAIN.CPP,v 1.4 1999/07/11 00:46:53 MJRoberts Exp $";
7
* Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved.
9
* Please see the accompanying license file, LICENSE.TXT, for information
10
* on using and copying this software.
14
tcmain.cpp - TADS 3 Compiler - main compiler driver
20
04/22/99 MJRoberts - Creation
40
/* ------------------------------------------------------------------------ */
45
/* references to the error subsystem */
46
int CTcMain::err_refs_ = 0;
48
/* flag: we have failed to load external messages */
49
int CTcMain::err_no_extern_messages_ = FALSE;
51
/* console output character mapper */
52
CCharmapToLocal *CTcMain::console_mapper_ = 0;
55
/* ------------------------------------------------------------------------ */
57
* Initialize the error subsystem for the compiler
59
void CTcMain::tc_err_init(size_t param_stack_size,
60
CResLoader *res_loader)
62
/* initialize the error stack */
65
/* if this is the first initializer, set things up */
68
/* if we haven't loaded external compiler messages, load them */
69
if (!err_no_extern_messages_
70
&& tc_messages == &tc_messages_english[0])
74
/* try finding a message file */
75
fp = res_loader->open_res_file("t3make.msg", 0, "XMSG");
79
err_load_message_file(fp, &tc_messages, &tc_message_count,
80
&tc_messages_english[0],
81
tc_message_count_english);
83
/* done with the file */
88
/* note the failure, so we don't try again */
89
err_no_extern_messages_ = FALSE;
94
/* count the reference depth */
99
* terminate the error subsystem for the compiler
101
void CTcMain::tc_err_term()
103
/* reduce the reference count */
106
/* delete the error stack */
109
/* if this is the last reference, clean things up */
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);
119
/* ------------------------------------------------------------------------ */
121
* Initialize the compiler
123
void CTcMain::init(CTcHostIfc *hostifc, CResLoader *res_loader,
124
const char *default_charset)
126
/* initialize the error subsystem */
127
tc_err_init(1024, res_loader);
129
/* remember the host interface */
132
/* perform static initializations on the parser symbol table class */
133
CTcPrsSymtab::s_init();
135
/* create the compiler main object */
136
G_tcmain = new CTcMain(res_loader, default_charset);
140
* Terminate the compiler
142
void CTcMain::terminate()
144
/* delete the tokenizer */
148
/* delete the compiler main object */
152
/* forget any object and property fixups */
158
* make sure we explicitly turn the fixup flags on again if we want
159
* them in a future run
161
G_keep_objfixups = FALSE;
162
G_keep_propfixups = FALSE;
163
G_keep_enumfixups = FALSE;
165
/* perform static termination on the parser symbol table class */
166
CTcPrsSymtab::s_terminate();
168
/* forget the host interface */
171
/* terminate the error subsystem */
175
/* ------------------------------------------------------------------------ */
177
* set up the compiler
179
CTcMain::CTcMain(CResLoader *res_loader, const char *default_charset)
184
* if the caller didn't provide a default character set, ask the OS
187
if (default_charset == 0)
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
193
os_get_charmap(csbuf, OS_CHARMAP_FILECONTENTS);
195
/* use our OS-provided character set */
196
default_charset = csbuf;
199
/* if there's no static console output character map, create one */
200
if (console_mapper_ == 0)
204
/* get the console character set name */
205
os_get_charmap(mapname, OS_CHARMAP_DISPLAY);
207
/* create a resource loader for the console character map */
208
console_mapper_ = CCharmapToLocal::load(res_loader, mapname);
210
/* if that failed, create an ASCII mapper */
211
if (console_mapper_ == 0)
212
console_mapper_ = CCharmapToLocal::load(res_loader, "us-ascii");
215
/* remember our resource loader */
216
res_loader_ = res_loader;
219
* set default options - minimum verbosity, no numeric error codes,
220
* show standard warnings but not pedantic warnings, not test mode
222
err_options_ = TCMAIN_ERR_WARNINGS;
224
/* we have no warning suppression list yet */
228
/* remember our default character set */
229
default_charset_ = lib_copy_str(default_charset);
231
/* create the tokenizer */
232
G_tok = new CTcTokenizer(res_loader_, default_charset_);
235
* Create the parser and node memory pool. Create the memory pool
236
* first, because the parser allocates objects out of the pool.
238
G_prsmem = new CTcPrsMem();
239
G_prs = new CTcParser();
241
/* create the generator data stream (for constant data) */
242
G_ds = new CTcDataStream(TCGEN_DATA_STREAM);
244
/* create the primary generator code stream */
245
G_cs_main = new CTcCodeStream(TCGEN_CODE_STREAM);
247
/* create the static initializer code stream */
248
G_cs_static = new CTcCodeStream(TCGEN_STATIC_CODE_STREAM);
250
/* make the primary code stream active */
253
/* create the generator object data stream */
254
G_os = new CTcDataStream(TCGEN_OBJECT_STREAM);
256
/* create the intrinsic class modifier object data stream */
257
G_icmod_stream = new CTcDataStream(TCGEN_ICMOD_STREAM);
259
/* create the dictionary object data stream */
260
G_dict_stream = new CTcDataStream(TCGEN_DICT_STREAM);
262
/* create the grammar-production object data stream */
263
G_gramprod_stream = new CTcDataStream(TCGEN_GRAMPROD_STREAM);
265
/* create the BigNumber object data stream */
266
G_bignum_stream = new CTcDataStream(TCGEN_BIGNUM_STREAM);
268
/* create the IntrinsicClass object data stream */
269
G_int_class_stream = new CTcDataStream(TCGEN_INTCLASS_STREAM);
271
/* create the static initializer identifier stream */
272
G_static_init_id_stream = new CTcDataStream(TCGEN_STATIC_INIT_ID_STREAM);
274
/* create the target-specific code generator */
275
G_cg = new CTcGenTarg();
277
/* initialize the parser */
280
/* no errors or warnings yet */
286
/* set a fairly liberal maximum error limit */
287
max_error_count_ = 100;
289
/* there's no disassembly output stream yet */
294
/* ------------------------------------------------------------------------ */
296
* delete the compiler driver
300
/* if there's a disassembly stream, delete it */
301
if (G_disasm_out != 0)
304
/* delete the various data streams */
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;
316
/* delete the console output character map, if there is one */
317
if (console_mapper_ != 0)
319
/* release our reference on it */
320
console_mapper_->release_ref();
322
/* forget it (since it's static) */
326
/* delete the target-specific code generator */
329
/* delete the parser and node memory pool */
333
/* delete the parser */
336
/* delete our default character set name string */
337
lib_free_str(default_charset_);
341
/* ------------------------------------------------------------------------ */
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
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)
358
* If this is a warning or a pedantic warning, and it's in the list of
359
* suppressed messages, ignore it entirely.
361
if (severity == TC_SEV_PEDANTIC || severity == TC_SEV_WARNING)
366
/* scan the suppress list */
367
for (p = suppress_list, rem = suppress_cnt ; rem != 0 ; ++p, --rem)
369
/* check for a match */
372
/* it's in the suppress list - ignore the error */
378
/* increment the appropriate counter */
383
* we don't need to count informational messages, and no prefix is
389
case TC_SEV_PEDANTIC:
391
* if we're not in "pedantic" mode, or we're not even showing
392
* regular errors, ignore it
394
if (!(options & TCMAIN_ERR_PEDANTIC)
395
|| !(options & TCMAIN_ERR_WARNINGS))
398
/* if this is the first warning, remember the code */
399
if (*warn_counter == 0 && first_warning != 0)
400
*first_warning = err;
410
/* if we're suppressing warnings, ignore it */
411
if (!(options & TCMAIN_ERR_WARNINGS))
414
/* if this is the first warning, remember the code */
415
if (*warn_counter == 0 && first_warning != 0)
416
*first_warning = err;
418
/* count the warning */
421
/* use an appropriate prefix */
426
/* if this is the first error, remember the code */
427
if (*err_counter == 0 && first_error != 0)
430
/* count the error */
433
/* use an appropriate prefix */
438
/* if this is the first error, remember the code */
439
if (*err_counter == 0 && first_error != 0)
442
/* count this as an error */
445
/* use an appropriate prefix */
446
prefix = "fatal error";
449
case TC_SEV_INTERNAL:
450
/* if this is the first error, remember the code */
451
if (*err_counter == 0 && first_error != 0)
454
/* count this as an error */
457
/* use an appropriate prefix */
458
prefix = "internal error";
462
/* display the current parsing position, if available */
466
char qu_buf[OSFNMAX*2 + 2];
468
/* get the filename from the source descriptor */
469
fname = linedesc->get_fname();
472
* if we're in test reporting mode, show only the root part of the
475
if ((options & TCMAIN_ERR_TESTMODE) != 0)
476
fname = os_get_root_name((char *)fname);
478
/* if they want quoted filenames, quote the filename */
479
if ((options & TCMAIN_ERR_FNAME_QU) != 0)
484
/* quote each character of the filename */
485
for (src = fname, qu_buf[0] = '"', dst = qu_buf + 1 ;
488
/* if this is a quote character, stutter it */
492
/* add this character */
496
/* add a closing quote and trailing null */
500
/* use the quoted version of the filename */
504
/* show the filename and line number prefix */
505
G_hostifc->print_err("%s(%ld): ", fname, linenum);
508
/* display the error type prefix */
509
G_hostifc->print_err("%s", prefix);
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);
515
/* add a colon and a space for separation */
516
G_hostifc->print_err(": ");
518
/* get the error message */
519
msg = tcerr_get_msg(err, (options & TCMAIN_ERR_VERBOSE) != 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.]";
527
/* return the message text, so the caller can format it with arguments */
532
* Log an error, part 2: show the message suffix.
534
static void log_msg_internal_2(unsigned long options, tc_severity_t severity)
537
* if we're in verbose mode, and this is an internal error, add the
538
* internal error explanation text
540
if (severity == TC_SEV_INTERNAL && (options & TCMAIN_ERR_VERBOSE) != 0)
544
/* get the internal error explanation text and display it */
545
msg = tcerr_get_msg(TCERR_INTERNAL_EXPLAN, TRUE);
547
G_hostifc->print_err("\n%s", msg);
551
G_hostifc->print_err((options & TCMAIN_ERR_VERBOSE) != 0 ? "\n\n" : "\n");
554
/* ------------------------------------------------------------------------ */
556
* Print an error message. Word-wrap the message if we're in verbose mode.
558
static void format_message(const char *msg, unsigned long options)
561
* if we're in verbose mode, word-wrap to 80 columns; otherwise just
564
if ((options & TCMAIN_ERR_VERBOSE) != 0)
567
const int line_wid = 79;
569
/* start on a new line, to skip any prefix text */
570
G_hostifc->print_err("\n");
572
/* word-wrap to 80 columns */
573
for (p = msg ; *p != '\0' ; )
578
/* find the next word break */
579
for (sp = 0, start = p ; ; )
581
/* if this is a space, note it */
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
589
if (*p == '\0' || p - start >= line_wid && sp != 0)
591
/* if we've reached the end, print the rest */
595
/* trim off trailing spaces */
596
for ( ; sp > start && *(sp-1) == ' ' ; --sp) ;
599
G_hostifc->print_err("%.*s\n", sp - start, start);
601
/* skip leading spaces */
602
for ( ; *sp == ' ' ; ++sp) ;
604
/* if this is the end of the line, we're done */
608
/* start over here */
613
/* this one fits - skip it */
622
G_hostifc->print_err("%s", msg);
626
/* ------------------------------------------------------------------------ */
628
* log an error from an exception object
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)
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());
644
/* if the message is suppressed, we're done */
648
/* format the message using arguments stored in the exception */
649
err_format_msg(msgbuf, sizeof(msgbuf), msg, exc);
651
/* print the error */
652
format_message(msgbuf, options);
654
/* show the suffix */
655
log_msg_internal_2(options, severity);
658
/* ------------------------------------------------------------------------ */
660
* Log an error using va_list arguments
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)
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);
677
/* if the message is suppressed, we're done */
681
/* format the message using the va_list argument */
682
t3vsprintf(msgbuf, sizeof(msgbuf), msg, args);
685
format_message(msgbuf, options);
687
/* show the suffix */
688
log_msg_internal_2(options, severity);
691
/* ------------------------------------------------------------------------ */
693
* Check the current error count against the maximum error limit, and throw
694
* a fatal error if we've reached the limit.
696
void CTcMain::check_error_limit()
698
/* check the error count against the limit */
699
if (error_count_ > max_error_count_)
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
707
max_error_count_ = error_count_ + 100;
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);
713
/* throw the generic fatal error, since we've logged this */
714
err_throw(TCERR_FATAL_ERROR);