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