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