-/* CC65 main program */
+/*****************************************************************************/
+/* */
+/* main.c */
+/* */
+/* cc65 main program */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* 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 <ctype.h>
#include <errno.h>
+#include "../common/cmdline.h"
+#include "../common/fname.h"
#include "../common/version.h"
+#include "../common/xmalloc.h"
#include "asmcode.h"
#include "compile.h"
+#include "cpu.h"
#include "error.h"
#include "global.h"
-#include "include.h"
-#include "io.h"
+#include "incpath.h"
+#include "input.h"
#include "macrotab.h"
-#include "mem.h"
#include "optimize.h"
#include "scanner.h"
-static void usage (int ExitCode)
-{
- 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);
-}
-
-
-
-static char* GetArg (int* ArgNum, char* argv [], unsigned Len)
-/* Get an option argument */
+static void Usage (void)
{
- 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;
- }
+ fprintf (stderr,
+ "Usage: %s [options] file\n"
+ "Short options:\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"
+ " -t sys\t\tSet the target system\n"
+ " -v\t\t\tIncrease verbosity\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"
+ "\n"
+ "Long options:\n"
+ " --ansi\t\tStrict ANSI mode\n"
+ " --cpu type\t\tSet cpu type\n"
+ " --debug\t\tDebug mode\n"
+ " --debug-info\t\tAdd debug info to object file\n"
+ " --help\t\tHelp (this text)\n"
+ " --include-dir dir\tSet an include directory search path\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);
}
-/* Define a CBM system */
static void cbmsys (const char* sys)
+/* Define a CBM system */
{
AddNumericMacro ("__CBM__", 1);
AddNumericMacro (sys, 1);
-/* Define a target system */
static void SetSys (const char* Sys)
+/* Define a target system */
{
switch (Target = MapSys (Sys)) {
break;
case TGT_ATARI:
- AddNumericMacro ("__ATARI__", 1);
+ AddNumericMacro ("__ATARI__", 1);
break;
case TGT_C64:
default:
fputs ("Unknown system type\n", stderr);
- usage (EXIT_FAILURE);
+ exit (EXIT_FAILURE);
}
}
-static void InvSym (const char* Def)
-/* Print an error about an invalid macro definition and die */
-{
- fprintf (stderr, "Invalid macro definition: `%s'\n", Def);
- exit (EXIT_FAILURE);
-}
-
-
-
static void DefineSym (const char* Def)
/* Define a symbol on the command line */
{
/* The symbol must start with a character or underline */
if (Def [0] != '_' && !isalpha (Def [0])) {
- InvSym (Def);
+ InvDef (Def);
}
/* Check the symbol name */
/* 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);
/* Define this as a macro */
AddTextMacro (S, Q);
- /* Release the allocated memory */
- xfree (S);
+ /* Release the allocated memory */
+ xfree (S);
+ }
+}
+
+
+
+static void OptAddSource (const char* Opt, const char* Arg)
+/* Add source lines as comments in generated assembler file */
+{
+ AddSource = 1;
+}
+
+
+
+static void OptAnsi (const char* Opt, const char* Arg)
+/* Compile in strict ANSI mode */
+{
+ ANSI = 1;
+}
+
+
+
+static void OptCPU (const char* Opt, const char* Arg)
+/* Handle the --cpu option */
+{
+ if (Arg == 0) {
+ NeedArg (Opt);
+ }
+ if (strcmp (Arg, "6502") == 0) {
+ CPU = CPU_6502;
+ } else if (strcmp (Arg, "65C02") == 0) {
+ CPU = CPU_65C02;
+ } else {
+ fprintf (stderr, "Invalid CPU: `%s'\n", Arg);
+ exit (EXIT_FAILURE);
+ }
+}
+
+
+
+static void OptDebug (const char* Opt, const char* Arg)
+/* Compiler debug mode */
+{
+ Debug = 1;
+}
+
+
+
+static void OptDebugInfo (const char* Opt, const char* Arg)
+/* Add debug info to the object file */
+{
+ DebugInfo = 1;
+}
+
+
+
+static void OptHelp (const char* Opt, const char* Arg)
+/* Print usage information and exit */
+{
+ Usage ();
+ exit (EXIT_SUCCESS);
+}
+
+
+
+static void OptIncludeDir (const char* Opt, const char* Arg)
+/* Add an include search path */
+{
+ if (Arg == 0) {
+ NeedArg (Opt);
+ }
+ AddIncludePath (Arg, INC_SYS | INC_USER);
+}
+
+
+
+static void OptSignedChars (const char* Opt, const char* Arg)
+/* Make default characters signed */
+{
+ SignedChars = 1;
+}
+
+
+
+static void OptStaticLocals (const char* Opt, const char* Arg)
+/* Place local variables in static storage */
+{
+ StaticLocals = 1;
+}
+
+
+
+static void OptTarget (const char* Opt, const char* Arg)
+/* Set the target system */
+{
+ if (Arg == 0) {
+ NeedArg (Opt);
}
+ SetSys (Arg);
+}
+
+
+
+static void OptVerbose (const char* Opt, const char* Arg)
+/* Increase verbosity */
+{
+ ++Verbose;
}
-int main (int argc, char **argv)
+static void OptVersion (const char* Opt, const char* Arg)
+/* Print the assembler version */
{
- int i;
- char *argp;
- char out_name [256];
- char* p;
+ 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 },
+ { "--cpu", 1, OptCPU },
+ { "--debug", 0, OptDebug },
+ { "--debug-info", 0, OptDebugInfo },
+ { "--help", 0, OptHelp },
+ { "--include-dir", 1, OptIncludeDir },
+ { "--signed-chars", 0, OptSignedChars },
+ { "--static-locals", 0, OptStaticLocals },
+ { "--target", 1, OptTarget },
+ { "--verbose", 0, OptVerbose },
+ { "--version", 0, OptVersion },
+ };
+
+ int I;
/* Initialize the output file name */
- out_name [0] = '\0';
+ const char* OutputFile = 0;
+ const char* InputFile = 0;
- fin = NULL;
+ /* Initialize the cmdline module */
+ InitCmdLine (argc, argv, "cc65");
/* Parse the command line */
- for (i = 1; i < argc; i++) {
- if (*(argp = argv[i]) == '-') {
- switch (argp[1]) {
+ I = 1;
+ while (I < argc) {
+
+ const char* P;
+
+ /* Get the argument */
+ const char* Arg = argv [I];
- case 'd': /* debug mode */
- Debug = 1;
+ /* 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':
+ OutputFile = GetArg (&I, 2);
break;
case 't':
- SetSys (GetArg (&i, argv, 2));
+ OptTarget (Arg, GetArg (&I, 2));
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;
+ 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;
+ 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) {
+
+ /* Did we have a file spec on the command line? */
+ if (InputFile == 0) {
fprintf (stderr, "%s: No input files\n", argv [0]);
exit (EXIT_FAILURE);
}
- /* 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");
+ /* Open the input file */
+ OpenMainFile (InputFile);
+
+ /* Create the output file name if it was not explicitly given */
+ if (OutputFile == 0) {
+ OutputFile = MakeFilename (InputFile, ".s");
}
/* Go! */
}
/* Open the file */
- F = fopen (out_name, "w");
+ F = fopen (OutputFile, "w");
if (F == 0) {
Fatal (FAT_CANNOT_OPEN_OUTPUT, strerror (errno));
}
/* Close the file, check for errors */
if (fclose (F) != 0) {
- remove (out_name);
+ remove (OutputFile);
Fatal (FAT_CANNOT_WRITE_OUTPUT);
}
}
}
+