]> git.sur5r.net Git - cc65/blobdiff - src/cc65/main.c
Added dummy classification macros for the remaining targets - even for those that...
[cc65] / src / cc65 / main.c
index 296d297312fc6de4729c3c722588a45253d316cf..4165bc8575e6d93a5b55d55c7a3f8048e6bf2c50 100644 (file)
-/* CC65 main program */
+/*****************************************************************************/
+/*                                                                           */
+/*                                 main.c                                   */
+/*                                                                           */
+/*                            cc65 main program                             */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2000-2011, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 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 <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <ctype.h>
 #include <errno.h>
 
-#include "../common/version.h"
-
+/* common */
+#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 "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 "output.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"
+#include "standard.h"
+#include "svnversion.h"
 
 
 
 /*****************************************************************************/
-/*                                  code                                    */
+/*                                  Code                                    */
 /*****************************************************************************/
 
 
 
-static void usage (int ExitCode)
+static void Usage (void)
+/* Print usage information to stderr */
 {
-    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);
+    printf ("Usage: %s [options] file\n"
+            "Short options:\n"
+            "  -Cl\t\t\t\tMake local variables static\n"
+            "  -Dsym[=defn]\t\t\tDefine a symbol\n"
+            "  -E\t\t\t\tStop after the preprocessing stage\n"
+            "  -I dir\t\t\tSet an include directory search path\n"
+            "  -O\t\t\t\tOptimize code\n"
+            "  -Oi\t\t\t\tOptimize code, inline more code\n"
+            "  -Or\t\t\t\tEnable register variables\n"
+            "  -Os\t\t\t\tInline some known functions\n"
+            "  -T\t\t\t\tInclude source as comment\n"
+            "  -V\t\t\t\tPrint the compiler version number\n"
+            "  -W warning[,...]\t\tSuppress warnings\n"
+            "  -d\t\t\t\tDebug mode\n"
+            "  -g\t\t\t\tAdd debug info to object file\n"
+            "  -h\t\t\t\tHelp (this text)\n"
+            "  -j\t\t\t\tDefault characters are signed\n"
+            "  -mm model\t\t\tSet the memory model\n"
+            "  -o name\t\t\tName the output file\n"
+            "  -r\t\t\t\tEnable register variables\n"
+            "  -t sys\t\t\tSet the target system\n"
+            "  -v\t\t\t\tIncrease verbosity\n"
+            "\n"
+            "Long options:\n"
+            "  --add-source\t\t\tInclude source as comment\n"
+            "  --bss-name seg\t\tSet the name of the BSS segment\n"
+            "  --check-stack\t\t\tGenerate stack overflow checks\n"
+            "  --code-name seg\t\tSet the name of the CODE segment\n"
+            "  --codesize x\t\t\tAccept larger code by factor x\n"
+            "  --cpu type\t\t\tSet cpu type (6502, 65c02)\n"
+            "  --create-dep name\t\tCreate a make dependency file\n"
+            "  --create-full-dep name\tCreate a full make dependency file\n"
+            "  --data-name seg\t\tSet the name of the DATA segment\n"
+            "  --debug\t\t\tDebug mode\n"
+            "  --debug-info\t\t\tAdd debug info to object file\n"
+            "  --debug-opt name\t\tDebug optimization steps\n"
+            "  --dep-target target\t\tUse this dependency target\n"
+            "  --disable-opt name\t\tDisable an optimization step\n"
+            "  --enable-opt name\t\tEnable an optimization step\n"
+            "  --forget-inc-paths\t\tForget include search paths\n"
+            "  --help\t\t\tHelp (this text)\n"
+            "  --include-dir dir\t\tSet an include directory search path\n"
+            "  --list-opt-steps\t\tList all optimizer steps and exit\n"
+            "  --list-warnings\t\tList available warning types for -W\n"
+            "  --local-strings\t\tEmit string literals immediately\n"
+            "  --memory-model model\t\tSet the memory model\n"
+            "  --register-space b\t\tSet space available for register variables\n"
+            "  --register-vars\t\tEnable register variables\n"
+            "  --rodata-name seg\t\tSet the name of the RODATA segment\n"
+            "  --signed-chars\t\tDefault characters are signed\n"
+            "  --standard std\t\tLanguage standard (c89, c99, cc65)\n"
+            "  --static-locals\t\tMake local variables static\n"
+            "  --target sys\t\t\tSet the target system\n"
+            "  --verbose\t\t\tIncrease verbosity\n"
+            "  --version\t\t\tPrint the compiler version number\n"
+            "  --writable-strings\t\tMake string literals writable\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_C128:
-           cbmsys ("__C128__");
+       case TGT_VIC20:
+           cbmsys ("__VIC20__");
            break;
 
-       case TGT_ACE:
-           cbmsys ("__ACE__");
+       case TGT_C128:
+           cbmsys ("__C128__");
            break;
 
        case TGT_PLUS4:
            cbmsys ("__PLUS4__");
            break;
 
+       case TGT_CBM510:
+           cbmsys ("__CBM510__");
+           break;
+
        case TGT_CBM610:
            cbmsys ("__CBM610__");
            break;
 
        case TGT_PET:
-           cbmsys ("__PET__");
+           cbmsys ("__PET__");
+           break;
+
+       case TGT_BBC:
+           DefineNumericMacro ("__BBC__", 1);
+           break;
+
+       case TGT_APPLE2:
+           DefineNumericMacro ("__APPLE2__", 1);
+           break;
+
+       case TGT_APPLE2ENH:
+            DefineNumericMacro ("__APPLE2ENH__", 1);
+           break;
+
+       case TGT_GEOS_CBM:
+           /* Do not handle as a CBM system */
+           DefineNumericMacro ("__GEOS__", 1);
+           DefineNumericMacro ("__GEOS_CBM__", 1);
+           break;
+
+       case TGT_GEOS_APPLE:
+           DefineNumericMacro ("__GEOS__", 1);
+           DefineNumericMacro ("__GEOS_APPLE__", 1);
+           break;
+
+       case TGT_LUNIX:
+           DefineNumericMacro ("__LUNIX__", 1);
            break;
 
-       case TGT_NES:
-           AddNumericMacro ("__NES__", 1);
-           break;
+        case TGT_ATMOS:
+            DefineNumericMacro ("__ATMOS__", 1);
+            break;
 
-       case TGT_APPLE2:
-           AddNumericMacro ("__APPLE2__", 1);
-           break;
+        case TGT_NES:
+            DefineNumericMacro ("__NES__", 1);
+            break;
 
-       case TGT_GEOS:
-           /* Do not handle as a CBM system */
-           AddNumericMacro ("__GEOS__", 1);
-           break;
+        case TGT_SUPERVISION:
+            DefineNumericMacro ("__SUPERVISION__", 1);
+            break;
 
-       default:
-           fputs ("Unknown system type\n", stderr);
-           usage (EXIT_FAILURE);
+        case TGT_LYNX:
+            DefineNumericMacro ("__LYNX__", 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 FileNameOption (const char* Opt, const char* Arg, StrBuf* Name)
+/* Handle an option that remembers a file name for later */
 {
-    fprintf (stderr, "Invalid macro definition: `%s'\n", Def);
-    exit (EXIT_FAILURE);
+    /* Cannot have the option twice */
+    if (SB_NotEmpty (Name)) {
+        AbEnd ("Cannot use option `%s' twice", Opt);
+    }
+    /* Remember the file name for later */
+    SB_CopyStr (Name, Arg);
+    SB_Terminate (Name);
 }
 
 
@@ -214,22 +271,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,439 +294,705 @@ 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;
+}
+
+
+
+static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the --bss-name option */
+{
+    /* Check for a valid name */
+    CheckSegName (Arg);
+
+    /* Set the name */
+    SetSegName (SEG_BSS, Arg);
+}
+
+
+
+static void OptCheckStack (const char* Opt attribute ((unused)),
+                          const char* Arg attribute ((unused)))
+/* Handle the --check-stack option */
+{
+    IS_Set (&CheckStack, 1);
+}
+
+
+
+static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the --code-name option */
+{
+    /* Check for a valid name */
+    CheckSegName (Arg);
+
+    /* Set the name */
+    SetSegName (SEG_CODE, 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%c", &Factor, &BoundsCheck) != 1 ||
+        Factor < 10 || Factor > 1000) {
+       AbEnd ("Argument for %s is invalid", Opt);
+    }
+    IS_Set (&CodeSizeFactor, Factor);
+}
+
+
+
+static void OptCreateDep (const char* Opt, const char* Arg)
+/* Handle the --create-dep option */
+{
+    FileNameOption (Opt, Arg, &DepName);
+}
+
+
+
+static void OptCreateFullDep (const char* Opt attribute ((unused)),
+                             const char* Arg)
+/* Handle the --create-full-dep option */
+{
+    FileNameOption (Opt, Arg, &FullDepName);
+}
+
+
+
+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_6502X && CPU != CPU_65SC02 &&
+        CPU != CPU_65C02 && CPU != CPU_65816 && CPU != CPU_HUC6280) {
+               AbEnd ("Invalid argument for %s: `%s'", Opt, Arg);
+    }
+}
+
+
+
+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 */
+    SetSegName (SEG_DATA, Arg);
+}
+
+
+
+static void OptDebug (const char* Opt attribute ((unused)),
+                     const char* Arg attribute ((unused)))
+/* Compiler debug mode */
+{
+    ++Debug;
+}
 
-       /* 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 OptDebugInfo (const char* Opt attribute ((unused)),
+                         const char* Arg attribute ((unused)))
+/* Add debug info to the object file */
+{
+    DebugInfo = 1;
+}
+
+
+
+static void OptDebugOpt (const char* Opt attribute ((unused)), const char* Arg)
+/* Debug optimization steps */
+{
+    char Buf [128];
+    char* Line;
+
+    /* Open the file */
+    FILE* F = fopen (Arg, "r");
+    if (F == 0) {
+               AbEnd ("Cannot open `%s': %s", Arg, strerror (errno));
+    }
+
+    /* 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;
        }
+       Buf[Len] = '\0';
 
-       /* Check if this is only a type declaration */
-       if (curtok == SEMI) {
-           gettok ();
-           continue;
+       /* Get a pointer to the buffer and remove leading white space */
+       Line = Buf;
+       while (IsBlank (*Line)) {
+           ++Line;
        }
 
-               /* 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.
+       /* Check the first character and enable/disable the step or
+        * ignore the line
         */
-       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;
-           }
+       switch (*Line) {
 
-           /* 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;
-               }
-           }
+           case '\0':
+           case '#':
+           case ';':
+               /* Empty or comment line */
+               continue;
+
+           case '-':
+               DisableOpt (Line+1);
+               break;
 
-           /* Add an entry to the symbol table */
-           Entry = AddGlobalSym (Decl.Ident, Decl.Type, SymFlags);
+           case '+':
+               ++Line;
+               /* FALLTHROUGH */
 
-           /* Reserve storage for the variable if we need to */
-                   if (SymFlags & SC_STORAGE) {
+           default:
+               EnableOpt (Line);
+               break;
 
-               /* Get the size of the variable */
-               unsigned Size = SizeOf (Decl.Type);
+       }
 
-               /* Allow initialization */
-               if (curtok == ASGN) {
+    }
 
-                   /* 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);
-                       }
-                   }
+    /* Close the file, no error check here since we were just reading and
+     * this is only a debug function.
+     */
+    (void) fclose (F);
+}
 
-                   /* Switch to the data segment */
-                   g_usedata ();
 
-                   /* Define a label */
-                   g_defgloblabel (Entry->Name);
 
-                   /* Skip the '=' */
-                   gettok ();
+static void OptDepTarget (const char* Opt attribute ((unused)), const char* Arg)
+/* Handle the --dep-target option */
+{
+    FileNameOption (Opt, Arg, &DepTarget);
+}
 
-                   /* 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 OptDisableOpt (const char* Opt attribute ((unused)), const char* Arg)
+/* Disable an optimization step */
+{
+    DisableOpt (Arg);
+}
 
-                   /* Define a label */
-                   g_defgloblabel (Entry->Name);
 
-                   /* Allocate space for uninitialized variable */
-                   g_res (SizeOf (Entry->Type));
-               }
 
-           }
+static void OptEnableOpt (const char* Opt attribute ((unused)), const char* Arg)
+/* Enable an optimization step */
+{
+    EnableOpt (Arg);
+}
 
-           /* 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 OptForgetIncPaths (const char* Opt attribute ((unused)),
+                               const char* Arg attribute ((unused)))
+/* Forget all currently defined include paths */
+{
+    ForgetAllIncludePaths ();
+}
 
-               if (curtok == SEMI) {
 
-                   /* Prototype only */
-                   gettok ();
 
-               } else {
-                   if (Entry) {
-                       NewFunc (Entry);
-                   }
-               }
-           }
+static void OptHelp (const char* Opt attribute ((unused)),
+                    const char* Arg attribute ((unused)))
+/* Print usage information and exit */
+{
+    Usage ();
+    exit (EXIT_SUCCESS);
+}
 
-       } else {
 
-           /* Must be followed by a semicolon */
-           ConsumeSemi ();
 
-       }
-    }
+static void OptIncludeDir (const char* Opt attribute ((unused)), const char* Arg)
+/* Add an include search path */
+{
+    AddSearchPath (SysIncSearchPath, Arg);
+    AddSearchPath (UsrIncSearchPath, Arg);
+}
+
+
+
+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 OptListWarnings (const char* Opt attribute ((unused)),
+                            const char* Arg attribute ((unused)))
+/* List all warning types */
+{
+    /* List the warnings */
+    ListWarnings (stdout);
+
+    /* Terminate */
+    exit (EXIT_SUCCESS);
 }
 
 
 
-static void Compile (void)
-/* Compiler begins execution here. inp is input fd, output is output fd. */
+static void OptLocalStrings (const char* Opt attribute ((unused)),
+                            const char* Arg attribute ((unused)))
+/* Emit string literals immediately */
 {
-    char* Path;
+    IS_Set (&LocalStrings, 1);
+}
+
 
 
-    /* Setup variables */
-    filetab[0].f_iocb = inp;
-    LiteralLabel = GetLabel ();
+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);
+    }
 
-    /* Add some standard paths to the include search path */
-    AddIncludePath ("", INC_USER);             /* Current directory */
-    AddIncludePath ("include", INC_SYS);
-#ifdef CC65_INC
-    /* Allow modifications of the given string by dup'ing it */
-    AddIncludePath (xstrdup (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);
+    /* 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);
     }
 
-    /* Add macros that are always defined */
-    AddNumericMacro ("__CC65__", (VER_MAJOR * 0x100) + (VER_MINOR * 0x10) + VER_PATCH);
+    /* Set the memory model */
+    SetMemoryModel (M);
+}
+
+
 
-    /* Strict ANSI macro */
-    if (ANSI) {
-       AddNumericMacro ("__STRICT_ANSI__", 1);
+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);
     }
+}
 
-    /* Optimization macros */
-    if (Optimize) {
-       AddNumericMacro ("__OPT__", 1);
-       if (FavourSize == 0) {
-           AddNumericMacro ("__OPT_i__", 1);
-       }
-       if (EnableRegVars) {
-           AddNumericMacro ("__OPT_r__", 1);
-       }
-       if (InlineStdFuncs) {
-           AddNumericMacro ("__OPT_s__", 1);
-       }
+
+
+static void OptRegisterVars (const char* Opt attribute ((unused)),
+                             const char* Arg attribute ((unused)))
+/* Handle the --register-vars option */
+{
+    IS_Set (&EnableRegVars, 1);
+}
+
+
+
+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 */
+    SetSegName (SEG_RODATA, Arg);
+}
+
+
+
+static void OptSignedChars (const char* Opt attribute ((unused)),
+                           const char* Arg attribute ((unused)))
+/* Make default characters signed */
+{
+    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)))
+/* Place local variables in static storage */
+{
+    IS_Set (&StaticLocals, 1);
+}
+
+
 
-    /* Create the base lexical level */
-    EnterGlobalLevel ();
+static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
+/* Set the target system */
+{
+    SetSys (Arg);
+}
 
-    /* Generate the code generator preamble */
-    g_preamble ();
 
-    /* Ok, start the ball rolling... */
-    Parse ();
 
-    /* Dump literal pool. */
-    DumpLiteralPool ();
+static void OptVerbose (const char* Opt attribute ((unused)),
+                       const char* Arg attribute ((unused)))
+/* Increase verbosity */
+{
+    ++Verbosity;
+}
 
-    /* Write imported/exported symbols */
-    EmitExternals ();
 
-    if (Debug) {
-       PrintLiteralStats (stdout);
-       PrintMacroStats (stdout);
+
+static void OptVersion (const char* Opt attribute ((unused)),
+                       const char* Arg attribute ((unused)))
+/* Print the compiler version */
+{
+    fprintf (stderr,
+                    "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);
     }
 
-    /* Leave the main lexical level */
-    LeaveGlobalLevel ();
+    /* Free allocated memory */
+    SB_Done (&W);
+}
 
-    /* Print an error report */
-    ErrorReport ();
+
+
+static void OptWritableStrings (const char* Opt attribute ((unused)),
+                               const char* Arg attribute ((unused)))
+/* Make string literals writable */
+{
+    IS_Set (&WritableStrings, 1);
 }
 
 
 
-int main (int argc, char **argv)
+int main (int argc, char* argv[])
 {
-    int i;
-    char *argp;
-    char out_name [256];
-    char* p;
+    /* Program long options */
+    static const LongOpt OptTab[] = {
+       { "--add-source",       0,      OptAddSource            },
+       { "--bss-name",         1,      OptBssName              },
+               { "--check-stack",      0,      OptCheckStack           },
+       { "--code-name",        1,      OptCodeName             },
+       { "--codesize",         1,      OptCodeSize             },
+        { "--cpu",                     1,      OptCPU                  },
+       { "--create-dep",       1,      OptCreateDep            },
+        { "--create-full-dep",  1,      OptCreateFullDep        },
+       { "--data-name",        1,      OptDataName             },
+               { "--debug",            0,      OptDebug                },
+       { "--debug-info",       0,      OptDebugInfo            },
+        { "--debug-opt",        1,      OptDebugOpt             },
+        { "--dep-target",       1,      OptDepTarget            },
+       { "--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         },
+               { "--list-warnings",    0,      OptListWarnings         },
+        { "--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 input file name */
+    const char* InputFile  = 0;
+
+    /* Initialize the cmdline module */
+    InitCmdLine (&argc, &argv, "cc65");
 
-    /* Initialize the output file name */
-    out_name [0] = '\0';
+    /* Initialize the default segment names */
+    InitSegNames ();
 
-    fin = NULL;
+    /* 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) {
 
-               case 'd':       /* debug mode */
-                   Debug = 1;
+       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':
+                   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':
+                   SetOutputName (GetArg (&I, 2));
                    break;
 
+                case 'r':
+                    OptRegisterVars (Arg, 0);
+                    break;
+
                case 't':
-                   SetSys (GetArg (&i, argv, 2));
+                   OptTarget (Arg, GetArg (&I, 2));
                    break;
 
-               case 'v':
-                   ++Verbose;
+               case 'u':
+                   OptCreateDep (Arg, 0);
                    break;
 
-               case 'A':
-                   ANSI = 1;
+               case 'v':
+                   OptVerbose (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);
-                   break;
+                case 'E':
+                    PreprocessOnly = 1;
+                    break;
+
+                       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;
+                   IS_Set (&Optimize, 1);
+                   P = Arg + 2;
+                   while (*P) {
+                       switch (*P++) {
+                           case 'i':
+                               IS_Set (&CodeSizeFactor, 200);
+                               break;
+                           case 'r':
+                               IS_Set (&EnableRegVars, 1);
+                               break;
+                           case 's':
+                               IS_Set (&InlineStdFuncs, 1);
+                               break;
+                       }
+                   }
+                   break;
+
+               case 'T':
+                           OptAddSource (Arg, 0);
+                           break;
+
+                       case 'V':
+                           OptVersion (Arg, 0);
+                           break;
+
+                       case 'W':
+                    OptWarning (Arg, GetArg (&I, 2));
+                           break;
+
+                       default:
+                           UnknownOption (Arg);
+                           break;
+                   }
+               } else {
+                   if (InputFile) {
+                       fprintf (stderr, "additional file specs ignored\n");
+                   } else {
+                       InputFile = Arg;
+           }
+       }
 
-               case 'T':
-                   IncSource = 1;
-                   break;
+       /* Next argument */
+       ++I;
+    }
 
-               case 'V':
-                   fprintf (stderr, "cc65 V%u.%u.%u\n",
-                            VER_MAJOR, VER_MINOR, VER_PATCH);
-                   break;
+    /* Did we have a file spec on the command line? */
+    if (InputFile == 0) {
+       AbEnd ("No input files");
+    }
 
-               case 'W':
-                   NoWarn = 1;
-                   break;
+    /* Create the output file name if it was not explicitly given */
+    MakeDefaultOutputName (InputFile);
 
-               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));
-               }
-           }
-       }
+    /* If no CPU given, use the default CPU for the target */
+    if (CPU == CPU_UNKNOWN) {
+        if (Target != TGT_UNKNOWN) {
+            CPU = GetTargetProperties (Target)->DefaultCPU;
+        } else {
+            CPU = CPU_6502;
+        }
     }
-    if (!fin) {
-       fprintf (stderr, "%s: No input files\n", argv [0]);
-       exit (EXIT_FAILURE);
+
+    /* If no memory model was given, use the default */
+    if (MemoryModel == MMODEL_UNKNOWN) {
+        SetMemoryModel (MMODEL_NEAR);
     }
 
-    /* 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");
+    /* If no language standard was given, use the default one */
+    if (IS_Get (&Standard) == STD_UNKNOWN) {
+        IS_Set (&Standard, STD_DEFAULT);
     }
 
     /* Go! */
-    Compile ();
+    Compile (InputFile);
 
     /* Create the output file if we didn't had any errors */
-    if (ErrorCount == 0 || Debug) {
-
-       FILE* F;
+    if (PreprocessOnly == 0 && (ErrorCount == 0 || Debug)) {
 
-       /* Optimize the output if requested */
-       if (Optimize) {
-           OptDoOpt ();
-       }
+        /* Emit literals, externals, do cleanup and optimizations */
+        FinishCompile ();
 
-       /* Open the file */
-       F = fopen (out_name, "w");
-       if (F == 0) {
-           Fatal (FAT_CANNOT_OPEN_OUTPUT, strerror (errno));
-       }
+       /* Open the file */
+        OpenOutputFile ();
 
-       /* 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 (out_name);
-           Fatal (FAT_CANNOT_WRITE_OUTPUT);
-       }
+        CloseOutputFile ();
+
+       /* Create dependencies if requested */
+        CreateDependencies ();
     }
 
     /* Return an apropriate exit code */
@@ -677,3 +1000,4 @@ int main (int argc, char **argv)
 }
 
 
+