1 /*
2  *      Small C+ Compiler -
3  *
4  *      Main() part
5  *
6  *      $Id: main.c,v 1.42 2016-09-01 04:08:32 aralbrec Exp $
7  */
8 
9 #include "../config.h"
10 #include "ccdefs.h"
11 
12 #if defined(__MSDOS__) && defined(__TURBOC__)
13 extern unsigned _stklen = 8192U; /* Default stack size 4096 bytes is too small. */
14 #endif
15 
16 static char   *c_output_extension = "asm";
17 static char   *c_output_file = NULL;
18 static char    c_debug_adb_file = 0;
19 static char    c_debug_adb_defc = 0;
20 
21 static int      gargc; /* global copies of command line args */
22 static char   **gargv;
23 static SYMBOL  *savecurr;    /* copy of currfn for #include */
24 static int      saveline;    /* copy of lineno  "    " */
25 static int      saveinfn;    /* copy of infunc  "    " */
26 static int      filenum; /* next argument to be used */
27 
28 UT_string       *debug_utstr;
29 UT_string       *debug2_utstr;
30 
31 static Type *type_double4 = &(Type){ KIND_DOUBLE, 4, 0, .len=1 };
32 static Type *type_double8 = &(Type){ KIND_DOUBLE, 8, 0, .len=1 };
33 
34 char Filenorig[FILENAME_LEN + 1];
35 
36 
37 int c_notaltreg; /* No alternate registers */
38 int c_standard_escapecodes = 0; /* \n = 10, \r = 13 */
39 int c_disable_builtins = 0;
40 int c_cline_directive = 0;
41 int c_cpu = CPU_Z80;
42 int c_old_diagnostic_fmt = 0;
43 char *c_zcc_opt = "zcc_opt.def";
44 
45 /* Settings for genmath + math48 */
46 int c_fp_mantissa_bytes = 5;
47 int c_fp_exponent_bias = 128;
48 int c_fp_fudge_offset = 0;    // Fudge offset for z88math - it starts pickup from FA+1
49 int c_fp_size = 6;
50 
51 enum maths_mode c_maths_mode = MATHS_Z80;
52 
53 uint32_t c_speed_optimisation = OPT_RSHIFT32|OPT_LSHIFT32;
54 
55 char *c_rodata_section = "rodata_compiler";
56 char *c_data_section = "data_compiler";
57 char *c_bss_section = "bss_compiler";
58 char *c_code_section = "code_compiler";
59 char *c_init_section = "code_crt_init";
60 
61 #include "option.h"
62 
63 
64 
65 static void dumpsymdebug(void);
66 static void dumpdebug(void);
67 static void dumpfns(void);
68 static void dumpvars(void);
69 static void parse(void);
70 static void errsummary(void);
71 static char *nextarg(int n, char *s, int size);
72 static void setup_sym(void);
73 static void info(void);
74 static void openout(void);
75 
76 static void SetWarning(option *arg, char* val);
77 static void SetDefine(option *arg, char *val);
78 static void SetUndefine(option *arg, char *val);
79 static void DispInfo(option *arg, char *val);
80 static void opt_code_speed(option *arg, char* val);
81 static void atexit_deallocate(void);
82 
83 
84 static option  sccz80_opts[] = {
85     { 'v', "verbose", OPT_BOOL, "Be verbose", &c_verbose, NULL, 0 },
86     { 'h', "help", OPT_FUNCTION|OPT_BOOL, "Show this help page", NULL, DispInfo, 0 },
87     { 'o', "output", OPT_STRING, "Set the output filename", &c_output_file, NULL, 0 },
88     { 0, "", OPT_HEADER, "CPU Targetting:", NULL, NULL, 0 },
89     { 0, "m8080", OPT_ASSIGN|OPT_INT, "Generate output for the i8080", &c_cpu, NULL, CPU_8080 },
90     { 0, "m8085", OPT_ASSIGN|OPT_INT, "Generate output for the i8085", &c_cpu, NULL, CPU_8085 },
91     { 0, "mz80", OPT_ASSIGN|OPT_INT, "Generate output for the z80", &c_cpu, NULL, CPU_Z80 },
92     { 0, "mz80n", OPT_ASSIGN|OPT_INT, "Generate output for the z80n", &c_cpu, NULL, CPU_Z80N },
93     { 0, "mz180", OPT_ASSIGN|OPT_INT, "Generate output for the z180", &c_cpu, NULL, CPU_Z180 },
94     { 0, "mr2k", OPT_ASSIGN|OPT_INT, "Generate output for the Rabbit 2000", &c_cpu, NULL, CPU_R2K },
95     { 0, "mr3k", OPT_ASSIGN|OPT_INT, "Generate output for the Rabbit 3000", &c_cpu, NULL, CPU_R3K },
96     { 0, "mgbz80", OPT_ASSIGN|OPT_INT, "Generate output for the Gameboy Z80", &c_cpu, NULL, CPU_GBZ80 },
97     { 0, "", OPT_HEADER, "Code generation options", NULL, NULL, 0 },
98     { 0, "unsigned", OPT_BOOL, "Make all types unsigned", &c_default_unsigned, NULL, 0 },
99     { 0, "disable-builtins", OPT_BOOL|OPT_DOUBLE_DASH, "Disable builtin functions",&c_disable_builtins, NULL, 0},
100     { 0, "doublestr", OPT_BOOL, "Store FP constants as strings", &c_double_strings, NULL, 0 },
101     { 0, "math-z88", OPT_ASSIGN|OPT_INT, "(deprecated) Make FP constants match z88", &c_maths_mode, NULL, MATHS_Z88 },
102 
103     { 0, "fp-exponent-bias", OPT_INT, "=<num> FP exponent bias (default: 128)", &c_fp_exponent_bias, NULL, 0 },
104     { 0, "fp-mantissa-size", OPT_INT, "=<num> FP mantissa size (default: 5 bytes)", &c_fp_mantissa_bytes, NULL, 0 },
105     { 0, "fp-mode=z80", OPT_ASSIGN|OPT_INT, "Use 48 bit doubles", &c_maths_mode, NULL, MATHS_Z80 },
106     { 0, "fp-mode=ieee", OPT_ASSIGN|OPT_INT, "Use 32 bit IEEE doubles", &c_maths_mode, NULL, MATHS_IEEE },
107     { 0, "fp-mode=mbf32", OPT_ASSIGN|OPT_INT, "Use 32 bit Microsoft Binary format", &c_maths_mode, NULL, MATHS_MBFS },
108     { 0, "fp-mode=mbf40", OPT_ASSIGN|OPT_INT, "Use 40 bit Microsoft binary format", &c_maths_mode, NULL, MATHS_MBF40 },
109     { 0, "fp-mode=mbf64", OPT_ASSIGN|OPT_INT, "Use 64 bit Microsoft binary format", &c_maths_mode, NULL, MATHS_MBF64 },
110     { 0, "fp-mode=z88", OPT_ASSIGN|OPT_INT, "Use 40 bit z88 doubles", &c_maths_mode, NULL, MATHS_Z88 },
111     { 0, "fp-mode=am9511", OPT_ASSIGN|OPT_INT, "Use 32 bit AM9511 doubles", &c_maths_mode, NULL, MATHS_AM9511 },
112 
113     { 0, "noaltreg", OPT_BOOL, "Try not to use the alternative register set", &c_notaltreg, NULL, 0 },
114     { 0, "standard-escape-chars", OPT_BOOL, "Use standard mappings for \\r and \\n", &c_standard_escapecodes, NULL, 0},
115     { 0, "set-r2l-by-default", OPT_BOOL, "Use r->l calling convention by default", &c_use_r2l_calling_convention, NULL, 0 },
116     { 0, "constseg", OPT_STRING|OPT_DOUBLE_DASH, "=<name> Set the const section name", &c_rodata_section, NULL, 0 },
117     { 0, "codeseg", OPT_STRING|OPT_DOUBLE_DASH, "=<name> Set the code section name", &c_code_section, NULL, 0 },
118     { 0, "bssseg", OPT_STRING|OPT_DOUBLE_DASH, "=<name> Set the bss section name", &c_bss_section, NULL, 0 },
119     { 0, "dataseg", OPT_STRING|OPT_DOUBLE_DASH, "=<name> Set the data section name", &c_data_section, NULL, 0 },
120     { 0, "initseg", OPT_STRING|OPT_DOUBLE_DASH, "=<name> Set the initialisation section name", &c_init_section, NULL, 0 },
121     { 0, "gcline", OPT_BOOL, "Generate C_LINE directives", &c_cline_directive, NULL, 0 },
122     { 0, "opt-code-speed", OPT_FUNCTION|OPT_STRING|OPT_DOUBLE_DASH, "Optimise for speed not size", NULL, opt_code_speed, 0},
123     { 0, "", OPT_HEADER, "Framepointer configuration (for debugging):", NULL, NULL, 0 },
124     { 0, "frameix", OPT_ASSIGN|OPT_INT, "Use ix as the frame pointer", &c_framepointer_is_ix, NULL, 1},
125     { 0, "frameiy", OPT_ASSIGN|OPT_INT, "Use iy as the frame pointer", &c_framepointer_is_ix, NULL, 0},
126     { 0, "zcc-opt", OPT_STRING, "Location for zcc_opt.def", &c_zcc_opt, NULL, (intptr_t)(void *)"zcc_opt.def"},
127 
128     { 0, "", OPT_HEADER, "Error/warning handling:", NULL, NULL, 0 },
129     { 0, "stop-on-error", OPT_BOOL, "Stop on any error", &c_errstop, NULL, 0 },
130     { 0, "old-diagnostic-format", OPT_BOOL|OPT_DOUBLE_DASH, "Use old style diagnostic messages", &c_old_diagnostic_fmt, NULL, 0 },
131 #if 0
132     { 0, "Wnone", OPT_FUNCTION|OPT_BOOL, "Disable all warnings", NULL, SetNoWarn, 0 },
133     { 0, "Wall", OPT_FUNCTION|OPT_BOOL, "Enable all warnings", NULL, SetAllWarn, 0 },
134     { 0, "Wn", OPT_FUNCTION, "<num> Disable a warning", NULL, UnSetWarning, 0},
135 #endif
136     { 0, "W", OPT_FUNCTION, "<type> Enable a class of warnings", NULL,  SetWarning, 0 },
137     { 0, "", OPT_HEADER, "Debugging options", NULL, NULL, 0 },
138     { 0, "debug-sect", OPT_BOOL, "Create adb/cdb debug section", &c_debug_adb_file, NULL, 0 },
139     { 0, "debug-defc", OPT_BOOL, "Create adb/cdb debug defc", &c_debug_adb_defc, NULL, 0 },
140     { 0, "cc", OPT_BOOL, "Intersperse the assembler output with the source C code", &c_intermix_ccode, NULL, 0 },
141     { 0, "intlog", OPT_INT, "=<val> Enable some extra logging", &debuglevel, NULL, 0 },
142     { 0, "ext", OPT_STRING, "=<ext> Set the file extension for the generated output", &c_output_extension, NULL, 0 },
143     { 0, "D", OPT_FUNCTION, "Define a preprocessor directive", NULL, SetDefine, 0 },
144     { 0, "U", OPT_FUNCTION, "Undefine a preprocessor directive", NULL, SetUndefine, 0 },
145     { 0, "", OPT_HEADER, "Assignments can either be = or as next argument", NULL, NULL, 0},
146     { 0 }
147 };
148 
149 
150 
151 
152 /*
153  *
154  *      Code...
155  *
156  */
157 
158 /*
159  *      Compiler begins execution here
160  */
main(int argc,char ** argv)161 int main(int argc, char** argv)
162 {
163     gargc = argc;
164     gargv = argv;
165 
166     /* allocate space for arrays */
167     litq = MALLOC(FNLITQ); /* literals, these 2 dumped end */
168     dubq = MALLOC(FNLITQ); /* Doubles */
169     tempq = MALLOC(LITABSZ); /* Temp strings... */
170     glbq = MALLOC(LITABSZ); /* Used for glb lits, dumped now */
171     symtab = NULL;
172     loctab = MALLOC(NUMLOC * sizeof(SYMBOL));
173     wqueue = MALLOC(NUMWHILE * sizeof(WHILE_TAB));
174     gotoq = MALLOC(NUMGOTO * sizeof(GOTO_TAB));
175 
176     swnext = MALLOC(NUMCASE * sizeof(SW_TAB));
177     swend = swnext + (NUMCASE - 1);
178 
179     stage = MALLOC(STAGESIZE);
180     stagelast = stage + STAGELIMIT;
181 
182 
183     glbcnt = 0; /* clear global symbols */
184     locptr = STARTLOC; /* clear local symbols */
185     wqptr = wqueue; /* clear while queue */
186     gltptr = 0; /* clear literal pools */
187     *litq = 0; /* First entry in literal queue is zero */
188     litptr = 1; /* So miniprintf search works */
189 
190     Zsp = /* stack ptr (relative) */
191         errcnt = /* no errors */
192         c_errstop = /* keep going after an error */
193         eof = /* not eof yet */
194         ncmp = /* no open compound states */
195         lastst = /* not first file to asm */
196         lineno = /* no lines read from file */
197         infunc = /* not in function now */
198         0; /*  ...all set to zero.... */
199 
200     stagenext = NULL; /* direct output mode */
201 
202     input = /* no input file */
203         inpt2 = /* or include file */
204         saveout = /* no diverted output */
205         output = NULL; /* no open units */
206 
207     currfn = NULL; /* no function yet */
208     macptr = cmode = 1; /* clear macro pool and enable preprocessing */
209     ncomp = need_floatpack = 0;
210     c_default_unsigned = NO;
211     nxtlab = 0;/* start numbers at lowest possible */
212     c_intermix_ccode = 0; /* don't include the C text as comments */
213     c_errstop =0;  /* don't stop after errors */
214     c_verbose = 0;
215     c_double_strings = 0;
216     c_notaltreg = NO;
217     debuglevel = NO;
218     c_framepointer_is_ix = -1;
219     c_use_r2l_calling_convention = NO;
220 
221     setup_sym(); /* define some symbols */
222     /* Parse the command line options */
223     atexit(atexit_deallocate); /* To free everything */
224     clear();
225     filenum = 0;
226     gargc = option_parse(sccz80_opts, argc, argv);
227     clear();
228 
229     if (gargc == 0) {
230         info();
231         exit(1);
232     }
233 
234     if ( c_maths_mode == MATHS_IEEE ) {
235         c_fp_size = 4;
236         type_double = type_double4;
237         c_fp_exponent_bias = 126;
238         c_fp_mantissa_bytes = 3;
239         WriteDefined("CLIB_32BIT_FLOATS", 1);
240     } else if ( c_maths_mode == MATHS_MBFS ) {
241         c_fp_size = 4;
242         type_double = type_double4;
243         c_fp_exponent_bias = 128;
244         c_fp_mantissa_bytes = 3;
245         WriteDefined("CLIB_32BIT_FLOATS", 1);
246     } else if ( c_maths_mode == MATHS_MBF40 ) {
247         c_fp_exponent_bias = 128;
248         c_fp_mantissa_bytes = 4;
249     } else if ( c_maths_mode == MATHS_MBF64 ) {
250         c_fp_size = 8;
251         type_double = type_double8;
252         c_fp_exponent_bias = 128;
253         c_fp_mantissa_bytes = 7;
254         WriteDefined("CLIB_64BIT_FLOATS", 1);
255     } else if ( c_maths_mode == MATHS_Z88 ) {
256         c_fp_exponent_bias = 127;
257         c_fp_mantissa_bytes = 4;
258         c_fp_fudge_offset = 1;
259     } else if ( c_maths_mode == MATHS_AM9511 ) {
260         type_double = type_double4;
261         c_fp_exponent_bias = 0;
262         c_fp_mantissa_bytes = 3;
263         c_fp_size = 4;
264     }
265 
266     if ( c_debug_adb_file || c_debug_adb_defc ) {
267         c_cline_directive = 1;
268         // Turn on the framepointer entry so we can get local variables
269         if ( !IS_808x() && !IS_GBZ80() && c_framepointer_is_ix == -1 ) {
270             c_framepointer_is_ix = 1;
271         }
272     }
273 
274 
275     if ( c_cpu == CPU_8080 ) {
276         c_notaltreg = 1;
277         WriteDefined("CPU_8080", 1);
278     }
279 
280     if ( c_cpu == CPU_GBZ80 ) {
281         c_notaltreg = 1;
282         WriteDefined("CPU_GBZ80", 1);
283     }
284 
285     utstring_new(debug_utstr);
286     utstring_new(debug2_utstr);
287 
288     litlab = getlabel(); /* Get labels for function lits*/
289     openout(); /* get the output file */
290     openin(); /* and initial input file */
291     gen_file_header(); /* intro code */
292     parse(); /* process ALL input */
293 
294 
295 
296 
297     /* dump literal queues, with label */
298     /* litq starts from 1, so literp has to be -1 */
299     dumplits(0, YES, litptr - 1, litlab, litq + 1);
300     write_constant_queue();
301     dumpvars();
302     dumpfns();
303 
304     if ( c_debug_adb_defc ) {
305         dumpsymdebug();
306     }
307     if ( c_debug_adb_file ) {
308         dumpdebug();
309     }
310 
311     gen_file_footer(); /* follow-up code */
312     closeout();
313     errsummary(); /* summarize errors */
314     if (errcnt)
315         exit(1);
316     exit(0);
317 }
318 
319 /*
320  *      Abort compilation
321  */
ccabort()322 void ccabort()
323 {
324     if (inpt2 != NULL)
325         endinclude();
326     if (input != NULL)
327         fclose(input);
328     closeout();
329     fprintf(stderr, "Compilation aborted\n");
330     exit(1);
331 }
332 
333 /*
334  * Process all input text
335  *
336  * At this level, only static declarations,
337  * defines, includes, and function
338  * definitions are legal...
339  */
parse()340 void parse()
341 {
342     while (eof == 0) { /* do until no more input */
343         if (amatch("extern")) {
344             dodeclare(EXTERNAL);
345         } else if (amatch("static")) {
346             dodeclare(LSTATIC);
347         } else if (amatch("typedef")) {
348             dodeclare(TYPDEF);
349         } else if (dodeclare(STATIK)) {
350             ;
351         } else if ( amatch("__addressmod")) {
352             parse_addressmod();
353         } else if (ch() == '#') {
354             if (match("#asm")) {
355                 doasm();
356             } else if (match("#include")) {
357                 doinclude();
358             } else if (match("#define")) {
359                 addmac();
360             } else {
361                 clear();
362                 blanks();
363             }
364         } else {
365             declare_func_kr();
366         }
367         blanks(); /* force eof if pending */
368     }
369 }
370 
371 /*
372  *      Report errors for user
373  */
errsummary()374 void errsummary()
375 {
376     /* see if anything left hanging... */
377     if (ncmp) {
378         errorfmt("Missing closing bracket", 0);
379         nl();
380     }
381     if (c_verbose) {
382         printf("Symbol table usage: %d\n", glbcnt);
383         // printf("Structures defined: %ld\n", (long)(tagptr - tagtab));
384         // printf("Members defined:    %ld\n", (long)(membptr - membtab));
385         // printf("There %s %d %s in compilation.\n", (errcnt == 1 ? "was" : "were"), errcnt, (errcnt == 1 ? "error" : "errors"));
386     }
387 }
388 
389 /*
390  * places in s the n-th argument (up to "size"
391  * bytes). If successful, returns s. Returns 0
392  * if the n-th argument doesn't exist.
393  */
394 
nextarg(int n,char * s,int size)395 char *nextarg(int n, char* s, int size)
396 {
397     char* str;
398     char* str2;
399     int i;
400 
401     if (n < 0 || n >= gargc)
402         return NULL;
403     i = 0;
404     str = str2 = gargv[n];
405     while (++i < size && (*s++ = *str++))
406         ;
407     if (*str2 == '\0')
408         return NULL;
409     return s;
410 }
411 
412 /*
413  * make a few preliminary entries in the symbol table
414  */
415 
setup_sym()416 void setup_sym()
417 {
418     defmac("Z80");
419     defmac("SMALL_C");
420 
421     addglb("asm", asm_function("asm"), 0, KIND_LONG, 0, LSTATIC);
422     addglb("__asm__", asm_function("__asm__"), 0, KIND_LONG, 0, LSTATIC);
423 }
424 
info()425 void info()
426 {
427     fputs(titlec, stderr);
428     fputs(Version, stderr);
429     fputs("\n(C) 1980-2017 Cain, Van Zandt, Hendrix, Yorston, z88dk\n", stderr);
430     fprintf(stderr, "Usage: %s [flags] [file]\n", gargv[0]);
431 }
432 
433 
dumpdebug(void)434 static void dumpdebug(void)
435 {
436     const char *debug = utstring_body(debug_utstr);
437     const char *end = NULL;
438 
439     gen_switch_section("__ADBDEBUG");
440     while ( ( end = strchr(debug,'\n')) != NULL ) {
441         defmesg();
442         outfmt("%.*s\\n\"\n", end - debug, debug);
443         debug = end+1;
444     }
445 }
446 
dumpsymdebug(void)447 static void dumpsymdebug(void)
448 {
449     const char *debug = utstring_body(debug2_utstr);
450     const char *end = NULL;
451 
452     while ( ( end = strchr(debug,'\n')) != NULL ) {
453         outfmt("%.*s\n", end - debug, debug);
454         debug = end+1;
455     }
456 }
457 
458 /*
459  ***********************************************************************
460  *
461  *
462  *      Routines To Write Out Scope of labels and to Dump
463  *      the static variables, also for dumping the literal pool
464  *
465  *
466  ***********************************************************************
467  */
468 
dumpfns()469 static void dumpfns()
470 {
471     int type, storage;
472     SYMBOL* ptr;
473     FILE* fp;
474 
475     outstr("\n\n; --- Start of Scope Defns ---\n\n");
476 
477     if (!glbcnt)
478         return;
479 
480     for ( ptr = symtab; ptr != NULL; ptr = ptr->hh.next ) {
481         if (ptr->name[0] != '0' && ptr->ctype ) {
482             type = ptr->type;
483             storage = ptr->storage;
484             if ( type == KIND_ENUM )
485                 continue;
486             if ( ptr->ident == ID_MACRO )
487                 continue;
488             if (ptr->ctype->kind == KIND_PORT8 || ptr->ctype->kind == KIND_PORT16 ) {
489                 outfmt("\tdefc\t_%s =\t%d\n", ptr->name, ptr->ctype->value);
490             } else {
491                 if ( storage == EXTERNP ) {
492                     outfmt("\tdefc\t"); outname(ptr->name,1); outfmt("\t= %d\n", ptr->ctype->value);
493                 } else if ( storage != LSTATIC && storage != TYPDEF ) {
494                     GlobalPrefix();
495                     outname(ptr->name, dopref(ptr)); nl();
496                     if ( storage != STATIK ) {
497                         debug_write_symbol(ptr);
498                     }
499                 }
500             }
501         }
502     }
503 
504     if ((fp = fopen(c_zcc_opt, "a")) == NULL) {
505         errorfmt("Can't open zcc_opt.def file", 1);
506     }
507 
508     if (need_floatpack) {
509         fprintf(fp, "\nIF !NEED_floatpack\n");
510         fprintf(fp, "\tDEFINE\tNEED_floatpack\n");
511         fprintf(fp, "ENDIF\n\n");
512     }
513     /*
514      * Now, we're gonna use #pragma define _FAR_PTR to indicate whether we need
515      * far stuff - this has to go with a -D_FAR_PTR from the compile line
516      * as well for everything to work just right, so if we find this then
517      * we can indicate to the startup code via zcc_opt.def what the scam
518      * is - this could be used for eg. to allocate space for file structures
519      * etc
520      */
521     if ((ptr = findglb("_FAR_PTR")) && ptr->ident == ID_MACRO) {
522         fprintf(fp, "\nIF !NEED_farstartup\n");
523         fprintf(fp, "\tDEFINE NEED_farstartup\n");
524         fprintf(fp, "ENDIF\n\n");
525     }
526 
527     if (printf_format_option) {
528         fprintf(fp, "\nIF !DEFINED_CRT_printf_format\n");
529         fprintf(fp, "\tdefc\tDEFINED_CRT_printf_format = 1\n");
530         fprintf(fp, "\tdefc CRT_printf_format = 0x%08x\n", printf_format_option);
531         fprintf(fp, "ELSE\n");
532         fprintf(fp, "\tUNDEFINE temp_printf_format\n");
533         fprintf(fp, "\tdefc temp_printf_format = CRT_printf_format\n");
534         fprintf(fp, "\tUNDEFINE CRT_printf_format\n");
535         fprintf(fp, "\tdefc CRT_printf_format = temp_printf_format | 0x%08x\n", printf_format_option);
536         fprintf(fp, "ENDIF\n\n");
537         fprintf(fp, "\nIF !NEED_printf\n");
538         fprintf(fp, "\tDEFINE\tNEED_printf\n");
539         fprintf(fp, "ENDIF\n\n");
540     }
541 
542     if (scanf_format_option) {
543         fprintf(fp, "\nIF !DEFINED_CRT_scanf_format\n");
544         fprintf(fp, "\tdefc\tDEFINED_CRT_scanf_format = 1\n");
545         fprintf(fp, "\tdefc CRT_scanf_format = 0x%08x\n", scanf_format_option);
546         fprintf(fp, "ELSE\n");
547         fprintf(fp, "\tUNDEFINE temp_scanf_format\n");
548         fprintf(fp, "\tdefc temp_scanf_format = CRT_scanf_format\n");
549         fprintf(fp, "\tUNDEFINE CRT_scanf_format\n");
550         fprintf(fp, "\tdefc CRT_scanf_format = temp_scanf_format | 0x%08x\n", scanf_format_option);
551         fprintf(fp, "ENDIF\n\n");
552         fprintf(fp, "\nIF !NEED_scanf\n");
553         fprintf(fp, "\tDEFINE\tNEED_scanf\n");
554         fprintf(fp, "ENDIF\n\n");
555     }
556     fclose(fp);
557 
558 
559     outstr("\n\n; --- End of Scope Defns ---\n\n");
560 }
561 
562 /*
563  * Dump a function into the zcc_opt.def file - this allows us to pass
564  * important functions to the appstartup code so it can call them
565  * when appropriate, we also XREF it so we don't have to do that in
566  * the startup code
567  */
568 
WriteDefined(char * sname,int value)569 void WriteDefined(char* sname, int value)
570 {
571     FILE* fp;
572 
573     if ((fp = fopen(c_zcc_opt, "a")) == NULL) {
574         errorfmt("Can't open zcc_opt.def file", 1);
575     }
576     fprintf(fp, "\nIF !DEFINED_%s\n", sname);
577     fprintf(fp, "\tdefc\tDEFINED_%s = 1\n", sname);
578     fprintf(fp, "\tdefc %s = %d\n", sname, value);
579     fprintf(fp, "ENDIF\n\n");
580     fclose(fp);
581 }
582 
583 /*
584  */
dumpvars()585 void dumpvars()
586 {
587     int ident, type, storage;
588     SYMBOL* ptr;
589 
590     if (!glbcnt)
591         return;
592 
593     /* Start at the start! */
594     outstr("; --- Start of Static Variables ---\n\n");
595 
596     gen_switch_section(c_bss_section); // gen_switch_section("bss");
597 
598     for ( ptr = symtab; ptr != NULL; ptr = ptr->hh.next ) {
599         if (ptr->name[0] != '0' ) {
600             ident = ptr->ident;
601             type = ptr->ctype ? ptr->ctype->kind : KIND_NONE;
602             storage = ptr->storage;
603             if ( ptr->initialised )
604                 continue;
605             if ( ident == ID_ENUM || ident == ID_MACRO || ident == ID_GOTOLABEL )
606                 continue;
607             if ( type == KIND_FUNC || type == KIND_PORT8 || type == KIND_PORT16 )
608                 continue;
609             if ( storage == TYPDEF ||  storage == EXTERNAL )
610                 continue;
611             if ( type == KIND_ENUM )
612                 continue;
613             if ( ptr->ctype->size == -1 )
614                 continue;
615             if ( ptr->bss_section ) gen_switch_section(ptr->bss_section);
616             prefix();
617             outname(ptr->name, 1);
618             col();
619             defstorage();
620             outdec(ptr->ctype->size);
621             nl();
622         }
623     }
624 
625     /* Switch back to standard section */
626     gen_switch_section(c_code_section); // gen_switch_section("code");
627 }
628 
629 /*
630  *      Dump the literal pool if it's not empty
631  *      Modified by djm to be able to input which queue should be
632  *      dumped..
633  */
dumplits(int size,int pr_label,int queueptr,int queuelab,unsigned char * queue)634 void dumplits(
635     int size, int pr_label,
636     int queueptr, int queuelab,
637     unsigned char* queue)
638 {
639     int j, k, lit;
640 
641     if (queueptr) {
642         if (pr_label) {
643             gen_switch_section(c_rodata_section); // gen_switch_section("text");
644             prefix();
645             queuelabel(queuelab);
646             col();
647             nl();
648         }
649         k = 0;
650         while (k < queueptr) {
651             /* pseudo-op to define byte */
652             if (infunc)
653                 j = 1;
654             else
655                 j = 10;
656             if (size == 1)
657                 defbyte();
658             else if (size == 4)
659                 deflong();
660             else if (size == 0) {
661                 defmesg();
662                 j = 30;
663             } else if ( size == 6 ) {
664                 defbyte();
665                 j = 6;
666                 size = 1;
667             } else if ( size == 8 ) {
668                 defbyte();
669                 j = 8;
670                 size = 1;
671             } else
672                 defword();
673             while (j--) {
674                 if (size == 0) {
675                     lit = getint(queue + k, 1);
676                     if (lit >= 32 && lit <= 126 && lit != '"' && lit != '\\')
677                         outbyte(lit);
678                     else {
679                         outstr("\"\n");
680                         defbyte();
681                         outdec(lit);
682                         nl();
683                         lit = 0;
684                     }
685                     k++;
686                     if (j == 0 || k >= queueptr || lit == 0) {
687                         if (lit)
688                             outbyte('"');
689                         nl();
690                         break;
691                     }
692                 } else {
693                     outdec(getint(queue + k, size));
694                     k += size;
695                     if (j == 0 || k >= queueptr) {
696                         nl(); /* need <cr> */
697                         break;
698                     }
699                     outbyte(','); /* separate bytes */
700                 }
701             }
702         }
703         //gen_switch_section(c_code_section); // gen_switch_section("code");
704     }
705 }
706 
707 /*
708  * dump zeroes for default initial value
709  * (or rather, get loader to do it for us)
710  */
dumpzero(int size,int count)711 int dumpzero(int size, int count)
712 {
713     if (count <= 0)
714         return (0);
715     defstorage();
716     outdec(size * count);
717     nl();
718     return (size * count);
719 }
720 
721 /********************************************************************
722  *
723  *      Routines to open the assembly and C source files
724  *
725  ********************************************************************
726  */
727 
728 /*
729  *      Get output filename
730  */
openout()731 void openout()
732 {
733     char filen2[FILENAME_LEN + 1];
734     char extension[FILENAME_LEN+1];
735 
736     snprintf(extension,sizeof(extension),".%s",c_output_extension);
737     FILE* fp;
738     clear(); /* erase line */
739     output = 0; /* start with none */
740     if (nextarg(filenum, filen2, FILENAME_LEN) == NULL)
741         return;
742     if ((fp = fopen(filen2, "r")) == NULL) {
743         fprintf(stderr, "Cannot open source file: %s\n", filen2);
744         exit(1);
745     }
746     fclose(fp); /* Close it again... */
747 
748     /* copy file name to string */
749     strcpy(Filename, filen2);
750 
751     if ( c_output_file != NULL ) {
752         if ((output = fopen(c_output_file, "w")) == NULL && (!eof)) {
753             fprintf(stderr, "Cannot open output file: %s\n", line);
754             exit(1);
755         }
756     } else {
757         strcpy(Filenorig, filen2);
758         changesuffix(filen2, extension); /* Change appendix to .asm */
759         if ((output = fopen(filen2, "w")) == NULL && (!eof)) {
760             fprintf(stderr, "Cannot open output file: %s\n", line);
761             exit(1);
762         }
763     }
764     clear(); /* erase line */
765 }
766 
767 /*
768  *      Get (next) input file
769  */
openin()770 void openin()
771 {
772     input = NULL; /* none to start with */
773     while (input == NULL) { /* any above 1 allowed */
774         clear(); /* clear line */
775         if (eof)
776             break; /* if user said none */
777         /* Deleted hopefully irrelevant code */
778         if (Filename[0] == '-') {
779             if (ncomp == 0)
780                 info();
781             exit(1);
782         }
783         if ((input = fopen(Filename, "r")) == NULL) {
784             fprintf(stderr, "Can't open: %s\n", Filename);
785             exit(1);
786         } else {
787             if (c_verbose)
788                 fprintf(stderr, "Compiling: %s\n", Filename);
789             ncomp++;
790             newfile();
791         }
792     }
793     clear(); /* erase line */
794 }
795 
796 /*
797  *      Reset line count, etc.
798  */
newfile()799 void newfile()
800 {
801     lineno = /* no lines read */
802         infunc = 0; /* therefore not in fn. */
803     currfn = NULL; /* no fn. yet */
804 }
805 
806 /*
807  *      Open an include file
808  */
doinclude()809 void doinclude()
810 {
811     char name[FILENAME_LEN + 1], *cp;
812 
813     blanks(); /* skip over to name */
814     if (c_verbose) {
815         toconsole();
816         outstr(line);
817         nl();
818         tofile();
819     }
820 
821     if (inpt2) {
822         errorfmt("Can't nest include files", 1);
823     } else {
824         /* ignore quotes or angle brackets round file name */
825         strcpy(name, line + lptr);
826         cp = name;
827         if (*cp == '"' || *cp == '<') {
828             name[strlen(name) - 1] = '\0';
829             ++cp;
830         }
831         if ((inpt2 = fopen(cp, "r")) == NULL) {
832             errorfmt( "Can't open include file", 1 );
833             closeout();
834             exit(1);
835         } else {
836             saveline = lineno;
837             savecurr = currfn;
838             saveinfn = infunc;
839             newfile();
840         }
841     }
842     clear(); /* clear rest of line */
843     /* so next read will come from */
844     /* new file (if open) */
845 }
846 
847 /*
848  *      Close an include file
849  */
endinclude()850 void endinclude()
851 {
852     if (c_verbose) {
853         toconsole();
854         outstr("#end include\n");
855         tofile();
856     }
857 
858     inpt2 = 0;
859     lineno = saveline;
860     currfn = savecurr;
861     infunc = saveinfn;
862 }
863 
864 /*
865  *      Close the output file
866  */
closeout()867 void closeout()
868 {
869     tofile(); /* if diverted, return to file */
870     if (output) {
871         /* if open, close it */
872         fclose(output);
873     }
874     output = 0; /* mark as closed */
875 }
876 
877 
878 
879 
opt_code_speed(option * arg,char * val)880 static void opt_code_speed(option *arg, char* val)
881 {
882     char   *ptr = val - 1;
883 
884     c_speed_optimisation = 0;
885 
886     do {
887         ptr++;
888         if ( strncmp(ptr,"all",3) == 0 ) {
889             c_speed_optimisation = ~0;
890             break;
891         } else if ( strncmp(ptr, "lshift32", 8) == 0 ) {
892             c_speed_optimisation |= OPT_LSHIFT32;
893         } else if ( strncmp(ptr, "rshift32", 8) == 0 ) {
894             c_speed_optimisation |= OPT_RSHIFT32;
895         } else if ( strncmp(ptr, "add32", 5) == 0 ) {
896             c_speed_optimisation |= OPT_ADD32;
897         } else if ( strncmp(ptr, "sub32", 5) == 0 ) {
898             c_speed_optimisation |= OPT_SUB32;
899         } else if ( strncmp(ptr, "sub16", 5) == 0 ) {
900             c_speed_optimisation |= OPT_SUB16;
901         } else if ( strncmp(ptr, "intcompare", 10) == 0 ) {
902             c_speed_optimisation |= OPT_INT_COMPARE;
903         } else if ( strncmp(ptr, "charcompare", 10) == 0 ) {
904             c_speed_optimisation |= OPT_CHAR_COMPARE;
905         } else if ( strncmp(ptr, "longcompare", 11) == 0 ) {
906             c_speed_optimisation |= OPT_LONG_COMPARE;
907         } else if ( strncmp(ptr, "ucharmult", 9) == 0 ) {
908             c_speed_optimisation |= OPT_UCHAR_MULT;
909         } else if ( strncmp(ptr, "floatconst", 10) == 0 ) {
910             c_speed_optimisation |= OPT_DOUBLE_CONST;
911         }
912     } while ( (ptr = strchr(ptr, ',')) != NULL );
913 }
914 
915 
916 
SetDefine(option * arg,char * val)917 void SetDefine(option *arg, char* val)
918 {
919     defmac(val);
920 }
921 
SetUndefine(option * arg,char * val)922 void SetUndefine(option *arg, char* val)
923 {
924     strcpy(line, val);
925     delmac();
926 }
927 
928 
SetWarning(option * arg,char * value)929 void SetWarning(option *arg, char *value)
930 {
931     parse_warning_option(value);
932 }
933 
934 
DispInfo(option * arg,char * val)935 void DispInfo(option *arg, char *val)
936 {
937     option *cur = &sccz80_opts[0];
938     info();
939 
940     option_list(cur);
941 
942     exit(1);
943 }
944 
DispVersion(char * arg)945 void DispVersion(char* arg)
946 {
947     info();
948     exit(1);
949 }
950 
951 
952 
953 
954 /*
955  *      This routine called via atexit to clean up memory
956  */
957 
atexit_deallocate()958 void atexit_deallocate()
959 {
960     FREENULL(litq);
961     FREENULL(dubq);
962     FREENULL(tempq);
963     FREENULL(glbq);
964     FREENULL(loctab);
965     FREENULL(wqueue);
966     FREENULL(swnext);
967     FREENULL(stage);
968     FREENULL(gotoq);
969 }
970 
mymalloc(size_t size)971 void* mymalloc(size_t size)
972 {
973     void* ptr;
974 
975     if ((ptr = calloc(size, 1)) != NULL)
976         return ptr;
977     else {
978         fprintf(stderr, "Out of memory...\n");
979         exit(1);
980     }
981     return 0; /* Sigh */
982 }
983