a fix for the initialized structs and some others, see
[fw/sdcc] / src / SDCCmain.c
1 /*-------------------------------------------------------------------------
2   SDCCmain.c - main file
3
4              Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1999)
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any
9    later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20    In other words, you are welcome to use, share and improve this program.
21    You are forbidden to forbid anyone else to use, share and improve
22    what you give them.   Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
24
25 #include "common.h"
26 #include <ctype.h>
27 #include "newalloc.h"
28 #include "SDCCerr.h"
29 #include "BuildCmd.h"
30 #include "MySystem.h"
31
32 #if NATIVE_WIN32
33 #include <process.h>
34 #else
35 #include "spawn.h"
36 #endif
37
38 // This is a bit messy because we define link ourself
39 #if !defined(__BORLANDC__) && !defined(_MSC_VER)
40
41 #include <unistd.h>
42
43 #else
44 // No unistd.h in Borland C++
45 /*
46 extern int access (const char *, int);
47 #define X_OK 1
48 */
49
50 #endif
51
52 //REMOVE ME!!!
53 extern int yyparse ();
54
55 FILE *srcFile;                  /* source file          */
56 FILE *cdbFile = NULL;           /* debugger information output file */
57 char *fullSrcFileName;          /* full name for the source file */
58 char *srcFileName;              /* source file name with the .c stripped */
59 char *moduleName;               /* module name is srcFilename stripped of any path */
60 const char *preArgv[128];       /* pre-processor arguments  */
61 int currRegBank = 0;
62 struct optimize optimize;
63 struct options options;
64 char *VersionString = SDCC_VERSION_STR /*"Version 2.1.8a" */ ;
65 int preProcOnly = 0;
66 int noAssemble = 0;
67 char *linkOptions[128];
68 const char *asmOptions[128];
69 char *libFiles[128];
70 int nlibFiles = 0;
71 char *libPaths[128];
72 int nlibPaths = 0;
73 char *relFiles[128];
74 int nrelFiles = 0;
75 bool verboseExec = FALSE;
76 char *preOutName;
77
78 // Globally accessible scratch buffer for file names.
79 char scratchFileName[FILENAME_MAX];
80
81 // In MSC VC6 default search path for exe's to path for this
82
83 char DefaultExePath[128];
84
85 #define OPTION_HELP     "-help"
86
87 #define LENGTH(_a)      (sizeof(_a)/sizeof(*(_a)))
88
89 #define OPTION_STACK_8BIT       "--stack-8bit"
90 #define OPTION_OUT_FMT_IHX      "--out-fmt-ihx"
91 #define OPTION_LARGE_MODEL      "--model-large"
92 #define OPTION_MEDIUM_MODEL     "--model-medium"
93 #define OPTION_SMALL_MODEL      "--model-small"
94 #define OPTION_FLAT24_MODEL     "--model-flat24"
95 #define OPTION_DUMP_ALL         "--dumpall"
96 #define OPTION_PEEP_FILE        "--peep-file"
97 #define OPTION_LIB_PATH         "--lib-path"
98 #define OPTION_XSTACK_LOC       "--xstack-loc"
99 #define OPTION_CALLEE_SAVES     "--callee-saves"
100 #define OPTION_STACK_LOC        "--stack-loc"
101 #define OPTION_XRAM_LOC         "--xram-loc"
102 #define OPTION_IRAM_SIZE        "--iram-size"
103 #define OPTION_VERSION          "--version"
104 #define OPTION_DATA_LOC         "--data-loc"
105 #define OPTION_CODE_LOC         "--code-loc"
106 #define OPTION_IDATA_LOC        "--idata-loc"
107 #define OPTION_NO_LOOP_INV      "--noinvariant"
108 #define OPTION_NO_LOOP_IND      "--noinduction"
109 #define OPTION_LESS_PEDANTIC    "--lesspedantic"
110 #define OPTION_NO_GCSE          "--nogcse"
111 #define OPTION_SHORT_IS_CHAR    "--short-is-char"
112
113 /** Table of all options supported by all ports.
114     This table provides:
115       * A reference for all options.
116       * An easy way to maintain help for the options.
117       * Automatic support for setting flags on simple options.
118 */
119 typedef struct {
120     /** The short option character e.g. 'h' for -h.  0 for none. */
121     char shortOpt;
122     /** Long option e.g. "--help".  Includes the -- prefix.  NULL for
123         none. */
124     const char *longOpt;
125     /** Pointer to an int that will be incremented every time the
126         option is encountered.  May be NULL.
127     */
128     int *pparameter;
129     /** Help text to go with this option.  May be NULL. */
130     const char *help;
131 } OPTION;
132
133 static const OPTION 
134 optionsTable[] = {
135     { 'm',  NULL,                   NULL, "Set the port to use e.g. -mz80." },
136     { 'd',  NULL,                   NULL, NULL },
137     { 'D',  NULL,                   NULL, "Define macro as in -Dmacro" },
138     { 'I',  NULL,                   NULL, "Add to the include (*.h) path, as in -Ipath" },
139     { 'A',  NULL,                   NULL, NULL },
140     { 'U',  NULL,                   NULL, NULL },
141     { 'C',  NULL,                   NULL, "Preprocessor option" },
142     { 'M',  NULL,                   NULL, "Preprocessor option" },
143     { 'V',  NULL,                   &verboseExec, "Execute verbosely.  Show sub commands as they are run" },
144     { 'S',  NULL,                   &noAssemble, "Assemble only" },
145     { 'W',  NULL,                   NULL, "Pass through options to the assembler (a) or linker (l)" },
146     { 'L',  NULL,                   NULL, "Add the next field to the library search path" },
147     { 0,    OPTION_LARGE_MODEL,     NULL, "Far functions, far data" },
148     { 0,    OPTION_MEDIUM_MODEL,    NULL, "Far functions, near data" },
149     { 0,    OPTION_SMALL_MODEL,     NULL, "Small model (default)" },
150     { 0,    OPTION_FLAT24_MODEL,    NULL, NULL },
151     { 0,    "--stack-auto",         &options.stackAuto, "Stack automatic variables" },
152     { 0,    OPTION_STACK_8BIT,      NULL, NULL },
153     { 0,    "--stack-10bit",        &options.stack10bit, NULL },
154     { 0,    "--xstack",             &options.useXstack, "Use external stack" },
155     { 0,    "--generic",            &options.genericPtr, "All unqualified ptrs converted to '_generic'" },
156     { 0,    OPTION_NO_GCSE,         NULL, "Disable the GCSE optimisation" },
157     { 0,    OPTION_NO_LOOP_INV,     NULL, "Disable optimisation of invariants" },
158     { 0,    OPTION_NO_LOOP_IND,     NULL, NULL },
159     { 0,    "--nojtbound",          &optimize.noJTabBoundary, "Don't generate boundary check for jump tables" },
160     { 0,    "--noloopreverse",      &optimize.noLoopReverse, "Disable the loop reverse optimisation" },
161     { 0,    "--regextend",          &options.regExtend, NULL },
162     { 'c',  "--compile-only",       &options.cc_only, "Compile only, do not assemble or link" },
163     { 0,    "--dumpraw",            &options.dump_raw, "Dump the internal structure after the initial parse" },
164     { 0,    "--dumpgcse",           &options.dump_gcse, NULL },
165     { 0,    "--dumploop",           &options.dump_loop, NULL },
166     { 0,    "--dumpdeadcode",       &options.dump_kill, NULL },
167     { 0,    "--dumpliverange",      &options.dump_range, NULL },
168     { 0,    "--dumpregpack",        &options.dump_pack, NULL },
169     { 0,    "--dumpregassign",      &options.dump_rassgn, NULL },
170     { 0,    OPTION_DUMP_ALL,        NULL, "Dump the internal structure at all stages" },
171     { 0,    OPTION_XRAM_LOC,        NULL, NULL },
172     { 0,    OPTION_IRAM_SIZE,       NULL, "<nnnn> Internal Ram size" },
173     { 0,    OPTION_XSTACK_LOC,      NULL, "<nnnn> External Ram start location" },
174     { 0,    OPTION_CODE_LOC,        NULL, "<nnnn> Code Segment Location" },
175     { 0,    OPTION_STACK_LOC,       NULL, "<nnnn> Stack pointer initial value" },
176     { 0,    OPTION_DATA_LOC,        NULL, "<nnnn> Direct data start location" },
177     { 0,    OPTION_IDATA_LOC,       NULL, NULL },
178     { 0,    OPTION_PEEP_FILE,       NULL, NULL },
179     { 0,    OPTION_LIB_PATH,        NULL, NULL },
180     { 0,    "--int-long-reent",     &options.intlong_rent, "Use reenterant calls on the int and long support functions" },
181     { 0,    "--float-reent",        &options.float_rent, "Use reenterant calls on the floar support functions" },
182     { 0,    OPTION_OUT_FMT_IHX,     NULL, NULL },
183     { 0,    "--out-fmt-s19",        &options.out_fmt, NULL },
184     { 0,    "--cyclomatic",         &options.cyclomatic, NULL },
185     { 0,    "--nooverlay",          &options.noOverlay, NULL },
186     { 0,    "--main-return",        &options.mainreturn, "Issue a return after main()" },
187     { 0,    "--no-peep",            &options.nopeep, "Disable the peephole assembly file optimisation" },
188     { 0,    "--peep-asm",           &options.asmpeep, NULL },
189     { 0,    "--debug",              &options.debug, "Enable debugging symbol output" },
190     { 0,    "--nodebug",            &options.nodebug, "Disable debugging symbol output" },
191     { 'v',  OPTION_VERSION,         NULL, "Display sdcc's version" },
192     { 0,    "--stack-after-data",   &options.stackOnData, NULL },
193     { 'E',  "--preprocessonly",     &preProcOnly, "Preprocess only, do not compile" },
194     { 0,    "--c1mode",             &options.c1mode, "Act in c1 mode.  The input is preprocessed code, the output is assembly code." },
195     { 0,    "--help",               NULL, "Display this help" },
196     { 0,    OPTION_CALLEE_SAVES,    NULL, "Cause the called function to save registers insted of the caller" },
197     { 0,    "--nostdlib",           &options.nostdlib, "Do not include the standard library directory in the search path" },
198     { 0,    "--nostdinc",           &options.nostdinc, NULL },
199     { 0,    "--verbose",            &options.verbose, "Trace calls to the preprocessor, assembler, and linker" },
200     { 0,    OPTION_LESS_PEDANTIC,   NULL, "Disable some of the more pedantic warnings" },
201     { 0,    "--short-is-int",       &options.shortisint, "Make short the same size as int" },
202     { 0,    OPTION_SHORT_IS_CHAR,   NULL, "Make short the same size as char (default)" }
203 };
204
205 /** Table of all unsupported options and help text to display when one
206     is used.
207 */
208 typedef struct {
209     /** shortOpt as in OPTIONS. */
210     char shortOpt;
211     /** longOpt as in OPTIONS. */
212     const char *longOpt;
213     /** Message to display inside W_UNSUPPORTED_OPT when this option
214         is used. */
215     const char *message;
216 } UNSUPPORTEDOPT;
217
218 static const UNSUPPORTEDOPT 
219 unsupportedOptTable[] = {
220     { 'a',  NULL,       "use --stack-auto instead." },
221     { 'g',  NULL,       "use --generic instead" },
222     { 'X',  NULL,       "use --xstack-loc instead" },
223     { 'x',  NULL,       "use --xstack instead" },
224     { 'p',  NULL,       "use --stack-loc instead" },
225     { 'P',  NULL,       "use --stack-loc instead" },
226     { 'i',  NULL,       "use --idata-loc instead" },
227     { 'r',  NULL,       "use --xdata-loc instead" },
228     { 's',  NULL,       "use --code-loc instead" },
229     { 'Y',  NULL,       "use -I instead" }
230 };
231
232 static const char *_preCmd[] =
233 {
234   "sdcpp", "-Wall", "-lang-c++", "-DSDCC=1",
235   "$l", "$1", "$2", NULL
236 };
237
238 PORT *port;
239
240 static PORT *_ports[] =
241 {
242 #if !OPT_DISABLE_MCS51
243   &mcs51_port,
244 #endif
245 #if !OPT_DISABLE_GBZ80
246   &gbz80_port,
247 #endif
248 #if !OPT_DISABLE_Z80
249   &z80_port,
250 #endif
251 #if !OPT_DISABLE_AVR
252   &avr_port,
253 #endif
254 #if !OPT_DISABLE_DS390
255   &ds390_port,
256 #endif
257 #if !OPT_DISABLE_PIC
258   &pic_port,
259 #endif
260 #if !OPT_DISABLE_I186
261   &i186_port,
262 #endif
263 #if !OPT_DISABLE_TLCS900H
264   &tlcs900h_port,
265 #endif
266 };
267
268 #define NUM_PORTS (sizeof(_ports)/sizeof(_ports[0]))
269
270 /**
271    remove me - TSD a hack to force sdcc to generate gpasm format .asm files.
272  */
273 extern void picglue ();
274
275 /** Sets the port to the one given by the command line option.
276     @param    The name minus the option (eg 'mcs51')
277     @return     0 on success.
278 */
279 static void
280 _setPort (const char *name)
281 {
282   int i;
283   for (i = 0; i < NUM_PORTS; i++)
284     {
285       if (!strcmp (_ports[i]->target, name))
286         {
287           port = _ports[i];
288           return;
289         }
290     }
291   /* Error - didnt find */
292   werror (E_UNKNOWN_TARGET, name);
293   exit (1);
294 }
295
296 static void
297 _validatePorts (void)
298 {
299   int i;
300   for (i = 0; i < NUM_PORTS; i++)
301     {
302       if (_ports[i]->magic != PORT_MAGIC)
303         {
304           printf ("Error: port %s is incomplete.\n", _ports[i]->target);
305           wassert (0);
306         }
307     }
308 }
309 /*-----------------------------------------------------------------*/
310 /* printVersionInfo - prints the version info        */
311 /*-----------------------------------------------------------------*/
312 void
313 printVersionInfo ()
314 {
315   int i;
316
317   fprintf (stderr,
318            "SDCC : ");
319   for (i = 0; i < NUM_PORTS; i++)
320     fprintf (stderr, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
321
322   fprintf (stderr, " %s"
323 #ifdef SDCC_SUB_VERSION_STR
324            "/" SDCC_SUB_VERSION_STR
325 #endif
326 #ifdef __CYGWIN32__
327            " (CYGWIN32)\n"
328 #else
329 #ifdef __DJGPP__
330            " (DJGPP) \n"
331 #else
332 #if defined(_MSC_VER)
333            " (WIN32) \n"
334 #else
335            " (UNIX) \n"
336 #endif
337 #endif
338 #endif
339
340            ,VersionString
341     );
342 }
343
344 /*
345        "\t-m<proc>             -     Target processor <proc>.  Default %s\n"
346            "\t                           Try --version for supported values of <proc>\n"
347            "\t--model-large        -     Large Model\n"
348            "\t--model-small        -     Small Model (default)\n"
349            "\t--stack-auto         -     Stack automatic variables\n"
350            "\t--xstack             -     Use external stack\n"
351            "\t--xram-loc <nnnn>    -     External Ram start location\n"
352            "\t--xstack-loc <nnnn>  -     Xternal Stack Location\n"
353            "\t--code-loc <nnnn>    -     Code Segment Location\n"
354            "\t--stack-loc <nnnn>   -     Stack pointer initial value\n"
355            "\t--data-loc <nnnn>    -     Direct data start location\n"
356            "\t--idata-loc <nnnn>   -     Indirect data start location\n"
357            "\t--iram-size <nnnn>   -     Internal Ram size\n"
358            "\t--nojtbound          -     Don't generate boundary check for jump tables\n"
359            "\t--generic            -     All unqualified ptrs converted to '_generic'\n"
360            "PreProcessor Options :-\n"
361            "\t-Dmacro   - Define Macro\n"
362            "\t-Ipath    - Include \"*.h\" path\n"
363       "Note: this is NOT a complete list of options see docs for details\n",
364 */
365 /*-----------------------------------------------------------------*/
366 /* printUsage - prints command line syntax         */
367 /*-----------------------------------------------------------------*/
368 void
369 printUsage ()
370 {
371     int i;
372     printVersionInfo();
373     fprintf (stdout,
374              "Usage : sdcc [options] filename\n"
375              "Options :-\n"
376              );
377     
378     for (i = 0; i < LENGTH(optionsTable); i++) {
379         fprintf(stdout, "  %c%c  %-20s  %s\n", 
380                 optionsTable[i].shortOpt !=0 ? '-' : ' ',
381                 optionsTable[i].shortOpt !=0 ? optionsTable[i].shortOpt : ' ',
382                 optionsTable[i].longOpt != NULL ? optionsTable[i].longOpt : "",
383                 optionsTable[i].help != NULL ? optionsTable[i].help : ""
384                 );
385     }
386     exit (0);
387 }
388
389 /*-----------------------------------------------------------------*/
390 /* parseWithComma - separates string with comma                    */
391 /*-----------------------------------------------------------------*/
392 void
393 parseWithComma (char **dest, char *src)
394 {
395   int i = 0;
396
397   strtok (src, "\n \t");
398   /* skip the initial white spaces */
399   while (isspace (*src))
400     src++;
401   dest[i++] = src;
402   while (*src)
403     {
404       if (*src == ',')
405         {
406           *src = '\0';
407           src++;
408           if (*src)
409             dest[i++] = src;
410           continue;
411         }
412       src++;
413     }
414 }
415
416 /*-----------------------------------------------------------------*/
417 /* setDefaultOptions - sets the default options                    */
418 /*-----------------------------------------------------------------*/
419 static void
420 setDefaultOptions ()
421 {
422   int i;
423
424   for (i = 0; i < 128; i++)
425     preArgv[i] = asmOptions[i] =
426       linkOptions[i] = relFiles[i] = libFiles[i] =
427       libPaths[i] = NULL;
428
429   /* first the options part */
430   options.stack_loc = 0;        /* stack pointer initialised to 0 */
431   options.xstack_loc = 0;       /* xternal stack starts at 0 */
432   options.code_loc = 0;         /* code starts at 0 */
433   options.data_loc = 0x0030;    /* data starts at 0x0030 */
434   options.xdata_loc = 0;
435   options.idata_loc = 0x80;
436   options.genericPtr = 1;       /* default on */
437   options.nopeep = 0;
438   options.model = port->general.default_model;
439   options.nostdlib = 0;
440   options.nostdinc = 0;
441   options.verbose = 0;
442   options.shortisint = 0;
443
444   options.stack10bit=0;
445
446   /* now for the optimizations */
447   /* turn on the everything */
448   optimize.global_cse = 1;
449   optimize.label1 = 1;
450   optimize.label2 = 1;
451   optimize.label3 = 1;
452   optimize.label4 = 1;
453   optimize.loopInvariant = 1;
454   optimize.loopInduction = 1;
455
456   /* now for the ports */
457   port->setDefaultOptions ();
458 }
459
460 /*-----------------------------------------------------------------*/
461 /* processFile - determines the type of file from the extension    */
462 /*-----------------------------------------------------------------*/
463 static void
464 processFile (char *s)
465 {
466   char *fext = NULL;
467
468   /* get the file extension */
469   fext = s + strlen (s);
470   while ((fext != s) && *fext != '.')
471     fext--;
472
473   /* now if no '.' then we don't know what the file type is
474      so give a warning and return */
475   if (fext == s)
476     {
477       werror (W_UNKNOWN_FEXT, s);
478       return;
479     }
480
481   /* otherwise depending on the file type */
482   if (strcmp (fext, ".c") == 0 || strcmp (fext, ".C") == 0 || options.c1mode)
483     {
484       /* source file name : not if we already have a
485          source file */
486       if (srcFileName)
487         {
488           werror (W_TOO_MANY_SRC, s);
489           return;
490         }
491
492       /* the only source file */
493       if (!(srcFile = fopen ((fullSrcFileName = s), "r")))
494         {
495           werror (E_FILE_OPEN_ERR, s);
496           exit (1);
497         }
498
499       /* copy the file name into the buffer */
500       strcpy (buffer, s);
501
502       /* get rid of the "." */
503       strtok (buffer, ".");
504       srcFileName = Safe_calloc (1, strlen (buffer) + 1);
505       strcpy (srcFileName, buffer);
506
507       /* get rid of any path information
508          for the module name; do this by going
509          backwards till we get to either '/' or '\' or ':'
510          or start of buffer */
511       fext = buffer + strlen (buffer);
512       while (fext != buffer &&
513              *(fext - 1) != '\\' &&
514              *(fext - 1) != '/' &&
515              *(fext - 1) != ':')
516         fext--;
517       moduleName = Safe_calloc (1, strlen (fext) + 1);
518       strcpy (moduleName, fext);
519
520       return;
521     }
522
523   /* if the extention is type .rel or .r or .REL or .R
524      addtional object file will be passed to the linker */
525   if (strcmp (fext, ".r") == 0 || strcmp (fext, ".rel") == 0 ||
526       strcmp (fext, ".R") == 0 || strcmp (fext, ".REL") == 0 ||
527       strcmp (fext, port->linker.rel_ext) == 0)
528     {
529       relFiles[nrelFiles++] = s;
530       return;
531     }
532
533   /* if .lib or .LIB */
534   if (strcmp (fext, ".lib") == 0 || strcmp (fext, ".LIB") == 0)
535     {
536       libFiles[nlibFiles++] = s;
537       return;
538     }
539
540   werror (W_UNKNOWN_FEXT, s);
541
542 }
543
544 static void
545 _processC1Arg (char *s)
546 {
547   if (srcFileName)
548     {
549       if (options.out_name)
550         {
551           werror (W_TOO_MANY_SRC, s);
552           return;
553         }
554       options.out_name = strdup (s);
555     }
556   else
557     {
558       processFile (s);
559     }
560 }
561
562 static void
563 _addToList (const char **list, const char *str)
564 {
565   /* This is the bad way to do things :) */
566   while (*list)
567     list++;
568   *list = strdup (str);
569   if (!*list)
570     {
571       werror (E_OUT_OF_MEM, __FILE__, 0);
572       exit (1);
573     }
574   *(++list) = NULL;
575 }
576
577 static void
578 _setModel (int model, const char *sz)
579 {
580   if (port->general.supported_models & model)
581     options.model = model;
582   else
583     werror (W_UNSUPPORTED_MODEL, sz, port->target);
584 }
585
586 /** Gets the string argument to this option.  If the option is '--opt'
587     then for input of '--optxyz' or '--opt xyz' returns xyz.
588 */
589 static char *
590 getStringArg(const char *szStart, char **argv, int *pi)
591 {
592     if (argv[*pi][strlen(szStart)]) {
593         return &argv[*pi][strlen(szStart)];
594     }
595     else {
596         return argv[++(*pi)];
597     }
598 }
599
600 /** Gets the integer argument to this option using the same rules as
601     getStringArg. 
602 */
603 static int
604 getIntArg(const char *szStart, char **argv, int *pi)
605 {
606     return (int)floatFromVal(constVal(getStringArg(szStart, argv, pi)));
607 }
608
609 static bool
610 tryHandleUnsupportedOpt(char **argv, int *pi)
611 {
612     if (argv[*pi][0] == '-') 
613         {
614             const char *longOpt = "";
615             char shortOpt = -1;
616             int i;
617
618             if (argv[*pi][1] == '-') 
619                 {
620                     // Long option.
621                     longOpt = argv[*pi];
622                 }
623             else 
624                 {
625                     shortOpt = argv[*pi][1];
626                 }
627             for (i = 0; i < LENGTH(unsupportedOptTable); i++) 
628                 {
629                     if (unsupportedOptTable[i].shortOpt == shortOpt || 
630                         (longOpt && unsupportedOptTable[i].longOpt && !strcmp(unsupportedOptTable[i].longOpt, longOpt))) {
631                         // Found an unsupported opt.
632                         char buffer[100];
633                         sprintf(buffer, "%s%c%c", longOpt ? longOpt : "", shortOpt ? '-' : ' ', shortOpt ? shortOpt : ' ');
634                         werror (W_UNSUPP_OPTION, buffer, unsupportedOptTable[i].message);
635                         return 1;
636                     }
637                 }
638             // Didn't find in the table
639             return 0;
640         }
641     else 
642         {
643             // Not an option, so can't be unsupported :)
644             return 0;
645     }
646 }
647
648 static bool
649 tryHandleSimpleOpt(char **argv, int *pi)
650 {
651     if (argv[*pi][0] == '-') 
652         {
653             const char *longOpt = "";
654             char shortOpt = -1;
655             int i;
656
657             if (argv[*pi][1] == '-') 
658                 {
659                     // Long option.
660                     longOpt = argv[*pi];
661                 }
662             else 
663                 {
664                     shortOpt = argv[*pi][1];
665                 }
666
667             for (i = 0; i < LENGTH(optionsTable); i++) 
668                 {
669                     if (optionsTable[i].shortOpt == shortOpt || 
670                         (longOpt && optionsTable[i].longOpt && strcmp(optionsTable[i].longOpt, longOpt) == 0))
671                         {
672                             // If it is a flag then we can handle it here
673                             if (optionsTable[i].pparameter != NULL) 
674                                 {
675                                     (*optionsTable[i].pparameter)++;
676                                     return 1;
677                                 }
678                             else {
679                                 // Not a flag.  Handled manually later.
680                                 return 0;
681                             }
682                         }
683                 }
684             // Didn't find in the table
685             return 0;
686         }
687     else 
688         {
689             // Not an option, so can't be handled.
690             return 0;
691         }
692 }
693
694 /*-----------------------------------------------------------------*/
695 /* parseCmdLine - parses the command line and sets the options     */
696 /*-----------------------------------------------------------------*/
697 int
698 parseCmdLine (int argc, char **argv)
699 {
700   int i;
701
702   /* go thru all whole command line */
703   for (i = 1; i < argc; i++)
704     {
705       if (i >= argc)
706         break;
707
708       if (tryHandleUnsupportedOpt(argv, &i) == TRUE) 
709           {
710               continue;
711           }
712
713       if (tryHandleSimpleOpt(argv, &i) == TRUE)
714           {
715               continue;
716           }
717
718       /* options */
719       if (argv[i][0] == '-' && argv[i][1] == '-')
720         {
721           if (strcmp (argv[i], OPTION_HELP) == 0)
722             {
723               printUsage ();
724               exit (0);
725             }
726
727           if (strcmp (argv[i], OPTION_STACK_8BIT) == 0)
728             {
729               options.stack10bit = 0;
730               continue;
731             }
732
733           if (strcmp (argv[i], OPTION_OUT_FMT_IHX) == 0)
734             {
735               options.out_fmt = 0;
736               continue;
737             }
738
739           if (strcmp (argv[i], OPTION_LARGE_MODEL) == 0)
740             {
741               _setModel (MODEL_LARGE, argv[i]);
742               continue;
743             }
744
745           if (strcmp (argv[i], OPTION_MEDIUM_MODEL) == 0)
746             {
747               _setModel (MODEL_MEDIUM, argv[i]);
748               continue;
749             }
750
751           if (strcmp (argv[i], OPTION_SMALL_MODEL) == 0)
752             {
753               _setModel (MODEL_SMALL, argv[i]);
754               continue;
755             }
756
757           if (strcmp (argv[i], OPTION_FLAT24_MODEL) == 0)
758             {
759               _setModel (MODEL_FLAT24, argv[i]);
760               continue;
761             }
762
763           if (strcmp (argv[i], OPTION_DUMP_ALL) == 0)
764             {
765               options.dump_rassgn =
766                 options.dump_pack =
767                 options.dump_range =
768                 options.dump_kill =
769                 options.dump_loop =
770                 options.dump_gcse =
771                 options.dump_raw = 1;
772               continue;
773             }
774
775           if (strcmp (argv[i], OPTION_PEEP_FILE) == 0)
776             {
777                 options.peep_file = getStringArg(OPTION_PEEP_FILE, argv, &i);
778                 continue;
779             }
780
781           if (strcmp (argv[i], OPTION_LIB_PATH) == 0)
782             {
783                 libPaths[nlibPaths++] = getStringArg(OPTION_LIB_PATH, argv, &i);
784                 continue;
785             }
786
787           if (strcmp (argv[i], OPTION_VERSION) == 0)
788             {
789               printVersionInfo ();
790               exit (0);
791               continue;
792             }
793
794           if (strcmp (argv[i], OPTION_CALLEE_SAVES) == 0)
795             {
796                 parseWithComma (options.calleeSaves, getStringArg(OPTION_CALLEE_SAVES, argv, &i));
797                 continue;
798             }
799
800           if (strcmp (argv[i], OPTION_XSTACK_LOC) == 0)
801             {
802                 options.xstack_loc = getIntArg(OPTION_XSTACK_LOC, argv, &i);
803                 continue;
804             }
805
806           if (strcmp (argv[i], OPTION_STACK_LOC) == 0)
807             {
808                 options.stack_loc = getIntArg(OPTION_STACK_LOC, argv, &i);
809                 continue;
810             }
811
812           if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
813             {
814                 options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i);
815                 continue;
816             }
817
818           if (strcmp (argv[i], OPTION_IRAM_SIZE) == 0)
819             {
820                 options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i);
821                 continue;
822             }
823
824           if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
825             {
826                 options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i);
827                 continue;
828             }
829
830           if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
831             {
832                 options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i);
833                 continue;
834             }
835
836           if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
837             {
838                 options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i);
839                 continue;
840             }
841
842           if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
843             {
844               optimize.global_cse = 0;
845               continue;
846             }
847
848           if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
849             {
850               optimize.loopInvariant = 0;
851               continue;
852             }
853
854           if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
855             {
856               optimize.loopInduction = 0;
857               continue;
858             }
859
860           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0) 
861               {
862                   setErrorLogLevel(ERROR_LEVEL_WARNING);
863                   continue;
864               }
865
866           if (strcmp (&argv[i][1], OPTION_SHORT_IS_CHAR) == 0) {
867             options.shortisint=0;
868             continue;
869           }
870           
871           if (!port->parseOption (&argc, argv, &i))
872             {
873               werror (W_UNKNOWN_OPTION, argv[i]);
874             }
875           else
876             {
877               continue;
878             }
879         }
880
881       /* if preceded by  '-' then option */
882       if (*argv[i] == '-')
883         {
884           switch (argv[i][1])
885             {
886             case 'h':
887               printUsage ();
888               exit (0);
889               break;
890
891             case 'm':
892               /* Used to select the port */
893               _setPort (argv[i] + 2);
894               break;
895
896             case 'c':
897               options.cc_only = 1;
898               break;
899
900             case 'L':
901                 libPaths[nlibPaths++] = getStringArg("-L", argv, &i);
902                 break;
903
904             case 'W':
905               /* linker options */
906               if (argv[i][2] == 'l')
907                 {
908                     parseWithComma(linkOptions, getStringArg("-Wl", argv, &i));
909                 }
910               else
911                 {
912                   /* assembler options */
913                   if (argv[i][2] == 'a')
914                     {
915                         parseWithComma ((char **) asmOptions, getStringArg("-Wa", argv, &i));
916                     }
917                   else
918                     {
919                       werror (W_UNKNOWN_OPTION, argv[i]);
920                     }
921                 }
922               break;
923
924             case 'v':
925               printVersionInfo ();
926               exit (0);
927               break;
928
929               /* preprocessor options */
930             case 'M':
931               {
932                 preProcOnly = 1;
933                 _addToList (preArgv, "-M");
934                 break;
935               }
936             case 'C':
937               {
938                 _addToList (preArgv, "-C");
939                 break;
940               }
941             case 'd':
942             case 'D':
943             case 'I':
944             case 'A':
945             case 'U':
946               {
947                 char sOpt = argv[i][1];
948                 char *rest;
949
950                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
951                   {
952                     i++;
953                     if (i >= argc) 
954                       {
955                           /* No argument. */
956                           werror(E_ARGUMENT_MISSING, argv[i-1]);
957                           break;
958                       }
959                     else 
960                       {
961                           rest = argv[i];
962                       }
963                   }
964                 else
965                   rest = &argv[i][2];
966
967                 if (sOpt == 'Y')
968                   sOpt = 'I';
969
970                 sprintf (buffer, "-%c%s", sOpt, rest);
971                 _addToList (preArgv, buffer);
972               }
973               break;
974
975             default:
976               if (!port->parseOption (&argc, argv, &i))
977                 werror (W_UNKNOWN_OPTION, argv[i]);
978             }
979           continue;
980         }
981
982       if (!port->parseOption (&argc, argv, &i))
983         {
984           /* no option must be a filename */
985           if (options.c1mode)
986             _processC1Arg (argv[i]);
987           else
988             processFile (argv[i]);
989         }
990     }
991
992   /* set up external stack location if not explicitly specified */
993   if (!options.xstack_loc)
994     options.xstack_loc = options.xdata_loc;
995
996   /* if debug option is set the open the cdbFile */
997   if (!options.nodebug && srcFileName)
998     {
999       sprintf (scratchFileName, "%s.cdb", srcFileName);
1000       if ((cdbFile = fopen (scratchFileName, "w")) == NULL)
1001         werror (E_FILE_OPEN_ERR, scratchFileName);
1002       else
1003         {
1004           /* add a module record */
1005           fprintf (cdbFile, "M:%s\n", moduleName);
1006         }
1007     }
1008   return 0;
1009 }
1010
1011 /*-----------------------------------------------------------------*/
1012 /* linkEdit : - calls the linkage editor  with options             */
1013 /*-----------------------------------------------------------------*/
1014 static void
1015 linkEdit (char **envp)
1016 {
1017   FILE *lnkfile;
1018   char *segName, *c;
1019
1020   int i;
1021   if (!srcFileName)
1022     srcFileName = "temp";
1023
1024   /* first we need to create the <filename>.lnk file */
1025   sprintf (scratchFileName, "%s.lnk", srcFileName);
1026   if (!(lnkfile = fopen (scratchFileName, "w")))
1027     {
1028       werror (E_FILE_OPEN_ERR, scratchFileName);
1029       exit (1);
1030     }
1031
1032   /* now write the options */
1033   fprintf (lnkfile, "-mux%c\n", (options.out_fmt ? 's' : 'i'));
1034
1035   /* if iram size specified */
1036   if (options.iram_size)
1037     fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1038
1039   /*if (options.debug) */
1040   fprintf (lnkfile, "-z\n");
1041
1042 #define WRITE_SEG_LOC(N, L) \
1043     segName = strdup(N); \
1044     c = strtok(segName, " \t"); \
1045     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1046     if (segName) { free(segName); }
1047
1048   /* code segment start */
1049   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1050
1051   /* data segment start */
1052   WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1053
1054   /* xdata start */
1055   WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1056
1057   /* indirect data */
1058   WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1059
1060   /* bit segment start */
1061   WRITE_SEG_LOC (BIT_NAME, 0);
1062
1063   /* add the extra linker options */
1064   for (i = 0; linkOptions[i]; i++)
1065     fprintf (lnkfile, "%s\n", linkOptions[i]);
1066
1067   /* other library paths if specified */
1068   for (i = 0; i < nlibPaths; i++)
1069     fprintf (lnkfile, "-k %s\n", libPaths[i]);
1070
1071   /* standard library path */
1072   if (!options.nostdlib)
1073     {
1074       if (TARGET_IS_DS390)
1075         {
1076           c = "ds390";
1077         }
1078       else
1079         {
1080           switch (options.model)
1081             {
1082             case MODEL_SMALL:
1083               c = "small";
1084               break;
1085             case MODEL_LARGE:
1086               c = "large";
1087               break;
1088             case MODEL_FLAT24:
1089               c = "flat24";
1090               break;
1091             default:
1092               werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1093               c = "unknown";
1094               break;
1095             }
1096         }
1097       fprintf (lnkfile, "-k %s/%s\n", SDCC_LIB_DIR /*STD_LIB_PATH */ , c);
1098
1099       /* standard library files */
1100       if (strcmp (port->target, "ds390") == 0)
1101         {
1102           fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1103         }
1104       fprintf (lnkfile, "-l %s\n", STD_LIB);
1105       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1106       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1107       fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1108     }
1109
1110   /* additional libraries if any */
1111   for (i = 0; i < nlibFiles; i++)
1112     fprintf (lnkfile, "-l %s\n", libFiles[i]);
1113
1114   /* put in the object files */
1115   if (strcmp (srcFileName, "temp"))
1116     fprintf (lnkfile, "%s ", srcFileName);
1117
1118   for (i = 0; i < nrelFiles; i++)
1119     fprintf (lnkfile, "%s\n", relFiles[i]);
1120
1121   fprintf (lnkfile, "\n-e\n");
1122   fclose (lnkfile);
1123
1124   if (options.verbose)
1125     printf ("sdcc: Calling linker...\n");
1126
1127   buildCmdLine (buffer, port->linker.cmd, srcFileName, NULL, NULL, NULL);
1128   if (my_system (buffer))
1129     {
1130       exit (1);
1131     }
1132
1133   if (strcmp (srcFileName, "temp") == 0)
1134     {
1135       /* rename "temp.cdb" to "firstRelFile.cdb" */
1136       char *f = strtok (strdup (relFiles[0]), ".");
1137       f = strcat (f, ".cdb");
1138       rename ("temp.cdb", f);
1139       srcFileName = NULL;
1140     }
1141 }
1142
1143 /*-----------------------------------------------------------------*/
1144 /* assemble - spawns the assembler with arguments                  */
1145 /*-----------------------------------------------------------------*/
1146 static void
1147 assemble (char **envp)
1148 {
1149   buildCmdLine (buffer, port->assembler.cmd, srcFileName, NULL, NULL, asmOptions);
1150   if (my_system (buffer))
1151     {
1152       /* either system() or the assembler itself has reported an error
1153          perror ("Cannot exec assembler");
1154        */
1155       exit (1);
1156     }
1157 }
1158
1159
1160
1161 /*-----------------------------------------------------------------*/
1162 /* preProcess - spawns the preprocessor with arguments       */
1163 /*-----------------------------------------------------------------*/
1164 static int
1165 preProcess (char **envp)
1166 {
1167   char procDef[128];
1168
1169   preOutName = NULL;
1170
1171   if (!options.c1mode)
1172     {
1173       /* if using external stack define the macro */
1174       if (options.useXstack)
1175         _addToList (preArgv, "-DSDCC_USE_XSTACK");
1176
1177       /* set the macro for stack autos  */
1178       if (options.stackAuto)
1179         _addToList (preArgv, "-DSDCC_STACK_AUTO");
1180
1181       /* set the macro for stack autos  */
1182       if (options.stack10bit)
1183         _addToList (preArgv, "-DSDCC_STACK_TENBIT");
1184
1185       /* set the macro for large model  */
1186       switch (options.model)
1187         {
1188         case MODEL_LARGE:
1189           _addToList (preArgv, "-DSDCC_MODEL_LARGE");
1190           break;
1191         case MODEL_SMALL:
1192           _addToList (preArgv, "-DSDCC_MODEL_SMALL");
1193           break;
1194         case MODEL_COMPACT:
1195           _addToList (preArgv, "-DSDCC_MODEL_COMPACT");
1196           break;
1197         case MODEL_MEDIUM:
1198           _addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
1199           break;
1200         case MODEL_FLAT24:
1201           _addToList (preArgv, "-DSDCC_MODEL_FLAT24");
1202           break;
1203         default:
1204           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1205           break;
1206         }
1207
1208       /* standard include path */
1209       if (!options.nostdinc) {
1210         _addToList (preArgv, "-I" SDCC_INCLUDE_DIR);
1211       }
1212
1213       /* add port (processor information to processor */
1214       sprintf (procDef, "-DSDCC_%s", port->target);
1215       _addToList (preArgv, procDef);
1216       sprintf (procDef, "-D__%s", port->target);
1217       _addToList (preArgv, procDef);
1218
1219       if (!preProcOnly)
1220         preOutName = strdup (tmpnam (NULL));
1221
1222       if (options.verbose)
1223         printf ("sdcc: Calling preprocessor...\n");
1224
1225       buildCmdLine (buffer, _preCmd, fullSrcFileName,
1226                     preOutName, srcFileName, preArgv);
1227       if (my_system (buffer))
1228         {
1229           // @FIX: Dario Vecchio 03-05-2001
1230           if (preOutName)
1231             {
1232               unlink (preOutName);
1233               free (preOutName);
1234             }
1235           // EndFix
1236           exit (1);
1237         }
1238
1239       if (preProcOnly)
1240       {
1241         exit (0);
1242       }
1243     }
1244   else
1245     {
1246       preOutName = fullSrcFileName;
1247     }
1248
1249   yyin = fopen (preOutName, "r");
1250   if (yyin == NULL)
1251     {
1252       perror ("Preproc file not found\n");
1253       exit (1);
1254     }
1255
1256   return 0;
1257 }
1258
1259 static void
1260 _findPort (int argc, char **argv)
1261 {
1262   _validatePorts ();
1263
1264   while (argc--)
1265     {
1266       if (!strncmp (*argv, "-m", 2))
1267         {
1268           _setPort (*argv + 2);
1269           return;
1270         }
1271       argv++;
1272     }
1273   /* Use the first in the list */
1274   port = _ports[0];
1275 }
1276
1277 /*
1278  * main routine
1279  * initialises and calls the parser
1280  */
1281
1282 int
1283 main (int argc, char **argv, char **envp)
1284 {
1285   /* turn all optimizations off by default */
1286   memset (&optimize, 0, sizeof (struct optimize));
1287
1288   /*printVersionInfo (); */
1289
1290   if (NUM_PORTS==0) {
1291     fprintf (stderr, "Build error: no ports are enabled.\n");
1292     exit (1);
1293   }
1294
1295   _findPort (argc, argv);
1296   /* Initalise the port. */
1297   if (port->init)
1298     port->init ();
1299
1300   // Create a default exe search path from the path to the sdcc command
1301
1302
1303
1304   if (strchr (argv[0], DIR_SEPARATOR_CHAR))
1305     {
1306       strcpy (DefaultExePath, argv[0]);
1307       *(strrchr (DefaultExePath, DIR_SEPARATOR_CHAR)) = 0;
1308       ExePathList[0] = DefaultExePath;
1309     }
1310
1311
1312   setDefaultOptions ();
1313   parseCmdLine (argc, argv);
1314
1315   initMem ();
1316
1317   port->finaliseOptions ();
1318
1319   /* if no input then printUsage & exit */
1320   if ((!options.c1mode && !srcFileName && !nrelFiles) || 
1321       (options.c1mode && !srcFileName && !options.out_name))
1322     {
1323       printUsage ();
1324       exit (0);
1325     }
1326
1327   if (srcFileName)
1328     {
1329       preProcess (envp);
1330
1331       initSymt ();
1332       initiCode ();
1333       initCSupport ();
1334       initPeepHole ();
1335
1336       if (options.verbose)
1337         printf ("sdcc: Generating code...\n");
1338
1339       yyparse ();
1340
1341       if (!fatalError)
1342         {
1343           if (TARGET_IS_PIC) {
1344             /* TSD PIC port hack - if the PIC port option is enabled
1345                and SDCC is used to generate PIC code, then we will
1346                generate .asm files in gpasm's format instead of SDCC's
1347                assembler's format
1348             */
1349 #if !OPT_DISABLE_PIC
1350             picglue ();
1351 #endif
1352           } else {
1353             glue ();
1354           }
1355
1356           if (fatalError)
1357             {
1358               // @FIX: Dario Vecchio 03-05-2001
1359               if (preOutName)
1360                 {
1361                   if (yyin && yyin != stdin)
1362                     fclose (yyin);
1363                   unlink (preOutName);
1364                   free (preOutName);
1365                 }
1366               // EndFix
1367               return 1;
1368             }
1369           if (!options.c1mode)
1370             {
1371               if (options.verbose)
1372                 printf ("sdcc: Calling assembler...\n");
1373               assemble (envp);
1374             }
1375         }
1376       else
1377         {
1378           // @FIX: Dario Vecchio 03-05-2001
1379           if (preOutName)
1380             {
1381               if (yyin && yyin != stdin)
1382                 fclose (yyin);
1383               unlink (preOutName);
1384               free (preOutName);
1385             }
1386           // EndFix
1387           return 1;
1388         }
1389
1390     }
1391
1392   closeDumpFiles();
1393
1394   if (cdbFile)
1395     fclose (cdbFile);
1396
1397   if (!options.cc_only &&
1398       !fatalError &&
1399       !noAssemble &&
1400       !options.c1mode &&
1401       (srcFileName || nrelFiles))
1402     {
1403       if (port->linker.do_link)
1404         port->linker.do_link ();
1405       else
1406         linkEdit (envp);
1407     }
1408
1409   if (yyin && yyin != stdin)
1410     fclose (yyin);
1411
1412   if (preOutName && !options.c1mode)
1413     {
1414       unlink (preOutName);
1415       free (preOutName);
1416     }
1417
1418   return 0;
1419
1420 }