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