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