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