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