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