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