summaryrefslogtreecommitdiff
path: root/src/SDCCmain.c
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/SDCCmain.c
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/SDCCmain.c')
-rw-r--r--src/SDCCmain.c2726
1 files changed, 2726 insertions, 0 deletions
diff --git a/src/SDCCmain.c b/src/SDCCmain.c
new file mode 100644
index 0000000..b20ef66
--- /dev/null
+++ b/src/SDCCmain.c
@@ -0,0 +1,2726 @@
+/*-------------------------------------------------------------------------
+ SDCCmain.c - main file
+
+ Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+#ifdef _WIN32
+#include <io.h>
+#else
+#include <unistd.h>
+#include <libgen.h>
+#endif
+
+#include <signal.h>
+#include "common.h"
+#include <ctype.h>
+#include "dbuf_string.h"
+#include "SDCCerr.h"
+#include "SDCCmacro.h"
+#include "SDCCargs.h"
+#include "SDCCglue.h"
+
+#ifdef _WIN32
+#include <process.h>
+#else
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/resource.h>
+#endif
+
+/* REMOVE ME!!! */
+extern int yyparse (void);
+
+FILE *srcFile; /* source file */
+const char *fullSrcFileName; /* full name for the source file; */
+ /* can be NULL while c1mode or linking without compiling */
+const char *fullDstFileName; /* full name for the output file; */
+ /* only given by -o, otherwise NULL */
+const char *dstFileName; /* destination file name without extension */
+const char *moduleName; /* module name is same as module name base, but with all */
+ /* non-alphanumeric characters replaced with underscore */
+int currRegBank = 0;
+int RegBankUsed[4] = { 1, 0, 0, 0 }; /*JCF: Reg Bank 0 used by default */
+
+int BitBankUsed; /* MB: overlayable bit bank */
+struct optimize optimize;
+struct options options;
+int preProcOnly = 0;
+int noAssemble = 0;
+int gasOutput;
+set *preArgvSet = NULL; /* pre-processor arguments */
+set *asmOptionsSet = NULL; /* set of assembler options */
+set *linkOptionsSet = NULL; /* set of linker options */
+set *libFilesSet = NULL;
+set *libPathsSet = NULL;
+set *relFilesSet = NULL;
+set *dataDirsSet = NULL; /* list of data search directories */
+set *includeDirsSet = NULL; /* list of include search directories */
+set *userIncDirsSet = NULL; /* list of user include directories */
+set *libDirsSet = NULL; /* list of lib search directories */
+bool regalloc_dry_run = FALSE;
+
+static const char *dstPath = ""; /* path for the output files; */
+ /* "" is equivalent with cwd */
+static const char *moduleNameBase = NULL; /* module name base is source file without path and extension */
+ /* can be NULL while linking without compiling */
+
+/* uncomment JAMIN_DS390 to always override and use ds390 port
+ for mcs51 work. This is temporary, for compatibility testing. */
+/* #define JAMIN_DS390 */
+#ifdef JAMIN_DS390
+static int ds390_jammed = 0;
+#endif
+
+/* Globally accessible scratch buffer for file names.
+ TODO: replace them with local buffers */
+char buffer[PATH_MAX * 2];
+
+#define LENGTH(_a) (sizeof (_a) / sizeof (*(_a)))
+
+#define OPTION_HELP "--help"
+#define OPTION_OUT_FMT_IHX "--out-fmt-ihx"
+#define OPTION_OUT_FMT_S19 "--out-fmt-s19"
+#define OPTION_PEEP_FILE "--peep-file"
+#define OPTION_LIB_PATH "--lib-path"
+#define OPTION_CALLEE_SAVES "--callee-saves"
+#define OPTION_STACK_LOC "--stack-loc"
+#define OPTION_XSTACK_LOC "--xstack-loc"
+#define OPTION_DATA_LOC "--data-loc"
+#define OPTION_IDATA_LOC "--idata-loc"
+#define OPTION_XRAM_LOC "--xram-loc"
+#define OPTION_CODE_LOC "--code-loc"
+#define OPTION_IRAM_SIZE "--iram-size"
+#define OPTION_XRAM_SIZE "--xram-size"
+#define OPTION_CODE_SIZE "--code-size"
+#define OPTION_VERSION "--version"
+#define OPTION_NO_LABEL_OPT "--nolabelopt"
+#define OPTION_NO_LOOP_INV "--noinvariant"
+#define OPTION_NO_LOOP_IND "--noinduction"
+#define OPTION_LESS_PEDANTIC "--less-pedantic"
+#define OPTION_DISABLE_WARNING "--disable-warning"
+#define OPTION_WERROR "--Werror"
+#define OPTION_DEBUG "--debug"
+#define OPTION_NO_GCSE "--nogcse"
+#define OPTION_NO_XINIT_OPT "--no-xinit-opt"
+#define OPTION_NO_CCODE_IN_ASM "--no-c-code-in-asm"
+#define OPTION_ICODE_IN_ASM "--i-code-in-asm"
+#define OPTION_PRINT_SEARCH_DIRS "--print-search-dirs"
+#define OPTION_MSVC_ERROR_STYLE "--vc"
+#define OPTION_USE_STDOUT "--use-stdout"
+#define OPTION_NO_PEEP_COMMENTS "--no-peep-comments"
+#define OPTION_VERBOSE_ASM "--fverbose-asm"
+#define OPTION_OPT_CODE_SPEED "--opt-code-speed"
+#define OPTION_OPT_CODE_SIZE "--opt-code-size"
+#define OPTION_STD_C89 "--std-c89"
+#define OPTION_STD_C95 "--std-c95"
+#define OPTION_STD_C99 "--std-c99"
+#define OPTION_STD_C11 "--std-c11"
+#define OPTION_STD_C2X "--std-c2x"
+#define OPTION_STD_SDCC89 "--std-sdcc89"
+#define OPTION_STD_SDCC99 "--std-sdcc99"
+#define OPTION_STD_SDCC11 "--std-sdcc11"
+#define OPTION_STD_SDCC2X "--std-sdcc2x"
+#define OPTION_CODE_SEG "--codeseg"
+#define OPTION_CONST_SEG "--constseg"
+#define OPTION_DATA_SEG "--dataseg"
+#define OPTION_DOLLARS_IN_IDENT "--fdollars-in-identifiers"
+#define OPTION_SIGNED_CHAR "--fsigned-char"
+#define OPTION_USE_NON_FREE "--use-non-free"
+#define OPTION_PEEP_RETURN "--peep-return"
+#define OPTION_NO_PEEP_RETURN "--no-peep-return"
+#define OPTION_NO_OPTSDCC_IN_ASM "--no-optsdcc-in-asm"
+#define OPTION_MAX_ALLOCS_PER_NODE "--max-allocs-per-node"
+#define OPTION_NO_LOSPRE "--nolospre"
+#define OPTION_ALLOW_UNSAFE_READ "--allow-unsafe-read"
+#define OPTION_DUMP_AST "--dump-ast"
+#define OPTION_DUMP_I_CODE "--dump-i-code"
+#define OPTION_DUMP_GRAPHS "--dump-graphs"
+
+#define OPTION_SMALL_MODEL "--model-small"
+#define OPTION_MEDIUM_MODEL "--model-medium"
+#define OPTION_LARGE_MODEL "--model-large"
+#define OPTION_HUGE_MODEL "--model-huge"
+
+static const OPTION optionsTable[] = {
+ {0, NULL, NULL, "General options"},
+ {0, OPTION_HELP, NULL, "Display this help"},
+ {'v', OPTION_VERSION, NULL, "Display sdcc's version"},
+ {0, "--verbose", &options.verbose, "Trace calls to the preprocessor, assembler, and linker"},
+ {'V', NULL, &options.verboseExec, "Execute verbosely. Show sub commands as they are run"},
+ {'d', NULL, NULL, "Output list of mcaro definitions in effect. Use with -E"},
+ {'D', NULL, NULL, "Define macro as in -Dmacro"},
+ {'I', NULL, NULL, "Add to the include (*.h) path, as in -Ipath"},
+ {'A', NULL, NULL, NULL},
+ {'U', NULL, NULL, "Undefine macro as in -Umacro"},
+ {'M', NULL, NULL, "Preprocessor option"},
+ {'W', NULL, NULL, "Pass through options to the pre-processor (p), assembler (a) or linker (l)"},
+ {'S', NULL, &noAssemble, "Compile only; do not assemble or link"},
+ {0 , "--gas", &gasOutput, "Compile only in GAS (GNU Assembler) format. Incompatible with other assembly or compilation options."},
+ {'c', "--compile-only", &options.cc_only, "Compile and assemble, but do not link"},
+ {'E', "--preprocessonly", &preProcOnly, "Preprocess only, do not compile"},
+ {0, "--c1mode", &options.c1mode, "Act in c1 mode. The standard input is preprocessed code, the output is assembly code."},
+ {'o', NULL, NULL, "Place the output into the given path resp. file"},
+ {0, OPTION_PRINT_SEARCH_DIRS, &options.printSearchDirs, "display the directories in the compiler's search path"},
+ {0, OPTION_MSVC_ERROR_STYLE, &options.vc_err_style, "messages are compatible with Micro$oft visual studio"},
+ {0, OPTION_USE_STDOUT, NULL, "send errors to stdout instead of stderr"},
+ {0, "--nostdlib", &options.nostdlib, "Do not include the standard library directory in the search path"},
+ {0, "--nostdinc", &options.nostdinc, "Do not include the standard include directory in the search path"},
+ {0, OPTION_LESS_PEDANTIC, NULL, "Disable some of the more pedantic warnings"},
+ {0, OPTION_DISABLE_WARNING, NULL, "<nnnn> Disable specific warning"},
+ {0, OPTION_WERROR, NULL, "Treat the warnings as errors"},
+ {0, OPTION_DEBUG, NULL, "Enable debugging symbol output"},
+ {0, "--cyclomatic", &options.cyclomatic, "Display complexity of compiled functions"},
+ {0, OPTION_STD_C89, NULL, "Use ISO C90 (aka ANSI C89) standard (slightly incomplete)"},
+ {0, OPTION_STD_SDCC89, NULL, "Use ISO C90 (aka ANSI C89) standard with SDCC extensions"},
+ {0, OPTION_STD_C95, NULL, "Use ISO C95 (aka ISO C94) standard (slightly incomplete)"},
+ {0, OPTION_STD_C99, NULL, "Use ISO C99 standard (incomplete)"},
+ {0, OPTION_STD_SDCC99, NULL, "Use ISO C99 standard with SDCC extensions"},
+ {0, OPTION_STD_C11, NULL, "Use ISO C11 standard (incomplete)"},
+ {0, OPTION_STD_SDCC11, NULL, "Use ISO C11 standard with SDCC extensions (default)"},
+ {0, OPTION_STD_C2X, NULL, "Use ISO C2X standard (incomplete)"},
+ {0, OPTION_STD_SDCC2X, NULL, "Use ISO C2X standard with SDCC extensions"},
+ {0, OPTION_DOLLARS_IN_IDENT, &options.dollars_in_ident, "Permit '$' as an identifier character"},
+ {0, OPTION_SIGNED_CHAR, &options.signed_char, "Make \"char\" signed by default"},
+ {0, OPTION_USE_NON_FREE, &options.use_non_free, "Search / include non-free licensed libraries and header files"},
+
+ {0, NULL, NULL, "Code generation options"},
+ {'m', NULL, NULL, "Set the port to use e.g. -mz80."},
+ {'p', NULL, NULL, "Select port specific processor e.g. -mpic14 -p16f84"},
+ {0, "--stack-auto", &options.stackAuto, "Stack automatic variables"},
+ {0, "--xstack", &options.useXstack, "Use external stack"},
+ {0, "--int-long-reent", &options.intlong_rent, "Use reentrant calls on the int and long support functions"},
+ {0, "--float-reent", &options.float_rent, "Use reentrant calls on the float support functions"},
+ {0, "--xram-movc", &options.xram_movc, "Use movc instead of movx to read xram (xdata)"},
+ {0, OPTION_CALLEE_SAVES, &options.calleeSavesSet, "<func[,func,...]> Cause the called function to save registers instead of the caller", CLAT_SET},
+ {0, "--profile", &options.profile, "On supported ports, generate extra profiling information"},
+ {0, "--fomit-frame-pointer", &options.omitFramePtr, "Leave out the frame pointer."},
+ {0, "--all-callee-saves", &options.all_callee_saves, "callee will always save registers used"},
+ {0, "--stack-probe", &options.stack_probe, "insert call to function __stack_probe at each function prologue"},
+ {0, OPTION_NO_XINIT_OPT, &options.noXinitOpt, "don't memcpy initialized xram from code"},
+ {0, OPTION_NO_CCODE_IN_ASM, &options.noCcodeInAsm, "don't include c-code as comments in the asm file"},
+ {0, OPTION_NO_PEEP_COMMENTS, &options.noPeepComments, "don't include peephole optimizer comments"},
+ {0, OPTION_CODE_SEG, NULL, "<name> use this name for the code segment"},
+ {0, OPTION_CONST_SEG, NULL, "<name> use this name for the const segment"},
+ {0, OPTION_DATA_SEG, NULL, "<name> use this name for the data segment"},
+
+ {0, NULL, NULL, "Optimization options"},
+ {0, "--nooverlay", &options.noOverlay, "Disable overlaying leaf function auto variables"},
+ {0, OPTION_NO_GCSE, NULL, "Disable the GCSE optimisation"},
+ {0, OPTION_NO_LABEL_OPT, NULL, "Disable label optimisation"},
+ {0, OPTION_NO_LOOP_INV, NULL, "Disable optimisation of invariants"},
+ {0, OPTION_NO_LOOP_IND, NULL, "Disable loop variable induction"},
+ {0, "--noloopreverse", &optimize.noLoopReverse, "Disable the loop reverse optimisation"},
+ {0, "--no-peep", &options.nopeep, "Disable the peephole assembly file optimisation"},
+ {0, "--no-reg-params", &options.noRegParams, "On some ports, disable passing some parameters in registers"},
+ {0, "--peep-asm", &options.asmpeep, "Enable peephole optimization on inline assembly"},
+ {0, OPTION_PEEP_RETURN, NULL, "Enable peephole optimization for return instructions"},
+ {0, OPTION_NO_PEEP_RETURN, NULL, "Disable peephole optimization for return instructions"},
+ {0, OPTION_PEEP_FILE, &options.peep_file, "<file> use this extra peephole file", CLAT_STRING},
+ {0, OPTION_OPT_CODE_SPEED, NULL, "Optimize for code speed rather than size"},
+ {0, OPTION_OPT_CODE_SIZE, NULL, "Optimize for code size rather than speed"},
+ {0, OPTION_MAX_ALLOCS_PER_NODE, &options.max_allocs_per_node, "Maximum number of register assignments considered at each node of the tree decomposition", CLAT_INTEGER},
+ {0, OPTION_NO_LOSPRE, NULL, "Disable lospre"},
+ {0, OPTION_ALLOW_UNSAFE_READ, NULL, "Allow optimizations to read any memory location anytime"},
+ {0, "--nostdlibcall", &optimize.noStdLibCall, "Disable optimization of calls to standard library"},
+
+ {0, NULL, NULL, "Internal debugging options"},
+ {0, OPTION_DUMP_AST, &options.dump_ast, "Dump front-end AST before generating i-code"},
+ {0, OPTION_DUMP_I_CODE, &options.dump_i_code, "Dump the i-code structure at all stages"},
+ {0, OPTION_DUMP_GRAPHS, &options.dump_graphs, "Dump graphs (control-flow, conflict, etc)"},
+ {0, OPTION_ICODE_IN_ASM, &options.iCodeInAsm, "Include i-code as comments in the asm file"},
+ {0, OPTION_VERBOSE_ASM, &options.verboseAsm, "Include code generator comments in the asm output"},
+
+ {0, NULL, NULL, "Linker options"},
+ {'l', NULL, NULL, "Include the given library in the link"},
+ {'L', NULL, NULL, "Add the next field to the library search path"},
+ {0, OPTION_LIB_PATH, &libPathsSet, "<path> use this path to search for libraries", CLAT_ADD_SET},
+ {0, OPTION_OUT_FMT_IHX, NULL, "Output in Intel hex format"},
+ {0, OPTION_OUT_FMT_S19, NULL, "Output in S19 hex format"},
+ {0, OPTION_XRAM_LOC, NULL, "<nnnn> External Ram start location", CLAT_INTEGER},
+ {0, OPTION_XRAM_SIZE, NULL, "<nnnn> External Ram size"},
+ {0, OPTION_IRAM_SIZE, &options.iram_size, "<nnnn> Internal Ram size", CLAT_INTEGER},
+ {0, OPTION_XSTACK_LOC, &options.xstack_loc, "<nnnn> External Stack start location", CLAT_INTEGER},
+ {0, OPTION_CODE_LOC, &options.code_loc, "<nnnn> Code Segment Location", CLAT_INTEGER},
+ {0, OPTION_CODE_SIZE, &options.code_size, "<nnnn> Code Segment size", CLAT_INTEGER},
+ {0, OPTION_STACK_LOC, &options.stack_loc, "<nnnn> Stack pointer initial value", CLAT_INTEGER},
+ {0, OPTION_DATA_LOC, &options.data_loc, "<nnnn> Direct data start location", CLAT_INTEGER},
+ {0, OPTION_IDATA_LOC, &options.idata_loc, NULL, CLAT_INTEGER},
+
+ {0, OPTION_NO_OPTSDCC_IN_ASM, &options.noOptsdccInAsm, "Do not emit .optsdcc in asm"},
+ /* End of options */
+ {0, NULL}
+};
+
+/** Table of all unsupported options and help text to display when one
+ is used.
+*/
+typedef struct
+{
+ /** shortOpt as in OPTIONS. */
+ char shortOpt;
+ /** longOpt as in OPTIONS. */
+ const char *longOpt;
+ /** Message to display inside W_UNSUPPORTED_OPT when this option
+ is used. */
+ const char *message;
+} UNSUPPORTEDOPT;
+
+static const UNSUPPORTEDOPT unsupportedOptTable[] = {
+ {'X', NULL, "use --xstack-loc instead"},
+ {'x', NULL, "use --xstack instead"},
+ {'i', NULL, "use --idata-loc instead"},
+ {'r', NULL, "use --xdata-loc instead"},
+ {'s', NULL, "use --code-loc instead"},
+ {'Y', NULL, "use -I instead"},
+ {0, "--fommit-frame-pointer", "use --fomit-frame-pointer instead"},
+};
+
+/** List of all default constant macros.
+ */
+static const char *_baseValues[] = {
+ "cpp", "sdcpp",
+ "cppextraopts", "",
+ /* Path seperator character */
+ "sep", DIR_SEPARATOR_STRING,
+ NULL
+};
+
+static const char *_preCmd = "{cpp} -nostdinc -Wall {cppstd}{cppextraopts} {fullsrcfilename} {cppoutfilename}";
+
+PORT *port;
+
+static PORT *_ports[] = {
+#if !OPT_DISABLE_MCS51
+ &mcs51_port,
+#endif
+#if !OPT_DISABLE_Z80
+ &z80_port,
+#endif
+#if !OPT_DISABLE_Z180
+ &z180_port,
+#endif
+#if !OPT_DISABLE_R2K
+ &r2k_port,
+#endif
+#if !OPT_DISABLE_R3KA
+ &r3ka_port,
+#endif
+#if !OPT_DISABLE_GBZ80
+ &gbz80_port,
+#endif
+#if !OPT_DISABLE_TLCS90
+ &tlcs90_port,
+#endif
+#if !OPT_DISABLE_EZ80_Z80
+ &ez80_z80_port,
+#endif
+#if !OPT_DISABLE_AVR
+ &avr_port,
+#endif
+#if !OPT_DISABLE_DS390
+ &ds390_port,
+#endif
+#if !OPT_DISABLE_PIC16
+ &pic16_port,
+#endif
+#if !OPT_DISABLE_PIC14
+ &pic_port,
+#endif
+#if !OPT_DISABLE_TININative
+ &tininative_port,
+#endif
+#if !OPT_DISABLE_DS400
+ &ds400_port,
+#endif
+#if !OPT_DISABLE_HC08
+ &hc08_port,
+#endif
+#if !OPT_DISABLE_S08
+ &s08_port,
+#endif
+#if !OPT_DISABLE_STM8
+ &stm8_port,
+#endif
+#if !OPT_DISABLE_PDK13
+ &pdk13_port,
+#endif
+#if !OPT_DISABLE_PDK14
+ &pdk14_port,
+#endif
+#if !OPT_DISABLE_PDK15
+ &pdk15_port,
+#endif
+};
+
+#define NUM_PORTS (sizeof(_ports)/sizeof(_ports[0]))
+
+/** Sets the port to the one given by the command line option.
+ @param The name minus the option (eg 'mcs51')
+ @return 0 on success.
+*/
+static void
+_setPort (const char *name)
+{
+ int i;
+ for (i = 0; i < NUM_PORTS; i++)
+ {
+ if (!strcmp (_ports[i]->target, name))
+ {
+ port = _ports[i];
+ return;
+ }
+ }
+ /* Error - didnt find */
+ werror (E_UNKNOWN_TARGET, name);
+ exit (EXIT_FAILURE);
+}
+
+/* Override the default processor with the one specified
+ * on the command line */
+static void
+_setProcessor (char *_processor)
+{
+ port->processor = _processor;
+}
+
+static void
+_validatePorts (void)
+{
+ int i;
+ for (i = 0; i < NUM_PORTS; i++)
+ {
+ if (_ports[i]->magic != PORT_MAGIC)
+ {
+ /* Uncomment this line to debug which port is causing the problem
+ * (the target name is close to the beginning of the port struct
+ * and probably can be accessed just fine). */
+ fprintf (stderr, "%s :", _ports[i]->target);
+ wassertl (0, "Port definition structure is incomplete");
+ }
+ }
+}
+
+
+static char *
+program_name (const char *path)
+{
+#ifdef _WIN32
+ char fname[_MAX_FNAME];
+
+ _splitpath (path, NULL, NULL, fname, NULL);
+ return Safe_strdup (fname);
+#else
+ char *tmpPath = Safe_strdup (path);
+ char *res = Safe_strdup (basename (tmpPath));
+
+ Safe_free (tmpPath);
+ return res;
+#endif
+}
+
+/* search through the command line for the port */
+static void
+_findPort (int argc, char **argv)
+{
+ char *programName = program_name (*argv);
+ int found = 0;
+ int i;
+
+ _validatePorts ();
+
+ /* try to assign port by command line option */
+ while (argc-- && !found)
+ {
+ if (!strncmp (*argv, "-m", 2))
+ {
+ _setPort (*argv + 2);
+ found = 1;
+ }
+ argv++;
+ }
+
+ /* try to assign port by the name of the executable */
+ for (i = 0; i < NUM_PORTS && !found; i++)
+ {
+ if (strstr (programName, _ports[i]->target))
+ {
+ _setPort (_ports[i]->target);
+ found = 1;
+ }
+ }
+
+ if (!found)
+ {
+ /* Use the first in the list as default */
+ port = _ports[0];
+ }
+
+ Safe_free (programName);
+}
+
+/* search through the command line options for the processor */
+static void
+_findProcessor (int argc, char **argv)
+{
+ while (argc--)
+ {
+ if (!strncmp (*argv, "-p", 2))
+ {
+ _setProcessor (*argv + 2);
+ return;
+ }
+ argv++;
+ }
+
+ /* no error if processor was not specified. */
+}
+
+/*-----------------------------------------------------------------*/
+/* printVersionInfo - prints the version info */
+/*-----------------------------------------------------------------*/
+void
+printVersionInfo (FILE * stream)
+{
+ int i;
+
+ fprintf (stream, "SDCC : ");
+ for (i = 0; i < NUM_PORTS; i++)
+ fprintf (stream, "%s%s", i == 0 ? "" : "/", _ports[i]->target);
+
+ fprintf (stream, " " SDCC_VERSION_STR
+#ifdef SDCC_SUB_VERSION_STR
+ "/" SDCC_SUB_VERSION_STR
+#endif
+ " #%s (%s)\n", getBuildNumber (), getBuildEnvironment ());
+ fprintf (stream, "published under GNU General Public License (GPL)\n");
+}
+
+static void
+printOptions (const OPTION * optionsTable, FILE * stream)
+{
+ int i;
+ for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL || optionsTable[i].help != NULL; i++)
+ {
+ if (!optionsTable[i].shortOpt && !optionsTable[i].longOpt && optionsTable[i].help)
+ {
+ fprintf (stream, "\n%s:\n", optionsTable[i].help);
+ }
+ else
+ {
+ fprintf (stream, " %c%c %-20s %s\n",
+ optionsTable[i].shortOpt != 0 ? '-' : ' ',
+ optionsTable[i].shortOpt != 0 ? optionsTable[i].shortOpt : ' ',
+ optionsTable[i].longOpt != NULL ? optionsTable[i].longOpt : "",
+ optionsTable[i].help != NULL ? optionsTable[i].help : "");
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* printUsage - prints command line syntax */
+/*-----------------------------------------------------------------*/
+static void
+printUsage (bool err)
+{
+ int i;
+ FILE *stream = err ? stderr : stdout;
+
+ printVersionInfo (stream);
+ fprintf (stream,
+ "Usage : sdcc [options] filename\n"
+ "Options :-\n");
+
+ printOptions (optionsTable, stream);
+
+ for (i = 0; i < NUM_PORTS; i++)
+ {
+ if (_ports[i]->poptions != NULL)
+ {
+ fprintf (stream, "\nSpecial options for the %s port:\n", _ports[i]->target);
+ printOptions (_ports[i]->poptions, stream);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* setParseWithComma - separates string with comma to a set */
+/*-----------------------------------------------------------------*/
+void
+setParseWithComma (set ** dest, const char *src)
+{
+ const char *p, *end;
+ struct dbuf_s dbuf;
+
+ /* skip the initial white spaces */
+ while (isspace ((unsigned char) *src))
+ ++src;
+
+ /* skip the trailing white spaces */
+ end = &src[strlen (src) - 1];
+ while (end >= src && isspace ((unsigned char) *end))
+ --end;
+ ++end;
+
+ p = src;
+ while (src < end)
+ {
+ dbuf_init (&dbuf, 16);
+
+ while (p < end && ',' != *p)
+ ++p;
+ dbuf_append (&dbuf, src, p - src);
+ addSet (dest, dbuf_detach_c_str (&dbuf));
+
+ src = ++p;
+ }
+}
+
+/*-------------------------------------------------------------*/
+/* setStackSize - set the stack size of a running sdcc process */
+/*-------------------------------------------------------------*/
+static void
+setStackSize (void)
+{
+#if defined (HAVE_SETRLIMIT) && defined (RLIMIT_STACK)
+ struct rlimit rl = {4 * 1024 * 1024, 4 * 1024 * 1024};
+ setrlimit (RLIMIT_STACK, &rl);
+#endif
+}
+
+/*-----------------------------------------------------------------*/
+/* setDefaultOptions - sets the default options */
+/*-----------------------------------------------------------------*/
+static void
+setDefaultOptions (void)
+{
+ /* first the options part */
+ options.stack_loc = 0; /* stack pointer initialised to 0 */
+ options.xstack_loc = 1; /* xternal stack starts at 1 */
+ options.code_loc = 0; /* code starts at 0 */
+ options.data_loc = 0; /* JCF: By default let the linker locate data */
+ options.xdata_loc = 1; /* MB: Do not use address 0 by default as it equals NULL */
+ options.idata_loc = 0; /* MB: No need to limit idata to 0x80-0xFF */
+ options.nopeep = 0;
+ options.model = port->general.default_model;
+ options.nostdlib = 0;
+ options.nostdinc = 0;
+ options.verbose = 0;
+ options.std_sdcc = 1; /* enable SDCC language extensions */
+ options.std_c95 = 1;
+ options.std_c99 = 1;
+ options.std_c11 = 1; /* default to C11 (we want inline by default, so we need at least C99, and support for C11 is more complete than C99) */
+ options.std_c2x = 0;
+ options.code_seg = CODE_NAME ? Safe_strdup (CODE_NAME) : NULL; /* default to CSEG for generated code */
+ options.const_seg = CONST_NAME ? Safe_strdup (CONST_NAME) : NULL; /* default to CONST for generated code */
+ options.data_seg = DATA_NAME ? Safe_strdup (DATA_NAME) : NULL; /* default to DATA for non-initialized data */
+ options.stack10bit = 0;
+ options.out_fmt = 0;
+ options.dump_graphs = 0;
+ options.dependencyFileOpt = 0;
+
+ /* now for the optimizations */
+ /* turn on the everything */
+ optimize.global_cse = 1;
+ optimize.label1 = 1;
+ optimize.label2 = 1;
+ optimize.label3 = 1;
+ optimize.label4 = 1;
+ optimize.loopInvariant = 1;
+ optimize.loopInduction = 1;
+ options.max_allocs_per_node = 3000;
+ optimize.lospre = 1;
+ optimize.allow_unsafe_read = 0;
+
+ /* now for the ports */
+ port->setDefaultOptions ();
+}
+
+/*-----------------------------------------------------------------*/
+/* processFile - determines the type of file from the extension */
+/*-----------------------------------------------------------------*/
+static void
+processFile (char *s)
+{
+ const char *extp;
+ struct dbuf_s ext;
+ struct dbuf_s path;
+
+ dbuf_init (&ext, 128);
+ dbuf_init (&path, PATH_MAX);
+
+ /* get the file extension.
+ If no '.' then we don't know what the file type is
+ so give an error and return */
+ if (!dbuf_splitFile (s, &path, &ext))
+ {
+ werror (E_UNKNOWN_FEXT, s);
+
+ dbuf_destroy (&ext);
+ dbuf_destroy (&path);
+
+ return;
+ }
+
+ /* otherwise depending on the file type */
+ extp = dbuf_c_str (&ext);
+ if (STRCASECMP (extp, ".c") == 0 || STRCASECMP (extp, ".h") == 0)
+ {
+ char *p, *m;
+
+ dbuf_destroy (&ext);
+
+ /* source file name : not if we already have a
+ source file */
+ if (fullSrcFileName)
+ {
+ werror (W_TOO_MANY_SRC, s);
+
+ dbuf_destroy (&path);
+
+ return;
+ }
+
+ /* the only source file */
+ fullSrcFileName = s;
+ if (!(srcFile = fopen (fullSrcFileName, "r")))
+ {
+ werror (E_FILE_OPEN_ERR, s);
+
+ dbuf_destroy (&path);
+
+ exit (EXIT_FAILURE);
+ }
+
+ /* get rid of any path information
+ for the module name; */
+ dbuf_init (&ext, 128);
+
+ dbuf_splitPath (dbuf_c_str (&path), NULL, &ext);
+ dbuf_destroy (&path);
+
+ moduleNameBase = Safe_strdup (dbuf_c_str (&ext));
+ m = dbuf_detach (&ext);
+
+ for (p = m; *p; ++p)
+ if (!isalnum ((unsigned char) *p))
+ *p = '_';
+ moduleName = m;
+ return;
+ }
+
+ /* if the extension is type rel_ext
+ additional object file will be passed to the linker */
+ if (STRCASECMP (extp, port->linker.rel_ext) == 0)
+ {
+ dbuf_destroy (&ext);
+ dbuf_destroy (&path);
+
+ addSet (&relFilesSet, Safe_strdup (s));
+ return;
+ }
+
+ /* if .lib or .LIB */
+ if (STRCASECMP (extp, ".lib") == 0)
+ {
+ dbuf_destroy (&ext);
+ dbuf_destroy (&path);
+
+ addSet (&libFilesSet, Safe_strdup (s));
+ return;
+ }
+
+ dbuf_destroy (&ext);
+ dbuf_destroy (&path);
+
+ werror (E_UNKNOWN_FEXT, s);
+}
+
+static void
+_setModel (int model, const char *sz)
+{
+ if (port->general.supported_models & model)
+ options.model = model;
+ else
+ werror (W_UNSUPPORTED_MODEL, sz, port->target);
+}
+
+/** Gets the string argument to this option. If the option is '--opt'
+ then for input of '--optxyz' or '--opt xyz' returns xyz.
+*/
+char *
+getStringArg (const char *szStart, char **argv, int *pi, int argc)
+{
+ if (argv[*pi][strlen (szStart)])
+ {
+ return &argv[*pi][strlen (szStart)];
+ }
+ else
+ {
+ ++(*pi);
+ if (*pi >= argc)
+ {
+ werror (E_ARGUMENT_MISSING, szStart);
+ /* Die here rather than checking for errors later. */
+ exit (EXIT_FAILURE);
+ }
+ else
+ {
+ return argv[*pi];
+ }
+ }
+}
+
+/** Gets the integer argument to this option using the same rules as
+ getStringArg.
+*/
+long
+getIntArg (const char *szStart, char **argv, int *pi, int argc)
+{
+ char *p;
+ int val;
+ char *str = getStringArg (szStart, argv, pi, argc);
+
+ val = strtol (str, &p, 0);
+ if (p == str || *p != '\0')
+ {
+ werror (E_BAD_INT_ARGUMENT, szStart);
+ /* Die here rather than checking for errors later. */
+ exit (EXIT_FAILURE);
+ }
+ return val;
+}
+
+static void
+verifyShortOption (const char *opt)
+{
+ if (strlen (opt) != 2)
+ {
+ werror (W_EXCESS_SHORT_OPTIONS, opt);
+ }
+}
+
+static bool
+tryHandleUnsupportedOpt (char **argv, int *pi)
+{
+ if (argv[*pi][0] == '-')
+ {
+ const char *longOpt = "";
+ char shortOpt = -1;
+ int i;
+
+ if (argv[*pi][1] == '-')
+ {
+ /* Long option. */
+ longOpt = argv[*pi];
+ }
+ else
+ {
+ shortOpt = argv[*pi][1];
+ }
+ for (i = 0; i < LENGTH (unsupportedOptTable); i++)
+ {
+ if (unsupportedOptTable[i].shortOpt == shortOpt ||
+ (longOpt && unsupportedOptTable[i].longOpt && !strcmp (unsupportedOptTable[i].longOpt, longOpt)))
+ {
+ /* Found an unsupported opt. */
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 100);
+ dbuf_printf (&dbuf, "%s%c%c", longOpt ? longOpt : "", shortOpt ? '-' : ' ', shortOpt ? shortOpt : ' ');
+ werror (W_UNSUPP_OPTION, dbuf_detach_c_str (&dbuf), unsupportedOptTable[i].message);
+ return 1;
+ }
+ }
+ /* Didn't find in the table */
+ return 0;
+ }
+ else
+ {
+ /* Not an option, so can't be unsupported :) */
+ return 0;
+ }
+}
+
+static bool
+scanOptionsTable (const OPTION * optionsTable, char shortOpt, const char *longOpt, char **argv, int *pi, int argc)
+{
+ int i;
+
+ for (i = 0; optionsTable[i].shortOpt != 0 || optionsTable[i].longOpt != NULL || optionsTable[i].help != NULL; i++)
+ {
+ if (optionsTable[i].shortOpt == shortOpt)
+ {
+ if (optionsTable[i].pparameter != NULL)
+ {
+ verifyShortOption (argv[*pi]);
+
+ (*(int *) optionsTable[i].pparameter)++;
+
+ return TRUE;
+ }
+ }
+ else
+ {
+ size_t len = optionsTable[i].longOpt ? strlen (optionsTable[i].longOpt) : 0;
+
+ if (longOpt &&
+ (optionsTable[i].arg_type != CLAT_BOOLEAN ||
+ (optionsTable[i].arg_type == CLAT_BOOLEAN && len == strlen (longOpt) && optionsTable[i].longOpt)) &&
+ strncmp (optionsTable[i].longOpt, longOpt, len) == 0)
+ {
+ /* If it is a flag then we can handle it here */
+ if (optionsTable[i].pparameter != NULL)
+ {
+ switch (optionsTable[i].arg_type)
+ {
+ case CLAT_BOOLEAN:
+ (*(int *) optionsTable[i].pparameter)++;
+ break;
+
+ case CLAT_INTEGER:
+ *(int *) optionsTable[i].pparameter = getIntArg (optionsTable[i].longOpt, argv, pi, argc);
+ break;
+
+ case CLAT_STRING:
+ if (*(char **) optionsTable[i].pparameter)
+ Safe_free (*(char **) optionsTable[i].pparameter);
+ *(char **) optionsTable[i].pparameter =
+ Safe_strdup (getStringArg (optionsTable[i].longOpt, argv, pi, argc));
+ break;
+
+ case CLAT_SET:
+ if (*(set **) optionsTable[i].pparameter)
+ {
+ deleteSet ((set **) optionsTable[i].pparameter);
+ }
+ setParseWithComma ((set **) optionsTable[i].pparameter,
+ getStringArg (optionsTable[i].longOpt, argv, pi, argc));
+ break;
+
+ case CLAT_ADD_SET:
+ addSet ((set **) optionsTable[i].pparameter,
+ Safe_strdup (getStringArg (optionsTable[i].longOpt, argv, pi, argc)));
+ break;
+ }
+ return TRUE;
+ }
+ else
+ {
+ /* Not a flag. Handled manually later. */
+ return FALSE;
+ }
+ }
+ }
+ }
+ /* Didn't find in the table */
+ return FALSE;
+}
+
+static bool
+tryHandleSimpleOpt (char **argv, int *pi, int argc)
+{
+ if (argv[*pi][0] == '-')
+ {
+ const char *longOpt = "";
+ char shortOpt = -1;
+
+ if (argv[*pi][1] == '-')
+ {
+ /* Long option. */
+ longOpt = argv[*pi];
+ }
+ else
+ {
+ shortOpt = argv[*pi][1];
+ }
+
+ if (scanOptionsTable (optionsTable, shortOpt, longOpt, argv, pi, argc))
+ {
+ return TRUE;
+ }
+ else if (port && port->poptions && scanOptionsTable (port->poptions, shortOpt, longOpt, argv, pi, argc))
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ /* Not an option, so can't be handled. */
+ return FALSE;
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* parseCmdLine - parses the command line and sets the options */
+/*-----------------------------------------------------------------*/
+static int
+parseCmdLine (int argc, char **argv)
+{
+ int i;
+
+ /* go thru all whole command line */
+ for (i = 1; i < argc; i++)
+ {
+ if (i >= argc)
+ break;
+
+ /* check port specific options before general ones */
+ if (port->parseOption (&argc, argv, &i) == TRUE)
+ {
+ continue;
+ }
+
+ if (tryHandleUnsupportedOpt (argv, &i) == TRUE)
+ {
+ continue;
+ }
+
+ if (tryHandleSimpleOpt (argv, &i, argc) == TRUE)
+ {
+ continue;
+ }
+
+ /* options */
+ if (argv[i][0] == '-' && argv[i][1] == '-')
+ {
+ if (strcmp (argv[i], OPTION_USE_STDOUT) == 0)
+ {
+ if (options.use_stdout == 0)
+ {
+ options.use_stdout = 1;
+ dup2 (STDOUT_FILENO, STDERR_FILENO);
+ }
+ continue;
+ }
+ if (strcmp (argv[i], OPTION_HELP) == 0)
+ {
+ printUsage (FALSE);
+ exit (EXIT_SUCCESS);
+ }
+
+ if (strcmp (argv[i], OPTION_OUT_FMT_IHX) == 0)
+ {
+ options.out_fmt = 'i';
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_OUT_FMT_S19) == 0)
+ {
+ options.out_fmt = 's';
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_SMALL_MODEL) == 0)
+ {
+ _setModel (MODEL_SMALL, argv[i]);
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_MEDIUM_MODEL) == 0)
+ {
+ _setModel (MODEL_MEDIUM, argv[i]);
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_LARGE_MODEL) == 0)
+ {
+ _setModel (MODEL_LARGE, argv[i]);
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_HUGE_MODEL) == 0)
+ {
+ _setModel (MODEL_HUGE, argv[i]);
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_VERSION) == 0)
+ {
+ printVersionInfo (stdout);
+ exit (EXIT_SUCCESS);
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_XRAM_LOC) == 0)
+ {
+ int val = getIntArg (OPTION_XRAM_LOC, argv, &i, argc);
+ if (options.xdata_loc == options.xstack_loc)
+ options.xstack_loc = val;
+ options.xdata_loc = val;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_XRAM_SIZE) == 0)
+ {
+ options.xram_size = getIntArg (OPTION_XRAM_SIZE, argv, &i, argc);
+ options.xram_size_set = TRUE;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_NO_GCSE) == 0)
+ {
+ optimize.global_cse = 0;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_NO_LOOP_INV) == 0)
+ {
+ optimize.loopInvariant = 0;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_NO_LABEL_OPT) == 0)
+ {
+ optimize.label2 = 0;
+ optimize.label4 = 0;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_NO_LOOP_IND) == 0)
+ {
+ optimize.loopInduction = 0;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_OPT_CODE_SPEED) == 0)
+ {
+ optimize.codeSpeed = 1;
+ optimize.codeSize = 0;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_OPT_CODE_SIZE) == 0)
+ {
+ optimize.codeSpeed = 0;
+ optimize.codeSize = 1;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_NO_LOSPRE) == 0)
+ {
+ optimize.lospre = 0;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_ALLOW_UNSAFE_READ) == 0)
+ {
+ optimize.allow_unsafe_read = 1;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_LESS_PEDANTIC) == 0)
+ {
+ options.lessPedantic = 1;
+ setErrorLogLevel (ERROR_LEVEL_WARNING);
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_DISABLE_WARNING) == 0)
+ {
+ int w = getIntArg (OPTION_DISABLE_WARNING, argv, &i, argc);
+ setWarningDisabled (w);
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_WERROR) == 0)
+ {
+ setWError (1);
+ addSet (&preArgvSet, Safe_strdup ("-Werror"));
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_STD_C89) == 0)
+ {
+ options.std_c95 = 0;
+ options.std_c99 = 0;
+ options.std_c11 = 0;
+ options.std_c2x = 0;
+ options.std_sdcc = 0;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_STD_C95) == 0)
+ {
+ options.std_c95 = 1;
+ options.std_c99 = 0;
+ options.std_c11 = 0;
+ options.std_c2x = 0;
+ options.std_sdcc = 0;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_STD_C99) == 0)
+ {
+ options.std_c95 = 1;
+ options.std_c99 = 1;
+ options.std_c11 = 0;
+ options.std_c2x = 0;
+ options.std_sdcc = 0;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_STD_C11) == 0)
+ {
+ options.std_c95 = 1;
+ options.std_c99 = 1;
+ options.std_c11 = 1;
+ options.std_c2x = 0;
+ options.std_sdcc = 0;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_STD_C2X) == 0)
+ {
+ options.std_c95 = 1;
+ options.std_c99 = 1;
+ options.std_c11 = 1;
+ options.std_c2x = 1;
+ options.std_sdcc = 0;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_STD_SDCC89) == 0)
+ {
+ options.std_c95 = 0;
+ options.std_c99 = 0;
+ options.std_c11 = 0;
+ options.std_c2x = 0;
+ options.std_sdcc = 1;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_STD_SDCC99) == 0)
+ {
+ options.std_c95 = 1;
+ options.std_c99 = 1;
+ options.std_c11 = 0;
+ options.std_c2x = 0;
+ options.std_sdcc = 1;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_STD_SDCC11) == 0)
+ {
+ options.std_c95 = 1;
+ options.std_c99 = 1;
+ options.std_c11 = 1;
+ options.std_c2x = 0;
+ options.std_sdcc = 1;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_STD_SDCC2X) == 0)
+ {
+ options.std_c95 = 1;
+ options.std_c99 = 1;
+ options.std_c11 = 1;
+ options.std_c2x = 1;
+ options.std_sdcc = 1;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_CODE_SEG) == 0)
+ {
+ struct dbuf_s segname;
+
+ dbuf_init (&segname, 16);
+ dbuf_printf (&segname, "%-8s(CODE)", getStringArg (OPTION_CODE_SEG, argv, &i, argc));
+ if (options.code_seg)
+ Safe_free (options.code_seg);
+ options.code_seg = dbuf_detach (&segname);
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_CONST_SEG) == 0)
+ {
+ struct dbuf_s segname;
+
+ dbuf_init (&segname, 16);
+ dbuf_printf (&segname, "%-8s(CODE)", getStringArg (OPTION_CONST_SEG, argv, &i, argc));
+ if (options.const_seg)
+ Safe_free (options.const_seg);
+ options.const_seg = dbuf_detach (&segname);
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_DATA_SEG) == 0)
+ {
+ struct dbuf_s segname;
+
+ dbuf_init (&segname, 16);
+ dbuf_printf (&segname, "%-8s(DATA)", getStringArg (OPTION_DATA_SEG, argv, &i, argc));
+ if (options.data_seg)
+ Safe_free (options.data_seg);
+ options.data_seg = dbuf_detach (&segname);
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_PEEP_RETURN) == 0)
+ {
+ options.peepReturn = 1;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_NO_PEEP_RETURN) == 0)
+ {
+ options.peepReturn = -1;
+ continue;
+ }
+
+ if (strcmp (argv[i], OPTION_DEBUG) == 0)
+ {
+ if (options.peepReturn == 0)
+ options.peepReturn = -1;
+ options.debug = 1;
+ continue;
+ }
+
+ werror (W_UNKNOWN_OPTION, argv[i]);
+ continue;
+ }
+
+ /* if preceded by '-' then option */
+ if (*argv[i] == '-')
+ {
+ switch (argv[i][1])
+ {
+ case 'h':
+ verifyShortOption (argv[i]);
+
+ printUsage (FALSE);
+ exit (EXIT_SUCCESS);
+ break;
+
+ case 'm':
+ /* Used to select the port. But this has already been done. */
+ break;
+
+ case 'p':
+ /* Used to select the processor in port. But this has
+ * already been done. */
+ break;
+
+ case 'c':
+ verifyShortOption (argv[i]);
+
+ options.cc_only = 1;
+ break;
+
+ case 'L':
+ addSet (&libPathsSet, Safe_strdup (getStringArg ("-L", argv, &i, argc)));
+ break;
+
+ case 'l':
+ addSet (&libFilesSet, Safe_strdup (getStringArg ("-l", argv, &i, argc)));
+ break;
+
+ case 'o':
+ {
+ char *outName = getStringArg ("-o", argv, &i, argc);
+ size_t len = strlen (outName);
+
+ /* point to last character */
+ if (IS_DIR_SEPARATOR (outName[len - 1]))
+ {
+ /* only output path specified */
+ dstPath = Safe_strndup (outName, len - 1);
+ fullDstFileName = NULL;
+ }
+ else
+ {
+ struct dbuf_s path;
+
+ dbuf_init (&path, PATH_MAX);
+ fullDstFileName = Safe_strdup (outName);
+
+ /* get rid of the "."-extension */
+ dbuf_splitFile (outName, &path, NULL);
+
+ dstFileName = dbuf_detach_c_str (&path);
+
+ dbuf_init (&path, PATH_MAX);
+ /* strip module name to get path */
+ if (dbuf_splitPath (dstFileName, &path, NULL))
+ dstPath = dbuf_detach_c_str (&path);
+ else
+ dbuf_destroy (&path);
+ }
+ break;
+ }
+
+ case 'W':
+ /* pre-processer options */
+ if (argv[i][2] == 'p')
+ {
+ setParseWithComma (&preArgvSet, getStringArg ("-Wp", argv, &i, argc));
+ }
+ /* linker options */
+ else if (argv[i][2] == 'l')
+ {
+ setParseWithComma (&linkOptionsSet, getStringArg ("-Wl", argv, &i, argc));
+ }
+ /* assembler options */
+ else if (argv[i][2] == 'a')
+ {
+ setParseWithComma (&asmOptionsSet, getStringArg ("-Wa", argv, &i, argc));
+ }
+ else
+ {
+ werror (W_UNKNOWN_OPTION, argv[i]);
+ }
+ break;
+
+ case 'v':
+ verifyShortOption (argv[i]);
+
+ printVersionInfo (stdout);
+ exit (EXIT_SUCCESS);
+ break;
+
+ /* preprocessor options */
+ case 'M':
+ {
+ if (argv[i][2] == 'M')
+ {
+ if (argv[i][3] == 'D')
+ {
+ options.dependencyFileOpt = USER_DEPENDENCY_FILE_OPT;
+ }
+ else
+ {
+ addSet (&preArgvSet, Safe_strdup ("-MM"));
+ preProcOnly = 1;
+ }
+ }
+ else
+ {
+ if (argv[i][2] == 'D')
+ {
+ options.dependencyFileOpt = SYSTEM_DEPENDENCY_FILE_OPT;
+ }
+ else
+ {
+ addSet (&preArgvSet, Safe_strdup ("-M"));
+ preProcOnly = 1;
+ }
+ }
+ break;
+ }
+
+ case 'd':
+ case 'D':
+ case 'I':
+ case 'A':
+ case 'U':
+ {
+ char sOpt = argv[i][1];
+ char *rest, *s;
+ struct dbuf_s dbuf;
+
+ if (argv[i][2] == ' ' || argv[i][2] == '\0')
+ {
+ i++;
+ if (i >= argc)
+ {
+ /* No argument. */
+ werror (E_ARGUMENT_MISSING, argv[i - 1]);
+ break;
+ }
+ else
+ {
+ rest = argv[i];
+ }
+ }
+ else
+ rest = &argv[i][2];
+
+ if (sOpt == 'Y')
+ sOpt = 'I';
+
+ s = shell_escape (rest);
+ dbuf_init (&dbuf, 256);
+ dbuf_printf (&dbuf, "-%c%s", sOpt, s);
+ Safe_free (s);
+ addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
+ if (sOpt == 'I')
+ {
+ addSet (&includeDirsSet, Safe_strdup (rest));
+ addSet (&userIncDirsSet, Safe_strdup (rest));
+ }
+ }
+ break;
+
+ default:
+ werror (W_UNKNOWN_OPTION, argv[i]);
+ }
+ continue;
+ }
+
+ /* no option must be a filename */
+ if (options.c1mode)
+ {
+ werror (W_NO_FILE_ARG_IN_C1, argv[i]);
+ }
+ else
+ {
+ processFile (argv[i]);
+ }
+ }
+
+ if (gasOutput && noAssemble)
+ {
+ /* Incompatible assembly output formats. */
+ werror(W_ILLEGAL_OPT_COMBINATION);
+ }
+
+ /* some sanity checks in c1 mode */
+ if (options.c1mode)
+ {
+ const char *s;
+
+ if (fullSrcFileName)
+ {
+ fclose (srcFile);
+ werror (W_NO_FILE_ARG_IN_C1, fullSrcFileName);
+ }
+ fullSrcFileName = NULL;
+ for (s = setFirstItem (relFilesSet); s != NULL; s = setNextItem (relFilesSet))
+ {
+ werror (W_NO_FILE_ARG_IN_C1, s);
+ }
+ for (s = setFirstItem (libFilesSet); s != NULL; s = setNextItem (libFilesSet))
+ {
+ werror (W_NO_FILE_ARG_IN_C1, s);
+ }
+ deleteSet (&relFilesSet);
+ deleteSet (&libFilesSet);
+
+ if (options.cc_only || noAssemble || preProcOnly || gasOutput)
+ {
+ werror (W_ILLEGAL_OPT_COMBINATION);
+ }
+ options.cc_only = noAssemble = preProcOnly = 0;
+ if (!dstFileName)
+ {
+ werror (E_NEED_OPT_O_IN_C1);
+ exit (EXIT_FAILURE);
+ }
+ else
+ {
+ char *p, *m;
+
+ m = Safe_strdup (dstFileName);
+ for (p = m; *p; ++p)
+ if (!isalnum ((unsigned char) *p))
+ *p = '_';
+ moduleName = m;
+ }
+ }
+ /* if no dstFileName given with -o, we've to find one: */
+ if (!dstFileName)
+ {
+ const char *s;
+
+ /* use the modulename from the C-source */
+ if (fullSrcFileName)
+ {
+ struct dbuf_s path;
+
+ if (*dstPath != '\0')
+ {
+ dbuf_init (&path, 128);
+ dbuf_makePath (&path, dstPath, moduleNameBase);
+ dstFileName = dbuf_detach_c_str (&path);
+ }
+ else
+ dstFileName = Safe_strdup (moduleNameBase);
+ }
+ /* use the modulename from the first object file */
+ else if ((s = peekSet (relFilesSet)) != NULL)
+ {
+ struct dbuf_s file;
+
+ dbuf_init (&file, 128);
+
+ /* get rid of the "."-extension */
+ dbuf_splitFile (s, &file, NULL);
+
+ s = dbuf_detach_c_str (&file);
+
+ dbuf_init (&file, PATH_MAX);
+
+ dbuf_splitPath (s, NULL, &file);
+
+ if (*dstPath != '\0')
+ {
+ struct dbuf_s path;
+
+ dbuf_init (&path, PATH_MAX);
+ dbuf_makePath (&path, dstPath, dbuf_detach_c_str (&file));
+ dstFileName = dbuf_detach_c_str (&path);
+ }
+ else
+ {
+ dstFileName = dbuf_detach_c_str (&file);
+ }
+ }
+ /* else no module given: help text is displayed */
+ }
+
+ /* set int, long and float reentrancy based on stack-auto */
+ if (options.stackAuto)
+ {
+ options.intlong_rent++;
+ options.float_rent++;
+ }
+
+ /* if debug option is set then open the cdbFile */
+ if (options.debug && fullSrcFileName)
+ {
+ struct dbuf_s adbFile;
+
+ dbuf_init (&adbFile, PATH_MAX);
+ dbuf_append_str (&adbFile, dstFileName);
+ dbuf_append_str (&adbFile, ".adb");
+
+ if (debugFile->openFile (dbuf_c_str (&adbFile)))
+ debugFile->writeModule (moduleName);
+ else
+ werror (E_FILE_OPEN_ERR, dbuf_c_str (&adbFile));
+
+ dbuf_destroy (&adbFile);
+ }
+ MSVC_style (options.vc_err_style);
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+/* finalizeOptions - finalize (post-process) options */
+/*-----------------------------------------------------------------*/
+static void
+finalizeOptions (void)
+{
+ /* no peephole comments if not verbose asm */
+ if (!options.verboseAsm)
+ options.noPeepComments = 1;
+}
+
+static const char *
+getOutFmtExt (void)
+{
+ switch (options.out_fmt)
+ {
+ default:
+ case 'i':
+ return ".ihx";
+
+ case 's':
+ return ".s19";
+
+ case 'E':
+ return ".elf";
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* linkEdit : - calls the linkage editor with options */
+/*-----------------------------------------------------------------*/
+static void
+linkEdit (char **envp)
+{
+ FILE *lnkfile;
+ int system_ret;
+ const char *s;
+ struct dbuf_s linkerScriptFileName;
+ struct dbuf_s binFileName;
+ char *buf, *tb;
+
+ dbuf_init (&linkerScriptFileName, PATH_MAX);
+ dbuf_init (&binFileName, PATH_MAX);
+
+ if (port->linker.needLinkerScript)
+ {
+ char out_fmt = (options.out_fmt == 0) ? 'i' : options.out_fmt;
+
+ if (NULL != fullDstFileName)
+ {
+ dbuf_append_str (&binFileName, fullDstFileName);
+ }
+ else
+ {
+ dbuf_append_str (&binFileName, dstFileName);
+ dbuf_append_str (&binFileName, getOutFmtExt ());
+ }
+
+ /* first we need to create the <filename>.lk file */
+ dbuf_printf (&linkerScriptFileName, "%s.lk", dstFileName);
+ if (!(lnkfile = fopen (dbuf_c_str (&linkerScriptFileName), "w")))
+ {
+ werror (E_FILE_OPEN_ERR, dbuf_c_str (&linkerScriptFileName));
+ exit (EXIT_FAILURE);
+ }
+
+ if (TARGET_Z80_LIKE)
+ {
+ fprintf (lnkfile, "-mjwx\n-%c %s\n", out_fmt, dbuf_c_str (&binFileName));
+ }
+ else /* For all the other ports which need linker script */
+ {
+ fprintf (lnkfile, "-muwx\n-%c %s\n", out_fmt, dbuf_c_str (&binFileName));
+ if (TARGET_MCS51_LIKE)
+ fprintf (lnkfile, "-M\n");
+ if (!options.no_pack_iram)
+ fprintf (lnkfile, "-Y\n");
+ else
+ werror (W_DEPRECATED_OPTION, "--no-pack-iram");
+ }
+
+ if (!TARGET_Z80_LIKE) /* Not for the z80, gbz80 */
+ {
+ /* if iram size specified */
+ if (options.iram_size)
+ fprintf (lnkfile, "-I 0x%04x\n", options.iram_size);
+
+ /* if stack size specified */
+ if (options.stack_size)
+ fprintf (lnkfile, "-S 0x%02x\n", options.stack_size);
+
+ /* if xram size specified */
+ if (options.xram_size_set)
+ fprintf (lnkfile, "-X 0x%04x\n", options.xram_size);
+
+ /* if code size specified */
+ if (options.code_size)
+ fprintf (lnkfile, "-C 0x%04x\n", options.code_size);
+ }
+
+ if (options.debug)
+ fprintf (lnkfile, "-y\n");
+
+#define WRITE_SEG_LOC(N, L) \
+ if (N) \
+ { \
+ char *c, *segName; \
+ segName = Safe_strdup (N); \
+ c = strtok (segName, " \t"); \
+ fprintf (lnkfile,"-b %s = 0x%04x\n", c, L); \
+ if (segName) { Safe_free (segName); } \
+ }
+
+ if (!TARGET_Z80_LIKE) /* Not for the z80, z180, gbz80 */
+ {
+
+ /* code segment start */
+ WRITE_SEG_LOC (HOME_NAME, options.code_loc);
+
+ /* data segment start. If zero, the linker chooses
+ the best place for data */
+ if (options.data_loc)
+ {
+ WRITE_SEG_LOC (DATA_NAME, options.data_loc);
+ }
+
+ /* xdata segment start. If zero, the linker chooses
+ the best place for xdata */
+ if (options.xdata_loc)
+ {
+ WRITE_SEG_LOC (XDATA_NAME, options.xdata_loc);
+ }
+
+ /* pdata/xstack segment start. If zero, the linker
+ chooses the best place for them */
+ if (options.xstack_loc)
+ {
+ WRITE_SEG_LOC (PDATA_NAME, options.xstack_loc);
+ }
+
+ /* indirect data */
+ if (IDATA_NAME)
+ {
+ WRITE_SEG_LOC (IDATA_NAME, options.idata_loc);
+ }
+
+ /* bit segment start */
+ WRITE_SEG_LOC (BIT_NAME, 0);
+
+ /* stack start */
+ if ((options.stack_loc) && (options.stack_loc < 0x100) && !TARGET_HC08_LIKE)
+ {
+ WRITE_SEG_LOC ("SSEG", options.stack_loc);
+ }
+ }
+ else /* For the z80, z180, gbz80 */
+ {
+ WRITE_SEG_LOC ("_CODE", options.code_loc);
+ WRITE_SEG_LOC ("_DATA", options.data_loc);
+ }
+
+ /* If the port has any special linker area declarations, get 'em */
+ if (port->extraAreas.genExtraAreaLinkOptions)
+ {
+ port->extraAreas.genExtraAreaLinkOptions (lnkfile);
+ }
+
+ /* add the extra linker options */
+ fputStrSet (lnkfile, linkOptionsSet);
+
+ /* command line defined library paths if specified */
+ for (s = setFirstItem (libPathsSet); s != NULL; s = setNextItem (libPathsSet))
+ fprintf (lnkfile, "-k %s\n", s);
+
+ /* standard library path */
+ if (!options.nostdlib)
+ {
+ for (s = setFirstItem (libDirsSet); s != NULL; s = setNextItem (libDirsSet))
+ fprintf (lnkfile, "-k %s\n", s);
+ }
+
+ /* command line defined library files if specified */
+ for (s = setFirstItem (libFilesSet); s != NULL; s = setNextItem (libFilesSet))
+ fprintf (lnkfile, "-l %s\n", s);
+
+ /* standard library files */
+ if (!options.nostdlib)
+ {
+ if (NULL != port->linker.libs)
+ {
+ const char *const *p;
+
+ for (p = port->linker.libs; NULL != *p; ++p)
+ {
+ fprintf (lnkfile, "-l %s\n", *p);
+ }
+ }
+ }
+
+ /* put in the object file, generated from the C cource */
+ if (fullSrcFileName)
+ {
+ struct dbuf_s path;
+
+ dbuf_init (&path, PATH_MAX);
+ dbuf_printf (&path, "%s%s", dstFileName, port->linker.rel_ext);
+ addSetHead (&relFilesSet, dbuf_detach (&path));
+ }
+
+ if (!options.no_std_crt0)
+ {
+ const char *const *p;
+ set *crtSet = NULL;
+
+ if (NULL != port->linker.crt)
+ {
+ struct dbuf_s crtpath;
+
+ dbuf_init (&crtpath, PATH_MAX);
+
+ for (p = port->linker.crt; NULL != *p; ++p)
+ {
+ /* Try to find where C runtime files are ...
+ It is very important for this file to be first on the linking proccess
+ so the areas are set in the correct order, expecially _GSINIT */
+ for (s = setFirstItem (libDirsSet); s != NULL; s = setNextItem (libDirsSet))
+ {
+ dbuf_set_length (&crtpath, 0);
+ dbuf_printf (&crtpath, "%s%c%s", s, DIR_SEPARATOR_CHAR, *p);
+
+ if (!access (dbuf_c_str (&crtpath), 0)) /* Found it! */
+ {
+ /* append C runtime file to the crt list */
+ addSet (&crtSet, Safe_strdup (dbuf_c_str (&crtpath)));
+ break;
+ }
+ }
+ if (NULL == s)
+ {
+ /* not found in standard library directories, search in user defined library paths */
+ /* TODO: should crt be searched here at all? */
+ for (s = setFirstItem (libPathsSet); s != NULL; s = setNextItem (libPathsSet))
+ {
+ dbuf_set_length (&crtpath, 0);
+ dbuf_printf (&crtpath, "%s%c%s", s, DIR_SEPARATOR_CHAR, *p);
+
+ if (!access (dbuf_c_str (&crtpath), 0)) /* Found it! */
+ {
+ /* append C runtime file to the crt list */
+ addSet (&crtSet, Safe_strdup (dbuf_c_str (&crtpath)));
+ break;
+ }
+ }
+ }
+ if (NULL == s)
+ fprintf (stderr, "Warning: couldn't find %s\n", *p);
+ }
+ dbuf_destroy (&crtpath);
+ }
+
+ /* Merge crtSet and relFilesSet */
+ mergeSets (&crtSet, relFilesSet);
+ relFilesSet = crtSet;
+ }
+
+ /* put in all object files */
+ fputStrSet (lnkfile, relFilesSet);
+
+ fprintf (lnkfile, "\n-e\n");
+ fclose (lnkfile);
+ } /* if(port->linker.needLinkerScript) */
+
+ if (port->linker.cmd)
+ {
+ /* shell_escape file names */
+ char *b3 = shell_escape (dbuf_c_str (&linkerScriptFileName));
+ char *bfn = shell_escape (dbuf_c_str (&binFileName));
+
+ buf = buildCmdLine (port->linker.cmd, b3, bfn, NULL, linkOptionsSet);
+ Safe_free (b3);
+ Safe_free (bfn);
+ }
+ else
+ {
+ buf = buildMacros (port->linker.mcmd);
+ }
+
+ dbuf_destroy (&linkerScriptFileName);
+
+ tb = setPrefixSuffix (buf);
+ if (options.verbose)
+ printf ("sdcc: %s\n", tb);
+ system_ret = sdcc_system (tb);
+
+ /* if the binary file name is defined,
+ rename the linker output file name to binary file name */
+ if (fullDstFileName)
+ {
+ struct dbuf_s lkrFileName;
+
+ dbuf_init (&lkrFileName, PATH_MAX);
+ dbuf_append_str (&lkrFileName, dstFileName);
+ dbuf_append_str (&lkrFileName, getOutFmtExt ());
+
+ if (FILENAME_CMP (dbuf_c_str (&binFileName), dbuf_c_str (&lkrFileName)))
+ remove (dbuf_c_str (&binFileName));
+ rename (dbuf_c_str (&lkrFileName), dbuf_c_str (&binFileName));
+
+ dbuf_destroy (&lkrFileName);
+ }
+
+ dbuf_destroy (&binFileName);
+
+ if (system_ret)
+ exit (EXIT_FAILURE);
+}
+
+/*-----------------------------------------------------------------*/
+/* assemble - spawns the assembler with arguments */
+/*-----------------------------------------------------------------*/
+static void
+assemble (char **envp)
+{
+ struct dbuf_s asmName;
+
+ if (port->assembler.do_assemble)
+ {
+ port->assembler.do_assemble (asmOptionsSet);
+ }
+ else
+ {
+ char *buf, *tb;
+
+ /* build assembler output filename */
+ dbuf_init (&asmName, PATH_MAX);
+
+ /* -o option overrides default name? */
+ if (options.cc_only && fullDstFileName)
+ {
+ dbuf_append_str (&asmName, fullDstFileName);
+ }
+ else
+ {
+ /* the assembled file gets the name of the first module */
+ dbuf_printf (&asmName, "%s%s", dstFileName, port->linker.rel_ext);
+ }
+
+ if (port->assembler.cmd)
+ {
+ /* shell_escape file names */
+ char *dfn = shell_escape (dstFileName);
+ char *asmn = shell_escape (dbuf_c_str (&asmName));
+
+ buf = buildCmdLine (port->assembler.cmd, dfn, asmn,
+ options.debug ? port->assembler.debug_opts : port->assembler.plain_opts, asmOptionsSet);
+ Safe_free (dfn);
+ Safe_free (asmn);
+ }
+ else
+ {
+ buf = buildMacros (port->assembler.mcmd);
+ }
+
+ dbuf_destroy (&asmName);
+ tb = setPrefixSuffix (buf);
+
+ if (options.verbose)
+ printf ("sdcc: %s\n", tb);
+ if (sdcc_system (tb))
+ {
+ Safe_free (buf);
+ /* either system() or the assembler itself has reported an error */
+ exit (EXIT_FAILURE);
+ }
+ Safe_free (buf);
+
+ if (options.cc_only && fullDstFileName && TARGET_PIC_LIKE)
+ {
+ /* gpasm assembler doesn't properly handle the -o option:
+ the file extension is replaced with .o,
+ so sdcc have to rename the object file manually.
+ This has been fixed in gpasm svn:
+ http://sourceforge.net/tracker/?func=detail&aid=3018645&group_id=41924&atid=431665
+ TODO: This code should be removed when the next gputils version
+ after gpasm-0.13.7 beta will be released */
+ struct dbuf_s outName;
+ dbuf_init (&outName, PATH_MAX);
+ dbuf_printf (&outName, "%s%s", dstFileName, port->linker.rel_ext);
+
+ if (strcmp (dbuf_c_str (&outName), fullDstFileName))
+ {
+ /* file names are different: rename the genatated object file */
+ remove (fullDstFileName);
+ rename (dbuf_c_str (&outName), fullDstFileName);
+ }
+ dbuf_destroy (&outName);
+ }
+ }
+}
+
+/*-----------------------------------------------------------------*/
+/* preProcess - spawns the preprocessor with arguments */
+/*-----------------------------------------------------------------*/
+static int
+preProcess (char **envp)
+{
+ if (options.c1mode)
+ {
+ yyin = stdin;
+ }
+ else
+ {
+ const char *s;
+ set *inclList = NULL;
+ char *buf;
+
+ if (NULL != port->linker.rel_ext)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 256);
+ dbuf_printf (&dbuf, "-obj-ext=%s", port->linker.rel_ext);
+ addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
+ }
+
+ if (options.dependencyFileOpt)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, PATH_MAX);
+ if (options.dependencyFileOpt == SYSTEM_DEPENDENCY_FILE_OPT)
+ dbuf_append_str (&dbuf, "-MD ");
+ else
+ dbuf_append_str (&dbuf, "-MMD ");
+ if (fullDstFileName)
+ dbuf_splitFile (fullDstFileName, &dbuf, NULL);
+ else
+ dbuf_append_str (&dbuf, dstFileName);
+ dbuf_append_str (&dbuf, ".d");
+ addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
+
+ dbuf_init (&dbuf, PATH_MAX);
+ if (fullDstFileName)
+ dbuf_printf (&dbuf, "-MT %s", fullDstFileName);
+ else
+ dbuf_printf (&dbuf, "-MT %s%s", dstFileName, port->linker.rel_ext);
+ addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
+ }
+
+ /* if using dollar signs in identifiers */
+ if (options.dollars_in_ident)
+ addSet (&preArgvSet, Safe_strdup ("-fdollars-in-identifiers"));
+
+ /* if using external stack define the macro */
+ if (options.useXstack)
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_USE_XSTACK"));
+
+ /* set the macro for stack autos */
+ if (options.stackAuto)
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_STACK_AUTO"));
+
+ /* set the macro for stack autos */
+ if (options.stack10bit)
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_STACK_TENBIT"));
+
+ /* set the macro for no overlay */
+ if (options.noOverlay)
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_NOOVERLAY"));
+
+ /* set the macro for unsigned char */
+ if (options.signed_char)
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_CHAR_SIGNED"));
+ else
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_CHAR_UNSIGNED"));
+
+ /* set the macro for non-free */
+ if (options.use_non_free)
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_USE_NON_FREE"));
+
+ /* set the macro for large model */
+ switch (options.model)
+ {
+ case MODEL_LARGE:
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_MODEL_LARGE"));
+ break;
+
+ case MODEL_SMALL:
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_MODEL_SMALL"));
+ break;
+
+ case MODEL_COMPACT:
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_MODEL_COMPACT"));
+ break;
+
+ case MODEL_MEDIUM:
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_MODEL_MEDIUM"));
+ break;
+
+ case MODEL_HUGE:
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_MODEL_HUGE"));
+ break;
+
+ case MODEL_FLAT24:
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_MODEL_FLAT24"));
+ break;
+
+ case NO_MODEL:
+ break;
+
+ default:
+ werror (W_UNKNOWN_MODEL, __FILE__, __LINE__);
+ break;
+ }
+
+ /* set macro corresponding to compiler option */
+ if (options.intlong_rent)
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_INT_LONG_REENT"));
+
+ /* set macro corresponding to compiler option */
+ if (options.float_rent)
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_FLOAT_REENT"));
+
+ if (options.all_callee_saves)
+ addSet(&preArgvSet, Safe_strdup("-D__SDCC_ALL_CALLEE_SAVES"));
+
+ /* add SDCC version number */
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 32);
+ dbuf_printf (&dbuf, "-D__SDCC=%d_%d_%d", SDCC_VERSION_HI, SDCC_VERSION_LO, SDCC_VERSION_P);
+ addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
+ }
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 32);
+ dbuf_printf (&dbuf, "-D__SDCC_VERSION_MAJOR=%d", SDCC_VERSION_HI);
+ addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
+ }
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 32);
+ dbuf_printf (&dbuf, "-D__SDCC_VERSION_MINOR=%d", SDCC_VERSION_LO);
+ addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
+ }
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 32);
+ dbuf_printf (&dbuf, "-D__SDCC_VERSION_PATCH=%d", SDCC_VERSION_P);
+ addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
+ }
+
+ /* A macro that has been deprecated since 3.2.0,
+ since its name makes it non-compliant.
+ It got removed a few times, but keeps coming back.
+ This time it got added back for the 3.7.0 release
+ to support the old SiLabs IDE */
+ if (TARGET_IS_MCS51 && options.std_sdcc)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 32);
+ dbuf_printf (&dbuf, "-DSDCC=%d%d%d", SDCC_VERSION_HI, SDCC_VERSION_LO, SDCC_VERSION_P);
+ addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
+ }
+
+ /* add SDCC revision number */
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 20);
+ dbuf_printf (&dbuf, "-D__SDCC_REVISION=%s", getBuildNumber ());
+ addSet (&preArgvSet, dbuf_detach_c_str (&dbuf));
+ }
+
+ /* add port (processor information to processor */
+ addSet (&preArgvSet, Safe_strdup ("-D__SDCC_{port}"));
+
+ /* Optional C features not (yet) supported by SDCC */
+ addSet (&preArgvSet, Safe_strdup ("-D__STDC_NO_COMPLEX__=1"));
+ addSet (&preArgvSet, Safe_strdup ("-D__STDC_NO_THREADS__=1"));
+ addSet (&preArgvSet, Safe_strdup ("-D__STDC_NO_ATOMICS__=1"));
+ addSet (&preArgvSet, Safe_strdup ("-D__STDC_NO_VLA__=1"));
+
+ /* Character encoding - these need to be set in device/lib/Makefile.in for $CPP, too */
+ addSet (&preArgvSet, Safe_strdup ("-D__STDC_ISO_10646__=201409L")); // wchar_t is UTF-32
+ addSet (&preArgvSet, Safe_strdup ("-D__STDC_UTF_16__=1")); // char16_t is UTF-16
+ addSet (&preArgvSet, Safe_strdup ("-D__STDC_UTF_32__=1")); // char32_t is UTF-32
+
+ /* standard include path */
+ if (!options.nostdinc)
+ {
+ inclList = processStrSet (includeDirsSet, "-isystem ", NULL, shell_escape);
+ mergeSets (&preArgvSet, inclList);
+ }
+
+ setMainValue ("cppextraopts", (s = joinStrSet (preArgvSet)));
+ Safe_free ((void *) s);
+ if (inclList != NULL)
+ deleteSet (&inclList);
+
+ if (preProcOnly && fullDstFileName)
+ {
+ /* -E and -o given */
+ char *s = shell_escape (fullDstFileName);
+
+ setMainValue ("cppoutfilename", s);
+ Safe_free (s);
+ }
+ else
+ {
+ /* Piping: set cppoutfilename to NULL, to avoid empty quotes */
+ setMainValue ("cppoutfilename", NULL);
+ }
+
+ if (options.verbose)
+ printf ("sdcc: Calling preprocessor...\n");
+ buf = buildMacros (_preCmd);
+ buf = setPrefixSuffix (buf);
+ if (options.verbose)
+ printf ("sdcc: %s\n", buf);
+
+ if (preProcOnly)
+ {
+ if (sdcc_system (buf))
+ {
+ exit (EXIT_FAILURE);
+ }
+
+ exit (EXIT_SUCCESS);
+ }
+
+ yyin = sdcc_popen (buf);
+ if (yyin == NULL)
+ {
+ perror ("Preproc file not found");
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ return 0;
+}
+
+/* Set bin paths */
+static void
+setBinPaths (const char *argv0)
+{
+ const char *p;
+
+ /*
+ * Search logic:
+ *
+ * 1. - $SDCCDIR/PREFIX2BIN_DIR
+ * 2. - path(argv[0])
+ * 3. - $PATH
+ */
+
+ /* do it in reverse mode, so that addSetHead() can be used
+ instead of slower addSet() */
+
+ if ((p = getBinPath (argv0)) != NULL)
+ addSetHead (&binPathSet, (void *) p);
+
+ if ((p = getenv (SDCC_DIR_NAME)) != NULL)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, PATH_MAX);
+ dbuf_append_str (&dbuf, p);
+ dbuf_append_str (&dbuf, PREFIX2BIN_DIR);
+ addSetHead (&binPathSet, dbuf_detach_c_str (&dbuf));
+ }
+}
+
+/* Set system include path */
+static void
+setIncludePath (void)
+{
+ /*
+ * Search logic:
+ *
+ * 1. - $SDCC_INCLUDE/target
+ * 2. - $SDCC_INCLUDE
+ * 3. - $SDCC_HOME/PREFIX2DATA_DIR/INCLUDE_DIR_SUFFIX/target
+ * 4. - path(argv[0])/BIN2DATA_DIR/INCLUDE_DIR_SUFFIX/target
+ * 5. - DATADIR/INCLUDE_DIR_SUFFIX/target (only on *nix)
+ * 6. - $SDCC_HOME/PREFIX2DATA_DIR/INCLUDE_DIR_SUFFIX
+ * 7. - path(argv[0])/BIN2DATA_DIR/INCLUDE_DIR_SUFFIX
+ * 8. - DATADIR/INCLUDE_DIR_SUFFIX (only on *nix)
+ * 9. - $SDCC_HOME/PREFIX2DATA_DIR/NON_FREE_INCLUDE_DIR_SUFFIX/target
+ * 10. - path(argv[0])/BIN2DATA_DIR/NON_FREE_INCLUDE_DIR_SUFFIX/target
+ * 11. - DATADIR/NON_FREE_INCLUDE_DIR_SUFFIX/target (only on *nix)
+ * 12. - $SDCC_HOME/PREFIX2DATA_DIR/NON_FREE_INCLUDE_DIR_SUFFIX
+ * 13. - path(argv[0])/BIN2DATA_DIR/NON_FREE_INCLUDE_DIR_SUFFIX
+ * 14. - DATADIR/NON_FREE_INCLUDE_DIR_SUFFIX (only on *nix)
+ */
+
+ if (!options.nostdinc)
+ {
+ char *p;
+ set *tempSet;
+
+ tempSet = processStrSet (dataDirsSet, NULL, INCLUDE_DIR_SUFFIX, NULL);
+ includeDirsSet = processStrSet (tempSet, NULL, DIR_SEPARATOR_STRING, NULL);
+ includeDirsSet = processStrSet (includeDirsSet, NULL, port->target, NULL);
+ mergeSets (&includeDirsSet, tempSet);
+
+ if (options.use_non_free)
+ {
+ set *tempSet1;
+
+ tempSet = processStrSet (dataDirsSet, NULL, NON_FREE_INCLUDE_DIR_SUFFIX, NULL);
+ tempSet1 = processStrSet (tempSet, NULL, DIR_SEPARATOR_STRING, NULL);
+ tempSet1 = processStrSet (tempSet1, NULL, port->target, NULL);
+ mergeSets (&tempSet1, tempSet);
+ mergeSets (&includeDirsSet, tempSet1);
+ }
+
+ if ((p = getenv (SDCC_INCLUDE_NAME)) != NULL)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, PATH_MAX);
+ addSetHead (&includeDirsSet, p);
+ dbuf_makePath (&dbuf, p, port->target);
+ addSetHead (&includeDirsSet, dbuf_detach (&dbuf));
+ }
+ }
+}
+
+/* Set system lib path */
+static void
+setLibPath (void)
+{
+ /*
+ * Search logic:
+ *
+ * 1. - $SDCC_LIB/<model>
+ * 2. - $SDCC_LIB
+ * 3. - $SDCC_HOME/PREFIX2DATA_DIR/LIB_DIR_SUFFIX/<model>
+ * 4. - path(argv[0])/BIN2DATA_DIR/LIB_DIR_SUFFIX/<model>
+ * 5. - DATADIR/LIB_DIR_SUFFIX/<model> (only on *nix)
+ * 6. - $SDCC_HOME/PREFIX2DATA_DIR/NON_FREE_LIB_DIR_SUFFIX/<model>
+ * 7. - path(argv[0])/BIN2DATA_DIR/NON_FREE_LIB_DIR_SUFFIX/<model>
+ * 8. - DATADIR/NON_FREE_LIB_DIR_SUFFIX/<model> (only on *nix)
+ */
+
+ if (!options.nostdlib)
+ {
+ char *p;
+ const char *targetname;
+
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, PATH_MAX);
+
+ targetname = port->target;
+
+ dbuf_makePath (&dbuf, LIB_DIR_SUFFIX, port->general.get_model ? port->general.get_model () : targetname);
+ libDirsSet = processStrSet (dataDirsSet, NULL, dbuf_c_str (&dbuf), NULL);
+
+ if (options.use_non_free)
+ {
+ dbuf_set_length (&dbuf, 0);
+ dbuf_makePath (&dbuf, NON_FREE_LIB_DIR_SUFFIX, port->general.get_model ? port->general.get_model () : targetname);
+ mergeSets (&libDirsSet, processStrSet (dataDirsSet, NULL, dbuf_c_str (&dbuf), NULL));
+ }
+
+ if ((p = getenv (SDCC_LIB_NAME)) != NULL)
+ {
+ addSetHead (&libDirsSet, Safe_strdup (p));
+
+ dbuf_set_length (&dbuf, 0);
+ dbuf_makePath (&dbuf, p, port->general.get_model ? port->general.get_model () : targetname);
+ addSetHead (&libDirsSet, dbuf_detach (&dbuf));
+ }
+ else
+ dbuf_destroy (&dbuf);
+ }
+}
+
+/* Set data path */
+static void
+setDataPaths (const char *argv0)
+{
+ const char *p;
+
+ /*
+ * Search logic:
+ *
+ * 1. - $SDCC_HOME/PREFIX2DATA_DIR
+ * 2. - path(argv[0])/BIN2DATA_DIR
+ * 3. - DATADIR (only on *nix)
+ */
+
+ if ((p = getenv (SDCC_DIR_NAME)) != NULL)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, PATH_MAX);
+ dbuf_append_str (&dbuf, p);
+ dbuf_append_str (&dbuf, PREFIX2DATA_DIR);
+ addSetHead (&dataDirsSet, dbuf_detach_c_str (&dbuf));
+ }
+
+ if ((p = getBinPath (argv0)) != NULL)
+ {
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, PATH_MAX);
+ dbuf_append_str (&dbuf, p);
+ dbuf_append_str (&dbuf, BIN2DATA_DIR);
+ addSetHead (&dataDirsSet, dbuf_detach_c_str (&dbuf));
+ }
+
+#ifdef _WIN32
+ if (peekSet (dataDirsSet) == NULL)
+ {
+ /* this should never happen... */
+ wassertl (0, "Can't get binary path");
+ }
+#else
+ addSet (&dataDirsSet, Safe_strdup (DATADIR));
+#endif
+
+ setIncludePath ();
+ setLibPath ();
+}
+
+static void
+initValues (void)
+{
+ char *s;
+
+ populateMainValues (_baseValues);
+ setMainValue ("port", port->target);
+ setMainValue ("objext", port->linker.rel_ext);
+ setMainValue ("asmext", port->assembler.file_ext);
+
+ setMainValue ("dstfilename", dstFileName);
+
+ s = fullSrcFileName ? shell_escape (fullSrcFileName) : "fullsrcfilename";
+ setMainValue ("fullsrcfilename", s);
+ if (fullSrcFileName)
+ Safe_free (s);
+
+ if (options.cc_only && fullDstFileName)
+ /* compile + assemble and -o given: -o specifies name of object file */
+ {
+ setMainValue ("objdstfilename", fullDstFileName);
+ }
+ else
+ {
+ setMainValue ("objdstfilename", "{stdobjdstfilename}");
+ }
+ if (fullDstFileName)
+ /* if we're linking, -o gives the final file name */
+ {
+ setMainValue ("linkdstfilename", fullDstFileName);
+ }
+ else
+ {
+ setMainValue ("linkdstfilename", "{stdlinkdstfilename}");
+ }
+
+ /*
+ * Make sure the preprocessor is called with the "-std" option
+ * corresponding to the --std used to start sdcc
+ */
+ setMainValue ("cppstd",
+ options.std_c11 ? "-std=c11 " :
+ (options.std_c99 ? "-std=c99 " :
+ (options.std_c95 ? "-std=iso9899:199409 " :
+ "-std=c89 ")));
+}
+
+static void
+doPrintSearchDirs (void)
+{
+ const char *s;
+
+ printf ("programs:\n");
+ fputStrSet (stdout, binPathSet);
+
+ printf ("datadir:\n");
+ fputStrSet (stdout, dataDirsSet);
+
+ printf ("includedir:\n");
+ fputStrSet (stdout, includeDirsSet);
+
+ printf ("libdir:\n");
+ for (s = setFirstItem (libDirsSet); s != NULL; s = setNextItem (libDirsSet))
+ fprintf (stdout, "%s\n", s);
+
+ printf ("libpath:\n");
+ fputStrSet (stdout, libPathsSet);
+}
+
+
+static void
+sig_handler (int signal)
+{
+ char *sig_string;
+
+ switch (signal)
+ {
+ case SIGABRT:
+ sig_string = "SIGABRT";
+ break;
+
+ case SIGTERM:
+ sig_string = "SIGTERM";
+ break;
+
+ case SIGINT:
+ sig_string = "SIGINT";
+ break;
+
+ case SIGSEGV:
+ sig_string = "SIGSEGV";
+ break;
+
+ default:
+ sig_string = "Unknown?";
+ break;
+ }
+ fprintf (stderr, "Caught signal %d: %s\n", signal, sig_string);
+ exit (EXIT_FAILURE);
+}
+
+/*
+ * main routine
+ * initialises and calls the parser
+ */
+
+int
+main (int argc, char **argv, char **envp)
+{
+ /* get the prefix and the suffix of the sdcc command */
+ getPrefixSuffix (argv[0]);
+
+ /* set a larger stack size of a running sdcc process to 4MB */
+ setStackSize ();
+
+ /* turn all optimizations off by default */
+ memset (&optimize, 0, sizeof (struct optimize));
+
+ if (NUM_PORTS == 0)
+ {
+ fprintf (stderr, "Build error: no ports are enabled.\n");
+ exit (EXIT_FAILURE);
+ }
+
+ /* install signal handler;
+ it's only purpose is to call exit() to remove temp files */
+ if (!getenv ("SDCC_LEAVE_SIGNALS"))
+ {
+ signal (SIGABRT, sig_handler);
+ signal (SIGTERM, sig_handler);
+ signal (SIGINT, sig_handler);
+ signal (SIGSEGV, sig_handler);
+ }
+
+ /* Before parsing the command line options, do a
+ * search for the port and processor and initialize
+ * them if they're found. (We can't gurantee that these
+ * will be the first options specified).
+ */
+
+ _findPort (argc, argv);
+
+#ifdef JAMIN_DS390
+ if (strcmp (port->target, "mcs51") == 0)
+ {
+ printf ("DS390 jammed in A\n");
+ _setPort ("ds390");
+ ds390_jammed = 1;
+ }
+#endif
+
+ _findProcessor (argc, argv);
+
+ /* Initalise the port. */
+ if (port->init)
+ port->init ();
+
+ setDefaultOptions ();
+#ifdef JAMIN_DS390
+ if (ds390_jammed)
+ {
+ options.model = MODEL_SMALL;
+ options.stack10bit = 0;
+ }
+#endif
+
+ parseCmdLine (argc, argv);
+
+ if (options.verbose && NULL != port->processor)
+ printf ("Processor: %s\n", port->processor);
+
+ initValues ();
+
+ setBinPaths (argv[0]);
+ setDataPaths (argv[0]);
+
+ if (port->initPaths)
+ port->initPaths ();
+
+ if (options.printSearchDirs)
+ doPrintSearchDirs ();
+
+ /* if no input then printUsage & exit */
+ if (!options.c1mode && !fullSrcFileName && peekSet (relFilesSet) == NULL)
+ {
+ if (options.printSearchDirs)
+ exit (EXIT_SUCCESS);
+ printUsage (TRUE);
+ exit (EXIT_FAILURE);
+ }
+
+ /* initMem() is expensive, but
+ initMem() must called before port->finaliseOptions ().
+ And the z80 port needs port->finaliseOptions(),
+ even if we're only linking. */
+ initMem ();
+
+ /* finalize target specific options */
+ port->finaliseOptions ();
+
+ /* finalize common options */
+ finalizeOptions ();
+
+ if (fullSrcFileName || options.c1mode)
+ {
+ preProcess (envp);
+
+ initSymt ();
+ initiCode ();
+ initCSupport ();
+ initBuiltIns ();
+ initPeepHole ();
+
+ if (options.verbose)
+ printf ("sdcc: Generating code...\n");
+
+ yyparse ();
+
+ if (!options.c1mode)
+ if (sdcc_pclose (yyin))
+ fatalError = 1;
+
+ if (fatalError)
+ exit (EXIT_FAILURE);
+
+ if (gasOutput)
+ {
+ if (port->general.gas_glue)
+ port->general.gas_glue();
+ else
+ {
+ werror(W_ILLEGAL_OPT_COMBINATION, __FILE__, __LINE__, "selected target does not support GNU assembler output");
+ exit (1);
+ }
+ }
+ else if (port->general.do_glue != NULL)
+ (*port->general.do_glue) ();
+ else
+ {
+ /* this shouldn't happen */
+ assert (FALSE);
+ /* in case of NDEBUG */
+ glue ();
+ }
+
+ if (fatalError)
+ exit (EXIT_FAILURE);
+
+ if (!options.c1mode && !noAssemble)
+ {
+ if (options.verbose)
+ printf ("sdcc: Calling assembler...\n");
+ assemble (envp);
+ }
+ }
+ closeDumpFiles ();
+
+ if (options.debug && debugFile)
+ debugFile->closeFile ();
+
+ if (!options.cc_only && !fatalError && !noAssemble && !options.c1mode && (fullSrcFileName || peekSet (relFilesSet) != NULL))
+ {
+ if (options.verbose)
+ printf ("sdcc: Calling linker...\n");
+
+ if (port->linker.do_link)
+ port->linker.do_link ();
+ else
+ linkEdit (envp);
+ }
+
+ return 0;
+}
+