fixed a parameter skip, added some more usage texts
[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, "\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 = 1;
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 bool
589 tryHandleUnsupportedOpt(char **argv, int *pi)
590 {
591     if (argv[*pi][0] == '-') 
592         {
593             const char *longOpt = "";
594             char shortOpt = -1;
595             int i;
596
597             if (argv[*pi][1] == '-') 
598                 {
599                     // Long option.
600                     longOpt = argv[*pi];
601                 }
602             else 
603                 {
604                     shortOpt = argv[*pi][1];
605                 }
606             for (i = 0; i < LENGTH(unsupportedOptTable); i++) 
607                 {
608                     if (unsupportedOptTable[i].shortOpt == shortOpt || 
609                         (longOpt && unsupportedOptTable[i].longOpt && !strcmp(unsupportedOptTable[i].longOpt, longOpt))) {
610                         // Found an unsupported opt.
611                         char buffer[100];
612                         sprintf(buffer, "%s%c%c", longOpt ? longOpt : "", shortOpt ? '-' : ' ', shortOpt ? shortOpt : ' ');
613                         werror (W_UNSUPP_OPTION, buffer, unsupportedOptTable[i].message);
614                         return 1;
615                     }
616                 }
617             // Didn't find in the table
618             return 0;
619         }
620     else 
621         {
622             // Not an option, so can't be unsupported :)
623             return 0;
624     }
625 }
626
627 static bool
628 tryHandleSimpleOpt(char **argv, int *pi)
629 {
630     if (argv[*pi][0] == '-') 
631         {
632             const char *longOpt = "";
633             char shortOpt = -1;
634             int i;
635
636             if (argv[*pi][1] == '-') 
637                 {
638                     // Long option.
639                     longOpt = argv[*pi];
640                 }
641             else 
642                 {
643                     shortOpt = argv[*pi][1];
644                 }
645
646             for (i = 0; i < LENGTH(optionsTable); i++) 
647                 {
648                     if (optionsTable[i].shortOpt == shortOpt || 
649                         (longOpt && optionsTable[i].longOpt && strcmp(optionsTable[i].longOpt, longOpt) == 0))
650                         {
651                             // If it is a flag then we can handle it here
652                             if (optionsTable[i].pparameter != NULL) 
653                                 {
654                                     (*optionsTable[i].pparameter)++;
655                                     return 1;
656                                 }
657                             else {
658                                 // Not a flag.  Handled manually later.
659                                 return 0;
660                             }
661                         }
662                 }
663             // Didn't find in the table
664             return 0;
665         }
666     else 
667         {
668             // Not an option, so can't be handled.
669             return 0;
670         }
671 }
672
673 /*-----------------------------------------------------------------*/
674 /* parseCmdLine - parses the command line and sets the options     */
675 /*-----------------------------------------------------------------*/
676 int
677 parseCmdLine (int argc, char **argv)
678 {
679   int i;
680
681   /* go thru all whole command line */
682   for (i = 1; i < argc; i++)
683     {
684       if (i >= argc)
685         break;
686
687       if (tryHandleUnsupportedOpt(argv, &i) == TRUE) 
688           {
689               continue;
690           }
691
692       if (tryHandleSimpleOpt(argv, &i) == TRUE)
693           {
694               continue;
695           }
696
697       /* options */
698       if (argv[i][0] == '-' && argv[i][1] == '-')
699         {
700           if (strcmp (argv[i], OPTION_HELP) == 0)
701             {
702               printUsage ();
703               exit (0);
704             }
705
706           if (strcmp (argv[i], OPTION_STACK_8BIT) == 0)
707             {
708               options.stack10bit = 0;
709               continue;
710             }
711
712           if (strcmp (argv[i], OPTION_OUT_FMT_IHX) == 0)
713             {
714               options.out_fmt = 0;
715               continue;
716             }
717
718           if (strcmp (argv[i], OPTION_LARGE_MODEL) == 0)
719             {
720               _setModel (MODEL_LARGE, argv[i]);
721               continue;
722             }
723
724           if (strcmp (argv[i], OPTION_MEDIUM_MODEL) == 0)
725             {
726               _setModel (MODEL_MEDIUM, argv[i]);
727               continue;
728             }
729
730           if (strcmp (argv[i], OPTION_SMALL_MODEL) == 0)
731             {
732               _setModel (MODEL_SMALL, argv[i]);
733               continue;
734             }
735
736           if (strcmp (argv[i], OPTION_FLAT24_MODEL) == 0)
737             {
738               _setModel (MODEL_FLAT24, argv[i]);
739               continue;
740             }
741
742           if (strcmp (argv[i], OPTION_DUMP_ALL) == 0)
743             {
744               options.dump_rassgn =
745                 options.dump_pack =
746                 options.dump_range =
747                 options.dump_kill =
748                 options.dump_loop =
749                 options.dump_gcse =
750                 options.dump_raw = 1;
751               continue;
752             }
753
754           if (strcmp (argv[i], OPTION_PEEP_FILE) == 0)
755             {
756                 options.peep_file = getStringArg(OPTION_PEEP_FILE, argv, &i, argc);
757                 continue;
758             }
759
760           if (strcmp (argv[i], OPTION_LIB_PATH) == 0)
761             {
762                 libPaths[nlibPaths++] = getStringArg(OPTION_LIB_PATH, argv, &i, argc);
763                 continue;
764             }
765
766           if (strcmp (argv[i], OPTION_VERSION) == 0)
767             {
768               printVersionInfo ();
769               exit (0);
770               continue;
771             }
772
773           if (strcmp (argv[i], OPTION_CALLEE_SAVES) == 0)
774             {
775                 parseWithComma (options.calleeSaves, getStringArg(OPTION_CALLEE_SAVES, argv, &i, argc));
776                 continue;
777             }
778
779           if (strcmp (argv[i], OPTION_XSTACK_LOC) == 0)
780             {
781                 options.xstack_loc = getIntArg(OPTION_XSTACK_LOC, argv, &i, argc);
782                 continue;
783             }
784
785           if (strcmp (argv[i], OPTION_STACK_LOC) == 0)
786             {
787                 options.stack_loc = getIntArg(OPTION_STACK_LOC, argv, &i, argc);
788                 continue;
789             }
790
791           if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
792             {
793                 options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i, argc);
794                 continue;
795             }
796
797           if (strcmp (argv[i], OPTION_IRAM_SIZE) == 0)
798             {
799                 options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
800                 continue;
801             }
802
803           if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
804             {
805                 options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i, argc);
806                 continue;
807             }
808
809           if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
810             {
811                 options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i, argc);
812                 continue;
813             }
814
815           if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
816             {
817                 options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i, argc);
818                 continue;
819             }
820
821           if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
822             {
823               optimize.global_cse = 0;
824               continue;
825             }
826
827           if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
828             {
829               optimize.loopInvariant = 0;
830               continue;
831             }
832
833           if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
834             {
835               optimize.loopInduction = 0;
836               continue;
837             }
838
839           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0) 
840             {
841               setErrorLogLevel(ERROR_LEVEL_WARNING);
842               continue;
843             }
844
845           if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0) 
846             {
847               options.shortis8bits=1;
848               continue;
849             }
850           
851           if (!port->parseOption (&argc, argv, &i))
852             {
853               werror (W_UNKNOWN_OPTION, argv[i]);
854             }
855           else
856             {
857               continue;
858             }
859         }
860
861       /* if preceded by  '-' then option */
862       if (*argv[i] == '-')
863         {
864           switch (argv[i][1])
865             {
866             case 'h':
867               printUsage ();
868               exit (0);
869               break;
870
871             case 'm':
872               /* Used to select the port */
873               _setPort (argv[i] + 2);
874               break;
875
876             case 'c':
877               options.cc_only = 1;
878               break;
879
880             case 'L':
881                 libPaths[nlibPaths++] = getStringArg("-L", argv, &i, argc);
882                 break;
883
884             case 'l':
885                 libFiles[nlibFiles++] = getStringArg("-l", argv, &i, argc);
886                 break;
887
888             case 'W':
889               /* linker options */
890               if (argv[i][2] == 'l')
891                 {
892                     parseWithComma(linkOptions, getStringArg("-Wl", argv, &i, argc));
893                 }
894               else
895                 {
896                   /* assembler options */
897                   if (argv[i][2] == 'a')
898                     {
899                         parseWithComma ((char **) asmOptions, getStringArg("-Wa", argv, &i, argc));
900                     }
901                   else
902                     {
903                       werror (W_UNKNOWN_OPTION, argv[i]);
904                     }
905                 }
906               break;
907
908             case 'v':
909               printVersionInfo ();
910               exit (0);
911               break;
912
913               /* preprocessor options */
914             case 'M':
915               {
916                 preProcOnly = 1;
917                 _addToList (preArgv, "-M");
918                 break;
919               }
920             case 'C':
921               {
922                 _addToList (preArgv, "-C");
923                 break;
924               }
925             case 'd':
926             case 'D':
927             case 'I':
928             case 'A':
929             case 'U':
930               {
931                 char sOpt = argv[i][1];
932                 char *rest;
933
934                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
935                   {
936                     i++;
937                     if (i >= argc) 
938                       {
939                           /* No argument. */
940                           werror(E_ARGUMENT_MISSING, argv[i-1]);
941                           break;
942                       }
943                     else 
944                       {
945                           rest = argv[i];
946                       }
947                   }
948                 else
949                   rest = &argv[i][2];
950
951                 if (sOpt == 'Y')
952                   sOpt = 'I';
953
954                 sprintf (buffer, "-%c%s", sOpt, rest);
955                 _addToList (preArgv, buffer);
956               }
957               break;
958
959             default:
960               if (!port->parseOption (&argc, argv, &i))
961                 werror (W_UNKNOWN_OPTION, argv[i]);
962             }
963           continue;
964         }
965
966       if (!port->parseOption (&argc, argv, &i))
967         {
968           /* no option must be a filename */
969           if (options.c1mode)
970             _processC1Arg (argv[i]);
971           else
972             processFile (argv[i]);
973         }
974     }
975
976   /* set up external stack location if not explicitly specified */
977   if (!options.xstack_loc)
978     options.xstack_loc = options.xdata_loc;
979
980   /* if debug option is set the open the cdbFile */
981   if (options.debug && srcFileName)
982     {
983       sprintf (scratchFileName, "%s.cdb", srcFileName);
984       if ((cdbFile = fopen (scratchFileName, "w")) == NULL)
985         werror (E_FILE_OPEN_ERR, scratchFileName);
986       else
987         {
988           /* add a module record */
989           fprintf (cdbFile, "M:%s\n", moduleName);
990         }
991     }
992   return 0;
993 }
994
995 /*-----------------------------------------------------------------*/
996 /* linkEdit : - calls the linkage editor  with options             */
997 /*-----------------------------------------------------------------*/
998 static void
999 linkEdit (char **envp)
1000 {
1001   FILE *lnkfile;
1002   char *segName, *c;
1003
1004   int i;
1005   if (!srcFileName)
1006     srcFileName = "temp";
1007
1008   /* first we need to create the <filename>.lnk file */
1009   sprintf (scratchFileName, "%s.lnk", srcFileName);
1010   if (!(lnkfile = fopen (scratchFileName, "w")))
1011     {
1012       werror (E_FILE_OPEN_ERR, scratchFileName);
1013       exit (1);
1014     }
1015
1016   /* now write the options */
1017   fprintf (lnkfile, "-mux%c\n", (options.out_fmt ? 's' : 'i'));
1018
1019   /* if iram size specified */
1020   if (options.iram_size)
1021     fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1022
1023   if (options.debug)
1024     fprintf (lnkfile, "-z\n");
1025
1026 #define WRITE_SEG_LOC(N, L) \
1027     segName = strdup(N); \
1028     c = strtok(segName, " \t"); \
1029     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1030     if (segName) { free(segName); }
1031
1032   /* code segment start */
1033   WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1034
1035   /* data segment start */
1036   WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1037
1038   /* xdata start */
1039   WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1040
1041   /* indirect data */
1042   WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1043
1044   /* bit segment start */
1045   WRITE_SEG_LOC (BIT_NAME, 0);
1046
1047   /* add the extra linker options */
1048   for (i = 0; linkOptions[i]; i++)
1049     fprintf (lnkfile, "%s\n", linkOptions[i]);
1050
1051   /* other library paths if specified */
1052   for (i = 0; i < nlibPaths; i++)
1053     fprintf (lnkfile, "-k %s\n", libPaths[i]);
1054
1055   /* standard library path */
1056   if (!options.nostdlib)
1057     {
1058       if (TARGET_IS_DS390)
1059         {
1060           c = "ds390";
1061         }
1062       else
1063         {
1064           switch (options.model)
1065             {
1066             case MODEL_SMALL:
1067               c = "small";
1068               break;
1069             case MODEL_LARGE:
1070               c = "large";
1071               break;
1072             case MODEL_FLAT24:
1073               c = "flat24";
1074               break;
1075             default:
1076               werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1077               c = "unknown";
1078               break;
1079             }
1080         }
1081       fprintf (lnkfile, "-k %s/%s\n", SDCC_LIB_DIR /*STD_LIB_PATH */ , c);
1082
1083       /* standard library files */
1084       if (strcmp (port->target, "ds390") == 0)
1085         {
1086           fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1087         }
1088       fprintf (lnkfile, "-l %s\n", STD_LIB);
1089       fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1090       fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1091       fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1092     }
1093
1094   /* additional libraries if any */
1095   for (i = 0; i < nlibFiles; i++)
1096     fprintf (lnkfile, "-l %s\n", libFiles[i]);
1097
1098   /* put in the object files */
1099   if (strcmp (srcFileName, "temp"))
1100     fprintf (lnkfile, "%s ", srcFileName);
1101
1102   for (i = 0; i < nrelFiles; i++)
1103     fprintf (lnkfile, "%s\n", relFiles[i]);
1104
1105   fprintf (lnkfile, "\n-e\n");
1106   fclose (lnkfile);
1107
1108   if (options.verbose)
1109     printf ("sdcc: Calling linker...\n");
1110
1111   buildCmdLine (buffer, port->linker.cmd, srcFileName, NULL, NULL, NULL);
1112   if (my_system (buffer))
1113     {
1114       exit (1);
1115     }
1116
1117   if (strcmp (srcFileName, "temp") == 0)
1118     {
1119       /* rename "temp.cdb" to "firstRelFile.cdb" */
1120       char *f = strtok (strdup (relFiles[0]), ".");
1121       f = strcat (f, ".cdb");
1122       rename ("temp.cdb", f);
1123       srcFileName = NULL;
1124     }
1125 }
1126
1127 /*-----------------------------------------------------------------*/
1128 /* assemble - spawns the assembler with arguments                  */
1129 /*-----------------------------------------------------------------*/
1130 static void
1131 assemble (char **envp)
1132 {
1133   buildCmdLine (buffer, port->assembler.cmd, srcFileName, NULL, NULL, asmOptions);
1134   if (my_system (buffer))
1135     {
1136       /* either system() or the assembler itself has reported an error
1137          perror ("Cannot exec assembler");
1138        */
1139       exit (1);
1140     }
1141 }
1142
1143
1144
1145 /*-----------------------------------------------------------------*/
1146 /* preProcess - spawns the preprocessor with arguments       */
1147 /*-----------------------------------------------------------------*/
1148 static int
1149 preProcess (char **envp)
1150 {
1151   char procDef[128];
1152
1153   preOutName = NULL;
1154
1155   if (!options.c1mode)
1156     {
1157       /* if using external stack define the macro */
1158       if (options.useXstack)
1159         _addToList (preArgv, "-DSDCC_USE_XSTACK");
1160
1161       /* set the macro for stack autos  */
1162       if (options.stackAuto)
1163         _addToList (preArgv, "-DSDCC_STACK_AUTO");
1164
1165       /* set the macro for stack autos  */
1166       if (options.stack10bit)
1167         _addToList (preArgv, "-DSDCC_STACK_TENBIT");
1168
1169       /* set the macro for large model  */
1170       switch (options.model)
1171         {
1172         case MODEL_LARGE:
1173           _addToList (preArgv, "-DSDCC_MODEL_LARGE");
1174           break;
1175         case MODEL_SMALL:
1176           _addToList (preArgv, "-DSDCC_MODEL_SMALL");
1177           break;
1178         case MODEL_COMPACT:
1179           _addToList (preArgv, "-DSDCC_MODEL_COMPACT");
1180           break;
1181         case MODEL_MEDIUM:
1182           _addToList (preArgv, "-DSDCC_MODEL_MEDIUM");
1183           break;
1184         case MODEL_FLAT24:
1185           _addToList (preArgv, "-DSDCC_MODEL_FLAT24");
1186           break;
1187         default:
1188           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1189           break;
1190         }
1191
1192       /* standard include path */
1193       if (!options.nostdinc) {
1194         _addToList (preArgv, "-I" SDCC_INCLUDE_DIR);
1195       }
1196
1197       /* add port (processor information to processor */
1198       sprintf (procDef, "-DSDCC_%s", port->target);
1199       _addToList (preArgv, procDef);
1200       sprintf (procDef, "-D__%s", port->target);
1201       _addToList (preArgv, procDef);
1202
1203       if (!preProcOnly)
1204         preOutName = strdup (tmpnam (NULL));
1205
1206       if (options.verbose)
1207         printf ("sdcc: Calling preprocessor...\n");
1208
1209       buildCmdLine (buffer, _preCmd, fullSrcFileName,
1210                     preOutName, srcFileName, preArgv);
1211       if (my_system (buffer))
1212         {
1213           // @FIX: Dario Vecchio 03-05-2001
1214           if (preOutName)
1215             {
1216               unlink (preOutName);
1217               free (preOutName);
1218             }
1219           // EndFix
1220           exit (1);
1221         }
1222
1223       if (preProcOnly)
1224       {
1225         exit (0);
1226       }
1227     }
1228   else
1229     {
1230       preOutName = fullSrcFileName;
1231     }
1232
1233   yyin = fopen (preOutName, "r");
1234   if (yyin == NULL)
1235     {
1236       perror ("Preproc file not found\n");
1237       exit (1);
1238     }
1239
1240   return 0;
1241 }
1242
1243 static void
1244 _findPort (int argc, char **argv)
1245 {
1246   _validatePorts ();
1247
1248   while (argc--)
1249     {
1250       if (!strncmp (*argv, "-m", 2))
1251         {
1252           _setPort (*argv + 2);
1253           return;
1254         }
1255       argv++;
1256     }
1257   /* Use the first in the list */
1258   port = _ports[0];
1259 }
1260
1261 /*
1262  * main routine
1263  * initialises and calls the parser
1264  */
1265
1266 int
1267 main (int argc, char **argv, char **envp)
1268 {
1269   /* turn all optimizations off by default */
1270   memset (&optimize, 0, sizeof (struct optimize));
1271
1272   /*printVersionInfo (); */
1273
1274   if (NUM_PORTS==0) {
1275     fprintf (stderr, "Build error: no ports are enabled.\n");
1276     exit (1);
1277   }
1278
1279   _findPort (argc, argv);
1280   /* Initalise the port. */
1281   if (port->init)
1282     port->init ();
1283
1284   // Create a default exe search path from the path to the sdcc command
1285
1286
1287
1288   if (strchr (argv[0], DIR_SEPARATOR_CHAR))
1289     {
1290       strcpy (DefaultExePath, argv[0]);
1291       *(strrchr (DefaultExePath, DIR_SEPARATOR_CHAR)) = 0;
1292       ExePathList[0] = DefaultExePath;
1293     }
1294
1295
1296   setDefaultOptions ();
1297   parseCmdLine (argc, argv);
1298
1299   initMem ();
1300
1301   port->finaliseOptions ();
1302
1303   /* if no input then printUsage & exit */
1304   if ((!options.c1mode && !srcFileName && !nrelFiles) || 
1305       (options.c1mode && !srcFileName && !options.out_name))
1306     {
1307       printUsage ();
1308       exit (0);
1309     }
1310
1311   if (srcFileName)
1312     {
1313       preProcess (envp);
1314
1315       initSymt ();
1316       initiCode ();
1317       initCSupport ();
1318       initPeepHole ();
1319
1320       if (options.verbose)
1321         printf ("sdcc: Generating code...\n");
1322
1323       yyparse ();
1324
1325       if (!fatalError)
1326         {
1327           if (TARGET_IS_PIC) {
1328             /* TSD PIC port hack - if the PIC port option is enabled
1329                and SDCC is used to generate PIC code, then we will
1330                generate .asm files in gpasm's format instead of SDCC's
1331                assembler's format
1332             */
1333 #if !OPT_DISABLE_PIC
1334             picglue ();
1335 #endif
1336           } else {
1337             glue ();
1338           }
1339
1340           if (fatalError)
1341             {
1342               // @FIX: Dario Vecchio 03-05-2001
1343               if (preOutName)
1344                 {
1345                   if (yyin && yyin != stdin)
1346                     fclose (yyin);
1347                   unlink (preOutName);
1348                   free (preOutName);
1349                 }
1350               // EndFix
1351               return 1;
1352             }
1353           if (!options.c1mode && !noAssemble)
1354             {
1355               if (options.verbose)
1356                 printf ("sdcc: Calling assembler...\n");
1357               assemble (envp);
1358             }
1359         }
1360       else
1361         {
1362           // @FIX: Dario Vecchio 03-05-2001
1363           if (preOutName)
1364             {
1365               if (yyin && yyin != stdin)
1366                 fclose (yyin);
1367               unlink (preOutName);
1368               free (preOutName);
1369             }
1370           // EndFix
1371           return 1;
1372         }
1373
1374     }
1375
1376   closeDumpFiles();
1377
1378   if (cdbFile)
1379     fclose (cdbFile);
1380
1381   if (!options.cc_only &&
1382       !fatalError &&
1383       !noAssemble &&
1384       !options.c1mode &&
1385       (srcFileName || nrelFiles))
1386     {
1387       if (port->linker.do_link)
1388         port->linker.do_link ();
1389       else
1390         linkEdit (envp);
1391     }
1392
1393   if (yyin && yyin != stdin)
1394     fclose (yyin);
1395
1396   if (preOutName && !options.c1mode)
1397     {
1398       unlink (preOutName);
1399       free (preOutName);
1400     }
1401
1402   return 0;
1403
1404 }