]> git.sur5r.net Git - cc65/blobdiff - src/cc65/main.c
New option and #pragma --local-strings that causes string literals to be
[cc65] / src / cc65 / main.c
index 19fb4db413c812b3d8473a40996fecfbdcb472bc..ed3c987ab5309417a0bd0a750129406839825654 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2000-2002 Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 2000-2009, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 #include "abend.h"
 #include "chartype.h"
 #include "cmdline.h"
+#include "cpu.h"
 #include "debugflag.h"
 #include "fname.h"
+#include "mmodel.h"
 #include "print.h"
 #include "segnames.h"
+#include "strbuf.h"
 #include "target.h"
 #include "tgttrans.h"
 #include "version.h"
 #include "asmcode.h"
 #include "compile.h"
 #include "codeopt.h"
-#include "cpu.h"
 #include "error.h"
 #include "global.h"
 #include "incpath.h"
 #include "input.h"
 #include "macrotab.h"
+#include "output.h"
 #include "scanner.h"
 #include "segments.h"
+#include "standard.h"
+#include "svnversion.h"
 
 
 
 
 
 static void Usage (void)
-{
-    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\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"
-            "  --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);
+/* Print usage information to stderr */
+{
+    printf ("Usage: %s [options] file\n"
+            "Short options:\n"
+            "  -Cl\t\t\tMake local variables static\n"
+            "  -Dsym[=defn]\t\tDefine a symbol\n"
+            "  -E\t\t\tStop after the preprocessing stage\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"
+            "  -mm model\t\tSet the memory model\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"
+            "  --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"
+            "  --local-strings\tEmit string literals immediately\n"
+            "  --memory-model model\tSet the memory model\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"
+            "  --standard std\tLanguage standard (c89, c99, cc65)\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"
+            "  --writable-strings\tMake string literals writable\n",
+            ProgName);
 }
 
 
@@ -169,10 +179,6 @@ static void SetSys (const char* Sys)
            cbmsys ("__C128__");
            break;
 
-       case TGT_ACE:
-           cbmsys ("__ACE__");
-           break;
-
        case TGT_PLUS4:
            cbmsys ("__PLUS4__");
            break;
@@ -197,6 +203,10 @@ static void SetSys (const char* Sys)
            DefineNumericMacro ("__APPLE2__", 1);
            break;
 
+       case TGT_APPLE2ENH:
+            DefineNumericMacro ("__APPLE2ENH__", 1);
+           break;
+
        case TGT_GEOS:
            /* Do not handle as a CBM system */
            DefineNumericMacro ("__GEOS__", 1);
@@ -210,8 +220,20 @@ static void SetSys (const char* Sys)
             DefineNumericMacro ("__ATMOS__", 1);
             break;
 
+        case TGT_NES:
+            DefineNumericMacro ("__NES__", 1);
+            break;
+
+        case TGT_SUPERVISION:
+            DefineNumericMacro ("__SUPERVISION__", 1);
+            break;
+
+        case TGT_LYNX:
+            DefineNumericMacro ("__LYNX__", 1);
+            break;
+
        default:
-                   AbEnd ("Unknown target system type");
+                   AbEnd ("Unknown target system type %d", Target);
     }
 
     /* Initialize the translation tables for the target system */
@@ -311,15 +333,6 @@ static void OptAddSource (const char* Opt attribute ((unused)),
 
 
 
-static void OptAnsi (const char* Opt attribute ((unused)),
-                    const char* Arg attribute ((unused)))
-/* Compile in strict ANSI mode */
-{
-    ANSI = 1;
-}
-
-
-
 static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
 /* Handle the --bss-name option */
 {
@@ -327,16 +340,16 @@ static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
     CheckSegName (Arg);
 
     /* Set the name */
-    NewSegName (SEG_BSS, Arg);
+    SetSegName (SEG_BSS, Arg);
 }
 
 
 
 static void OptCheckStack (const char* Opt attribute ((unused)),
-                          const char* Arg attribute ((unused)))
+                          const char* Arg attribute ((unused)))
 /* Handle the --check-stack option */
 {
-    CheckStack = 1;
+    IS_Set (&CheckStack, 1);
 }
 
 
@@ -348,7 +361,7 @@ static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg)
     CheckSegName (Arg);
 
     /* Set the name */
-    NewSegName (SEG_CODE, Arg);
+    SetSegName (SEG_CODE, Arg);
 }
 
 
@@ -356,12 +369,15 @@ static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg)
 static void OptCodeSize (const char* Opt, const char* Arg)
 /* Handle the --codesize option */
 {
+    unsigned Factor;
+    char     BoundsCheck;
+
     /* Numeric argument expected */
-    if (sscanf (Arg, "%u", &CodeSizeFactor) != 1 ||
-       CodeSizeFactor < 100 ||
-               CodeSizeFactor > 1000) {
+    if (sscanf (Arg, "%u%c", &Factor, &BoundsCheck) != 1 ||
+        Factor < 10 || Factor > 1000) {
        AbEnd ("Argument for %s is invalid", Opt);
     }
+    IS_Set (&CodeSizeFactor, Factor);
 }
 
 
@@ -378,11 +394,10 @@ static void OptCreateDep (const char* Opt attribute ((unused)),
 static void OptCPU (const char* Opt, const char* Arg)
 /* Handle the --cpu option */
 {
-    if (strcmp (Arg, "6502") == 0) {
-               CPU = CPU_6502;
-    } else if (strcmp (Arg, "65C02") == 0) {
-       CPU = CPU_65C02;
-    } else {
+    /* Find the CPU from the given name */
+    CPU = FindCPU (Arg);
+    if (CPU != CPU_6502 && CPU != CPU_6502X && CPU != CPU_65SC02 &&
+        CPU != CPU_65C02 && CPU != CPU_65816 && CPU != CPU_HUC6280) {
                AbEnd ("Invalid argument for %s: `%s'", Opt, Arg);
     }
 }
@@ -396,7 +411,7 @@ static void OptDataName (const char* Opt attribute ((unused)), const char* Arg)
     CheckSegName (Arg);
 
     /* Set the name */
-    NewSegName (SEG_DATA, Arg);
+    SetSegName (SEG_DATA, Arg);
 }
 
 
@@ -502,6 +517,15 @@ static void OptEnableOpt (const char* Opt attribute ((unused)), const char* Arg)
 
 
 
+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 */
@@ -533,6 +557,39 @@ static void OptListOptSteps (const char* Opt attribute ((unused)),
 
 
 
+static void OptLocalStrings (const char* Opt attribute ((unused)),
+                            const char* Arg attribute ((unused)))
+/* Emit string literals immediately */
+{
+    IS_Set (&LocalStrings, 1);
+}
+
+
+
+static void OptMemoryModel (const char* Opt, const char* Arg)
+/* Set the memory model */
+{
+    mmodel_t M;
+
+    /* Check the current memory model */
+    if (MemoryModel != MMODEL_UNKNOWN) {
+        AbEnd ("Cannot use option `%s' twice", Opt);
+    }
+
+    /* Translate the memory model name and check it */
+    M = FindMemoryModel (Arg);
+    if (M == MMODEL_UNKNOWN) {
+        AbEnd ("Unknown memory model: %s", Arg);
+    } else if (M == MMODEL_HUGE) {
+        AbEnd ("Unsupported memory model: %s", Arg);
+    }
+
+    /* Set the memory model */
+    SetMemoryModel (M);
+}
+
+
+
 static void OptRegisterSpace (const char* Opt, const char* Arg)
 /* Handle the --register-space option */
 {
@@ -548,7 +605,7 @@ static void OptRegisterVars (const char* Opt attribute ((unused)),
                              const char* Arg attribute ((unused)))
 /* Handle the --register-vars option */
 {
-    EnableRegVars = 1;
+    IS_Set (&EnableRegVars, 1);
 }
 
 
@@ -560,25 +617,41 @@ static void OptRodataName (const char* Opt attribute ((unused)), const char* Arg
     CheckSegName (Arg);
 
     /* Set the name */
-    NewSegName (SEG_RODATA, Arg);
+    SetSegName (SEG_RODATA, Arg);
 }
 
 
 
 static void OptSignedChars (const char* Opt attribute ((unused)),
-                           const char* Arg attribute ((unused)))
+                           const char* Arg attribute ((unused)))
 /* Make default characters signed */
 {
-    SignedChars = 1;
+    IS_Set (&SignedChars, 1);
+}
+
+
+
+static void OptStandard (const char* Opt, const char* Arg)
+/* Handle the --standard option */
+{
+    /* Find the standard from the given name */
+    standard_t Std = FindStandard (Arg);
+    if (Std == STD_UNKNOWN) {
+               AbEnd ("Invalid argument for %s: `%s'", Opt, Arg);
+    } else if (IS_Get (&Standard) != STD_UNKNOWN) {
+        AbEnd ("Option %s given more than once", Opt);
+    } else {
+        IS_Set (&Standard, Std);
+    }
 }
 
 
 
 static void OptStaticLocals (const char* Opt attribute ((unused)),
-                            const char* Arg attribute ((unused)))
+                            const char* Arg attribute ((unused)))
 /* Place local variables in static storage */
 {
-    StaticLocals = 1;
+    IS_Set (&StaticLocals, 1);
 }
 
 
@@ -601,12 +674,68 @@ static void OptVerbose (const char* Opt attribute ((unused)),
 
 
 static void OptVersion (const char* Opt attribute ((unused)),
-                       const char* Arg attribute ((unused)))
-/* Print the assembler version */
+                       const char* Arg attribute ((unused)))
+/* Print the compiler version */
 {
     fprintf (stderr,
-                    "cc65 V%u.%u.%u\n",
-                    VER_MAJOR, VER_MINOR, VER_PATCH);
+                    "cc65 V%s\nSVN version: %s\n",
+                    GetVersionAsString (), SVNVersion);
+    exit (EXIT_SUCCESS);
+}
+
+
+
+static void OptWarning (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the -W option */
+{
+    StrBuf W = AUTO_STRBUF_INITIALIZER;
+
+    /* Arg is a list of suboptions, separated by commas */
+    while (Arg) {
+
+        const char* Pos;
+        int         Enabled = 1;
+        IntStack*   S;
+
+        /* The suboption may be prefixed with '-' or '+' */
+        if (*Arg == '-') {
+            Enabled = 0;
+            ++Arg;
+        } else if (*Arg == '+') {
+            /* This is the default */
+            ++Arg;
+        }
+
+        /* Get the next suboption */
+        Pos = strchr (Arg, ',');
+        if (Pos) {
+            SB_CopyBuf (&W, Arg, Pos - Arg);
+            Arg = Pos + 1;
+        } else {
+            SB_CopyStr (&W, Arg);
+            Arg = 0;
+        }
+        SB_Terminate (&W);
+
+        /* Search for the warning */
+        S = FindWarning (SB_GetConstBuf (&W));
+        if (S == 0) {
+            InvArg (Opt, SB_GetConstBuf (&W));
+        }
+        IS_Set (S, Enabled);
+    }
+
+    /* Free allocated memory */
+    SB_Done (&W);
+}
+
+
+
+static void OptWritableStrings (const char* Opt attribute ((unused)),
+                               const char* Arg attribute ((unused)))
+/* Make string literals writable */
+{
+    IS_Set (&WritableStrings, 1);
 }
 
 
@@ -616,7 +745,6 @@ 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             },
@@ -628,24 +756,28 @@ int main (int argc, char* argv[])
        { "--debug-info",       0,      OptDebugInfo            },
         { "--debug-opt",        1,      OptDebugOpt             },
        { "--disable-opt",      1,      OptDisableOpt           },
-       { "--enable-opt",       1,      OptEnableOpt,           },
+       { "--enable-opt",       1,      OptEnableOpt            },
+               { "--forget-inc-paths", 0,      OptForgetIncPaths       },
        { "--help",             0,      OptHelp                 },
        { "--include-dir",      1,      OptIncludeDir           },
        { "--list-opt-steps",   0,      OptListOptSteps         },
+        { "--local-strings",    0,      OptLocalStrings         },
+        { "--memory-model",     1,      OptMemoryModel          },
         { "--register-space",   1,      OptRegisterSpace        },
         { "--register-vars",    0,      OptRegisterVars         },
        { "--rodata-name",      1,      OptRodataName           },
        { "--signed-chars",     0,      OptSignedChars          },
+        { "--standard",         1,      OptStandard             },
                { "--static-locals",    0,      OptStaticLocals         },
        { "--target",           1,      OptTarget               },
        { "--verbose",          0,      OptVerbose              },
        { "--version",          0,      OptVersion              },
+               { "--writable-strings", 0,      OptWritableStrings      },
     };
 
     unsigned I;
 
-    /* Initialize the output file name */
-    const char* OutputFile = 0;
+    /* Initialize the input file name */
     const char* InputFile  = 0;
 
     /* Initialize the cmdline module */
@@ -654,6 +786,9 @@ int main (int argc, char* argv[])
     /* Initialize the default segment names */
     InitSegNames ();
 
+    /* Initialize the include search paths */
+    InitIncludePaths ();
+
     /* Parse the command line */
     I = 1;
     while (I < ArgCount) {
@@ -664,9 +799,9 @@ int main (int argc, char* argv[])
                const char* Arg = ArgVec[I];
 
                /* Check for an option */
-               if (Arg [0] == '-') {
+               if (Arg[0] == '-') {
 
-                   switch (Arg [1]) {
+                   switch (Arg[1]) {
 
                case '-':
                    LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
@@ -690,7 +825,7 @@ int main (int argc, char* argv[])
                    break;
 
                case 'o':
-                   OutputFile = GetArg (&I, 2);
+                   SetOutputName (GetArg (&I, 2));
                    break;
 
                 case 'r':
@@ -709,10 +844,6 @@ int main (int argc, char* argv[])
                    OptVerbose (Arg, 0);
                    break;
 
-               case 'A':
-                   OptAnsi (Arg, 0);
-                   break;
-
                case 'C':
                            P = Arg + 2;
                    while (*P) {
@@ -723,7 +854,7 @@ int main (int argc, char* argv[])
                            default:
                                UnknownOption (Arg);
                                break;
-                       }
+                       }
                    }
                    break;
 
@@ -731,27 +862,27 @@ int main (int argc, char* argv[])
                    DefineSym (GetArg (&I, 2));
                    break;
 
+                case 'E':
+                    PreprocessOnly = 1;
+                    break;
+
                        case 'I':
                    OptIncludeDir (Arg, GetArg (&I, 2));
                    break;
 
                case 'O':
-                   Optimize = 1;
+                   IS_Set (&Optimize, 1);
                    P = Arg + 2;
                    while (*P) {
                        switch (*P++) {
-                           case 'f':
-                               sscanf (P, "%lx", (long*) &OptDisable);
-                               break;
                            case 'i':
-                               FavourSize = 0;
-                               CodeSizeFactor = 200;
+                               IS_Set (&CodeSizeFactor, 200);
                                break;
                            case 'r':
-                               EnableRegVars = 1;
+                               IS_Set (&EnableRegVars, 1);
                                break;
                            case 's':
-                               InlineStdFuncs = 1;
+                               IS_Set (&InlineStdFuncs, 1);
                                break;
                        }
                    }
@@ -766,7 +897,7 @@ int main (int argc, char* argv[])
                            break;
 
                        case 'W':
-                           NoWarn = 1;
+                    OptWarning (Arg, GetArg (&I, 2));
                            break;
 
                        default:
@@ -791,43 +922,50 @@ int main (int argc, char* argv[])
     }
 
     /* Create the output file name if it was not explicitly given */
-    if (OutputFile == 0) {
-       OutputFile = MakeFilename (InputFile, ".s");
+    MakeDefaultOutputName (InputFile);
+
+    /* 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;
+        }
+    }
+
+    /* If no memory model was given, use the default */
+    if (MemoryModel == MMODEL_UNKNOWN) {
+        SetMemoryModel (MMODEL_NEAR);
+    }
+
+    /* If no language standard was given, use the default one */
+    if (IS_Get (&Standard) == STD_UNKNOWN) {
+        IS_Set (&Standard, STD_DEFAULT);
     }
 
     /* Go! */
     Compile (InputFile);
 
     /* Create the output file if we didn't had any errors */
-    if (ErrorCount == 0 || Debug) {
+    if (PreprocessOnly == 0 && (ErrorCount == 0 || Debug)) {
 
-       FILE* F;
+        /* Emit literals, externals, do cleanup and optimizations */
+        FinishCompile ();
 
-#if 0
-       /* Optimize the output if requested */
-       if (Optimize) {
-           OptDoOpt ();
-       }
-#endif
+       /* Open the file */
+        OpenOutputFile ();
 
-       /* Open the file */
-       F = fopen (OutputFile, "w");
-       if (F == 0) {
-           Fatal ("Cannot open output file `%s': %s", OutputFile, strerror (errno));
-       }
-
-       /* Write the output to the file */
-       WriteOutput (F);
+       /* Write the output to the file */
+               WriteAsmOutput ();
+               Print (stdout, 1, "Wrote output to `%s'\n", OutputFilename);
 
        /* Close the file, check for errors */
-       if (fclose (F) != 0) {
-           remove (OutputFile);
-           Fatal ("Cannot write to output file (disk full?)");
-       }
+        CloseOutputFile ();
 
        /* Create dependencies if requested */
        if (CreateDep) {
-           DoCreateDep (OutputFile);
+           DoCreateDep (OutputFilename);
+           Print (stdout, 1, "Creating dependeny file\n");
        }
 
     }