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