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