X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fmain.c;h=3ed7127e3120c9a31d4f8a0b1e6b7e126256e803;hb=b821c2c8ae74aca5346429344034f3c5200e5570;hp=78090fd137d16845cb5a2a4371919718d0555ba0;hpb=a1c89d9aed34328b37363f9209e88c52f9cf5742;p=cc65 diff --git a/src/cc65/main.c b/src/cc65/main.c index 78090fd13..3ed7127e3 100644 --- a/src/cc65/main.c +++ b/src/cc65/main.c @@ -1,163 +1,171 @@ -/* CC65 main program */ +/*****************************************************************************/ +/* */ +/* main.c */ +/* */ +/* cc65 main program */ +/* */ +/* */ +/* */ +/* (C) 2000-2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + #include #include #include -#include #include -#include "../common/version.h" - +/* common */ +#include "abend.h" +#include "chartype.h" +#include "cmdline.h" +#include "cpu.h" +#include "debugflag.h" +#include "fname.h" +#include "print.h" +#include "segnames.h" +#include "target.h" +#include "tgttrans.h" +#include "version.h" +#include "xmalloc.h" + +/* cc65 */ #include "asmcode.h" -#include "asmlabel.h" -#include "codegen.h" -#include "datatype.h" -#include "declare.h" +#include "compile.h" +#include "codeopt.h" #include "error.h" -#include "expr.h" -#include "function.h" #include "global.h" -#include "include.h" -#include "io.h" -#include "litpool.h" +#include "incpath.h" +#include "input.h" #include "macrotab.h" -#include "mem.h" -#include "optimize.h" -#include "pragma.h" #include "scanner.h" -#include "stmt.h" -#include "symtab.h" - - - -/*****************************************************************************/ -/* data */ -/*****************************************************************************/ - - - -/* Names of the target systems sorted by target name */ -static const char* TargetNames [] = { - "none", - "atari", - "c64", - "c128", - "ace", - "plus4", - "cbm610", - "pet", - "nes", - "apple2", - "geos", -}; +#include "segments.h" /*****************************************************************************/ -/* code */ +/* Code */ /*****************************************************************************/ -static void usage (int ExitCode) +static void Usage (void) { - fputs ("Usage: cc65 [options] file\n" - "\t-d\t\tDebug mode\n" - "\t-g\t\tAdd debug info to object files\n" - "\t-h\t\tPrint this help\n" - "\t-j\t\tDefault characters are signed\n" - "\t-o name\t\tName the output file\n" - "\t-tx\t\tSet target system x\n" - "\t-v\t\tVerbose mode\n" - "\t-A\t\tStrict ANSI mode\n" - "\t-Cl\t\tMake local variables static\n" - "\t-Dsym[=defn]\tDefine a symbol\n" - "\t-I path\t\tSet include directory\n" - "\t-O\t\tOptimize code\n" - "\t-Oi\t\tOptimize code, inline more code\n" - "\t-Or\t\tEnable register variables\n" - "\t-Os\t\tInline some known functions\n" - "\t-T\t\tInclude source as comment\n" - "\t-V\t\tPrint version number\n" - "\t-W\t\tSuppress warnings\n", - stderr); - exit (ExitCode); + fprintf (stderr, + "Usage: %s [options] file\n" + "Short options:\n" + " -A\t\t\tStrict ANSI mode\n" + " -Cl\t\t\tMake local variables static\n" + " -Dsym[=defn]\t\tDefine a symbol\n" + " -I dir\t\tSet an include directory search path\n" + " -O\t\t\tOptimize code\n" + " -Oi\t\t\tOptimize code, inline more code\n" + " -Or\t\t\tEnable register variables\n" + " -Os\t\t\tInline some known functions\n" + " -T\t\t\tInclude source as comment\n" + " -V\t\t\tPrint the compiler version number\n" + " -W\t\t\tSuppress warnings\n" + " -d\t\t\tDebug mode\n" + " -g\t\t\tAdd debug info to object file\n" + " -h\t\t\tHelp (this text)\n" + " -j\t\t\tDefault characters are signed\n" + " -o name\t\tName the output file\n" + " -r\t\t\tEnable register variables\n" + " -t sys\t\tSet the target system\n" + " -v\t\t\tIncrease verbosity\n" + "\n" + "Long options:\n" + " --add-source\t\tInclude source as comment\n" + " --ansi\t\tStrict ANSI mode\n" + " --bss-name seg\tSet the name of the BSS segment\n" + " --check-stack\t\tGenerate stack overflow checks\n" + " --code-name seg\tSet the name of the CODE segment\n" + " --codesize x\t\tAccept larger code by factor x\n" + " --cpu type\t\tSet cpu type (6502, 65c02)\n" + " --create-dep\t\tCreate a make dependency file\n" + " --data-name seg\tSet the name of the DATA segment\n" + " --debug\t\tDebug mode\n" + " --debug-info\t\tAdd debug info to object file\n" + " --debug-opt name\tDebug optimization steps\n" + " --disable-opt name\tDisable an optimization step\n" + " --enable-opt name\tEnable an optimization step\n" + " --forget-inc-paths\tForget include search paths\n" + " --help\t\tHelp (this text)\n" + " --include-dir dir\tSet an include directory search path\n" + " --list-opt-steps\tList all optimizer steps and exit\n" + " --register-space b\tSet space available for register variables\n" + " --register-vars\tEnable register variables\n" + " --rodata-name seg\tSet the name of the RODATA segment\n" + " --signed-chars\tDefault characters are signed\n" + " --static-locals\tMake local variables static\n" + " --target sys\t\tSet the target system\n" + " --verbose\t\tIncrease verbosity\n" + " --version\t\tPrint the compiler version number\n", + ProgName); } -static char* GetArg (int* ArgNum, char* argv [], unsigned Len) -/* Get an option argument */ -{ - char* Arg = argv [*ArgNum]; - if (Arg [Len] != '\0') { - /* Argument appended */ - return Arg + Len; - } else { - /* Separate argument */ - Arg = argv [*ArgNum + 1]; - if (Arg == 0) { - /* End of arguments */ - fprintf (stderr, "Option requires an argument: %s\n", argv [*ArgNum]); - exit (EXIT_FAILURE); - } - ++(*ArgNum); - return Arg; - } -} - - - -/* Define a CBM system */ static void cbmsys (const char* sys) +/* Define a CBM system */ { - AddNumericMacro ("__CBM__", 1); - AddNumericMacro (sys, 1); -} - - - -static int MapSys (const char* Name) -/* Map a target name to a system code. Return -1 in case of an error */ -{ - unsigned I; - - /* Check for a numeric target */ - if (isdigit (*Name)) { - int Target = atoi (Name); - if (Target >= 0 && Target < TGT_COUNT) { - return Target; - } - } - - /* Check for a target string */ - for (I = 0; I < TGT_COUNT; ++I) { - if (strcmp (TargetNames [I], Name) == 0) { - return I; - } - } - /* Not found */ - return -1; + DefineNumericMacro ("__CBM__", 1); + DefineNumericMacro (sys, 1); } -/* Define a target system */ static void SetSys (const char* Sys) +/* Define a target system */ { - switch (Target = MapSys (Sys)) { + switch (Target = FindTarget (Sys)) { case TGT_NONE: break; + case TGT_MODULE: + AbEnd ("Cannot use `module' as a target for the compiler"); + break; + case TGT_ATARI: - AddNumericMacro ("__ATARI__", 1); + DefineNumericMacro ("__ATARI__", 1); + break; + + case TGT_C16: + cbmsys ("__C16__"); break; case TGT_C64: cbmsys ("__C64__"); break; + case TGT_VIC20: + cbmsys ("__VIC20__"); + break; + case TGT_C128: cbmsys ("__C128__"); break; @@ -170,40 +178,76 @@ static void SetSys (const char* Sys) cbmsys ("__PLUS4__"); break; + case TGT_CBM510: + cbmsys ("__CBM510__"); + break; + case TGT_CBM610: cbmsys ("__CBM610__"); break; case TGT_PET: - cbmsys ("__PET__"); - break; + cbmsys ("__PET__"); + break; - case TGT_NES: - AddNumericMacro ("__NES__", 1); - break; + case TGT_BBC: + DefineNumericMacro ("__BBC__", 1); + break; - case TGT_APPLE2: - AddNumericMacro ("__APPLE2__", 1); - break; + case TGT_APPLE2: + DefineNumericMacro ("__APPLE2__", 1); + break; - case TGT_GEOS: - /* Do not handle as a CBM system */ - AddNumericMacro ("__GEOS__", 1); + case TGT_GEOS: + /* Do not handle as a CBM system */ + DefineNumericMacro ("__GEOS__", 1); + break; + + case TGT_LUNIX: + DefineNumericMacro ("__LUNIX__", 1); break; - default: - fputs ("Unknown system type\n", stderr); - usage (EXIT_FAILURE); + case TGT_ATMOS: + DefineNumericMacro ("__ATMOS__", 1); + break; + + case TGT_NES: + DefineNumericMacro ("__NES__", 1); + break; + + default: + AbEnd ("Unknown target system type %d", Target); } + + /* Initialize the translation tables for the target system */ + TgtTranslateInit (); } -static void InvSym (const char* Def) -/* Print an error about an invalid macro definition and die */ +static void DoCreateDep (const char* OutputName) +/* Create the dependency file */ { - fprintf (stderr, "Invalid macro definition: `%s'\n", Def); - exit (EXIT_FAILURE); + /* Make the dependency file name from the output file name */ + char* DepName = MakeFilename (OutputName, ".u"); + + /* Open the file */ + FILE* F = fopen (DepName, "w"); + if (F == 0) { + Fatal ("Cannot open dependency file `%s': %s", DepName, strerror (errno)); + } + + /* Write the dependencies to the file */ + WriteDependencies (F, OutputName); + + /* Close the file, check for errors */ + if (fclose (F) != 0) { + remove (DepName); + Fatal ("Cannot write to dependeny file (disk full?)"); + } + + /* Free the name */ + xfree (DepName); } @@ -214,22 +258,22 @@ static void DefineSym (const char* Def) const char* P = Def; /* The symbol must start with a character or underline */ - if (Def [0] != '_' && !isalpha (Def [0])) { - InvSym (Def); + if (Def [0] != '_' && !IsAlpha (Def [0])) { + InvDef (Def); } /* Check the symbol name */ - while (isalnum (*P) || *P == '_') { + while (IsAlNum (*P) || *P == '_') { ++P; } /* Do we have a value given? */ if (*P != '=') { if (*P != '\0') { - InvSym (Def); + InvDef (Def); } /* No value given. Define the macro with the value 1 */ - AddNumericMacro (Def, 1); + DefineNumericMacro (Def, 1); } else { /* We have a value, P points to the '=' character. Since the argument * is const, create a copy and replace the '=' in the copy by a zero @@ -237,428 +281,555 @@ static void DefineSym (const char* Def) */ char* Q; unsigned Len = strlen (Def)+1; - char* S = xmalloc (Len); + char* S = (char*) xmalloc (Len); memcpy (S, Def, Len); Q = S + (P - Def); *Q++ = '\0'; /* Define this as a macro */ - AddTextMacro (S, Q); + DefineTextMacro (S, Q); - /* Release the allocated memory */ - xfree (S); + /* Release the allocated memory */ + xfree (S); } } -static void Parse (void) -/* Process all input text. - * At this level, only static declarations, defines, includes, and function - * definitions are legal.... - */ +static void CheckSegName (const char* Seg) +/* Abort if the given name is not a valid segment name */ { - int comma; - SymEntry* Entry; + /* Print an error and abort if the name is not ok */ + if (!ValidSegName (Seg)) { + AbEnd ("Segment name `%s' is invalid", Seg); + } +} - kill (); - gettok (); /* "prime" the pump */ - gettok (); - while (curtok != CEOF) { - DeclSpec Spec; - Declaration Decl; - int NeedStorage; - /* Check for an ASM statement (which is allowed also on global level) */ - if (curtok == ASM) { - doasm (); - ConsumeSemi (); - continue; - } +static void OptAddSource (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Add source lines as comments in generated assembler file */ +{ + AddSource = 1; +} - /* Check for a #pragma */ - if (curtok == PRAGMA) { - DoPragma (); - continue; - } - /* Read variable defs and functions */ - ParseDeclSpec (&Spec, SC_EXTERN | SC_STATIC, T_INT); - /* Don't accept illegal storage classes */ - if (Spec.StorageClass == SC_AUTO || Spec.StorageClass == SC_REGISTER) { - Error (ERR_ILLEGAL_STORAGE_CLASS); - Spec.StorageClass = SC_EXTERN | SC_STATIC; - } +static void OptAnsi (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Compile in strict ANSI mode */ +{ + ANSI = 1; +} - /* Check if this is only a type declaration */ - if (curtok == SEMI) { - gettok (); - continue; - } - /* Check if we must reserve storage for the variable. We do - * this if we don't had a storage class given ("int i") or - * if the storage class is explicitly specified as static. - * This means that "extern int i" will not get storage - * allocated. - */ - NeedStorage = (Spec.StorageClass & SC_TYPEDEF) == 0 && - ((Spec.Flags & DS_DEF_STORAGE) != 0 || - (Spec.StorageClass & (SC_STATIC | SC_EXTERN)) == SC_STATIC); - - /* Read declarations for this type */ - Entry = 0; - comma = 0; - while (1) { - - unsigned SymFlags; - - /* Read the next declaration */ - ParseDecl (&Spec, &Decl, DM_NEED_IDENT); - if (Decl.Ident[0] == '\0') { - gettok (); - break; - } - /* Get the symbol flags */ - SymFlags = Spec.StorageClass; - if (IsFunc (Decl.Type)) { - SymFlags |= SC_FUNC; - } else { - if (NeedStorage) { - /* We will allocate storage, variable is defined */ - SymFlags |= SC_STORAGE | SC_DEF; - } - } +static void OptBssName (const char* Opt attribute ((unused)), const char* Arg) +/* Handle the --bss-name option */ +{ + /* Check for a valid name */ + CheckSegName (Arg); - /* Add an entry to the symbol table */ - Entry = AddGlobalSym (Decl.Ident, Decl.Type, SymFlags); + /* Set the name */ + NewSegName (SEG_BSS, Arg); +} - /* Reserve storage for the variable if we need to */ - if (SymFlags & SC_STORAGE) { - /* Get the size of the variable */ - unsigned Size = SizeOf (Decl.Type); - /* Allow initialization */ - if (curtok == ASGN) { +static void OptCheckStack (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Handle the --check-stack option */ +{ + CheckStack = 1; +} - /* We cannot initialize types of unknown size, or - * void types in non ANSI mode. - */ - if (Size == 0) { - if (!IsVoid (Decl.Type)) { - if (!IsArray (Decl.Type)) { - /* Size is unknown and not an array */ - Error (ERR_UNKNOWN_SIZE); - } - } else if (ANSI) { - /* We cannot declare variables of type void */ - Error (ERR_ILLEGAL_TYPE); - } - } - /* Switch to the data segment */ - g_usedata (); - /* Define a label */ - g_defgloblabel (Entry->Name); +static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg) +/* Handle the --code-name option */ +{ + /* Check for a valid name */ + CheckSegName (Arg); - /* Skip the '=' */ - gettok (); + /* Set the name */ + NewSegName (SEG_CODE, Arg); +} - /* Parse the initialization */ - ParseInit (Entry->Type); - } else { - if (IsVoid (Decl.Type)) { - /* We cannot declare variables of type void */ - Error (ERR_ILLEGAL_TYPE); - } else if (Size == 0) { - /* Size is unknown */ - Error (ERR_UNKNOWN_SIZE); - } - /* Switch to the BSS segment */ - g_usebss (); +static void OptCodeSize (const char* Opt, const char* Arg) +/* Handle the --codesize option */ +{ + /* Numeric argument expected */ + if (sscanf (Arg, "%u", &CodeSizeFactor) != 1 || + CodeSizeFactor < 100 || + CodeSizeFactor > 1000) { + AbEnd ("Argument for %s is invalid", Opt); + } +} - /* Define a label */ - g_defgloblabel (Entry->Name); - /* Allocate space for uninitialized variable */ - g_res (SizeOf (Entry->Type)); - } - } +static void OptCreateDep (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Handle the --create-dep option */ +{ + CreateDep = 1; +} - /* Check for end of declaration list */ - if (curtok == COMMA) { - gettok (); - comma = 1; - } else { - break; - } - } - /* Function declaration? */ - if (IsFunc (Decl.Type)) { - /* Function */ - if (!comma) { +static void OptCPU (const char* Opt, const char* Arg) +/* Handle the --cpu option */ +{ + /* Find the CPU from the given name */ + CPU = FindCPU (Arg); + if (CPU != CPU_6502 && CPU != CPU_65C02) { + AbEnd ("Invalid argument for %s: `%s'", Opt, Arg); + } +} - if (curtok == SEMI) { - /* Prototype only */ - gettok (); - } else { - if (Entry) { - NewFunc (Entry); - } - } - } +static void OptDataName (const char* Opt attribute ((unused)), const char* Arg) +/* Handle the --data-name option */ +{ + /* Check for a valid name */ + CheckSegName (Arg); + + /* Set the name */ + NewSegName (SEG_DATA, Arg); +} - } else { - /* Must be followed by a semicolon */ - ConsumeSemi (); - } - } +static void OptDebug (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Compiler debug mode */ +{ + ++Debug; } -static void Compile (void) -/* Compiler begins execution here. inp is input fd, output is output fd. */ +static void OptDebugInfo (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Add debug info to the object file */ { - char* Path; - + DebugInfo = 1; +} - /* Setup variables */ - filetab[0].f_iocb = inp; - LiteralLabel = GetLabel (); - /* Add some standard paths to the include search path */ - AddIncludePath ("", INC_USER); /* Current directory */ - AddIncludePath ("include", INC_SYS); -#ifdef CC65_INC - AddIncludePath (CC65_INC, INC_SYS); -#else - AddIncludePath ("/usr/lib/cc65/include", INC_SYS); -#endif - Path = getenv ("CC65_INC"); - if (Path) { - AddIncludePath (Path, INC_SYS | INC_USER); - } - /* Add macros that are always defined */ - AddNumericMacro ("__CC65__", (VER_MAJOR * 0x100) + (VER_MINOR * 0x10) + VER_PATCH); +static void OptDebugOpt (const char* Opt attribute ((unused)), const char* Arg) +/* Debug optimization steps */ +{ + char Buf [128]; + char* Line; - /* Strict ANSI macro */ - if (ANSI) { - AddNumericMacro ("__STRICT_ANSI__", 1); + /* Open the file */ + FILE* F = fopen (Arg, "r"); + if (F == 0) { + AbEnd ("Cannot open `%s': %s", Arg, strerror (errno)); } - /* Optimization macros */ - if (Optimize) { - AddNumericMacro ("__OPT__", 1); - if (FavourSize == 0) { - AddNumericMacro ("__OPT_i__", 1); + /* Read line by line, ignore empty lines and switch optimization + * steps on/off. + */ + while (fgets (Buf, sizeof (Buf), F) != 0) { + + /* Remove trailing control chars. This will also remove the + * trailing newline. + */ + unsigned Len = strlen (Buf); + while (Len > 0 && IsControl (Buf[Len-1])) { + --Len; } - if (EnableRegVars) { - AddNumericMacro ("__OPT_r__", 1); + Buf[Len] = '\0'; + + /* Get a pointer to the buffer and remove leading white space */ + Line = Buf; + while (IsBlank (*Line)) { + ++Line; } - if (InlineStdFuncs) { - AddNumericMacro ("__OPT_s__", 1); + + /* Check the first character and enable/disable the step or + * ignore the line + */ + switch (*Line) { + + case '\0': + case '#': + case ';': + /* Empty or comment line */ + continue; + + case '-': + DisableOpt (Line+1); + break; + + case '+': + ++Line; + /* FALLTHROUGH */ + + default: + EnableOpt (Line); + break; + } + } - /* Create the base lexical level */ - EnterGlobalLevel (); + /* Close the file, no error check here since we were just reading and + * this is only a debug function. + */ + (void) fclose (F); +} + - /* Generate the code generator preamble */ - g_preamble (); - /* Ok, start the ball rolling... */ - Parse (); +static void OptDisableOpt (const char* Opt attribute ((unused)), const char* Arg) +/* Disable an optimization step */ +{ + DisableOpt (Arg); +} + + + +static void OptEnableOpt (const char* Opt attribute ((unused)), const char* Arg) +/* Enable an optimization step */ +{ + EnableOpt (Arg); +} - /* Dump literal pool. */ - DumpLiteralPool (); - /* Write imported/exported symbols */ - EmitExternals (); - if (Debug) { - PrintLiteralStats (stdout); - PrintMacroStats (stdout); +static void OptForgetIncPaths (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Forget all currently defined include paths */ +{ + ForgetAllIncludePaths (); +} + + + +static void OptHelp (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Print usage information and exit */ +{ + Usage (); + exit (EXIT_SUCCESS); +} + + + +static void OptIncludeDir (const char* Opt attribute ((unused)), const char* Arg) +/* Add an include search path */ +{ + AddIncludePath (Arg, INC_SYS | INC_USER); +} + + + +static void OptListOptSteps (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* List all optimizer steps */ +{ + /* List the optimizer steps */ + ListOptSteps (stdout); + + /* Terminate */ + exit (EXIT_SUCCESS); +} + + + +static void OptRegisterSpace (const char* Opt, const char* Arg) +/* Handle the --register-space option */ +{ + /* Numeric argument expected */ + if (sscanf (Arg, "%u", &RegisterSpace) != 1 || RegisterSpace > 256) { + AbEnd ("Argument for option %s is invalid", Opt); } +} + + + +static void OptRegisterVars (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Handle the --register-vars option */ +{ + EnableRegVars = 1; +} - /* Leave the main lexical level */ - LeaveGlobalLevel (); - /* Print an error report */ - ErrorReport (); + +static void OptRodataName (const char* Opt attribute ((unused)), const char* Arg) +/* Handle the --rodata-name option */ +{ + /* Check for a valid name */ + CheckSegName (Arg); + + /* Set the name */ + NewSegName (SEG_RODATA, Arg); } -int main (int argc, char **argv) +static void OptSignedChars (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Make default characters signed */ { - int i; - char *argp; - char out_name [256]; - char* p; + SignedChars = 1; +} + + + +static void OptStaticLocals (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Place local variables in static storage */ +{ + StaticLocals = 1; +} + + + +static void OptTarget (const char* Opt attribute ((unused)), const char* Arg) +/* Set the target system */ +{ + SetSys (Arg); +} + + + +static void OptVerbose (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Increase verbosity */ +{ + ++Verbosity; +} + + + +static void OptVersion (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Print the assembler version */ +{ + fprintf (stderr, + "cc65 V%u.%u.%u\n", + VER_MAJOR, VER_MINOR, VER_PATCH); +} + + + +int main (int argc, char* argv[]) +{ + /* Program long options */ + static const LongOpt OptTab[] = { + { "--add-source", 0, OptAddSource }, + { "--ansi", 0, OptAnsi }, + { "--bss-name", 1, OptBssName }, + { "--check-stack", 0, OptCheckStack }, + { "--code-name", 1, OptCodeName }, + { "--codesize", 1, OptCodeSize }, + { "--cpu", 1, OptCPU }, + { "--create-dep", 0, OptCreateDep }, + { "--data-name", 1, OptDataName }, + { "--debug", 0, OptDebug }, + { "--debug-info", 0, OptDebugInfo }, + { "--debug-opt", 1, OptDebugOpt }, + { "--disable-opt", 1, OptDisableOpt }, + { "--enable-opt", 1, OptEnableOpt }, + { "--forget-inc-paths", 0, OptForgetIncPaths }, + { "--help", 0, OptHelp }, + { "--include-dir", 1, OptIncludeDir }, + { "--list-opt-steps", 0, OptListOptSteps }, + { "--register-space", 1, OptRegisterSpace }, + { "--register-vars", 0, OptRegisterVars }, + { "--rodata-name", 1, OptRodataName }, + { "--signed-chars", 0, OptSignedChars }, + { "--static-locals", 0, OptStaticLocals }, + { "--target", 1, OptTarget }, + { "--verbose", 0, OptVerbose }, + { "--version", 0, OptVersion }, + }; + + unsigned I; /* Initialize the output file name */ - out_name [0] = '\0'; + const char* OutputFile = 0; + const char* InputFile = 0; + + /* Initialize the cmdline module */ + InitCmdLine (&argc, &argv, "cc65"); - fin = NULL; + /* Initialize the default segment names */ + InitSegNames (); + + /* Initialize the include search paths */ + InitIncludePaths (); /* Parse the command line */ - for (i = 1; i < argc; i++) { - if (*(argp = argv[i]) == '-') { - switch (argp[1]) { + I = 1; + while (I < ArgCount) { + + const char* P; + + /* Get the argument */ + const char* Arg = ArgVec[I]; + + /* Check for an option */ + if (Arg [0] == '-') { + + switch (Arg [1]) { + + case '-': + LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0])); + break; - case 'd': /* debug mode */ - Debug = 1; + case 'd': + OptDebug (Arg, 0); break; case 'h': case '?': - usage (EXIT_SUCCESS); + OptHelp (Arg, 0); break; case 'g': - DebugInfo = 1; + OptDebugInfo (Arg, 0); break; case 'j': - SignedChars = 1; - break; + OptSignedChars (Arg, 0); + break; - case 'o': - strcpy (out_name, GetArg (&i, argv, 2)); + case 'o': + OutputFile = GetArg (&I, 2); break; + case 'r': + OptRegisterVars (Arg, 0); + break; + case 't': - SetSys (GetArg (&i, argv, 2)); + OptTarget (Arg, GetArg (&I, 2)); + break; + + case 'u': + OptCreateDep (Arg, 0); break; case 'v': - ++Verbose; + OptVerbose (Arg, 0); break; case 'A': - ANSI = 1; + OptAnsi (Arg, 0); break; case 'C': - p = argp + 2; - while (*p) { - switch (*p++) { - case 'l': - LocalsAreStatic = 1; - break; - } + P = Arg + 2; + while (*P) { + switch (*P++) { + case 'l': + OptStaticLocals (Arg, 0); + break; + default: + UnknownOption (Arg); + break; + } } break; case 'D': - DefineSym (GetArg (&i, argv, 2)); + DefineSym (GetArg (&I, 2)); break; - case 'I': - AddIncludePath (GetArg (&i, argv, 2), INC_SYS | INC_USER); + case 'I': + OptIncludeDir (Arg, GetArg (&I, 2)); break; case 'O': Optimize = 1; - p = argp + 2; - while (*p) { - switch (*p++) { - case 'f': - sscanf (p, "%lx", (long*) &OptDisable); - break; - case 'i': - FavourSize = 0; - break; - case 'r': - EnableRegVars = 1; - break; - case 's': - InlineStdFuncs = 1; - break; - } - } - break; - - case 'T': - IncSource = 1; - break; - - case 'V': - fprintf (stderr, "cc65 V%u.%u.%u\n", - VER_MAJOR, VER_MINOR, VER_PATCH); - break; - - case 'W': - NoWarn = 1; - break; - - default: - fprintf (stderr, "Invalid option %s\n", argp); - usage (EXIT_FAILURE); - } - } else { - if (fin) { - fprintf (stderr, "additional file specs ignored\n"); - } else { - fin = xstrdup (argp); - inp = fopen (fin, "r"); - if (inp == 0) { - Fatal (FAT_CANNOT_OPEN_INPUT, strerror (errno)); - } + P = Arg + 2; + while (*P) { + switch (*P++) { + case 'f': + sscanf (P, "%lx", (long*) &OptDisable); + break; + case 'i': + FavourSize = 0; + CodeSizeFactor = 200; + break; + case 'r': + EnableRegVars = 1; + break; + case 's': + InlineStdFuncs = 1; + break; + } + } + break; + + case 'T': + OptAddSource (Arg, 0); + break; + + case 'V': + OptVersion (Arg, 0); + break; + + case 'W': + NoWarn = 1; + break; + + default: + UnknownOption (Arg); + break; + } + } else { + if (InputFile) { + fprintf (stderr, "additional file specs ignored\n"); + } else { + InputFile = Arg; } } + + /* Next argument */ + ++I; } - if (!fin) { - fprintf (stderr, "%s: No input files\n", argv [0]); - exit (EXIT_FAILURE); + + /* Did we have a file spec on the command line? */ + if (InputFile == 0) { + AbEnd ("No input files"); } - /* Create the output file name. We should really have - * some checks for string overflow, but I'll drop this because of the - * additional code size it would need (as in other places). Sigh. - */ - if (out_name [0] == '\0') { - /* No output name given, create default */ - strcpy (out_name, fin); - if ((p = strrchr (out_name, '.'))) { - *p = '\0'; - } - strcat (out_name, ".s"); + /* Create the output file name if it was not explicitly given */ + if (OutputFile == 0) { + OutputFile = MakeFilename (InputFile, ".s"); + } + + /* If no CPU given, use the default CPU for the target */ + if (CPU == CPU_UNKNOWN) { + if (Target != TGT_UNKNOWN) { + CPU = DefaultCPU[Target]; + } else { + CPU = CPU_6502; + } } /* Go! */ - Compile (); + Compile (InputFile); /* Create the output file if we didn't had any errors */ if (ErrorCount == 0 || Debug) { - FILE* F; - - /* Optimize the output if requested */ - if (Optimize) { - OptDoOpt (); - } - /* Open the file */ - F = fopen (out_name, "w"); + FILE* F = fopen (OutputFile, "w"); if (F == 0) { - Fatal (FAT_CANNOT_OPEN_OUTPUT, strerror (errno)); + Fatal ("Cannot open output file `%s': %s", OutputFile, strerror (errno)); } /* Write the output to the file */ @@ -666,9 +837,15 @@ int main (int argc, char **argv) /* Close the file, check for errors */ if (fclose (F) != 0) { - remove (out_name); - Fatal (FAT_CANNOT_WRITE_OUTPUT); + remove (OutputFile); + Fatal ("Cannot write to output file (disk full?)"); + } + + /* Create dependencies if requested */ + if (CreateDep) { + DoCreateDep (OutputFile); } + } /* Return an apropriate exit code */ @@ -676,3 +853,4 @@ int main (int argc, char **argv) } +