1 #ifdef RCSID
2 static char RCSid[] =
3 "$Header: d:/cvsroot/tads/TADS2/TCD.C,v 1.4 1999/07/11 00:46:30 MJRoberts Exp $";
4 #endif
5
6 /*
7 * Copyright (c) 1992, 2000 by 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 tcd.c - tads2 compiler driver
15 Function
16 compiles a game and writes to a binary file
17 Notes
18 This is essentially for the command line interface; main() calls
19 tcdmain(), which compiles the game and writes to a binary file.
20 Modified
21 04/04/98 CNebel - Use new headers.
22 12/16/92 MJRoberts - add TADS/Graphic extensions
23 04/02/92 MJRoberts - creation
24 */
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <time.h>
29 #include <ctype.h>
30 #include <stdarg.h>
31 #include "os.h"
32 #include "std.h"
33 #include "lin.h"
34 #include "linf.h"
35 #include "err.h"
36 #include "tok.h"
37 #include "mch.h"
38 #include "mcm.h"
39 #include "prs.h"
40 #include "emt.h"
41 #include "opc.h"
42 #include "run.h"
43 #include "voc.h"
44 #include "bif.h"
45 #include "dbg.h"
46 #include "sup.h"
47 #include "cmd.h"
48 #include "fio.h"
49 #include "oem.h"
50 #include "cmap.h"
51 #include "tcg.h"
52
53 /* this must be included after os.h, because of memory size #defines */
54 #include "tcd.h"
55
56 /* debugger not present */
dbgpresent()57 int dbgpresent()
58 {
59 return FALSE;
60 }
61
62 /* dummy debugger functions */
trchid()63 void trchid() {}
trcsho()64 void trcsho() {}
65
dbgu_err_resume(dbgcxdef * ctx)66 int dbgu_err_resume(dbgcxdef *ctx)
67 {
68 VARUSED(ctx);
69 return FALSE;
70 }
71
dbguquitting(dbgcxdef * ctx)72 void dbguquitting(dbgcxdef *ctx)
73 {
74 VARUSED(ctx);
75 }
76
dbgu_find_src(const char * origname,int origlen,char * fullname,size_t full_len,int must_find_file)77 int dbgu_find_src(const char *origname, int origlen,
78 char *fullname, size_t full_len, int must_find_file)
79 {
80 VARUSED(origname);
81 VARUSED(origlen);
82 VARUSED(fullname);
83 VARUSED(full_len);
84 VARUSED(must_find_file);
85
86 /* indicate failure */
87 return FALSE;
88 }
89
dbgfrfind(dbgcxdef * ctx,objnum frobj,uint frofs)90 struct runsdef *dbgfrfind(dbgcxdef *ctx, objnum frobj, uint frofs)
91 {
92 VARUSED(frobj);
93 VARUSED(frofs);
94 errsig(ctx->dbgcxerr, ERR_INACTFR);
95 return 0;
96 }
97
dbgss(struct dbgcxdef * ctx,uint ofs,int instr,int err,uchar * noreg * instrp)98 void dbgss(struct dbgcxdef *ctx, uint ofs, int instr, int err,
99 uchar *noreg *instrp)
100 {
101 VARUSED(ctx);
102 VARUSED(ofs);
103 VARUSED(instr);
104 VARUSED(err);
105 return;
106 }
107
dbgstart(struct dbgcxdef * ctx)108 int dbgstart(struct dbgcxdef *ctx)
109 {
110 VARUSED(ctx);
111 return(TRUE);
112 }
113
114 /* dummy functions to satisfy built-ins that can't be used by preinit */
115
vocinialo(voccxdef * ctx,vocddef ** what,int cnt)116 void vocinialo(voccxdef *ctx, vocddef **what, int cnt)
117 {
118 VARUSED(ctx);
119 VARUSED(what);
120 VARUSED(cnt);
121 }
122
vocremfd(voccxdef * ctx,vocddef * what,objnum func,prpnum prop,runsdef * val,int err)123 void vocremfd(voccxdef *ctx, vocddef *what, objnum func, prpnum prop,
124 runsdef *val, int err)
125 {
126 VARUSED(ctx);
127 VARUSED(what);
128 VARUSED(func);
129 VARUSED(prop);
130 VARUSED(val);
131 VARUSED(err);
132 }
133
vocsetfd(voccxdef * ctx,vocddef * what,objnum func,prpnum prop,uint tm,runsdef * val,int err)134 void vocsetfd(voccxdef *ctx, vocddef *what, objnum func, prpnum prop,
135 uint tm, runsdef *val, int err)
136 {
137 VARUSED(ctx);
138 VARUSED(what);
139 VARUSED(func);
140 VARUSED(prop);
141 VARUSED(tm);
142 VARUSED(val);
143 VARUSED(err);
144 }
145
vocturn(voccxdef * ctx,int cnt,int do_fuses)146 void vocturn(voccxdef *ctx, int cnt, int do_fuses)
147 {
148 VARUSED(ctx);
149 VARUSED(cnt);
150 VARUSED(do_fuses);
151 }
152
vocdmnclr(voccxdef * ctx)153 void vocdmnclr(voccxdef *ctx)
154 {
155 VARUSED(ctx);
156 }
157
voclistlen(vocoldef * lst)158 int voclistlen(vocoldef *lst)
159 {
160 VARUSED(lst);
161 return 0;
162 }
163
exedaem(voccxdef * ctx)164 void exedaem(voccxdef *ctx)
165 {
166 VARUSED(ctx);
167 }
168
exefuse(voccxdef * ctx,int do_run)169 int exefuse(voccxdef *ctx, int do_run)
170 {
171 VARUSED(ctx);
172 VARUSED(do_run);
173 return FALSE;
174 }
175
execmd_recurs(voccxdef * ctx,objnum actor,objnum verb,objnum dobj,objnum prep,objnum iobj,int validate_dobj,int validate_iobj)176 int execmd_recurs(voccxdef *ctx, objnum actor, objnum verb,
177 objnum dobj, objnum prep, objnum iobj,
178 int validate_dobj, int validate_iobj)
179 {
180 VARUSED(ctx);
181 VARUSED(actor);
182 VARUSED(verb);
183 VARUSED(dobj);
184 VARUSED(prep);
185 VARUSED(iobj);
186 return 0;
187 }
188
voc_parse_tok(voccxdef * ctx)189 void voc_parse_tok(voccxdef *ctx) { VARUSED(ctx); }
voc_parse_types(voccxdef * ctx)190 void voc_parse_types(voccxdef *ctx) { VARUSED(ctx); }
voc_parse_dict_lookup(voccxdef * ctx)191 void voc_parse_dict_lookup(voccxdef *ctx) { VARUSED(ctx); }
voc_parse_np(voccxdef * ctx)192 void voc_parse_np(voccxdef *ctx) { VARUSED(ctx); }
voc_parse_disambig(voccxdef * ctx)193 void voc_parse_disambig(voccxdef *ctx) { VARUSED(ctx); }
voc_parse_replace_cmd(voccxdef * ctx)194 void voc_parse_replace_cmd(voccxdef *ctx) { VARUSED(ctx); }
voc_push_objlist(voccxdef * ctx,objnum objlist[],int cnt)195 void voc_push_objlist(voccxdef *ctx, objnum objlist[], int cnt)
196 {
197 VARUSED(ctx);
198 VARUSED(objlist);
199 VARUSED(cnt);
200 }
201
202 /* more stub items for run-time */
203 FILE *scrfp;
204 int scrquiet;
205
qasgets(char * buf,int bufl)206 char *qasgets(char *buf, int bufl)
207 {
208 VARUSED(buf);
209 return((char *)0);
210 }
211
qasclose(void)212 void qasclose(void)
213 {
214 }
215
vocdusave_newobj(voccxdef * ctx,objnum objn)216 void vocdusave_newobj(voccxdef *ctx, objnum objn) {}
vocdusave_delobj(voccxdef * ctx,objnum objn)217 void vocdusave_delobj(voccxdef *ctx, objnum objn) {}
vocdusave_addwrd(voccxdef * ctx,objnum objn,prpnum typ,int flags,char * wrd)218 void vocdusave_addwrd(voccxdef *ctx, objnum objn, prpnum typ, int flags,
219 char *wrd) {}
vocdusave_delwrd(voccxdef * ctx,objnum objn,prpnum typ,int flags,char * wrd)220 void vocdusave_delwrd(voccxdef *ctx, objnum objn, prpnum typ, int flags,
221 char *wrd) {}
vocdusave_me(voccxdef * ctx,objnum old_me)222 void vocdusave_me(voccxdef *ctx, objnum old_me) {}
223
224 /*
225 * dummy runstat - we have no status line when running preinit under the
226 * compiler, so this doesn't need to do anything
227 */
runstat(void)228 void runstat(void)
229 {
230 }
231
232 /* printf-style formatting */
tcdptf(const char * fmt,...)233 static void tcdptf(const char *fmt, ...)
234 {
235 char buf[256];
236 va_list va;
237
238 /* format the string */
239 va_start(va, fmt);
240 vsprintf(buf, fmt, va);
241 va_end(va);
242
243 /* print the formatted buffer */
244 os_printz(buf);
245 }
246
tcduspt(errcxdef * ec,int first,int last)247 static void tcduspt(errcxdef *ec, int first, int last)
248 {
249 int i;
250 char buf[128];
251
252 for (i = first ; i <= last ; ++i)
253 {
254 errmsg(ec, buf, (uint)sizeof(buf), i);
255 tcdptf("%s\n", buf);
256 }
257 }
258
tcdtogusage(errcxdef * ec)259 static void tcdtogusage(errcxdef *ec)
260 {
261 tcduspt(ec, ERR_TCTGUS1, ERR_TCTGUSL);
262 }
263
tcdusage(errcxdef * ec)264 static void tcdusage(errcxdef *ec)
265 {
266 tcduspt(ec, ERR_TCUS1, ERR_TCUSL);
267 tcdtogusage(ec);
268 errsig(ec, ERR_USAGE);
269 }
270
tcdzusage(errcxdef * ec)271 static void tcdzusage(errcxdef *ec)
272 {
273 tcduspt(ec, ERR_TCZUS1, ERR_TCZUSL);
274 tcdtogusage(ec);
275 errsig(ec, ERR_USAGE);
276 }
277
tcd1usage(errcxdef * ec)278 static void tcd1usage(errcxdef *ec)
279 {
280 tcduspt(ec, ERR_TC1US1, ERR_TC1USL);
281 tcdtogusage(ec);
282 errsig(ec, ERR_USAGE);
283 }
284
tcdmusage(errcxdef * ec)285 static void tcdmusage(errcxdef *ec)
286 {
287 tcduspt(ec, ERR_TCMUS1, ERR_TCMUSL);
288 errsig(ec, ERR_USAGE);
289 }
290
tcdvusage(errcxdef * ec)291 static void tcdvusage(errcxdef *ec)
292 {
293 tcduspt(ec, ERR_TCVUS1, ERR_TCVUSL);
294 errsig(ec, ERR_USAGE);
295 }
296
297 /* context for tcdchkundef */
298 typedef struct tcdchkctx
299 {
300 mcmcxdef *mem;
301 errcxdef *ec;
302 int cnt;
303 } tcdchkctx;
304
305 /*
306 * Callback to check for undefined objects
307 */
tcdchkundef(void * ctx0,toksdef * t)308 static void tcdchkundef(void *ctx0, toksdef *t)
309 {
310 tcdchkctx *ctx = (tcdchkctx *)ctx0;
311 int err;
312
313 switch(t->tokstyp)
314 {
315 case TOKSTFWDOBJ:
316 /* undefined function */
317 err = ERR_UNDEFO;
318 goto log_the_error;
319
320 case TOKSTFWDFN:
321 /* undefined object */
322 err = ERR_UNDEFF;
323
324 log_the_error:
325 /* display the error */
326 sup_log_undefobj(ctx->mem, ctx->ec, err,
327 t->toksnam, (int)t->tokslen, (objnum)t->toksval);
328
329 /* count the symbol */
330 ++(ctx->cnt);
331 break;
332
333 default:
334 /* ignore defined objects */
335 break;
336 }
337 }
338
339
340 /*
341 * Error callback context
342 */
343 struct tcderrdef
344 {
345 FILE *tcderrfil; /* error logging file */
346 tokcxdef *tcderrtok; /* token parsing context */
347 int tcderrlvl; /* warning level */
348 int tcderrcnt; /* number of non-warning errors encountered */
349 int tcdwrncnt; /* number of warnings encountered */
350 int tcdfatal; /* a fatal error has occurred */
351 char tcdwrn_AMBIGBIN; /* warn on ERR_AMBIGBIN (-v-abin hides it) */
352 };
353 typedef struct tcderrdef tcderrdef;
354
355 /*
356 * Version string information. This information is used by both the
357 * pre-defined #define's that are set up by the compiler and by the
358 * version string display (keeping them common increases the likelihood
359 * that they'll remain in sync).
360 */
361 static char vsn_major[] = "2";
362 static char vsn_minor[] = "5";
363 static char vsn_maint[] = "9";
364
365
366 /*
367 * Default memory sizes, if previously defined
368 */
369 #ifndef TCD_SETTINGS_DEFINED
370 # define TCD_POOLSIZ (6 * 1024)
371 # define TCD_LCLSIZ 2048
372 # define TCD_HEAPSIZ 4096
373 # define TCD_STKSIZ 50
374 # define TCD_LABSIZ 1024
375 #endif
376
377 /* compiler main */
tcdmain1(errcxdef * ec,int argc,char * argv[],tcderrdef * errcbcx,char * save_ext)378 static void tcdmain1(errcxdef *ec, int argc, char *argv[], tcderrdef *errcbcx,
379 char *save_ext)
380 {
381 tokcxdef *tc;
382 prscxdef *pctx;
383 osfildef *swapfp = (osfildef *)0;
384 emtcxdef *ectx;
385 tokthdef symtab; /* hashed symbol table */
386 toktldef labtab; /* table for 'goto' labels */
387 runcxdef runctx;
388 bifcxdef bifctx;
389 uchar *labmem;
390 mcmon evalobj;
391 voccxdef vocctx;
392 void (*bif[100])(struct bifcxdef *, int);
393 mcmcxdef *mctx = 0;
394 mcmcx1def *globalctx;
395 objnum preinit;
396 dbgcxdef dbg;
397 supcxdef supctx;
398 int err;
399 char *swapname = 0;
400 char swapbuf[OSFNMAX];
401 char **argp;
402 char *arg;
403 char *outfile = (char *)0;
404 char *infile;
405 ulong swapsize = 0xffffffffL; /* allow unlimited swap space */
406 int pause = FALSE; /* TRUE if pause after compile/run */
407 int swapena = OS_DEFAULT_SWAP_ENABLED; /* swapping enabled? */
408 linfdef *noreg linf = 0; /* input file line source */
409 int i;
410 char inbuf[OSFNMAX];
411 char outbuf[OSFNMAX];
412 ulong cachelimit = 0xffffffffL;
413 int argchecking = TRUE; /* enable run-time arg checking */
414 int v1kw = FALSE; /* v1 keyword compatibility mode */
415 int v1else = FALSE; /* v1 'else' compat - ignore ';' after '}' */
416 int stats = FALSE; /* show statistics when done */
417 int symdeb = FALSE; /* generate source-level debug info */
418 int symdeb2 = FALSE; /* new-style source-level debug info */
419 int genoutput = TRUE; /* FALSE if output file is suppressed */
420 uint poolsiz = TCD_POOLSIZ; /* default space for parse node pool */
421 uint lclsiz = TCD_LCLSIZ; /* default space for local variables */
422 uint heapsiz = TCD_HEAPSIZ;
423 uint stksiz = TCD_STKSIZ;
424 uint labsiz = TCD_LABSIZ;
425 char *binout = (char *)0; /* precompiled header out */
426 char *binin = (char *)0; /* precompiled header in */
427 fiolcxdef fiolctx; /* load context */
428 noreg int loadopen = FALSE;
429 uint inflags;
430 char *do_kw = (char *)0; /* replacement keyword for "do" */
431 int warnlevel = 0; /* warning level */
432 char *filever = "*"; /* .GAM file compatibility setting */
433 int c_mode = FALSE; /* use C-style operators */
434 char *sym;
435 int symlen;
436 char *expan;
437 int explen;
438 static char vsn_major_nm[] = "__TADS_VERSION_MAJOR";
439 static char vsn_minor_nm[] = "__TADS_VERSION_MINOR";
440 static char sys_name[] = "__TADS_SYSTEM_NAME";
441 static char oem_name[] = "__TADS_OEM_NAME";
442 static char dbg_name[] = "__DEBUG";
443 static char date_name[] = "__DATE__";
444 static char time_name[] = "__TIME__";
445 static char line_name[] = "__LINE__";
446 static char file_name[] = "__FILE__";
447 static char si_sysinfo[] = "__SYSINFO_SYSINFO";
448 static char si_version[] = "__SYSINFO_VERSION";
449 static char si_osname[] = "__SYSINFO_OS_NAME";
450 static char si_html[] = "__SYSINFO_HTML";
451 static char si_jpeg[] = "__SYSINFO_JPEG";
452 static char si_png[] = "__SYSINFO_PNG";
453 static char si_wav[] = "__SYSINFO_WAV";
454 static char si_midi[] = "__SYSINFO_MIDI";
455 static char si_wav_midi_ovl[] = "__SYSINFO_WAV_MIDI_OVL";
456 static char si_wav_ovl[] = "__SYSINFO_WAV_OVL";
457 static char si_pref_images[] = "__SYSINFO_PREF_IMAGES";
458 static char si_pref_sounds[] = "__SYSINFO_PREF_SOUNDS";
459 static char si_pref_music[] = "__SYSINFO_PREF_MUSIC";
460 static char si_pref_links[] = "__SYSINFO_PREF_LINKS";
461 static char si_mpeg[] = "__SYSINFO_MPEG_AUDIO";
462 static char si_mpeg1[] = "__SYSINFO_MPEG_AUDIO_1";
463 static char si_mpeg2[] = "__SYSINFO_MPEG_AUDIO_2";
464 static char si_mpeg3[] = "__SYSINFO_MPEG_AUDIO_3";
465 static char si_htmlmode[] = "__SYSINFO_HTML_MODE";
466 static char si_links_http[] = "__SYSINFO_LINKS_HTTP";
467 static char si_links_ftp[] = "__SYSINFO_LINKS_FTP";
468 static char si_links_news[] = "__SYSINFO_LINKS_NEWS";
469 static char si_links_mailto[] = "__SYSINFO_LINKS_MAILTO";
470 static char si_links_telnet[] = "__SYSINFO_LINKS_TELNET";
471 static char si_png_trans[] = "__SYSINFO_PNG_TRANS";
472 static char si_png_alpha[] = "__SYSINFO_PNG_ALPHA";
473 static char si_ogg[] = "__SYSINFO_OGG";
474 static char si_mng[] = "__SYSINFO_MNG";
475 static char si_mng_trans[] = "__SYSINFO_MNG_TRANS";
476 static char si_mng_alpha[] = "__SYSINFO_MNG_ALPHA";
477 static char si_txtcol[] = "__SYSINFO_TEXT_COLORS";
478 static char si_txthi[] = "__SYSINFO_TEXT_HILITE";
479 static char si_banners[] = "__SYSINFO_BANNERS";
480 static char si_interp_class[] = "__SYSINFO_INTERP_CLASS";
481 static char si_ic_text[] = "__SYSINFO_ICLASS_TEXT";
482 static char si_ic_textgui[] = "__SYSINFO_ICLASS_TEXTGUI";
483 static char si_ic_html[] = "__SYSINFO_ICLASS_HTML";
484 time_t timer;
485 struct tm *tblock;
486 char *datetime;
487 char datebuf[15];
488 long totsize;
489 uchar *myheap;
490 runsdef *mystack;
491 char *strfile = 0; /* name of string capture file */
492 char *charmap = 0; /* character mapping file */
493 int checked_undefs = FALSE; /* checked for undefined symbols */
494
495 NOREG((&loadopen))
496 NOREG((&linf))
497
498 /* initialize the output formatter */
499 out_init();
500
501 /* initialize lexical analysis context */
502 tc = tokcxini(ec, (mcmcxdef *)0, supsctab);
503 tc->tokcxdbg = &dbg;
504 ec->errcxlgc = errcbcx;
505 errcbcx->tcderrfil = 0; /* no error capture file yet */
506 errcbcx->tcderrtok = tc; /* to allow error logger to figure file/line */
507 errcbcx->tcderrlvl = 0; /* presume a warning level of 0 */
508
509 /* add current directory as first entry in include path */
510 tokaddinc(tc, "", 0);
511
512 /* parse arguments */
513 for (i = 1, argp = argv + 1 ; i < argc ; ++argp, ++i)
514 {
515 arg = *argp;
516 if (*arg == '-')
517 {
518 switch(*(arg+1))
519 {
520 case 'D':
521 /* get the symbol */
522 sym = cmdarg(ec, &argp, &i, argc, 1, tcdusage);
523
524 /* look to see if there's a '=' specifying the expansion */
525 for (expan = sym ; *expan && *expan != '=' ; ++expan) ;
526
527 /* provide a default expansion of "1" if none was provided */
528 if (*expan == '\0')
529 {
530 expan = "1";
531 symlen = strlen(sym);
532 }
533 else
534 {
535 symlen = expan - sym;
536 ++expan;
537 }
538 explen = strlen(expan);
539
540 /* add the symbol */
541 tok_add_define_cvtcase(tc, sym, symlen, expan, explen);
542 break;
543
544 case 'U':
545 /* get the symbol and undefine it */
546 sym = cmdarg(ec, &argp, &i, argc, 1, tcdusage);
547 symlen = strlen(sym);
548 tok_del_define(tc, sym, symlen);
549 break;
550
551 case 'C':
552 c_mode = cmdtog(ec, c_mode, arg, 1, tcdusage);
553 break;
554
555 case 'c':
556 {
557 int case_sensitive;
558
559 if (strlen(arg+1) >= 4
560 && !memcmp(arg+1, "case", (size_t)4))
561 {
562 case_sensitive =
563 cmdtog(ec, (tc->tokcxflg & TOKCXCASEFOLD) == 0,
564 arg, 4, tcdusage);
565 if (case_sensitive)
566 tc->tokcxflg &= ~TOKCXCASEFOLD;
567 else
568 tc->tokcxflg |= TOKCXCASEFOLD;
569 }
570 else if (!strcmp(arg+1, "ctab"))
571 {
572 /* get the character mapping table */
573 charmap = cmdarg(ec, &argp, &i, argc, 4, tcdusage);
574 }
575 else
576 tcdusage(ec);
577 break;
578 }
579
580 case 'e': /* error capture file */
581 {
582 char *errfname;
583 errfname = cmdarg(ec, &argp, &i, argc, 1, tcdusage);
584 if (!(errcbcx->tcderrfil = fopen(errfname, "w")))
585 errsig(ec, ERR_ERRFIL);
586 break;
587 }
588
589 case 'd':
590 if (arg[2] == 's')
591 {
592 if (arg[3] == '2')
593 {
594 /* new-style - turn on symdeb2 as well as symdeb */
595 symdeb2 = cmdtog(ec, symdeb, arg, 3, tcdusage);
596 symdeb = symdeb2;
597 }
598 else
599 {
600 /* old-style - turn on only symdeb */
601 symdeb = cmdtog(ec, symdeb, arg, 2, tcdusage);
602 }
603 }
604 else
605 tcdusage(ec);
606 break;
607
608 case 'm':
609 switch(*(arg+2))
610 {
611 case '?':
612 tcdmusage(ec);
613
614 case 'g':
615 labsiz = atoi(cmdarg(ec, &argp, &i, argc, 2, tcdusage));
616 break;
617
618 case 'p':
619 poolsiz = atoi(cmdarg(ec, &argp, &i, argc, 2, tcdusage));
620 break;
621
622 case 'l':
623 lclsiz = atoi(cmdarg(ec, &argp, &i, argc, 2, tcdusage));
624 break;
625
626 case 's':
627 stksiz = atoi(cmdarg(ec, &argp, &i, argc, 2, tcdusage));
628 break;
629
630 case 'h':
631 heapsiz = atoi(cmdarg(ec, &argp, &i, argc, 2, tcdusage));
632 break;
633
634 default:
635 cachelimit = atol(cmdarg(ec, &argp, &i, argc,
636 1, tcdusage));
637 break;
638 }
639 break;
640
641 case 'o':
642 if (arg[2] == '-')
643 genoutput = FALSE;
644 else
645 outfile = cmdarg(ec, &argp, &i, argc, 1, tcdusage);
646 break;
647
648 case 's':
649 stats = cmdtog(ec, stats, arg, 1, tcdusage);
650 break;
651
652 case 't':
653 /* swap file options: -tf file, -ts size, -t- (no swap) */
654 switch(*(arg+2))
655 {
656 case 'f':
657 swapname = cmdarg(ec, &argp, &i, argc, 2, tcdusage);
658 break;
659
660 case 's':
661 swapsize = atol(cmdarg(ec, &argp, &i, argc, 2, tcdusage));
662 break;
663
664 default:
665 swapena = cmdtog(ec, swapena, arg, 1, tcdusage);
666 break;
667 }
668 break;
669
670 case 'i':
671 {
672 char *path = cmdarg(ec, &argp, &i, argc, 1, tcdusage);
673 tokaddinc(tc, path, (int)strlen(path));
674 break;
675 }
676
677 case 'l':
678 binin = cmdarg(ec, &argp, &i, argc, 1, tcdusage);
679 break;
680
681 case 'p':
682 pause = cmdtog(ec, pause, arg, 1, tcdusage);
683 break;
684
685 case 'w':
686 binout = cmdarg(ec, &argp, &i, argc, 1, tcdusage);
687 break;
688
689 case 'f':
690 switch(arg[2])
691 {
692 case 'v': /* file version */
693 filever = cmdarg(ec, &argp, &i, argc, 2, tcdusage);
694 if (filever[1] != '\0' ||
695 (*filever != 'a' && *filever != 'b' &&
696 *filever != 'c' && *filever != '*'))
697 tcdusage(ec);
698 break;
699
700 default:
701 tcdusage(ec);
702 }
703 break;
704
705 case 'F':
706 switch(arg[2])
707 {
708 case 's':
709 strfile = cmdarg(ec, &argp, &i, argc, 2, tcdusage);
710 break;
711
712 default:
713 tcdusage(ec);
714 }
715 break;
716
717 case '1':
718 switch(arg[2])
719 {
720 case '?':
721 tcd1usage(ec);
722
723 case 'k':
724 v1kw = cmdtog(ec, v1kw, arg, 2, tcdusage);
725 break;
726
727 case 'e':
728 v1else = cmdtog(ec, v1else, arg, 2, tcdusage);
729 break;
730
731 case 'a':
732 argchecking = cmdtog(ec, argchecking, arg, 2, tcdusage);
733 break;
734
735 case 'd':
736 do_kw = cmdarg(ec, &argp, &i, argc, 2, tcdusage);
737 break;
738
739 case '\0':
740 /* no suboption - invert all v1 options */
741 argchecking = !argchecking;
742 v1else = !v1else;
743 v1kw = !v1kw;
744 break;
745
746 default:
747 tcdusage(ec);
748 }
749 break;
750
751 case 'v': /* verbosity (warning) level */
752 {
753 char *p;
754
755 /* get the argument, and see what we have */
756 p = cmdarg(ec, &argp, &i, argc, 1, tcdusage);
757 if (isdigit((uchar)*p))
758 {
759 /* it's a numeric warning verbosity level */
760 warnlevel = atoi(p);
761 errcbcx->tcderrlvl = warnlevel;
762 }
763 else if (*p == '-' || *p == '+')
764 {
765 if (!strcmp(p+1, "abin"))
766 errcbcx->tcdwrn_AMBIGBIN = (*p == '+');
767 else
768 tcdvusage(ec);
769 }
770 else if (*p == '?')
771 tcdvusage(ec);
772 else
773 tcdusage(ec);
774 }
775 break;
776
777 case 'Z':
778 switch(arg[2])
779 {
780 case '?':
781 tcdzusage(ec);
782
783 case 'a':
784 argchecking = cmdtog(ec, argchecking, arg, 2, tcdusage);
785 break;
786
787 default:
788 tcdusage(ec);
789 }
790 break;
791
792 default:
793 tcdusage(ec);
794 }
795 }
796 else break;
797 }
798
799 /* load the character map */
800 if (cmap_load(charmap))
801 errsig(ec, ERR_INVCMAP);
802
803 /*
804 * Add built-in #define's for the system ID. We add a symbol named
805 * TADS_SYSTEM_NAME defined to an appropriate single-quoted string
806 * for the system, and we also add a #define of the same name as the
807 * expansion of TADS_SYSTEM_NAME and give it the value 1, for
808 * testing in #ifdef's.
809 */
810 {
811 char buf[40];
812
813 sprintf(buf, "'%s'", OS_SYSTEM_NAME);
814 tok_add_define_cvtcase(tc, sys_name, (int)sizeof(sys_name) - 1,
815 buf, (int)strlen(buf));
816 }
817 tok_add_define_cvtcase(tc, OS_SYSTEM_NAME, (int)strlen(OS_SYSTEM_NAME),
818 "1", 1);
819
820 /* add built-in #define's for major and minor version numbers */
821 tok_add_define_cvtcase(tc, vsn_major_nm, (int)sizeof(vsn_major_nm) - 1,
822 vsn_major, (int)sizeof(vsn_major) - 1);
823 tok_add_define_cvtcase(tc, vsn_minor_nm, (int)sizeof(vsn_minor_nm) - 1,
824 vsn_minor, (int)sizeof(vsn_minor) - 1);
825
826 /* add built-in #define for OEM name */
827 {
828 char buf[256];
829
830 sprintf(buf, "'%s'", TADS_OEM_NAME);
831 tok_add_define_cvtcase(tc, oem_name, (int)sizeof(oem_name) - 1,
832 buf, (int)strlen(buf));
833 }
834
835 /* get the current time and date */
836 timer = time(NULL);
837 tblock = localtime(&timer);
838 datetime = asctime(tblock);
839
840 /* build the __DATE__ definition, of the form 'Jan 01 1994' */
841 datebuf[0] = '\'';
842 memcpy(datebuf + 1, datetime + 4, (size_t)7);
843 memcpy(datebuf + 8, datetime + 20, (size_t)4);
844 datebuf[12] = '\'';
845 tok_add_define_cvtcase(tc, date_name, (int)sizeof(date_name) - 1,
846 datebuf, 13);
847
848 /* build the __TIME__ definition, of the form '01:23:45' */
849 memcpy(datebuf + 1, datetime + 11, (size_t)8);
850 datebuf[9] = '\'';
851 tok_add_define_cvtcase(tc, time_name, (int)sizeof(time_name)-1,
852 datebuf, 10);
853
854 /*
855 * add placeholders for __FILE__ and __LINE__ -- the actual
856 * definitions of these will be filled in dynamically whenever they
857 * are needed
858 */
859 tok_add_define_cvtcase(tc, file_name, (int)sizeof(file_name) - 1,
860 inbuf, OSFNMAX);
861 tok_add_define_cvtcase(tc, line_name, (int)sizeof(line_name) - 1,
862 inbuf, 40);
863
864 /*
865 * add the SYSINFO codes
866 */
867 tok_add_define_num_cvtcase(tc, si_sysinfo, (int)sizeof(si_sysinfo) - 1,
868 SYSINFO_SYSINFO);
869 tok_add_define_num_cvtcase(tc, si_version, (int)sizeof(si_version) - 1,
870 SYSINFO_VERSION);
871 tok_add_define_num_cvtcase(tc, si_osname, (int)sizeof(si_osname) - 1,
872 SYSINFO_OS_NAME);
873 tok_add_define_num_cvtcase(tc, si_html, (int)sizeof(si_html) - 1,
874 SYSINFO_HTML);
875 tok_add_define_num_cvtcase(tc, si_jpeg, (int)sizeof(si_jpeg) - 1,
876 SYSINFO_JPEG);
877 tok_add_define_num_cvtcase(tc, si_png, (int)sizeof(si_png) - 1,
878 SYSINFO_PNG);
879 tok_add_define_num_cvtcase(tc, si_wav, (int)sizeof(si_wav) - 1,
880 SYSINFO_WAV);
881 tok_add_define_num_cvtcase(tc, si_midi, (int)sizeof(si_midi) - 1,
882 SYSINFO_MIDI);
883 tok_add_define_num_cvtcase(tc, si_wav_midi_ovl,
884 (int)sizeof(si_wav_midi_ovl) - 1,
885 SYSINFO_WAV_MIDI_OVL);
886 tok_add_define_num_cvtcase(tc, si_wav_ovl, (int)sizeof(si_wav_ovl) - 1,
887 SYSINFO_WAV_OVL);
888 tok_add_define_num_cvtcase(tc, si_pref_images,
889 (int)sizeof(si_pref_images) - 1,
890 SYSINFO_PREF_IMAGES);
891 tok_add_define_num_cvtcase(tc, si_pref_sounds,
892 (int)sizeof(si_pref_sounds) - 1,
893 SYSINFO_PREF_SOUNDS);
894 tok_add_define_num_cvtcase(tc, si_pref_music,
895 (int)sizeof(si_pref_music) - 1,
896 SYSINFO_PREF_MUSIC);
897 tok_add_define_num_cvtcase(tc, si_pref_links,
898 (int)sizeof(si_pref_links) - 1,
899 SYSINFO_PREF_LINKS);
900 tok_add_define_num_cvtcase(tc, si_mpeg, (int)sizeof(si_mpeg) - 1,
901 SYSINFO_MPEG);
902 tok_add_define_num_cvtcase(tc, si_mpeg1, (int)sizeof(si_mpeg1) - 1,
903 SYSINFO_MPEG1);
904 tok_add_define_num_cvtcase(tc, si_mpeg2, (int)sizeof(si_mpeg2) - 1,
905 SYSINFO_MPEG2);
906 tok_add_define_num_cvtcase(tc, si_mpeg3, (int)sizeof(si_mpeg3) - 1,
907 SYSINFO_MPEG3);
908 tok_add_define_num_cvtcase(tc, si_htmlmode, (int)sizeof(si_htmlmode) - 1,
909 SYSINFO_HTML_MODE);
910 tok_add_define_num_cvtcase(tc, si_links_http,
911 (int)sizeof(si_links_http) - 1,
912 SYSINFO_LINKS_HTTP);
913 tok_add_define_num_cvtcase(tc, si_links_ftp,
914 (int)sizeof(si_links_ftp) - 1,
915 SYSINFO_LINKS_FTP);
916 tok_add_define_num_cvtcase(tc, si_links_news,
917 (int)sizeof(si_links_news) - 1,
918 SYSINFO_LINKS_NEWS);
919 tok_add_define_num_cvtcase(tc, si_links_mailto,
920 (int)sizeof(si_links_mailto) - 1,
921 SYSINFO_LINKS_MAILTO);
922 tok_add_define_num_cvtcase(tc, si_links_telnet,
923 (int)sizeof(si_links_telnet) - 1,
924 SYSINFO_LINKS_TELNET);
925 tok_add_define_num_cvtcase(tc, si_png_trans,
926 (int)sizeof(si_png_trans) - 1,
927 SYSINFO_PNG_TRANS);
928 tok_add_define_num_cvtcase(tc, si_png_alpha,
929 (int)sizeof(si_png_alpha) - 1,
930 SYSINFO_PNG_ALPHA);
931 tok_add_define_num_cvtcase(tc, si_ogg, (int)sizeof(si_ogg) - 1,
932 SYSINFO_OGG);
933 tok_add_define_num_cvtcase(tc, si_mng, (int)sizeof(si_mng) - 1,
934 SYSINFO_MNG);
935 tok_add_define_num_cvtcase(tc, si_mng_trans,
936 (int)sizeof(si_mng_trans) - 1,
937 SYSINFO_MNG_TRANS);
938 tok_add_define_num_cvtcase(tc, si_mng_alpha,
939 (int)sizeof(si_mng_alpha) - 1,
940 SYSINFO_MNG_ALPHA);
941 tok_add_define_num_cvtcase(tc, si_txthi, (int)sizeof(si_txthi) - 1,
942 SYSINFO_TEXT_HILITE);
943 tok_add_define_num_cvtcase(tc, si_txtcol, (int)sizeof(si_txtcol) - 1,
944 SYSINFO_TEXT_COLORS);
945 tok_add_define_num_cvtcase(tc, si_banners, (int)sizeof(si_banners) - 1,
946 SYSINFO_BANNERS);
947 tok_add_define_num_cvtcase(tc, si_interp_class,
948 (int)sizeof(si_interp_class) - 1,
949 SYSINFO_INTERP_CLASS);
950 tok_add_define_num_cvtcase(tc, si_ic_text,
951 (int)sizeof(si_ic_text) - 1,
952 SYSINFO_ICLASS_TEXT);
953 tok_add_define_num_cvtcase(tc, si_ic_textgui,
954 (int)sizeof(si_ic_textgui) - 1,
955 SYSINFO_ICLASS_TEXTGUI);
956 tok_add_define_num_cvtcase(tc, si_ic_html,
957 (int)sizeof(si_ic_html) - 1,
958 SYSINFO_ICLASS_HTML);
959
960 /* turn on the __DEBUG symbol if debugging is on */
961 if (symdeb)
962 tok_add_define_cvtcase(tc, dbg_name,
963 (int)(sizeof(dbg_name) - 1), "1", 1);
964
965 /* get input name argument, and make sure it's the last argument */
966 if (i == argc) tcdusage(ec);
967 infile = *argp;
968 if (i + 1 != argc) tcdusage(ec);
969
970 /* add default .T extension to input file */
971 strcpy(inbuf, infile);
972 os_defext(inbuf, "t");
973
974 /*
975 * if no output file is specified, use input file minus extension
976 * plus GAM extension; otherwise, use specified output file
977 */
978 if (outfile)
979 {
980 /* use their name exactly as-is */
981 strcpy(outbuf, outfile);
982
983 /* if it's exactly the same as the input file, apply an extension */
984 if (!strcmp(outfile, infile))
985 {
986 os_remext(outbuf);
987 os_addext(outbuf, "gam");
988 }
989 }
990 else
991 {
992 /* get the input name minus the current extension */
993 strcpy(outbuf, infile);
994 os_remext(outbuf);
995
996 /* add .GAM extension */
997 os_addext(outbuf, "gam");
998 }
999
1000 /* set input/output file pointers to refer to generated filenames */
1001 infile = inbuf;
1002 outfile = outbuf;
1003
1004 /* echo information to error logging file if present */
1005 if (errcbcx->tcderrfil)
1006 {
1007 time_t t;
1008
1009 t = time(NULL);
1010 fprintf(errcbcx->tcderrfil, "TADS Compilation of %s\n%s\n",
1011 infile, ctime(&t));
1012 }
1013
1014 /* open up the swap file */
1015 if (swapena && swapsize)
1016 {
1017 swapfp = os_create_tempfile(swapname, swapbuf);
1018 if (swapname == 0) swapname = swapbuf;
1019 if (swapfp == 0) errsig(ec, ERR_OPSWAP);
1020 }
1021
1022 ERRBEGIN(ec)
1023
1024 /* initialize cache manager context */
1025 globalctx = mcmini(cachelimit, 128, swapsize, swapfp, 0, ec);
1026 mctx = mcmcini(globalctx, 128, fioldobj, &fiolctx,
1027 (void (*)(void *, mcmon))objrevert, (void *)0);
1028 mctx->mcmcxrvc = mctx;
1029
1030 tc->tokcxmem = mctx;
1031
1032 /* allocate and initialize parsing context */
1033
1034 totsize = sizeof(prscxdef) + (long)poolsiz + (long)lclsiz;
1035 if (totsize != (ushort)totsize)
1036 errsig1(ec, ERR_PRSCXSIZ, ERRTINT, (int)(65535 - sizeof(prscxdef)));
1037 pctx = (prscxdef *)mchalo(ec, (ushort)totsize, "tcdmain");
1038 pctx->prscxerr = ec;
1039 pctx->prscxtok = tc;
1040 pctx->prscxmem = mctx;
1041 pctx->prscxprp = 0;
1042 pctx->prscxext = 0;
1043 pctx->prscxnsiz = pctx->prscxrrst = poolsiz;
1044 pctx->prscxnrst = pctx->prscxpool;
1045 pctx->prscxplcl = &pctx->prscxpool[poolsiz];
1046 pctx->prscxslcl = lclsiz;
1047 pctx->prscxflg = 0;
1048 pctx->prscxnode = &pctx->prscxpool[0];
1049 pctx->prscxgtab = (toktdef *)&labtab;
1050 pctx->prscxvoc = &vocctx;
1051 pctx->prscxcpp = (char *)0;
1052 pctx->prscxcps = 0;
1053 pctx->prscxcpf = 0;
1054 pctx->prscxspp = (char *)0;
1055 pctx->prscxspf = 0;
1056 pctx->prscxsps = 0;
1057 pctx->prscxfsp = (uchar *)0;
1058 pctx->prscxfsf = 0;
1059 pctx->prscxfss = 0;
1060 pctx->prscxextc = 0;
1061
1062 /* open the strings file, if one was specified */
1063 if (strfile != 0)
1064 {
1065 /* open the file */
1066 pctx->prscxstrfile = osfopwt(strfile, OSFTTEXT);
1067
1068 /* complain if we couldn't open it */
1069 if (pctx->prscxstrfile == 0)
1070 errsig(ec, ERR_OPNSTRFIL);
1071 }
1072 else
1073 pctx->prscxstrfile = 0;
1074
1075 /* set up flags */
1076 if (argchecking) pctx->prscxflg |= PRSCXFARC;
1077 if (symdeb) pctx->prscxflg |= (PRSCXFLIN | PRSCXFLCL);
1078 if (symdeb2) pctx->prscxflg |= (PRSCXFLIN2 | PRSCXFLCL);
1079 if (v1else) pctx->prscxflg |= PRSCXFV1E;
1080 if (c_mode) tc->tokcxflg |= TOKCXFCMODE;
1081 if (symdeb2) tc->tokcxflg |= TOKCXFLIN2;
1082 if (*filever != '*' && *filever < 'c') pctx->prscxflg |= PRSCXFTPL1;
1083
1084 /* set up vocabulary context */
1085 vocini(&vocctx, ec, mctx, &runctx, (objucxdef *)0, 50, 50, 100);
1086 vocctx.voccxflg |= VOCCXFVWARN;
1087
1088 /* allocate stack and heap */
1089 totsize = (ulong)stksiz * (ulong)sizeof(runsdef);
1090 if (totsize != (ushort)totsize)
1091 errsig1(ec, ERR_STKSIZE, ERRTINT, (uint)(65535/sizeof(runsdef)));
1092 mystack = (runsdef *)mchalo(ec, (ushort)totsize, "runtime stack");
1093 myheap = mchalo(ec, (ushort)heapsiz, "runtime heap");
1094
1095 /* set up linear symbol table for 'goto' labels */
1096 labmem = mchalo(ec, (ushort)labsiz, "main1");
1097 toktlini(ec, &labtab, labmem, labsiz);
1098 labtab.toktlsc.toktnxt = (toktdef *)&symtab; /* 2nd to last table */
1099
1100 /* set up to read from input file */
1101 tc->tokcxsst = (ushort (*)(void *))prsxsst;
1102 tc->tokcxsad = (void (*)(void *, char *, ushort))prsxsad;
1103 tc->tokcxsend = (void (*)(void *))prsxsend;
1104 tc->tokcxscx = (void *)pctx;
1105
1106 /* set up debug context */
1107 dbg.dbgcxtio = (tiocxdef *)0;
1108 dbg.dbgcxtab = &symtab;
1109 dbg.dbgcxmem = mctx;
1110 dbg.dbgcxerr = ec;
1111 dbg.dbgcxfcn = 0;
1112 dbg.dbgcxdep = 0;
1113 dbg.dbgcxfid = 0; /* start file serial numbers at zero */
1114 dbg.dbgcxflg = 0;
1115
1116 vocctx.voccxrun = &runctx;
1117 runctx.runcxdbg = &dbg;
1118 dbg.dbgcxtab = &symtab;
1119
1120 /* initialize a file line source for the input file */
1121 if (!(linf = linfini(mctx, ec, infile, (int)strlen(infile),
1122 (tokpdef *)0, TRUE, symdeb2)))
1123 errsig(ec, ERR_OPNINP);
1124
1125 linf->linflin.linpar = (lindef *)0;
1126 dbg.dbgcxlin = &linf->linflin; /* source file is start of line chain */
1127 tc->tokcxhdr = (linfdef *)&linf->linflin;
1128
1129 /* set up debug line source chain with just this record */
1130 tc->tokcxlin = &linf->linflin;
1131 linf->linflin.linid = dbg.dbgcxfid++;
1132 linf->linflin.linnxt = (lindef *)0;
1133
1134 /* set up a hashed symbol table */
1135 tokthini(ec, mctx, (toktdef *)&symtab);
1136 pctx->prscxstab = (toktdef *)&symtab; /* add symbols here */
1137 /*was: tc->tokcxstab = (toktdef *)&labtab; */
1138 tc->tokcxstab = (toktdef *)&symtab; /* search for symbols here */
1139
1140 /* allocate a code generator context */
1141 ectx = (emtcxdef *)mchalo(ec,
1142 (ushort)(sizeof(emtcxdef) + 511*sizeof(emtldef)),
1143 "tcdmain");
1144 ectx->emtcxerr = ec;
1145 ectx->emtcxmem = pctx->prscxmem;
1146 ectx->emtcxptr = 0; /* mcmalo(pctx->prscxmem, 1024, &ectx->emtcxobj); */
1147 ectx->emtcxlcnt = 512;
1148 ectx->emtcxfrob = MCMONINV; /* not using debugger frame locals */
1149 emtlini(ectx);
1150
1151 /* add code generator context to parser context */
1152 pctx->prscxemt = ectx;
1153
1154 /* set up execution context */
1155 runctx.runcxerr = ec;
1156 runctx.runcxmem = pctx->prscxmem;
1157 runctx.runcxstk = mystack;
1158 runctx.runcxstop = &mystack[stksiz];
1159 runctx.runcxsp = mystack;
1160 runctx.runcxbp = mystack;
1161 runctx.runcxheap = myheap;
1162 runctx.runcxhp = myheap;
1163 runctx.runcxhtop = &myheap[heapsiz];
1164 runctx.runcxundo = (objucxdef *)0;
1165 runctx.runcxbcx = &bifctx;
1166 runctx.runcxbi = bif;
1167 runctx.runcxtio = (tiocxdef *)0;
1168 runctx.runcxdbg = &dbg;
1169 runctx.runcxvoc = &vocctx;
1170 runctx.runcxdmd = (void (*)(void *, objnum, prpnum))supcont;
1171 runctx.runcxdmc = &supctx;
1172
1173 /* set up setup context */
1174 supctx.supcxerr = ec;
1175 supctx.supcxmem = mctx;
1176 supctx.supcxtab = &symtab;
1177 supctx.supcxbuf = (uchar *)0;
1178 supctx.supcxlen = 0;
1179 supctx.supcxvoc = &vocctx;
1180 supctx.supcxrun = &runctx;
1181
1182 /* set up built-in function context */
1183 CLRSTRUCT(bifctx);
1184 bifctx.bifcxerr = ec;
1185 bifctx.bifcxrun = &runctx;
1186 bifctx.bifcxtio = (tiocxdef *)0;
1187 bifctx.bifcxsavext = save_ext;
1188
1189 /* allocate object for expression code generation */
1190 mcmalo(pctx->prscxmem, (ushort)1024, &evalobj);
1191 mcmunlck(pctx->prscxmem, evalobj);
1192
1193 /* add vocabulary properties */
1194 pctx->prscxprp = PRP_LASTRSV + 1;
1195
1196 /* add the built-in functions, keywords, etc */
1197 suprsrv(&supctx, bif, (toktdef *)&symtab,
1198 (int)(sizeof(bif)/sizeof(bif[0])), v1kw, do_kw,
1199 tc->tokcxflg & TOKCXCASEFOLD);
1200
1201 /* load pre-compiled header file if one was specified */
1202 if (binin)
1203 {
1204 dbg.dbgcxfid--; /* reset the line id counter */
1205
1206 fiord(mctx, &vocctx, tc, binin, (char *)0, &fiolctx, &preinit,
1207 &inflags, tc->tokcxinc,
1208 &pctx->prscxfsp, &pctx->prscxfsf, &pctx->prscxprp, FALSE, 0,
1209 argv[0]);
1210 tc->tokcxhdr = (linfdef *)dbg.dbgcxlin;
1211 pctx->prscxfss = pctx->prscxfsf;
1212 pctx->prscxcpp = vocctx.voccxcpp;
1213 pctx->prscxcps =
1214 pctx->prscxcpf = vocctx.voccxcpl;
1215 pctx->prscxspp = vocctx.voccxspp;
1216 pctx->prscxsps =
1217 pctx->prscxspf = vocctx.voccxspl;
1218 loadopen = TRUE;
1219
1220 linf->linflin.linid = dbg.dbgcxfid++; /* get new line id for source */
1221
1222 /* use same case sensitivity as original compilation */
1223 if (inflags & FIOFCASE)
1224 tc->tokcxflg |= TOKCXCASEFOLD;
1225 else
1226 tc->tokcxflg &= ~TOKCXCASEFOLD;
1227
1228 /*
1229 * run through the arguments again, and remove any preprocessor
1230 * symbols loaded from the file that have been explicitly
1231 * undefined with -U in this run
1232 */
1233 for (i = 1, argp = argv + 1 ; i < argc ; ++argp, ++i)
1234 {
1235 arg = *argp;
1236 if (*arg == '-')
1237 {
1238 switch(*(arg+1))
1239 {
1240 case 'U':
1241 /* get the symbol and undefine it */
1242 sym = cmdarg(ec, &argp, &i, argc, 1, tcdusage);
1243 symlen = strlen(sym);
1244 tok_del_define(tc, sym, symlen);
1245 break;
1246
1247 default:
1248 /* ignore all other arguments on this pass */
1249 break;
1250 }
1251 }
1252 }
1253
1254 }
1255
1256 /* get the first token */
1257 prsrstn(pctx);
1258 toknext(tc);
1259
1260 /* parse the entire file, stopping when we encounter EOF */
1261 parse_loop:
1262 ERRBEGIN(ec)
1263 for ( ;; )
1264 {
1265 /* reset emit settings */
1266 ectx->emtcxofs = 0;
1267
1268 /* generate progress report */
1269 os_progress(((linfdef *)tc->tokcxlin)->linfnam,
1270 ((linfdef *)tc->tokcxlin)->linfnum);
1271
1272 /* cooperatively multitask if necessary, and check for interrupt */
1273 if (os_yield())
1274 errsig(ec, ERR_USRINT);
1275
1276 /* stop on a fatal error */
1277 if (errcbcx->tcdfatal)
1278 break;
1279
1280 /* stop on end of file */
1281 if (tc->tokcxcur.toktyp == TOKTEOF)
1282 break;
1283
1284 /* parse the next object or function definition */
1285 prscode(pctx, TRUE);
1286 }
1287 ERRCATCH(ec, err)
1288 if (err >= 100 && err < 450)
1289 {
1290 int brace_cnt;
1291 int paren_cnt;
1292
1293 /*
1294 * This is some kind of syntax error, which means we can
1295 * keep going. Log the error, throw away tokens up to the
1296 * next semicolon, then try to start again.
1297 */
1298 errclog(ec);
1299 for (brace_cnt = paren_cnt = 0 ;; )
1300 {
1301 switch(tc->tokcxcur.toktyp)
1302 {
1303 case TOKTSEM:
1304 /* if within braces, keep going */
1305 if (brace_cnt || paren_cnt)
1306 break;
1307
1308 /* FALLTHROUGH */
1309 case TOKTEOF:
1310 toknext(tc);
1311 goto parse_loop;
1312
1313 case TOKTLBRACE:
1314 /* count the brace, and clear the paren count */
1315 ++brace_cnt;
1316 paren_cnt = 0;
1317 break;
1318
1319 case TOKTRBRACE:
1320 /* uncount the brace, and clear the paren count */
1321 paren_cnt = 0;
1322 if (brace_cnt)
1323 --brace_cnt;
1324 break;
1325
1326 case TOKTLPAR:
1327 ++paren_cnt;
1328 break;
1329
1330 case TOKTRPAR:
1331 --paren_cnt;
1332 break;
1333 }
1334
1335 /* skip the token */
1336 toknext(tc);
1337 }
1338 }
1339
1340 /* can't deal with this error - resignal it */
1341 errrse(ec);
1342 ERREND(ec)
1343
1344 /* set up vocab context with format string information */
1345 vocctx.voccxcpp = pctx->prscxcpp;
1346 vocctx.voccxcpl = pctx->prscxcpf;
1347
1348 /* likewise the special word information */
1349 vocctx.voccxspp = pctx->prscxspp;
1350 vocctx.voccxspl = pctx->prscxspf;
1351
1352 if (!binout && !errcbcx->tcdfatal)
1353 {
1354 tcdchkctx cbctx;
1355
1356 /* apply TADS/Graphic external resources */
1357 tcgcomp(ec, pctx, infile);
1358
1359 /* tell output subsystem about format strings */
1360 tiosetfmt((tiocxdef *)0, &runctx, pctx->prscxfsp,
1361 (uint)pctx->prscxfsf);
1362
1363 /* get required object definitions if not precompiling headers */
1364 supfind(ec, &symtab, &vocctx, &preinit, warnlevel,
1365 tc->tokcxflg & TOKCXCASEFOLD);
1366
1367 /*
1368 * inherit vocabulary - do this before calling preinit, to ensure
1369 * that preinit sees the same inherited location and vocabulary
1370 * data that would be seen during normal execution
1371 */
1372 supivoc(&supctx);
1373
1374 /* check for undefined objects before running preinit */
1375 cbctx.mem = mctx;
1376 cbctx.ec = ec;
1377 cbctx.cnt = 0;
1378 toktheach(&symtab.tokthsc, tcdchkundef, &cbctx);
1379 checked_undefs = TRUE;
1380
1381 /*
1382 * run preinit function if it's defined, and we're not generating
1383 * debug output, and there have been no errors so far
1384 */
1385 if (preinit != MCMONINV && !symdeb
1386 && errcbcx->tcderrcnt == 0 && errcbcx->tcdfatal == 0)
1387 runfn(&runctx, preinit, 0);
1388 }
1389
1390 if (binout && errcbcx->tcderrcnt == 0)
1391 {
1392 fiowrt(mctx, &vocctx, tc, &symtab, pctx->prscxfsp,
1393 (uint)pctx->prscxfsf,
1394 binout, FIOFSYM + FIOFLIN + FIOFPRE + FIOFBIN
1395 + (tc->tokcxflg & TOKCXCASEFOLD ? FIOFCASE : 0),
1396 (objnum)MCMONINV, pctx->prscxextc, pctx->prscxprp, filever);
1397 }
1398
1399 /* write game to output if desired (and not precompiling headers) */
1400 if (genoutput && !binout
1401 && errcbcx->tcderrcnt == 0 && errcbcx->tcdfatal == 0)
1402 {
1403 fiowrt(mctx, &vocctx, tc,
1404 &symtab, pctx->prscxfsp, (uint)pctx->prscxfsf,
1405 outfile,
1406 (FIOFFAST
1407 + (symdeb ? (FIOFSYM + FIOFLIN + FIOFPRE
1408 + ((tc->tokcxflg & TOKCXCASEFOLD)
1409 ? FIOFCASE : 0)
1410 )
1411 : FIOFCRYPT
1412 )
1413 + (symdeb2 ? FIOFLIN2 : 0)
1414 ),
1415 preinit, pctx->prscxextc, (uint)0, filever);
1416 }
1417 else if (!binout && !checked_undefs)
1418 {
1419 tcdchkctx cbctx;
1420
1421 /* we're not writing the file, but still check for undefined objects */
1422 cbctx.mem = mctx;
1423 cbctx.ec = ec;
1424 cbctx.cnt = 0;
1425 toktheach(&symtab.tokthsc, tcdchkundef, &cbctx);
1426 }
1427
1428 /* show statistics if desired */
1429 if (stats)
1430 {
1431 int count;
1432 int i;
1433 int j;
1434 vocdef **vhsh;
1435 vocdef *voc;
1436 vocidef ***vpg;
1437 vocidef **v;
1438
1439 IF_DEBUG(extern ulong mchtotmem;)
1440
1441 tcdptf("\n* * * Statistics * * *\n");
1442 tcdptf("Virtual Object Cache size: %lu\n", mcmcsiz(mctx));
1443 tcdptf("Global symbol table size: %lu\n",
1444 ((ulong)symtab.tokthpcnt * (ulong)TOKTHSIZE));
1445 IF_DEBUG(tcdptf("Total heap memory: %lu\n", mchtotmem);)
1446
1447 /* count vocabulary words, eliminating duplicates */
1448 count = 0;
1449 for (i = 0, vhsh = vocctx.voccxhsh ; i < VOCHASHSIZ ; ++i, ++vhsh)
1450 {
1451 for (voc = *vhsh ; voc ; voc = voc->vocnxt)
1452 {
1453 /* check for duplicates; don't count if found one */
1454 ++count;
1455 #if 0
1456 /* no need to check for duplicates with new vocwdef system */
1457 {
1458 vocdef *voc2;
1459 for (voc2 = voc->vocnxt ; voc2 ; voc2 = voc2->vocnxt)
1460 {
1461 if (voc->voclen == voc2->voclen
1462 && voc->vocln2 == voc2->vocln2
1463 && !memcmp(voc->voctxt, voc2->voctxt,
1464 (size_t)(voc->voclen + voc->vocln2)))
1465 {
1466 --count;
1467 break;
1468 }
1469 }
1470 }
1471 #endif /* NEVER */
1472
1473 }
1474 }
1475 tcdptf("Vocabulary words: %d\n", count);
1476
1477 /* count objects, using inheritance records */
1478 count = 0;
1479 for (vpg = vocctx.voccxinh, i = 0 ; i < VOCINHMAX ; ++vpg, ++i)
1480 {
1481 if (!*vpg) continue;
1482 for (v = *vpg, j = 0 ; j < 256 ; ++v, ++j)
1483 {
1484 if (*v) ++count;
1485 }
1486 }
1487 tcdptf("Objects: %d\n", count);
1488 }
1489
1490 /* pause if desired */
1491 if (pause)
1492 {
1493 tcdptf("[done with compilation - strike a key to continue]");
1494 os_waitc();
1495 tcdptf("\n");
1496 }
1497
1498 /* close and delete swapfile, if one was opened */
1499 if (swapfp)
1500 {
1501 osfcls(swapfp);
1502 swapfp = (osfildef *)0;
1503 osfdel_temp(swapname);
1504 }
1505
1506 /* close load file if one was open */
1507 if (loadopen)
1508 fiorcls(&fiolctx);
1509
1510 /* close error echo file */
1511 if (errcbcx->tcderrfil)
1512 {
1513 fclose(errcbcx->tcderrfil);
1514 errcbcx->tcderrfil = 0;
1515 }
1516
1517 /* close the string file */
1518 if (pctx->prscxstrfile != 0)
1519 {
1520 osfcls(pctx->prscxstrfile);
1521 pctx->prscxstrfile = 0;
1522 }
1523
1524 /* close the input line source */
1525 if (linf != 0)
1526 linfcls(&linf->linflin);
1527
1528 ERRCATCH(ec, err)
1529 /* if out of memory, describe current cache condition */
1530 if (err == ERR_NOMEM)
1531 {
1532 tcdptf("*** Note for -m option:\n");
1533 tcdptf("*** Current cache size is %lu\n", mcmcsiz(mctx));
1534 }
1535
1536 /* close and delete swapfile, if one was opened */
1537 if (swapfp)
1538 {
1539 osfcls(swapfp);
1540 swapfp = (osfildef *)0;
1541 osfdel_temp(swapname);
1542 }
1543
1544 /* close load file if one was opened */
1545 if (loadopen)
1546 fiorcls(&fiolctx);
1547
1548 /* close the input line source */
1549 if (linf != 0)
1550 linfcls(&linf->linflin);
1551
1552 /* resignal the error */
1553 errrse(ec);
1554 ERREND(ec)
1555 }
1556
1557 /* log an error */
tcdlogerr(void * ectx0,char * fac,int err,int argc,erradef * argv)1558 static void tcdlogerr(void *ectx0, char *fac, int err, int argc,
1559 erradef *argv)
1560 {
1561 tcderrdef *ectx = (tcderrdef *)ectx0;
1562 char buf[256];
1563 char msg[256];
1564 tokcxdef *ctx = ectx->tcderrtok;
1565 FILE *fp;
1566
1567 /* ignore certain errors if the warning level is low */
1568 switch(err)
1569 {
1570 case ERR_INCRPT:
1571 if (ectx->tcderrlvl < 1) return;
1572 break;
1573 }
1574
1575 if (!ctx)
1576 {
1577 tcdptf("%s-%d: error message not available\n", buf, fac, err);
1578 return;
1579 }
1580
1581 /* figure out what kind of error we have, and increment the counter */
1582 switch(err)
1583 {
1584 case ERR_AMBIGBIN:
1585 /* check for suppression, and ignore the error if suppressed */
1586 if (!ectx->tcdwrn_AMBIGBIN) return;
1587 goto do_warning;
1588
1589 case ERR_TRUNC:
1590 case ERR_INCRPT:
1591 case ERR_WEQASI:
1592 case ERR_STREND:
1593 case ERR_RPLSPEC:
1594 case ERR_VOCREVB:
1595 case ERR_LOCNOBJ:
1596 case ERR_CNTNLST:
1597 case ERR_WRNONF:
1598 case ERR_GNOFIL:
1599 case ERR_PUNDEF:
1600 case ERR_PIA:
1601 do_warning:
1602 /* warning - increment warning count */
1603 ++(ectx->tcdwrncnt);
1604 break;
1605
1606 case ERR_NOMEM:
1607 case ERR_FSEEK:
1608 case ERR_FREAD:
1609 case ERR_FWRITE:
1610 case ERR_NOPAGE:
1611 case ERR_SWAPBIG:
1612 case ERR_SWAPPG:
1613 case ERR_CLIFULL:
1614 case ERR_NOMEM1:
1615 case ERR_NOMEM2:
1616 case ERR_NOLCLSY:
1617 case ERR_MANYSYM:
1618 case ERR_NONODE:
1619 case ERR_VOCSTK:
1620 case ERR_MANYDBG:
1621 case ERR_VOCMNPG:
1622 case ERR_NOMEMLC:
1623 case ERR_NOMEMAR:
1624 /* flag the fatal error, and increment the error count */
1625 ectx->tcdfatal = TRUE;
1626 ++(ectx->tcderrcnt);
1627 break;
1628
1629 default:
1630 /* error - increment error count */
1631 ++(ectx->tcderrcnt);
1632 break;
1633 }
1634
1635 /*
1636 * certain special errors include the line position in the argument
1637 * vector itself
1638 */
1639 switch(err)
1640 {
1641 case ERR_UNDFOBJ:
1642 case ERR_UNDEFO:
1643 case ERR_UNDEFF:
1644 /* these errors include the position as the second argument */
1645 strcpy(buf, argv[1].errastr);
1646 break;
1647
1648 default:
1649 /* for other errors, get the location from the line source */
1650 if (ctx->tokcxlin != 0)
1651 linppos(ctx->tokcxlin, buf, (uint)sizeof(buf));
1652 else
1653 buf[0] = '\0';
1654 }
1655
1656 fp = ectx->tcderrfil;
1657
1658 tcdptf("%serror %s-%d: ", buf, fac, err);
1659 if (fp) fprintf(fp, "%serror %s-%d: ", buf, fac, err);
1660
1661 errmsg(ctx->tokcxerr, msg, (uint)sizeof(msg), err);
1662 errfmt(buf, (int)sizeof(buf), msg, argc, argv);
1663 tcdptf("%s\n", buf);
1664 if (fp) fprintf(fp, "%s\n", buf);
1665
1666 #ifdef OS_ERRLINE
1667 if ((err >= ERR_INVTOK && err < ERR_VOCINUS)
1668 || err == ERR_UNDFOBJ || err == ERR_UNDEFO || err == ERR_UNDEFF)
1669 {
1670 char *p;
1671 int len;
1672
1673 switch(err)
1674 {
1675 case ERR_UNDFOBJ:
1676 case ERR_UNDEFO:
1677 case ERR_UNDEFF:
1678 p = argv[1].errastr;
1679 p += strlen(p) + 1;
1680 len = strlen(p);
1681 break;
1682
1683 default:
1684 p = ctx->tokcxlin->linbuf;
1685 len = ctx->tokcxlin->linlen;
1686 break;
1687 }
1688
1689 if (len + 1 > sizeof(buf)) len = sizeof(buf) - 1;
1690 memcpy(buf, p, (size_t)len);
1691 buf[len] = '\0';
1692 tcdptf("%s\n\n", buf);
1693 if (fp) fprintf(fp, "%s\n\n", buf);
1694 }
1695 #endif /* OS_ERRLINE */
1696 }
1697
1698 /* main - called by os main after setting up arguments */
tcdmain(int argc,char ** argv,char * save_ext)1699 int tcdmain(int argc, char **argv, char *save_ext)
1700 {
1701 errcxdef errctx;
1702 int err;
1703 osfildef *fp;
1704 extern char tcgname[];
1705 tcderrdef errcbcx; /* error callback context */
1706 char vsnbuf[128];
1707
1708 /* initialize the error structure */
1709 CLRSTRUCT(errcbcx);
1710 errcbcx.tcdwrn_AMBIGBIN = TRUE; /* -v+abin by default */
1711
1712 errctx.errcxlog = tcdlogerr;
1713 errctx.errcxlgc = (void *)0;
1714 errctx.errcxofs = 0;
1715 errctx.errcxfp = (osfildef *)0;
1716 errctx.errcxappctx = 0;
1717 fp = oserrop(argv[0]);
1718 errini(&errctx, fp);
1719
1720 /* copyright-date-string */
1721 sprintf(vsnbuf, "%s v%s.%s.%s %s\n", tcgname,
1722 vsn_major, vsn_minor, vsn_maint,
1723 "Copyright (c) 1993, 2004 Michael J. Roberts");
1724 tcdptf(vsnbuf);
1725 sprintf(vsnbuf, "TADS for %s [%s] patchlevel %s.%s\n",
1726 OS_SYSTEM_LDESC, OS_SYSTEM_NAME,
1727 TADS_OEM_VERSION, OS_SYSTEM_PATCHSUBLVL);
1728 tcdptf(vsnbuf);
1729 tcdptf("%s maintains this port.\n", TADS_OEM_NAME);
1730
1731 ERRBEGIN(&errctx)
1732 tcdmain1(&errctx, argc, argv, &errcbcx, save_ext);
1733 ERRCATCH(&errctx, err)
1734 if (err != ERR_USAGE)
1735 errclog(&errctx);
1736
1737 if (errctx.errcxfp) osfcls(errctx.errcxfp);
1738 if (errcbcx.tcderrfil) fclose(errcbcx.tcderrfil);
1739 /* os_expause(); */
1740 return(OSEXFAIL);
1741 ERREND(&errctx)
1742
1743 /* close message file */
1744 if (errctx.errcxfp) osfcls(errctx.errcxfp);
1745
1746 /* close error echo file if any */
1747 if (errcbcx.tcderrfil) fclose(errcbcx.tcderrfil);
1748
1749 /* os_expause(); */
1750 return(errcbcx.tcderrcnt == 0 ? OSEXSUCC : OSEXFAIL);
1751 }
1752
1753