84310c15d46b8aa9ae540869779e2fbee58a219c
[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 #ifdef _WIN32
26 #include <io.h>
27 #else
28 #include <unistd.h>
29 #endif
30
31 #include <signal.h>
32 #include "common.h"
33 #include <ctype.h>
34 #include "newalloc.h"
35 #include "SDCCerr.h"
36 #include "BuildCmd.h"
37 #include "MySystem.h"
38 #include "SDCCmacro.h"
39 #include "SDCCutil.h"
40 #include "SDCCdebug.h"
41 #include "SDCCargs.h"
42
43 #ifdef _WIN32
44 #include <process.h>
45 #else
46 #include <sys/stat.h>
47 #include <unistd.h>
48 #endif
49
50 /* REMOVE ME!!! */
51 extern int yyparse (void);
52
53 FILE *srcFile;                  /* source file          */
54 char *fullSrcFileName;          /* full name for the source file; */
55                                 /* can be NULL while c1mode or linking without compiling */
56 char *fullDstFileName;          /* full name for the output file; */
57                                 /* only given by -o, otherwise NULL */
58 char *dstFileName;              /* destination file name without extension */
59 char *dstPath = "";             /* path for the output files; */
60                                 /* "" is equivalent with cwd */
61 char *moduleName;               /* module name is source file without path and extension */
62                                 /* can be NULL while linking without compiling */
63 int currRegBank = 0;
64 int RegBankUsed[4] = {1, 0, 0, 0}; /*JCF: Reg Bank 0 used by default*/
65 struct optimize optimize;
66 struct options options;
67 int preProcOnly = 0;
68 int noAssemble = 0;
69 set *preArgvSet = NULL;         /* pre-processor arguments  */
70 set *asmOptionsSet = NULL;      /* set of assembler options */
71 set *linkOptionsSet = NULL;     /* set of linker options */
72 set *libFilesSet = NULL;
73 set *libPathsSet = NULL;
74 set *relFilesSet = NULL;
75 set *dataDirsSet = NULL;        /* list of data search directories */
76 set *includeDirsSet = NULL;     /* list of include search directories */
77 set *libDirsSet = NULL;         /* list of lib search directories */
78
79 /* uncomment JAMIN_DS390 to always override and use ds390 port
80   for mcs51 work.  This is temporary, for compatibility testing. */
81 /* #define JAMIN_DS390 */
82 #ifdef JAMIN_DS390
83 int ds390_jammed = 0;
84 #endif
85
86 /* Globally accessible scratch buffer for file names. */
87 char scratchFileName[PATH_MAX];
88 char buffer[PATH_MAX * 2];
89
90 #define OPTION_HELP     "-help"
91
92 #define LENGTH(_a)      (sizeof(_a)/sizeof(*(_a)))
93
94 #define OPTION_STACK_8BIT       "--stack-8bit"
95 #define OPTION_OUT_FMT_IHX      "--out-fmt-ihx"
96 #define OPTION_LARGE_MODEL      "--model-large"
97 #define OPTION_MEDIUM_MODEL     "--model-medium"
98 #define OPTION_SMALL_MODEL      "--model-small"
99 #define OPTION_FLAT24_MODEL     "--model-flat24"
100 #define OPTION_DUMP_ALL         "--dumpall"
101 #define OPTION_PEEP_FILE        "--peep-file"
102 #define OPTION_LIB_PATH         "--lib-path"
103 #define OPTION_XSTACK_LOC       "--xstack-loc"
104 #define OPTION_CALLEE_SAVES     "--callee-saves"
105 #define OPTION_STACK_LOC        "--stack-loc"
106 #define OPTION_XRAM_LOC         "--xram-loc"
107 #define OPTION_IRAM_SIZE        "--iram-size"
108 #define OPTION_VERSION          "--version"
109 #define OPTION_DATA_LOC         "--data-loc"
110 #define OPTION_CODE_LOC         "--code-loc"
111 #define OPTION_IDATA_LOC        "--idata-loc"
112 #define OPTION_NO_LABEL_OPT     "--nolabelopt"
113 #define OPTION_NO_LOOP_INV      "--noinvariant"
114 #define OPTION_NO_LOOP_IND      "--noinduction"
115 #define OPTION_LESS_PEDANTIC    "--less-pedantic"
116 #define OPTION_NO_GCSE          "--nogcse"
117 #define OPTION_SHORT_IS_8BITS   "--short-is-8bits"
118 #define OPTION_TINI_LIBID       "--tini-libid"
119 #define OPTION_NO_XINIT_OPT     "--no-xinit-opt"
120 #define OPTION_XRAM_SIZE        "--xram-size"
121 #define OPTION_CODE_SIZE        "--code-size"
122 #define OPTION_NO_CCODE_IN_ASM  "--no-c-code-in-asm"
123 #define OPTION_ICODE_IN_ASM     "--i-code-in-asm"
124 #define OPTION_PRINT_SEARCH_DIRS "--print-search-dirs"
125 #define OPTION_MSVC_ERROR_STYLE "--vc"
126 #define OPTION_USE_STDOUT "--use-stdout"
127
128 static const OPTION
129 optionsTable[] = {
130     { 'm',  NULL,                   NULL, "Set the port to use e.g. -mz80." },
131     { 'p',  NULL,                   NULL, "Select port specific processor e.g. -mpic14 -p16f84" },
132     { 'd',  NULL,                   NULL, NULL },
133     { 'D',  NULL,                   NULL, "Define macro as in -Dmacro" },
134     { 'I',  NULL,                   NULL, "Add to the include (*.h) path, as in -Ipath" },
135     { 'A',  NULL,                   NULL, NULL },
136     { 'U',  NULL,                   NULL, NULL },
137     { 'C',  NULL,                   NULL, "Preprocessor option" },
138     { 'M',  NULL,                   NULL, "Preprocessor option" },
139     { 'V',  NULL,                   &options.verboseExec, "Execute verbosely.  Show sub commands as they are run" },
140     { 'S',  NULL,                   &noAssemble, "Compile only; do not assemble or link" },
141     { 'W',  NULL,                   NULL, "Pass through options to the pre-processor (p), assembler (a) or linker (l)" },
142     { 'L',  NULL,                   NULL, "Add the next field to the library search path" },
143     { 'l',  NULL,                   NULL, "Include the given library in the link" },
144     { 0,    OPTION_LARGE_MODEL,     NULL, "external data space is used" },
145     { 0,    OPTION_MEDIUM_MODEL,    NULL, "not supported" },
146     { 0,    OPTION_SMALL_MODEL,     NULL, "internal data space is used (default)" },
147 #if !OPT_DISABLE_DS390
148     { 0,    OPTION_FLAT24_MODEL,    NULL, "use the flat24 model for the ds390 (default)" },
149 #endif
150     { 0,    "--stack-auto",         &options.stackAuto, "Stack automatic variables" },
151 #if !OPT_DISABLE_DS390
152     { 0,    OPTION_STACK_8BIT,      NULL, "use the 8bit stack for the ds390 (not supported yet)" },
153     { 0,    "--stack-10bit",        &options.stack10bit, "use the 10bit stack for ds390 (default)" },
154 #endif
155     { 0,    "--xstack",             &options.useXstack, "Use external stack" },
156     { 0,    OPTION_NO_GCSE,         NULL, "Disable the GCSE optimisation" },
157     { 0,    OPTION_NO_LABEL_OPT,    NULL, "Disable label optimisation" },
158     { 0,    OPTION_NO_LOOP_INV,     NULL, "Disable optimisation of invariants" },
159     { 0,    OPTION_NO_LOOP_IND,     NULL, NULL },
160     { 0,    "--nojtbound",          &optimize.noJTabBoundary, "Don't generate boundary check for jump tables" },
161     { 0,    "--noloopreverse",      &optimize.noLoopReverse, "Disable the loop reverse optimisation" },
162     { 'c',  "--compile-only",       &options.cc_only, "Compile and assemble, but do not link" },
163     { 'o',  NULL,                   NULL, "Place the output into the given path resp. file" },
164     { 0,    "--dumpraw",            &options.dump_raw, "Dump the internal structure after the initial parse" },
165     { 0,    "--dumpgcse",           &options.dump_gcse, NULL },
166     { 0,    "--dumploop",           &options.dump_loop, NULL },
167     { 0,    "--dumpdeadcode",       &options.dump_kill, NULL },
168     { 0,    "--dumpliverange",      &options.dump_range, NULL },
169     { 0,    "--dumpregpack",        &options.dump_pack, NULL },
170     { 0,    "--dumpregassign",      &options.dump_rassgn, NULL },
171     { 0,    "--dumptree",           &options.dump_tree, "dump front-end AST before generating iCode" },
172     { 0,    OPTION_DUMP_ALL,        NULL, "Dump the internal structure at all stages" },
173     { 0,    OPTION_XRAM_LOC,        NULL, "<nnnn> External Ram start location" },
174     { 0,    OPTION_XRAM_SIZE,       NULL, "<nnnn> External Ram size" },
175     { 0,    OPTION_IRAM_SIZE,       NULL, "<nnnn> Internal Ram size" },
176     { 0,    OPTION_XSTACK_LOC,      NULL, "<nnnn> External Ram start location" },
177     { 0,    OPTION_CODE_LOC,        NULL, "<nnnn> Code Segment Location" },
178     { 0,    OPTION_CODE_SIZE,       NULL, "<nnnn> Code Segment size" },
179     { 0,    OPTION_STACK_LOC,       NULL, "<nnnn> Stack pointer initial value" },
180     { 0,    OPTION_DATA_LOC,        NULL, "<nnnn> Direct data start location" },
181     { 0,    OPTION_IDATA_LOC,       NULL, NULL },
182     { 0,    OPTION_PEEP_FILE,       NULL, "<file> use this extra peep-hole file" },
183     { 0,    OPTION_LIB_PATH,        NULL, "<path> use this path to search for libraries" },
184     { 0,    "--int-long-reent",     &options.intlong_rent, "Use reenterant calls on the int and long support functions" },
185     { 0,    "--float-reent",        &options.float_rent, "Use reenterant calls on the floar support functions" },
186     { 0,    OPTION_OUT_FMT_IHX,     NULL, NULL },
187     { 0,    "--out-fmt-s19",        &options.out_fmt, NULL },
188     { 0,    "--cyclomatic",         &options.cyclomatic, NULL },
189     { 0,    "--nooverlay",          &options.noOverlay, NULL },
190     { 0,    "--main-return",        &options.mainreturn, "Issue a return after main()" },
191     { 0,    "--xram-movc",          &options.xram_movc, "Use movc instead of movx to read xram (xdata)" },
192     { 0,    "--no-peep",            &options.nopeep, "Disable the peephole assembly file optimisation" },
193     { 0,    "--no-reg-params",      &options.noRegParams, "On some ports, disable passing some parameters in registers" },
194     { 0,    "--peep-asm",           &options.asmpeep, NULL },
195     { 0,    "--debug",              &options.debug, "Enable debugging symbol output" },
196     { 'v',  OPTION_VERSION,         NULL, "Display sdcc's version" },
197     { 'E',  "--preprocessonly",     &preProcOnly, "Preprocess only, do not compile" },
198     { 0,    "--c1mode",             &options.c1mode, "Act in c1 mode.  The standard input is preprocessed code, the output is assembly code." },
199     { 0,    "--help",               NULL, "Display this help" },
200     { 0,    OPTION_CALLEE_SAVES,    NULL, "<func[,func,...]> Cause the called function to save registers insted of the caller" },
201     { 0,    "--nostdlib",           &options.nostdlib, "Do not include the standard library directory in the search path" },
202     { 0,    "--nostdinc",           &options.nostdinc, "Do not include the standard include directory in the search path" },
203     { 0,    "--verbose",            &options.verbose, "Trace calls to the preprocessor, assembler, and linker" },
204     { 0,    OPTION_LESS_PEDANTIC,   NULL, "Disable some of the more pedantic warnings" },
205     { 0,    OPTION_SHORT_IS_8BITS,   NULL, "Make short 8bits (for old times sake)" },
206     { 0,    "--profile",            &options.profile, "On supported ports, generate extra profiling information" },
207     { 0,    "--fommit-frame-pointer", &options.ommitFramePtr, "Leave out the frame pointer." },
208     { 0,    "--all-callee-saves",   &options.all_callee_saves, "callee will always save registers used" },
209 #if !OPT_DISABLE_DS390
210     { 0,    "--use-accelerator",    &options.useAccelerator,"generate code for  DS390 Arithmetic Accelerator"},
211 #endif
212     { 0,    "--stack-probe",        &options.stack_probe,"insert call to function __stack_probe at each function prologue"},
213 #if !OPT_DISABLE_TININative
214     { 0,    "--tini-libid",         NULL,"<nnnn> LibraryID used in -mTININative"},
215 #endif
216 #if !OPT_DISABLE_DS390
217     { 0,    "--protect-sp-update",  &options.protect_sp_update,"DS390 - will disable interrupts during ESP:SP updates"},
218 #endif
219 #if !OPT_DISABLE_DS390 || !OPT_DISABLE_MCS51
220     { 0,    "--parms-in-bank1",     &options.parms_in_bank1,"MCS51/DS390 - use Bank1 for parameter passing"},
221 #endif
222     { 0,    OPTION_NO_XINIT_OPT,    &options.noXinitOpt, "don't memcpy initialized xram from code"},
223     { 0,    OPTION_NO_CCODE_IN_ASM, &options.noCcodeInAsm, "don't include c-code as comments in the asm file"},
224     { 0,    OPTION_ICODE_IN_ASM,    &options.iCodeInAsm, "include i-code as comments in the asm file"},
225     { 0,    OPTION_PRINT_SEARCH_DIRS, &options.printSearchDirs, "display the directories in the compiler's search path"},
226     { 0,    OPTION_MSVC_ERROR_STYLE, &options.vc_err_style, "messages are compatible with Micro$oft visual studio"},
227     { 0,    OPTION_USE_STDOUT, &options.use_stdout, "send errors to stdout instead of stderr"},
228     /* End of options */
229 #if 0 /* 10jun03 !OPT_DISABLE_PIC16 */
230     { 0,    "--no-movff",           &options.no_movff, "disable generating MOVFF opcode in PIC16 port"},
231     { 0,    "--gen-banksel",        &options.gen_banksel, "enable the generation of banksel assembler directives in PIC16 port"},
232 #endif
233     { 0,    NULL }
234 };
235
236 /** Table of all unsupported options and help text to display when one
237     is used.
238 */
239 typedef struct {
240     /** shortOpt as in OPTIONS. */
241     char shortOpt;
242     /** longOpt as in OPTIONS. */
243     const char *longOpt;
244     /** Message to display inside W_UNSUPPORTED_OPT when this option
245         is used. */
246     const char *message;
247 } UNSUPPORTEDOPT;
248
249 static const UNSUPPORTEDOPT 
250 unsupportedOptTable[] = {
251     { 'X',  NULL,       "use --xstack-loc instead" },
252     { 'x',  NULL,       "use --xstack instead" },
253     { 'i',  NULL,       "use --idata-loc instead" },
254     { 'r',  NULL,       "use --xdata-loc instead" },
255     { 's',  NULL,       "use --code-loc instead" },
256     { 'Y',  NULL,       "use -I instead" }
257 };
258
259 /** List of all default constant macros.
260  */
261 static const char *_baseValues[] = {
262   "cpp", "sdcpp",
263   "cppextraopts", "",
264   /* Path seperator character */
265   "sep", DIR_SEPARATOR_STRING,
266   NULL
267 };
268
269 static const char *_preCmd = "{cpp} -nostdinc -Wall -std=c99 -DSDCC=1 {cppextraopts} \"{fullsrcfilename}\" \"{cppoutfilename}\"";
270
271 PORT *port;
272
273 static PORT *_ports[] =
274 {
275 #if !OPT_DISABLE_MCS51
276   &mcs51_port,
277 #endif
278 #if !OPT_DISABLE_GBZ80
279   &gbz80_port,
280 #endif
281 #if !OPT_DISABLE_Z80
282   &z80_port,
283 #endif
284 #if !OPT_DISABLE_AVR
285   &avr_port,
286 #endif
287 #if !OPT_DISABLE_DS390
288   &ds390_port,
289 #endif
290 #if !OPT_DISABLE_PIC
291   &pic_port,
292 #endif
293 #if !OPT_DISABLE_PIC16
294   &pic16_port,
295 #endif
296 #if !OPT_DISABLE_TININative
297   &tininative_port,
298 #endif
299 #if !OPT_DISABLE_XA51
300   &xa51_port,
301 #endif
302 #if !OPT_DISABLE_DS400
303   &ds400_port,  
304 #endif  
305 };
306
307 #define NUM_PORTS (sizeof(_ports)/sizeof(_ports[0]))
308
309 /** Sets the port to the one given by the command line option.
310     @param    The name minus the option (eg 'mcs51')
311     @return     0 on success.
312 */
313 static void
314 _setPort (const char *name)
315 {
316   int i;
317   for (i = 0; i < NUM_PORTS; i++)
318     {
319       if (!strcmp (_ports[i]->target, name))
320         {
321           port = _ports[i];
322           return;
323         }
324     }
325   /* Error - didnt find */
326   werror (E_UNKNOWN_TARGET, name);
327   exit (1);
328 }
329
330 /* Override the default processor with the one specified 
331  * on the command line */
332 static void
333 _setProcessor (char *_processor)
334 {
335   port->processor = _processor;
336   fprintf(stderr,"Processor: %s\n",_processor);
337 }
338
339 static void
340 _validatePorts (void)
341 {
342   int i;
343   for (i = 0; i < NUM_PORTS; i++)
344     {
345       if (_ports[i]->magic != PORT_MAGIC)
346         {
347           /* Uncomment this line to debug which port is causing the problem
348            * (the target name is close to the beginning of the port struct 
349            * and probably can be accessed just fine). */
350           fprintf(stderr,"%s :",_ports[i]->target);
351           wassertl (0, "Port definition structure is incomplete");
352         }
353     }
354 }
355
356 /* search through the command line options for the port */
357 static void
358 _findPort (int argc, char **argv)
359 {
360   _validatePorts ();
361
362   while (argc--)
363     {
364       if (!strncmp (*argv, "-m", 2))
365         {
366           _setPort (*argv + 2);
367           return;
368         }
369       argv++;
370     }
371
372   /* Use the first in the list */
373 #if defined(DEFAULT_PORT)
374         /* VR - 13/5/2003 DEFAULT_PORT is defined in port.h */
375         port = &DEFAULT_PORT;
376 #else
377         port = _ports[0];
378 #endif
379
380 }
381
382 /* search through the command line options for the processor */
383 static void
384 _findProcessor (int argc, char **argv)
385 {
386   while (argc--)
387     {
388       if (!strncmp (*argv, "-p", 2))
389         {
390           _setProcessor (*argv + 2);
391           return;
392         }
393       argv++;
394     }
395
396   /* no error if processor was not specified. */
397 }
398
399 /*-----------------------------------------------------------------*/
400 /* printVersionInfo - prints the version info        */
401 /*-----------------------------------------------------------------*/
402 void
403 printVersionInfo (void)
404 {
405   int i;
406
407   fprintf (stderr,
408            "SDCC : ");
409   for (i = 0; i < NUM_PORTS; i++) {
410     fprintf (stderr, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
411 #ifdef DEFAULT_PORT
412         fprintf(stderr, "%s", (&DEFAULT_PORT == _ports[i])?"*":"");
413 #endif
414   }
415   
416   fprintf (stderr, " " SDCC_VERSION_STR
417 #ifdef SDCC_SUB_VERSION_STR
418            "/" SDCC_SUB_VERSION_STR
419 #endif
420            " (" __DATE__ ")"
421 #ifdef __CYGWIN__
422            " (CYGWIN)\n"
423 #elif defined __MINGW32__
424            " (MINGW32)\n"
425 #elif defined __DJGPP__
426            " (DJGPP)\n"
427 #elif defined(_MSC_VER)
428            " (MSVC)\n"
429 #elif defined(__BORLANDC__)
430            " (BORLANDC)\n"
431 #else
432            " (UNIX) \n"
433 #endif
434     );
435 }
436
437 static void
438 printOptions(const OPTION *optionsTable)
439 {
440   int i;
441   for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL; i++) 
442     {
443       fprintf(stdout, "  %c%c  %-20s  %s\n", 
444               optionsTable[i].shortOpt !=0 ? '-' : ' ',
445               optionsTable[i].shortOpt !=0 ? optionsTable[i].shortOpt : ' ',
446               optionsTable[i].longOpt != NULL ? optionsTable[i].longOpt : "",
447               optionsTable[i].help != NULL ? optionsTable[i].help : ""
448               );
449     }
450 }
451
452 /*-----------------------------------------------------------------*/
453 /* printUsage - prints command line syntax         */
454 /*-----------------------------------------------------------------*/
455 void
456 printUsage (void)
457 {
458     int i;
459     printVersionInfo();
460     fprintf (stdout,
461              "Usage : sdcc [options] filename\n"
462              "Options :-\n"
463              );
464
465     printOptions(optionsTable);
466
467     for (i = 0; i < NUM_PORTS; i++)
468       {
469         if (_ports[i]->poptions != NULL)
470           {
471             fprintf (stdout, "\nSpecial options for the %s port:\n", _ports[i]->target);
472             printOptions (_ports[i]->poptions);
473           }
474       }
475
476     exit (0);
477 }
478
479 /*-----------------------------------------------------------------*/
480 /* setParseWithComma - separates string with comma to a set        */
481 /*-----------------------------------------------------------------*/
482 void
483 setParseWithComma (set **dest, char *src)
484 {
485   char *p;
486
487   /* skip the initial white spaces */
488   while (isspace(*src))
489     src++;
490
491   for (p = strtok(src, ","); p != NULL; p = strtok(NULL, ","))
492     addSet(dest, Safe_strdup(p));
493 }
494
495 /*-----------------------------------------------------------------*/
496 /* setDefaultOptions - sets the default options                    */
497 /*-----------------------------------------------------------------*/
498 static void
499 setDefaultOptions (void)
500 {
501   /* first the options part */
502   options.stack_loc = 0;        /* stack pointer initialised to 0 */
503   options.xstack_loc = 0;       /* xternal stack starts at 0 */
504   options.code_loc = 0;         /* code starts at 0 */
505   options.data_loc = 0;         /* JCF: By default let the linker locate data */
506   options.xdata_loc = 0;
507   options.idata_loc = 0x80;
508   options.nopeep = 0;
509   options.model = port->general.default_model;
510   options.nostdlib = 0;
511   options.nostdinc = 0;
512   options.verbose = 0;
513   options.shortis8bits = 0;
514
515   options.stack10bit=0;
516
517   /* now for the optimizations */
518   /* turn on the everything */
519   optimize.global_cse = 1;
520   optimize.label1 = 1;
521   optimize.label2 = 1;
522   optimize.label3 = 1;
523   optimize.label4 = 1;
524   optimize.loopInvariant = 1;
525   optimize.loopInduction = 1;
526
527   /* now for the ports */
528   port->setDefaultOptions ();
529 }
530
531 /*-----------------------------------------------------------------*/
532 /* processFile - determines the type of file from the extension    */
533 /*-----------------------------------------------------------------*/
534 static void
535 processFile (char *s)
536 {
537   char *fext = NULL;
538
539   /* get the file extension */
540   fext = s + strlen (s);
541   while ((fext != s) && *fext != '.')
542     fext--;
543
544   /* now if no '.' then we don't know what the file type is
545      so give a warning and return */
546   if (fext == s)
547     {
548       werror (W_UNKNOWN_FEXT, s);
549       return;
550     }
551
552   /* otherwise depending on the file type */
553   if (strcmp (fext, ".c") == 0 || strcmp (fext, ".C") == 0)
554     {
555       /* source file name : not if we already have a
556          source file */
557       if (fullSrcFileName)
558         {
559           werror (W_TOO_MANY_SRC, s);
560           return;
561         }
562
563       /* the only source file */
564       fullSrcFileName = s;
565       if (!(srcFile = fopen (fullSrcFileName, "r")))
566         {
567           werror (E_FILE_OPEN_ERR, s);
568           exit (1);
569         }
570
571       /* copy the file name into the buffer */
572       strncpyz (buffer, s, sizeof(buffer));
573
574       /* get rid of the "."-extension */
575
576       /* is there a dot at all? */
577       if (strrchr (buffer, '.') &&
578           /* is the dot in the filename, not in the path? */
579           (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
580         {
581         *strrchr (buffer, '.') = '\0';
582         }
583
584       /* get rid of any path information
585          for the module name; */
586       fext = buffer + strlen (buffer);
587 #if NATIVE_WIN32
588       /* do this by going backwards till we
589          get '\' or ':' or start of buffer */
590       while (fext != buffer &&
591              *(fext - 1) != DIR_SEPARATOR_CHAR &&
592              *(fext - 1) != ':')
593         {
594         fext--;
595         }
596 #else
597       /* do this by going backwards till we
598          get '/' or start of buffer */
599       while (fext != buffer &&
600              *(fext - 1) != DIR_SEPARATOR_CHAR)
601         {
602           fext--;
603         }
604 #endif
605       moduleName = Safe_strdup ( fext );
606       return;
607     }
608
609   /* if the extention is type .rel or .r or .REL or .R
610      addtional object file will be passed to the linker */
611   if (strcmp (fext, ".r") == 0 || strcmp (fext, ".rel") == 0 ||
612       strcmp (fext, ".R") == 0 || strcmp (fext, ".REL") == 0 ||
613       strcmp (fext, port->linker.rel_ext) == 0)
614     {
615       addSet(&relFilesSet, Safe_strdup(s));
616       return;
617     }
618
619   /* if .lib or .LIB */
620   if (strcmp (fext, ".lib") == 0 || strcmp (fext, ".LIB") == 0)
621     {
622       addSet(&libFilesSet, Safe_strdup(s));
623       return;
624     }
625
626   werror (W_UNKNOWN_FEXT, s);
627
628 }
629
630 static void
631 _setModel (int model, const char *sz)
632 {
633   if (port->general.supported_models & model)
634     options.model = model;
635   else
636     werror (W_UNSUPPORTED_MODEL, sz, port->target);
637 }
638
639 /** Gets the string argument to this option.  If the option is '--opt'
640     then for input of '--optxyz' or '--opt xyz' returns xyz.
641 */
642 static char *
643 getStringArg(const char *szStart, char **argv, int *pi, int argc)
644 {
645   if (argv[*pi][strlen(szStart)])
646     {
647       return &argv[*pi][strlen(szStart)];
648     }
649   else
650     {
651       ++(*pi);
652       if (*pi >= argc)
653         {
654           werror (E_ARGUMENT_MISSING, szStart);
655           /* Die here rather than checking for errors later. */
656           exit(-1);
657         }
658       else
659         {
660           return argv[*pi];
661         }
662     }
663 }
664
665 /** Gets the integer argument to this option using the same rules as
666     getStringArg.
667 */
668 static int
669 getIntArg(const char *szStart, char **argv, int *pi, int argc)
670 {
671     return (int)floatFromVal(constVal(getStringArg(szStart, argv, pi, argc)));
672 }
673
674 static void
675 verifyShortOption(const char *opt)
676 {
677   if (strlen(opt) != 2)
678     {
679       werror (W_EXCESS_SHORT_OPTIONS, opt);
680     }
681 }
682
683 static bool
684 tryHandleUnsupportedOpt(char **argv, int *pi)
685 {
686     if (argv[*pi][0] == '-') 
687         {
688             const char *longOpt = "";
689             char shortOpt = -1;
690             int i;
691
692             if (argv[*pi][1] == '-') 
693                 {
694                     /* Long option. */
695                     longOpt = argv[*pi];
696                 }
697             else 
698                 {
699                     shortOpt = argv[*pi][1];
700                 }
701             for (i = 0; i < LENGTH(unsupportedOptTable); i++) 
702                 {
703                     if (unsupportedOptTable[i].shortOpt == shortOpt || 
704                         (longOpt && unsupportedOptTable[i].longOpt && !strcmp(unsupportedOptTable[i].longOpt, longOpt))) {
705                         /* Found an unsupported opt. */
706                         char buffer[100];
707                         SNPRINTF(buffer, sizeof(buffer), 
708                                  "%s%c%c", 
709                                  longOpt ? longOpt : "", 
710                                  shortOpt ? '-' : ' ', shortOpt ? shortOpt : ' ');
711                         werror (W_UNSUPP_OPTION, buffer, unsupportedOptTable[i].message);
712                         return 1;
713                     }
714                 }
715             /* Didn't find in the table */
716             return 0;
717         }
718     else 
719         {
720             /* Not an option, so can't be unsupported :) */
721             return 0;
722     }
723 }
724
725 static bool
726 scanOptionsTable(const OPTION *optionsTable, char shortOpt, const char *longOpt, char **argv, int *pi)
727 {
728   int i;
729   for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL; i++)
730     {
731       if (optionsTable[i].shortOpt == shortOpt ||
732           (longOpt && optionsTable[i].longOpt && 
733            strcmp(optionsTable[i].longOpt, longOpt) == 0))
734         {
735
736           /* If it is a flag then we can handle it here */
737           if (optionsTable[i].pparameter != NULL) 
738             {
739               if (optionsTable[i].shortOpt == shortOpt)
740                 {
741                   verifyShortOption(argv[*pi]);
742                 }
743
744               (*optionsTable[i].pparameter)++;
745               return 1;
746             }
747           else {
748             /* Not a flag.  Handled manually later. */
749             return 0;
750           }
751         }
752     }
753   /* Didn't find in the table */
754   return 0;
755 }
756
757 static bool
758 tryHandleSimpleOpt(char **argv, int *pi)
759 {
760     if (argv[*pi][0] == '-') 
761         {
762             const char *longOpt = "";
763             char shortOpt = -1;
764
765             if (argv[*pi][1] == '-') 
766                 {
767                     /* Long option. */
768                     longOpt = argv[*pi];
769                 }
770             else 
771                 {
772                     shortOpt = argv[*pi][1];
773                 }
774
775             if (scanOptionsTable(optionsTable, shortOpt, longOpt, argv, pi))
776               {
777                 return 1;
778               }
779             else if (port && port->poptions &&
780                      scanOptionsTable(port->poptions, shortOpt, longOpt, argv, pi))
781               {
782                 return 1;
783               }
784             else
785               {
786                 return 0;
787               }
788         }
789     else 
790         {
791             /* Not an option, so can't be handled. */
792             return 0;
793         }
794 }
795
796 /*-----------------------------------------------------------------*/
797 /* parseCmdLine - parses the command line and sets the options     */
798 /*-----------------------------------------------------------------*/
799 static int
800 parseCmdLine (int argc, char **argv)
801 {
802   int i;
803
804   /* go thru all whole command line */
805   for (i = 1; i < argc; i++)
806     {
807       if (i >= argc)
808         break;
809
810       if (tryHandleUnsupportedOpt(argv, &i) == TRUE) 
811           {
812               continue;
813           }
814
815       if (tryHandleSimpleOpt(argv, &i) == TRUE)
816           {
817               continue;
818           }
819
820       /* options */
821       if (argv[i][0] == '-' && argv[i][1] == '-')
822         {
823           if (strcmp (argv[i], OPTION_HELP) == 0)
824             {
825               printUsage ();
826               exit (0);
827             }
828
829           if (strcmp (argv[i], OPTION_STACK_8BIT) == 0)
830             {
831               options.stack10bit = 0;
832               continue;
833             }
834
835           if (strcmp (argv[i], OPTION_OUT_FMT_IHX) == 0)
836             {
837               options.out_fmt = 0;
838               continue;
839             }
840
841           if (strcmp (argv[i], OPTION_LARGE_MODEL) == 0)
842             {
843               _setModel (MODEL_LARGE, argv[i]);
844               continue;
845             }
846
847           if (strcmp (argv[i], OPTION_MEDIUM_MODEL) == 0)
848             {
849               _setModel (MODEL_MEDIUM, argv[i]);
850               continue;
851             }
852
853           if (strcmp (argv[i], OPTION_SMALL_MODEL) == 0)
854             {
855               _setModel (MODEL_SMALL, argv[i]);
856               continue;
857             }
858
859           if (strcmp (argv[i], OPTION_FLAT24_MODEL) == 0)
860             {
861               _setModel (MODEL_FLAT24, argv[i]);
862               continue;
863             }
864
865           if (strcmp (argv[i], OPTION_DUMP_ALL) == 0)
866             {
867               options.dump_rassgn =
868                 options.dump_pack =
869                 options.dump_range =
870                 options.dump_kill =
871                 options.dump_loop =
872                 options.dump_gcse =
873                 options.dump_raw = 1;
874               continue;
875             }
876
877           if (strcmp (argv[i], OPTION_PEEP_FILE) == 0)
878             {
879                 options.peep_file = getStringArg(OPTION_PEEP_FILE, argv, &i, argc);
880                 continue;
881             }
882
883           if (strcmp (argv[i], OPTION_LIB_PATH) == 0)
884             {
885                 addSet(&libPathsSet, Safe_strdup(getStringArg(OPTION_LIB_PATH, argv, &i, argc)));
886                 continue;
887             }
888
889           if (strcmp (argv[i], OPTION_VERSION) == 0)
890             {
891               printVersionInfo ();
892               exit (0);
893               continue;
894             }
895
896           if (strcmp (argv[i], OPTION_CALLEE_SAVES) == 0)
897             {
898                 setParseWithComma(&options.calleeSavesSet, getStringArg(OPTION_CALLEE_SAVES, argv, &i, argc));
899                 continue;
900             }
901
902           if (strcmp (argv[i], OPTION_XSTACK_LOC) == 0)
903             {
904                 options.xstack_loc = getIntArg(OPTION_XSTACK_LOC, argv, &i, argc);
905                 continue;
906             }
907
908           if (strcmp (argv[i], OPTION_STACK_LOC) == 0)
909             {
910                 options.stack_loc = getIntArg(OPTION_STACK_LOC, argv, &i, argc);
911                 continue;
912             }
913
914           if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
915             {
916                 options.xdata_loc = getIntArg(OPTION_XRAM_LOC, argv, &i, argc);
917                 continue;
918             }
919
920           if (strcmp (argv[i], OPTION_IRAM_SIZE) == 0)
921             {
922                 options.iram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
923                 continue;
924             }
925
926           if (strcmp (argv[i], OPTION_XRAM_SIZE) == 0)
927             {
928                 options.xram_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
929                 options.xram_size_set = TRUE;
930                 continue;
931             }
932
933           if (strcmp (argv[i], OPTION_CODE_SIZE) == 0)
934             {
935                 options.code_size = getIntArg(OPTION_IRAM_SIZE, argv, &i, argc);
936                 continue;
937             }
938
939           if (strcmp (argv[i], OPTION_DATA_LOC) == 0)
940             {
941                 options.data_loc = getIntArg(OPTION_DATA_LOC, argv, &i, argc);
942                 continue;
943             }
944
945           if (strcmp (argv[i], OPTION_IDATA_LOC) == 0)
946             {
947                 options.idata_loc = getIntArg(OPTION_IDATA_LOC, argv, &i, argc);
948                 continue;
949             }
950
951           if (strcmp (argv[i], OPTION_CODE_LOC) == 0)
952             {
953                 options.code_loc = getIntArg(OPTION_CODE_LOC, argv, &i, argc);
954                 continue;
955             }
956
957           if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
958             {
959               optimize.global_cse = 0;
960               continue;
961             }
962
963           if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
964             {
965               optimize.loopInvariant = 0;
966               continue;
967             }
968
969           if (strcmp (argv[i], OPTION_NO_LABEL_OPT) == 0)
970             {
971               optimize.label4 = 0;
972               continue;
973             }
974
975           if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
976             {
977               optimize.loopInduction = 0;
978               continue;
979             }
980
981           if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0) 
982             {
983               options.lessPedantic = 1;
984               setErrorLogLevel(ERROR_LEVEL_WARNING);
985               continue;
986             }
987
988           if (strcmp (&argv[i][1], OPTION_SHORT_IS_8BITS) == 0) 
989             {
990               options.shortis8bits=1;
991               continue;
992             }
993
994           if (strcmp (argv[i], OPTION_TINI_LIBID) == 0)
995             {
996                 options.tini_libid = getIntArg(OPTION_TINI_LIBID, argv, &i, argc);
997                 continue;
998             }
999           
1000           if (!port->parseOption (&argc, argv, &i))
1001             {
1002               werror (W_UNKNOWN_OPTION, argv[i]);
1003             }
1004           else
1005             {
1006               continue;
1007             }
1008         }
1009
1010       /* if preceded by  '-' then option */
1011       if (*argv[i] == '-')
1012         {
1013           switch (argv[i][1])
1014             {
1015             case 'h':
1016               verifyShortOption(argv[i]);
1017
1018               printUsage ();
1019               exit (0);
1020               break;
1021
1022             case 'm':
1023               /* Used to select the port. But this has already been done. */
1024               break;
1025
1026             case 'p':
1027               /* Used to select the processor in port. But this has
1028                * already been done. */
1029               break;
1030
1031             case 'c':
1032               verifyShortOption(argv[i]);
1033
1034               options.cc_only = 1;
1035               break;
1036
1037             case 'L':
1038                 addSet(&libPathsSet, Safe_strdup(getStringArg("-L", argv, &i, argc)));
1039                 break;
1040
1041             case 'l':
1042                 addSet(&libFilesSet, Safe_strdup(getStringArg("-l", argv, &i, argc)));
1043                 break;
1044             
1045             case 'o':
1046               {
1047                 char *p;
1048
1049                 /* copy the file name into the buffer */
1050                 strncpyz(buffer, getStringArg("-o", argv, &i, argc), 
1051                          sizeof(buffer));
1052                 /* point to last character */
1053                 p = buffer + strlen (buffer) - 1;
1054                 if (*p == DIR_SEPARATOR_CHAR)
1055                   {
1056                     /* only output path specified */
1057                     dstPath = Safe_strdup (buffer);
1058                     fullDstFileName = NULL;
1059                   }
1060                 else
1061                   {
1062                     fullDstFileName = Safe_strdup (buffer);
1063
1064                     /* get rid of the "."-extension */
1065
1066                     /* is there a dot at all? */
1067                     if (strrchr (buffer, '.') &&
1068                         /* is the dot in the filename, not in the path? */
1069                         (strrchr (buffer, DIR_SEPARATOR_CHAR) < strrchr (buffer, '.')))
1070                       *strrchr (buffer, '.') = '\0';
1071
1072                     dstFileName = Safe_strdup (buffer);
1073
1074                     /* strip module name to get path */
1075                     p = strrchr (buffer, DIR_SEPARATOR_CHAR);
1076                     if (p)
1077                       {
1078                         /* path with trailing / */
1079                         p[1] = '\0';
1080                         dstPath = Safe_strdup (buffer);
1081                       }
1082                   }
1083                 break;
1084               }
1085
1086             case 'W':
1087               /* pre-processer options */
1088               if (argv[i][2] == 'p')
1089                 {
1090                   setParseWithComma(&preArgvSet, getStringArg("-Wp", argv, &i, argc));
1091                 }
1092               /* linker options */
1093               else if (argv[i][2] == 'l')
1094                 {
1095                   setParseWithComma(&linkOptionsSet, getStringArg("-Wl", argv, &i, argc));
1096                 }
1097               /* assembler options */
1098               else if (argv[i][2] == 'a')
1099                 {
1100                   setParseWithComma(&asmOptionsSet, getStringArg("-Wa", argv, &i, argc));
1101                 }
1102               else
1103                 {
1104                   werror (W_UNKNOWN_OPTION, argv[i]);
1105                 }
1106               break;
1107
1108             case 'v':
1109               verifyShortOption(argv[i]);
1110
1111               printVersionInfo ();
1112               exit (0);
1113               break;
1114
1115               /* preprocessor options */
1116             case 'M':
1117               {
1118                 preProcOnly = 1;
1119                 addSet(&preArgvSet, Safe_strdup("-M"));
1120                 break;
1121               }
1122             case 'C':
1123               {
1124                 addSet(&preArgvSet, Safe_strdup("-C"));
1125                 break;
1126               }
1127
1128             case 'd':
1129             case 'D':
1130             case 'I':
1131             case 'A':
1132             case 'U':
1133               {
1134                 char sOpt = argv[i][1];
1135                 char *rest;
1136
1137                 if (argv[i][2] == ' ' || argv[i][2] == '\0')
1138                   {
1139                     i++;
1140                     if (i >= argc)
1141                       {
1142                           /* No argument. */
1143                           werror(E_ARGUMENT_MISSING, argv[i-1]);
1144                           break;
1145                       }
1146                     else
1147                       {
1148                           rest = argv[i];
1149                       }
1150                   }
1151                 else
1152                   rest = &argv[i][2];
1153
1154                 if (sOpt == 'Y')
1155                   sOpt = 'I';
1156
1157                 SNPRINTF (buffer, sizeof(buffer),
1158                   ((sOpt == 'I') ? "-%c\"%s\"": "-%c%s"), sOpt, rest);
1159                 addSet(&preArgvSet, Safe_strdup(buffer));
1160               }
1161               break;
1162
1163             default:
1164               if (!port->parseOption (&argc, argv, &i))
1165                 werror (W_UNKNOWN_OPTION, argv[i]);
1166             }
1167           continue;
1168         }
1169
1170       if (!port->parseOption (&argc, argv, &i))
1171         {
1172            /* no option must be a filename */
1173            if (options.c1mode)
1174              {
1175                 werror (W_NO_FILE_ARG_IN_C1, argv[i]);
1176              }
1177          else
1178              {
1179                 processFile (argv[i]);
1180              }
1181         }
1182     }
1183
1184   /* some sanity checks in c1 mode */
1185   if (options.c1mode)
1186     {
1187       const char *s;
1188
1189       if (fullSrcFileName)
1190         {
1191           fclose (srcFile);
1192           werror (W_NO_FILE_ARG_IN_C1, fullSrcFileName);
1193         }
1194       fullSrcFileName = NULL;
1195       for (s = setFirstItem(relFilesSet); s != NULL; s = setNextItem(relFilesSet))
1196         {
1197           werror (W_NO_FILE_ARG_IN_C1, s);
1198         }
1199       for (s = setFirstItem(libFilesSet); s != NULL; s = setNextItem(libFilesSet))
1200         {
1201           werror (W_NO_FILE_ARG_IN_C1, s);
1202         }
1203       deleteSet(&relFilesSet);
1204       deleteSet(&libFilesSet);
1205
1206         if (options.cc_only || noAssemble || preProcOnly)
1207         {
1208           werror (W_ILLEGAL_OPT_COMBINATION);
1209         }
1210       options.cc_only = noAssemble = preProcOnly = 0;
1211       if (!dstFileName)
1212         {
1213           werror (E_NEED_OPT_O_IN_C1);
1214           exit (1);
1215         }
1216     }
1217   /* if no dstFileName given with -o, we've to find one: */
1218   if (!dstFileName)
1219     {
1220       const char *s;
1221
1222       /* use the modulename from the C-source */
1223       if (fullSrcFileName)
1224         {
1225           size_t bufSize = strlen (dstPath) + strlen (moduleName) + 1;
1226
1227           dstFileName = Safe_alloc (bufSize);
1228           strncpyz (dstFileName, dstPath, bufSize);
1229           strncatz (dstFileName, moduleName, bufSize);
1230         }
1231       /* use the modulename from the first object file */
1232       else if ((s = peekSet(relFilesSet)) != NULL)
1233         {
1234           char *objectName;
1235           size_t bufSize;
1236
1237           strncpyz (buffer, s, sizeof(buffer));
1238           /* remove extension (it must be .rel) */
1239           *strrchr (buffer, '.') = '\0';
1240           /* remove path */
1241           objectName = strrchr (buffer, DIR_SEPARATOR_CHAR);
1242           if (objectName)
1243             {
1244               ++objectName;
1245             }
1246           else
1247             {
1248               objectName = buffer;
1249             }
1250           bufSize = strlen (dstPath) + strlen (objectName) + 1;  
1251           dstFileName = Safe_alloc (bufSize);
1252           strncpyz (dstFileName, dstPath, bufSize);
1253           strncatz (dstFileName, objectName, bufSize);
1254         }
1255       /* else no module given: help text is displayed */
1256     }
1257
1258   /* set up external stack location if not explicitly specified */
1259   if (!options.xstack_loc)
1260     options.xstack_loc = options.xdata_loc;
1261
1262   /* if debug option is set then open the cdbFile */
1263   if (options.debug && fullSrcFileName)
1264     {
1265       SNPRINTF (scratchFileName, sizeof(scratchFileName),
1266                 "%s.adb", dstFileName); /*JCF: Nov 30, 2002*/
1267       if(debugFile->openFile(scratchFileName))
1268         debugFile->writeModule(moduleName);
1269       else
1270         werror (E_FILE_OPEN_ERR, scratchFileName);
1271     }
1272   MSVC_style(options.vc_err_style);
1273   if(options.use_stdout) dup2(STDOUT_FILENO, STDERR_FILENO);
1274
1275   return 0;
1276 }
1277
1278 /*-----------------------------------------------------------------*/
1279 /* linkEdit : - calls the linkage editor  with options             */
1280 /*-----------------------------------------------------------------*/
1281 static void
1282 linkEdit (char **envp)
1283 {
1284   FILE *lnkfile;
1285   char *segName, *c;
1286   int system_ret;
1287   const char *s;
1288
1289   /* first we need to create the <filename>.lnk file */
1290   SNPRINTF (scratchFileName, sizeof(scratchFileName),
1291             "%s.lnk", dstFileName);
1292   if (!(lnkfile = fopen (scratchFileName, "w")))
1293     {
1294       werror (E_FILE_OPEN_ERR, scratchFileName);
1295       exit (1);
1296     }
1297
1298    if (TARGET_IS_Z80 || TARGET_IS_GBZ80)
1299    {
1300           fprintf (lnkfile, "--\n-m\n-j\n-x\n-%c %s\n",
1301           (options.out_fmt ? 's' : 'i'), dstFileName);
1302    }
1303    else /*For all the other ports.  Including pics???*/
1304    {
1305           fprintf (lnkfile, "-myux%c\n", (options.out_fmt ? 's' : 'i'));
1306    }
1307
1308    if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80)) /*Not for the z80, gbz80*/
1309    {
1310           /* if iram size specified */
1311           if (options.iram_size)
1312                 fprintf (lnkfile, "-a 0x%04x\n", options.iram_size);
1313
1314           /* if xram size specified */
1315           if (options.xram_size_set)
1316                 fprintf (lnkfile, "-v 0x%04x\n", options.xram_size);
1317
1318           /* if code size specified */
1319           if (options.code_size)
1320                 fprintf (lnkfile, "-w 0x%04x\n", options.code_size);
1321
1322           if (options.debug)
1323                 fprintf (lnkfile, "-z\n");
1324    }
1325
1326 #define WRITE_SEG_LOC(N, L) \
1327     segName = Safe_strdup(N); \
1328     c = strtok(segName, " \t"); \
1329     fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
1330     if (segName) { Safe_free(segName); }
1331
1332    if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80)) /*Not for the z80, gbz80*/
1333    {
1334
1335           /* code segment start */
1336           WRITE_SEG_LOC (CODE_NAME, options.code_loc);
1337
1338           /* data segment start. If zero, the linker chooses
1339       the best place for data*/
1340           if(options.data_loc){
1341                   WRITE_SEG_LOC (DATA_NAME, options.data_loc);
1342           }
1343
1344           /* xdata start */
1345           WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
1346
1347           /* indirect data */
1348           if (IDATA_NAME) {
1349                 WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
1350           }
1351
1352           /* bit segment start */
1353           WRITE_SEG_LOC (BIT_NAME, 0);
1354
1355           /* stack start */
1356           if ( (options.stack_loc) && (options.stack_loc<0x100) ) {
1357                 WRITE_SEG_LOC ("SSEG", options.stack_loc);
1358           }
1359    }
1360    else /*For the z80, gbz80*/
1361    {
1362        WRITE_SEG_LOC ("_CODE", options.code_loc);
1363        WRITE_SEG_LOC ("_DATA", options.data_loc);
1364    }
1365   
1366   /* If the port has any special linker area declarations, get 'em */
1367   if (port->extraAreas.genExtraAreaLinkOptions)
1368   {
1369         port->extraAreas.genExtraAreaLinkOptions(lnkfile);
1370   }
1371
1372   /* add the extra linker options */
1373   fputStrSet(lnkfile, linkOptionsSet);
1374
1375   /* other library paths if specified */
1376   for (s = setFirstItem(libPathsSet); s != NULL; s = setNextItem(libPathsSet))
1377     fprintf (lnkfile, "-k %s\n", s);
1378   
1379   /* standard library path */
1380     if (!options.nostdlib)
1381     {
1382         if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80)) /*Not for the z80, gbz80*/
1383         {
1384             switch (options.model)
1385             {
1386                 case MODEL_SMALL:
1387                     c = "small";
1388                     break;
1389                 case MODEL_LARGE:
1390                     c = "large";
1391                     break;
1392                 case MODEL_FLAT24:
1393                     /* c = "flat24"; */
1394                     if (TARGET_IS_DS390)
1395                     {
1396                         c = "ds390";
1397                     }
1398                     else if (TARGET_IS_DS400)
1399                     {
1400                         c = "ds400";
1401                     }
1402                     else
1403                     {
1404                         fprintf(stderr, 
1405                                 "Add support for your FLAT24 target in %s @ line %d\n",
1406                                 __FILE__, __LINE__);
1407                         exit(-1);
1408                     }
1409                         break;
1410                     case MODEL_PAGE0:
1411                         c = "xa51";
1412                         break;
1413                     default:
1414                         werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1415                         c = "unknown";
1416                         break;
1417                 }
1418         }
1419         else /*for the z80, gbz80*/
1420         {
1421             if (TARGET_IS_Z80)
1422                 c = "z80";
1423             else
1424                 c = "gbz80";
1425         }
1426         for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
1427             mfprintf (lnkfile, getRuntimeVariables(), "-k %s{sep}%s\n", s, c);
1428
1429
1430       /* standard library files */
1431 #if !OPT_DISABLE_DS390
1432         if (options.model == MODEL_FLAT24)
1433         {
1434             if (TARGET_IS_DS390)
1435             {
1436                 fprintf (lnkfile, "-l %s\n", STD_DS390_LIB);
1437             }
1438             else if (TARGET_IS_DS400)
1439             {
1440                 fprintf (lnkfile, "-l %s\n", STD_DS400_LIB);
1441             }
1442             else
1443             {
1444                 fprintf(stderr, 
1445                     "Add support for your FLAT24 target in %s @ line %d\n",
1446                     __FILE__, __LINE__);
1447                 exit(-1);
1448             }
1449         }
1450 #endif
1451
1452 #if !OPT_DISABLE_XA51 
1453 #ifdef STD_XA51_LIB
1454         if (options.model == MODEL_PAGE0)
1455         {
1456             fprintf (lnkfile, "-l %s\n", STD_XA51_LIB);
1457         }
1458 #endif
1459 #endif
1460         if (!(TARGET_IS_Z80 || TARGET_IS_GBZ80)) /*Not for the z80, gbz80*/
1461         { /*Why the z80 port is not using the standard libraries?*/
1462             fprintf (lnkfile, "-l %s\n", STD_LIB);
1463             fprintf (lnkfile, "-l %s\n", STD_INT_LIB);
1464             fprintf (lnkfile, "-l %s\n", STD_LONG_LIB);
1465             fprintf (lnkfile, "-l %s\n", STD_FP_LIB);
1466         }
1467         else if (TARGET_IS_Z80)
1468         {
1469             fprintf (lnkfile, "-l z80\n");
1470         }
1471         else if (TARGET_IS_GBZ80)
1472         {
1473             fprintf (lnkfile, "-l gbz80\n");
1474         }
1475     }
1476
1477   /* additional libraries if any */
1478   for (s = setFirstItem(libFilesSet); s != NULL; s = setNextItem(libFilesSet))
1479     fprintf (lnkfile, "-l %s\n", s);
1480
1481   /*For the z80 and gbz80 ports, try to find where crt0.o is...
1482   It is very important for this file to be first on the linking proccess
1483   so the areas are set in the correct order, expecially _GSINIT*/
1484   if (TARGET_IS_Z80 || TARGET_IS_GBZ80) /*For the z80, gbz80*/
1485   {
1486       char crt0path[PATH_MAX];
1487       FILE * crt0fp;
1488       for (s = setFirstItem(libDirsSet); s != NULL; s = setNextItem(libDirsSet))
1489       {
1490           sprintf (crt0path, "%s%s%s%scrt0.o",
1491              s, DIR_SEPARATOR_STRING, c, DIR_SEPARATOR_STRING);
1492           
1493           crt0fp=fopen(crt0path, "r");
1494           if(crt0fp!=NULL)/*Found it!*/
1495           {
1496               fclose(crt0fp);
1497               #ifdef __CYGWIN__
1498               {
1499                  /*The CYGWIN version of the z80-gbz80 linker is getting confused with
1500                  windows paths, so convert them to the CYGWIN format*/
1501                  char posix_path[PATH_MAX];
1502                  void cygwin_conv_to_full_posix_path(char * win_path, char * posix_path);
1503                  cygwin_conv_to_full_posix_path(crt0path, posix_path);
1504                  strcpy(crt0path, posix_path);
1505               }
1506               #endif
1507               fprintf (lnkfile, "%s\n", crt0path);
1508               break;
1509           }
1510       }
1511       if(s==NULL) fprintf (stderr, "Warning: couldn't find crt0.o\n");
1512   }
1513
1514   /* put in the object files */
1515   if (fullSrcFileName)
1516     fprintf (lnkfile, "%s%s\n", dstFileName, port->linker.rel_ext);
1517
1518   fputStrSet(lnkfile, relFilesSet);
1519
1520   fprintf (lnkfile, "\n-e\n");
1521   fclose (lnkfile);
1522
1523   if (options.verbose)
1524     printf ("sdcc: Calling linker...\n");
1525
1526   /* build linker output filename */
1527
1528   /* -o option overrides default name? */
1529   if (fullDstFileName)
1530     {
1531       strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1532     }
1533   else
1534     {
1535       /* the linked file gets the name of the first modul */
1536       if (fullSrcFileName)
1537         {
1538           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1539         }
1540       else
1541         {
1542           s = peekSet(relFilesSet);
1543
1544           assert(s);
1545
1546           strncpyz (scratchFileName, s, sizeof(scratchFileName));
1547           /* strip ".rel" extension */
1548           *strrchr (scratchFileName, '.') = '\0';
1549         }
1550       strncatz (scratchFileName, 
1551                 options.out_fmt ? ".S19" : ".ihx",
1552                 sizeof(scratchFileName));
1553     }
1554
1555   if (port->linker.cmd)
1556     {
1557       char buffer2[PATH_MAX];
1558
1559         /* VR 030517 - gplink needs linker options to set the linker script,*/
1560         buildCmdLine (buffer2, port->linker.cmd, dstFileName, scratchFileName, NULL, linkOptionsSet);
1561
1562         buildCmdLine2 (buffer, sizeof(buffer), buffer2);
1563     }
1564   else
1565     {
1566       buildCmdLine2 (buffer, sizeof(buffer), port->linker.mcmd);
1567     }
1568
1569 /*  if (options.verbose)fprintf(stderr, "linker command line: %s\n", buffer); */
1570
1571   system_ret = my_system (buffer);
1572   /* TODO: most linker don't have a -o parameter */
1573   /* -o option overrides default name? */
1574   if (fullDstFileName)
1575     {
1576       char *p, *q;
1577       /* the linked file gets the name of the first modul */
1578       if (fullSrcFileName)
1579         {
1580           strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1581           p = strlen (scratchFileName) + scratchFileName;
1582         }
1583       else
1584         {
1585           s = peekSet(relFilesSet);
1586
1587           assert(s);
1588
1589           strncpyz (scratchFileName, s, sizeof(scratchFileName));
1590           /* strip ".rel" extension */
1591           p = strrchr (scratchFileName, '.');
1592           if (p)
1593             {
1594               *p = 0;
1595             }
1596         }
1597       strncatz (scratchFileName,
1598                 options.out_fmt ? ".S19" : ".ihx",
1599                 sizeof(scratchFileName));
1600       rename (scratchFileName, fullDstFileName);
1601
1602       strncpyz (buffer, fullDstFileName, sizeof(buffer));
1603       q = strrchr (buffer, '.');
1604       if (!q)
1605         {
1606           /* no extension: append new extensions */
1607           q = strlen (buffer) + buffer;
1608         }
1609
1610       *p = 0;
1611       strncatz (scratchFileName, ".map", sizeof(scratchFileName));
1612       *q = 0;
1613       strncatz(buffer, ".map", sizeof(buffer));
1614       rename (scratchFileName, buffer);
1615       *p = 0;
1616       strncatz (scratchFileName, ".mem", sizeof(scratchFileName));
1617       *q = 0;
1618       strncatz(buffer, ".mem", sizeof(buffer));
1619       rename (scratchFileName, buffer);
1620     }
1621   if (system_ret)
1622     {
1623       exit (1);
1624     }
1625 }
1626
1627 /*-----------------------------------------------------------------*/
1628 /* assemble - spawns the assembler with arguments                  */
1629 /*-----------------------------------------------------------------*/
1630 static void
1631 assemble (char **envp)
1632 {
1633     /* build assembler output filename */
1634
1635     /* -o option overrides default name? */
1636     if (options.cc_only && fullDstFileName) {
1637         strncpyz (scratchFileName, fullDstFileName, sizeof(scratchFileName));
1638     } else {
1639         /* the assembled file gets the name of the first modul */
1640         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1641         strncatz (scratchFileName, port->linker.rel_ext, 
1642                   sizeof(scratchFileName));
1643     }
1644
1645     if (port->assembler.do_assemble) {
1646         port->assembler.do_assemble(asmOptionsSet);
1647         return ;
1648     } else if (port->assembler.cmd) {
1649         buildCmdLine (buffer, port->assembler.cmd, dstFileName, scratchFileName,
1650                       options.debug ? port->assembler.debug_opts : port->assembler.plain_opts,
1651                       asmOptionsSet);
1652     } else {
1653         buildCmdLine2 (buffer, sizeof(buffer), port->assembler.mcmd);
1654     }
1655
1656     if (my_system (buffer)) {
1657         /* either system() or the assembler itself has reported an error
1658            perror ("Cannot exec assembler");
1659         */
1660         exit (1);
1661     }
1662     /* TODO: most assembler don't have a -o parameter */
1663     /* -o option overrides default name? */
1664     if (options.cc_only && fullDstFileName) {
1665         strncpyz (scratchFileName, dstFileName, sizeof(scratchFileName));
1666         strncatz (scratchFileName, 
1667                   port->linker.rel_ext,
1668                   sizeof(scratchFileName));
1669         rename (scratchFileName, fullDstFileName);
1670     }
1671 }
1672
1673 /*-----------------------------------------------------------------*/
1674 /* preProcess - spawns the preprocessor with arguments       */
1675 /*-----------------------------------------------------------------*/
1676 static int
1677 preProcess (char **envp)
1678 {
1679   if (options.c1mode)
1680     {
1681       yyin = stdin;
1682     }
1683   else
1684     {
1685       const char *s;
1686       set *inclList = NULL;
1687
1688       /* if using external stack define the macro */
1689       if (options.useXstack)
1690         addSet(&preArgvSet, Safe_strdup("-DSDCC_USE_XSTACK"));
1691
1692       /* set the macro for stack autos  */
1693       if (options.stackAuto)
1694         addSet(&preArgvSet, Safe_strdup("-DSDCC_STACK_AUTO"));
1695
1696       /* set the macro for stack autos  */
1697       if (options.stack10bit)
1698         addSet(&preArgvSet, Safe_strdup("-DSDCC_STACK_TENBIT"));
1699
1700       /* set the macro for no overlay  */
1701       if (options.noOverlay)
1702         addSet(&preArgvSet, Safe_strdup("-DSDCC_NOOVERLAY"));
1703
1704       /* set the macro for large model  */
1705       switch (options.model)
1706         {
1707         case MODEL_LARGE:
1708           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_LARGE"));
1709           break;
1710         case MODEL_SMALL:
1711           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_SMALL"));
1712           break;
1713         case MODEL_COMPACT:
1714           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_COMPACT"));
1715           break;
1716         case MODEL_MEDIUM:
1717           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_MEDIUM"));
1718           break;
1719         case MODEL_FLAT24:
1720           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_FLAT24"));
1721           break;
1722         case MODEL_PAGE0:
1723           addSet(&preArgvSet, Safe_strdup("-DSDCC_MODEL_PAGE0"));
1724           break;
1725         default:
1726           werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
1727           break;
1728         }
1729
1730       /* add port (processor information to processor */
1731       addSet(&preArgvSet, Safe_strdup("-DSDCC_{port}"));
1732       addSet(&preArgvSet, Safe_strdup("-D__{port}"));
1733
1734       /* standard include path */
1735       if (!options.nostdinc) {
1736         inclList = appendStrSet(includeDirsSet, "-I\"", "\"");
1737         mergeSets(&preArgvSet, inclList);
1738       }
1739
1740       setMainValue("cppextraopts", (s = joinStrSet(preArgvSet)));
1741       Safe_free((void *)s);
1742       if (inclList != NULL)
1743         deleteSet(&inclList);
1744
1745       if (preProcOnly && fullDstFileName)
1746         {
1747           /* -E and -o given */
1748           setMainValue ("cppoutfilename", fullDstFileName);
1749         }
1750       else
1751         {
1752           /* Piping: set cppoutfilename to NULL, to avoid empty quotes */
1753           setMainValue ("cppoutfilename", NULL);
1754         }
1755
1756       if (options.verbose)
1757         printf ("sdcc: Calling preprocessor...\n");
1758
1759       buildCmdLine2 (buffer, sizeof(buffer), _preCmd);
1760
1761       if (preProcOnly) {
1762         if (my_system (buffer)) {
1763           exit (1);
1764         }
1765
1766         exit (0);
1767       }
1768
1769       yyin = my_popen (buffer);
1770       if (yyin == NULL) {
1771           perror ("Preproc file not found");
1772           exit (1);
1773       }
1774       addSetHead (&pipeSet, yyin);
1775     }
1776
1777   return 0;
1778 }
1779
1780 /* Set bin paths */
1781 static void
1782 setBinPaths(const char *argv0)
1783 {
1784   char *p;
1785   char buf[PATH_MAX];
1786
1787   /*
1788    * Search logic:
1789    *
1790    * 1. - $SDCCDIR/PREFIX2BIN_DIR
1791    * 2. - path(argv[0])
1792    * 3. - $PATH
1793    */
1794
1795   /* do it in reverse mode, so that addSetHead() can be used
1796      instead of slower addSet() */
1797
1798   if ((p = getBinPath(argv0)) != NULL)
1799     addSetHead(&binPathSet, Safe_strdup(p));
1800
1801   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
1802     SNPRINTF(buf, sizeof buf, "%s" PREFIX2BIN_DIR, p);
1803     addSetHead(&binPathSet, Safe_strdup(buf));
1804   }
1805
1806   if (options.printSearchDirs) {
1807     printf("programs:\n");
1808     fputStrSet(stdout, binPathSet);
1809   }
1810 }
1811
1812 /* Set system include path */
1813 static void
1814 setIncludePath(void)
1815 {
1816   char *p;
1817
1818   /*
1819    * Search logic:
1820    *
1821    * 1. - $SDCC_INCLUDE
1822    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/INCLUDE_DIR_SUFFIX
1823    * 3. - path(argv[0])/BIN2DATA_DIR/INCLUDE_DIR_SUFFIX
1824    * 4. - DATADIR/INCLUDE_DIR_SUFFIX (only on *nix)
1825    */
1826
1827   includeDirsSet = appendStrSet(dataDirsSet, NULL, INCLUDE_DIR_SUFFIX);
1828
1829   if ((p = getenv(SDCC_INCLUDE_NAME)) != NULL)
1830     addSetHead(&includeDirsSet, p);
1831
1832   if (options.printSearchDirs) {
1833     printf("includedir:\n");
1834     fputStrSet(stdout, includeDirsSet);
1835   }
1836 }
1837
1838 /* Set system lib path */
1839 static void
1840 setLibPath(void)
1841 {
1842   char *p;
1843
1844   /*
1845    * Search logic:
1846    *
1847    * 1. - $SDCC_LIB
1848    * 2. - $SDCC_HOME/PREFIX2DATA_DIR/LIB_DIR_SUFFIX/<model>
1849    * 3. - path(argv[0])/BIN2DATA_DIR/LIB_DIR_SUFFIX/<model>
1850    * 4. - DATADIR/LIB_DIR_SUFFIX/<model> (only on *nix)
1851    */
1852
1853   libDirsSet = appendStrSet(dataDirsSet, NULL, LIB_DIR_SUFFIX);
1854
1855   if ((p = getenv(SDCC_LIB_NAME)) != NULL)
1856     addSetHead(&libDirsSet, p);
1857
1858   if (options.printSearchDirs) {
1859     printf("libdir:\n");
1860     fputStrSet(stdout, libDirsSet);
1861   }
1862 }
1863
1864 /* Set data path */
1865 static void
1866 setDataPaths(const char *argv0)
1867 {
1868   char *p;
1869   char buf[PATH_MAX];
1870
1871   /*
1872    * Search logic:
1873    *
1874    * 1. - $SDCC_HOME/PREFIX2DATA_DIR
1875    * 2. - path(argv[0])/BIN2DATA_DIR
1876    * 3. - DATADIR (only on *nix)
1877    */
1878
1879   if ((p = getenv(SDCC_DIR_NAME)) != NULL) {
1880     SNPRINTF(buf, sizeof buf, "%s" PREFIX2DATA_DIR, p);
1881     addSet(&dataDirsSet, Safe_strdup(buf));
1882   }
1883
1884   if ((p = getBinPath(argv0)) != NULL) {
1885     SNPRINTF(buf, sizeof buf, "%s" BIN2DATA_DIR, p);
1886     addSet(&dataDirsSet, Safe_strdup(buf));
1887   }
1888
1889 #ifdef _WIN32
1890   if (peekSet(dataDirsSet) == NULL) {
1891     /* this should never happen... */
1892     wassertl(0, "Can't get binary path");
1893   }
1894 #else
1895   addSet(&dataDirsSet, Safe_strdup(DATADIR));
1896 #endif
1897
1898   if (options.printSearchDirs) {
1899     printf("datadir:\n");
1900     fputStrSet(stdout, dataDirsSet);
1901   }
1902
1903   setIncludePath();
1904   setLibPath();
1905 }
1906
1907 static void
1908 initValues (void)
1909 {
1910   populateMainValues (_baseValues);
1911   setMainValue ("port", port->target);
1912   setMainValue ("objext", port->linker.rel_ext);
1913   setMainValue ("asmext", port->assembler.file_ext);
1914
1915   setMainValue ("dstfilename", dstFileName);
1916   setMainValue ("fullsrcfilename", fullSrcFileName ? fullSrcFileName : "fullsrcfilename");
1917
1918   if (options.cc_only && fullDstFileName)
1919     /* compile + assemble and -o given: -o specifies name of object file */
1920     {
1921       setMainValue ("objdstfilename", fullDstFileName);
1922     }
1923   else
1924     {
1925       setMainValue ("objdstfilename", "{stdobjdstfilename}");
1926     }
1927   if (fullDstFileName)
1928     /* if we're linking, -o gives the final file name */
1929     {
1930       setMainValue ("linkdstfilename", fullDstFileName);
1931     }
1932   else
1933     {
1934       setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
1935     }
1936
1937 }
1938
1939 static void
1940 sig_handler (int signal)
1941 {
1942   char *sig_string;
1943
1944   switch (signal)
1945     {
1946     case SIGABRT:
1947       sig_string = "SIGABRT";
1948       break;
1949     case SIGTERM:
1950       sig_string = "SIGTERM";
1951       break;
1952     case SIGINT:
1953       sig_string = "SIGINT";
1954       break;
1955     case SIGSEGV:
1956       sig_string = "SIGSEGV";
1957       break;
1958     default:
1959       sig_string = "Unknown?";
1960       break;
1961     }
1962   fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
1963   exit (1);
1964 }
1965
1966 /*
1967  * main routine
1968  * initialises and calls the parser
1969  */
1970
1971 int
1972 main (int argc, char **argv, char **envp)
1973 {
1974   /* turn all optimizations off by default */
1975   memset (&optimize, 0, sizeof (struct optimize));
1976
1977   /*printVersionInfo (); */
1978
1979   if (NUM_PORTS==0) {
1980     fprintf (stderr, "Build error: no ports are enabled.\n");
1981     exit (1);
1982   }
1983
1984   /* install atexit handler */
1985   atexit(rm_tmpfiles);
1986
1987   /* install signal handler;
1988      it's only purpuse is to call exit() to remove temp files */
1989   if (!getenv("SDCC_LEAVE_SIGNALS"))
1990     {
1991       signal (SIGABRT, sig_handler);
1992       signal (SIGTERM, sig_handler);
1993       signal (SIGINT , sig_handler);
1994       signal (SIGSEGV, sig_handler);
1995     }
1996
1997   /* Before parsing the command line options, do a
1998    * search for the port and processor and initialize
1999    * them if they're found. (We can't gurantee that these
2000    * will be the first options specified).
2001    */
2002
2003   _findPort (argc, argv);
2004
2005 #ifdef JAMIN_DS390
2006   if (strcmp(port->target, "mcs51") == 0) {
2007     printf("DS390 jammed in A\n");
2008           _setPort ("ds390");
2009     ds390_jammed = 1;
2010   }
2011 #endif
2012
2013   _findProcessor (argc, argv);
2014
2015   /* Initalise the port. */
2016   if (port->init)
2017     port->init ();
2018
2019   setDefaultOptions ();
2020 #ifdef JAMIN_DS390
2021   if (ds390_jammed) {
2022     options.model = MODEL_SMALL;
2023     options.stack10bit=0;
2024   }
2025 #endif
2026   parseCmdLine (argc, argv);
2027
2028   initValues ();
2029   setBinPaths(argv[0]);
2030   setDataPaths(argv[0]);
2031
2032   /* if no input then printUsage & exit */
2033   if (!options.c1mode && !fullSrcFileName && peekSet(relFilesSet) == NULL) {
2034     if (!options.printSearchDirs)
2035       printUsage();
2036
2037     exit(0);
2038   }
2039
2040   /* initMem() is expensive, but
2041      initMem() must called before port->finaliseOptions ().
2042      And the z80 port needs port->finaliseOptions(),
2043      even if we're only linking. */
2044   initMem ();
2045   port->finaliseOptions ();
2046
2047   if (fullSrcFileName || options.c1mode)
2048     {
2049       preProcess (envp);
2050
2051       initSymt ();
2052       initiCode ();
2053       initCSupport ();
2054       initBuiltIns();
2055       initPeepHole ();
2056
2057       if (options.verbose)
2058         printf ("sdcc: Generating code...\n");
2059
2060       yyparse ();
2061
2062       pclose(yyin);
2063       deleteSetItem(&pipeSet, yyin);
2064
2065       if (fatalError) {
2066         exit (1);
2067       }
2068
2069       if (port->general.do_glue != NULL)
2070         (*port->general.do_glue)();
2071       else
2072         {
2073           /* this shouldn't happen */
2074           assert(FALSE);
2075           /* in case of NDEBUG */
2076           glue();
2077         }
2078
2079       if (!options.c1mode && !noAssemble)
2080         {
2081           if (options.verbose)
2082             printf ("sdcc: Calling assembler...\n");
2083           assemble (envp);
2084         }
2085     }
2086   closeDumpFiles();
2087
2088   if (options.debug && debugFile)
2089     debugFile->closeFile();
2090
2091   if (!options.cc_only &&
2092       !fatalError &&
2093       !noAssemble &&
2094       !options.c1mode &&
2095       (fullSrcFileName || peekSet(relFilesSet) != NULL))
2096     {
2097       if (port->linker.do_link)
2098         port->linker.do_link ();
2099       else
2100         linkEdit (envp);
2101     }
2102
2103   return 0;
2104 }