X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fca65%2Fmain.c;h=b029e2f0cc64b67255ec5102819d2143cf6c9f64;hb=1d458e9f33d442052a2921f0678efb4875d2e8ab;hp=063f467af1ebdf9bb2ed1929fef91b1908a0606d;hpb=522c7e8c46d0aae3b13885a769ca4a9e87e36733;p=cc65 diff --git a/src/ca65/main.c b/src/ca65/main.c index 063f467af..b029e2f0c 100644 --- a/src/ca65/main.c +++ b/src/ca65/main.c @@ -36,19 +36,29 @@ #include #include #include -#include #include -#include "../common/version.h" +/* common */ +#include "chartype.h" +#include "cmdline.h" +#include "print.h" +#include "target.h" +#include "tgttrans.h" +#include "version.h" +/* ca65 */ +#include "abend.h" #include "error.h" #include "expr.h" +#include "feature.h" +#include "filetab.h" #include "global.h" #include "incpath.h" #include "instr.h" +#include "istack.h" +#include "lineinfo.h" #include "listing.h" #include "macro.h" -#include "mem.h" #include "nexttok.h" #include "objcode.h" #include "objfile.h" @@ -73,10 +83,12 @@ static void Usage (void) "Usage: %s [options] file\n" "Short options:\n" " -g\t\t\tAdd debug info to object file\n" + " -h\t\t\tHelp (this text)\n" " -i\t\t\tIgnore case of symbols\n" " -l\t\t\tCreate a listing if assembly was ok\n" " -o name\t\tName the output file\n" " -s\t\t\tEnable smart mode\n" + " -t sys\t\tSet the target system\n" " -v\t\t\tIncrease verbosity\n" " -D name[=value]\tDefine a symbol\n" " -I dir\t\tSet an include directory search path\n" @@ -88,63 +100,17 @@ static void Usage (void) " --auto-import\t\tMark unresolved symbols as import\n" " --cpu type\t\tSet cpu type\n" " --debug-info\t\tAdd debug info to object file\n" + " --feature name\tSet an emulation feature\n" + " --help\t\tHelp (this text)\n" " --ignore-case\t\tIgnore case of symbols\n" " --include-dir dir\tSet an include directory search path\n" " --listing\t\tCreate a listing if assembly was ok\n" " --pagelength n\tSet the page length for the listing\n" " --smart\t\tEnable smart mode\n" + " --target sys\t\tSet the target system\n" " --verbose\t\tIncrease verbosity\n" " --version\t\tPrint the assembler version\n", ProgName); - exit (EXIT_FAILURE); -} - - - -static void UnknownOption (const char* Arg) -/* Print an error about an unknown option. Print usage information and exit */ -{ - fprintf (stderr, "Unknown option: %s\n", Arg); - Usage (); -} - - - -static void NeedArg (const char* Arg) -/* Print an error about a missing option argument and exit. */ -{ - fprintf (stderr, "Option requires an argument: %s\n", Arg); - exit (EXIT_FAILURE); -} - - - -static void InvSym (const char* Def) -/* Print an error about an invalid symbol definition and die */ -{ - fprintf (stderr, "Invalid symbol definition: `%s'\n", Def); - exit (EXIT_FAILURE); -} - - - -static const char* GetArg (int* ArgNum, char* argv [], unsigned Len) -/* Get an option argument */ -{ - const 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 */ - NeedArg (argv [*ArgNum]); - } - ++(*ArgNum); - return Arg; - } } @@ -173,14 +139,14 @@ static void DefineSymbol (const char* Def) char SymName [MAX_STR_LEN+1]; /* 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); } P = Def; /* Copy the symbol, checking the rest */ I = 0; - while (isalnum (*P) || *P == '_') { + while (IsAlNum (*P) || *P == '_') { if (I <= MAX_STR_LEN) { SymName [I++] = *P; } @@ -191,7 +157,7 @@ static void DefineSymbol (const char* Def) /* Do we have a value given? */ if (*P != '=') { if (*P != '\0') { - InvSym (Def); + InvDef (Def); } Val = 0; } else { @@ -200,19 +166,18 @@ static void DefineSymbol (const char* Def) if (*P == '$') { ++P; if (sscanf (P, "%lx", &Val) != 1) { - InvSym (Def); + InvDef (Def); } } else { if (sscanf (P, "%li", &Val) != 1) { - InvSym (Def); + InvDef (Def); } } } /* Check if have already a symbol with this name */ if (SymIsDef (SymName)) { - fprintf (stderr, "`%s' is already defined\n", SymName); - exit (EXIT_FAILURE); + AbEnd ("`%s' is already defined", SymName); } /* Define the symbol */ @@ -221,7 +186,7 @@ static void DefineSymbol (const char* Def) -static void OptAutoImport (const char* Opt) +static void OptAutoImport (const char* Opt, const char* Arg) /* Mark unresolved symbols as imported */ { AutoImport = 1; @@ -246,14 +211,13 @@ static void OptCPU (const char* Opt, const char* Arg) SetCPU (CPU_SUNPLUS); #endif } else { - fprintf (stderr, "Invalid CPU: `%s'\n", Arg); - exit (EXIT_FAILURE); + AbEnd ("Invalid CPU: `%s'", Arg); } } -static void OptDebugInfo (const char* Opt) +static void OptDebugInfo (const char* Opt, const char* Arg) /* Add debug info to the object file */ { DbgSyms = 1; @@ -261,7 +225,27 @@ static void OptDebugInfo (const char* Opt) -static void OptIgnoreCase (const char* Opt) +static void OptFeature (const char* Opt, const char* Arg) +/* Set an emulation feature */ +{ + /* Set the feature, check for errors */ + if (SetFeature (Arg) == FEAT_UNKNOWN) { + AbEnd ("Illegal emulation feature: `%s'", Arg); + } +} + + + +static void OptHelp (const char* Opt, const char* Arg) +/* Print usage information and exit */ +{ + Usage (); + exit (EXIT_SUCCESS); +} + + + +static void OptIgnoreCase (const char* Opt, const char* Arg) /* Ignore case on symbols */ { IgnoreCase = 1; @@ -280,7 +264,7 @@ static void OptIncludeDir (const char* Opt, const char* Arg) -static void OptListing (const char* Opt) +static void OptListing (const char* Opt, const char* Arg) /* Create a listing file */ { Listing = 1; @@ -297,15 +281,14 @@ static void OptPageLength (const char* Opt, const char* Arg) } Len = atoi (Arg); if (Len != -1 && (Len < MIN_PAGE_LEN || Len > MAX_PAGE_LEN)) { - fprintf (stderr, "Invalid page length: %d\n", Len); - exit (EXIT_FAILURE); + AbEnd ("Invalid page length: %d", Len); } PageLength = Len; } -static void OptSmart (const char* Opt) +static void OptSmart (const char* Opt, const char* Arg) /* Handle the -s/--smart options */ { SmartMode = 1; @@ -313,15 +296,31 @@ static void OptSmart (const char* Opt) -static void OptVerbose (const char* Opt) +static void OptTarget (const char* Opt, const char* Arg) +/* Set the target system */ +{ + if (Arg == 0) { + NeedArg (Opt); + } + + /* Map the target name to a target id */ + Target = FindTarget (Arg); + if (Target == TGT_UNKNOWN) { + AbEnd ("Invalid target name: `%s'", Arg); + } +} + + + +static void OptVerbose (const char* Opt, const char* Arg) /* Increase verbosity */ { - ++Verbose; + ++Verbosity; } -static void OptVersion (const char* Opt) +static void OptVersion (const char* Opt, const char* Arg) /* Print the assembler version */ { fprintf (stderr, @@ -331,37 +330,14 @@ static void OptVersion (const char* Opt) -static void LongOption (int* ArgNum, char* argv []) -/* Handle a long command line option */ +static void DoPCAssign (void) +/* Start absolute code */ { - const char* Opt = argv [*ArgNum]; - const char* Arg = argv [*ArgNum+1]; - - if (strcmp (Opt, "--auto-import") == 0) { - OptAutoImport (Opt); - } else if (strcmp (Opt, "--cpu") == 0) { - OptCPU (Opt, Arg); - ++(*ArgNum); - } else if (strcmp (Opt, "--debug-info") == 0) { - OptIgnoreCase (Opt); - } else if (strcmp (Opt, "--ignore-case") == 0) { - OptIgnoreCase (Opt); - } else if (strcmp (Opt, "--include-dir") == 0) { - OptIncludeDir (Opt, Arg); - ++(*ArgNum); - } else if (strcmp (Opt, "--listing") == 0) { - OptListing (Opt); - } else if (strcmp (Opt, "--pagelength") == 0) { - OptPageLength (Opt, Arg); - ++(*ArgNum); - } else if (strcmp (Opt, "--smart") == 0) { - OptSmart (Opt); - } else if (strcmp (Opt, "--verbose") == 0) { - OptVerbose (Opt); - } else if (strcmp (Opt, "--version") == 0) { - OptVersion (Opt); + long PC = ConstExpression (); + if (PC < 0 || PC > 0xFFFFFF) { + Error (ERR_RANGE); } else { - UnknownOption (Opt); + SetAbsPC (PC); } } @@ -373,86 +349,94 @@ static void OneLine (void) char Ident [MAX_STR_LEN+1]; int Done = 0; - /* Initialize the listing line */ - InitListingLine (); + /* Initialize the new listing line if we are actually reading from file + * and not from internally pushed input. + */ + if (!HavePushedInput ()) { + InitListingLine (); + } if (Tok == TOK_COLON) { - /* An unnamed label */ - ULabDef (); - NextTok (); + /* An unnamed label */ + ULabDef (); + NextTok (); } /* Assemble the line */ if (Tok == TOK_IDENT) { - /* Is it a macro? */ - if (IsMacro (SVal)) { + /* Is it a macro? */ + if (IsMacro (SVal)) { - /* Yes, start a macro expansion */ - MacExpandStart (); - Done = 1; + /* Yes, start a macro expansion */ + MacExpandStart (); + Done = 1; - } else { + } else { - /* No, label. Remember the identifier, then skip it */ - int HadWS = WS; /* Did we have whitespace before the ident? */ - strcpy (Ident, SVal); - NextTok (); + /* No, label. Remember the identifier, then skip it */ + int HadWS = WS; /* Did we have whitespace before the ident? */ + strcpy (Ident, SVal); + NextTok (); - /* If a colon follows, this is a label definition. If there - * is no colon, it's an assignment. - */ + /* If a colon follows, this is a label definition. If there + * is no colon, it's an assignment. + */ if (Tok == TOK_EQ) { - /* Skip the '=' */ - NextTok (); - /* Define the symbol with the expression following the - * '=' - */ - SymDef (Ident, Expression (), 0); - /* Don't allow anything after a symbol definition */ - Done = 1; - } else { - /* Define a label */ - SymDef (Ident, CurrentPC (), IsZPSeg ()); - /* Skip the colon. If NoColonLabels is enabled, allow labels - * without a colon if there is no whitespace before the - * identifier. - */ - if (Tok != TOK_COLON) { - if (HadWS || !NoColonLabels) { - Error (ERR_COLON_EXPECTED); - } - if (Tok == TOK_NAMESPACE) { - /* Smart :: handling */ - NextTok (); - } - } else { - /* Skip the colon */ - NextTok (); - } - } - } + /* Skip the '=' */ + NextTok (); + /* Define the symbol with the expression following the '=' */ + SymDef (Ident, Expression (), 0); + /* Don't allow anything after a symbol definition */ + Done = 1; + } else { + /* Define a label */ + SymDef (Ident, CurrentPC (), IsZPSeg ()); + /* Skip the colon. If NoColonLabels is enabled, allow labels + * without a colon if there is no whitespace before the + * identifier. + */ + if (Tok != TOK_COLON) { + if (HadWS || !NoColonLabels) { + Error (ERR_COLON_EXPECTED); + } + if (Tok == TOK_NAMESPACE) { + /* Smart :: handling */ + NextTok (); + } + } else { + /* Skip the colon */ + NextTok (); + } + } + } } if (!Done) { - if (TokIsPseudo (Tok)) { - /* A control command, IVal is index into table */ - HandlePseudo (); - } else if (Tok == TOK_MNEMO) { - /* A mnemonic - assemble one instruction */ - HandleInstruction (IVal); - } else if (Tok == TOK_IDENT && IsMacro (SVal)) { - /* A macro expansion */ - MacExpandStart (); + if (TokIsPseudo (Tok)) { + /* A control command, IVal is index into table */ + HandlePseudo (); + } else if (Tok == TOK_MNEMO) { + /* A mnemonic - assemble one instruction */ + HandleInstruction (IVal); + } else if (Tok == TOK_IDENT && IsMacro (SVal)) { + /* A macro expansion */ + MacExpandStart (); + } else if (PCAssignment && (Tok == TOK_STAR || Tok == TOK_PC)) { + NextTok (); + if (Tok != TOK_EQ) { + Error (ERR_EQ_EXPECTED); + SkipUntilSep (); + } else { + /* Skip the equal sign */ + NextTok (); + /* Enter absolute mode */ + DoPCAssign (); + } } } - /* Calling InitListingLine again here is part of a hack that introduces - * enough magic to make the PC output in the listing work. - */ - InitListingLine (); - /* Line separator must come here */ ConsumeSep (); } @@ -497,6 +481,9 @@ static void CreateObjFile (void) /* Write debug symbols if requested */ WriteDbgSyms (); + /* Write line infos if requested */ + WriteLineInfo (); + /* Write an updated header and close the file */ ObjClose (); } @@ -506,15 +493,27 @@ static void CreateObjFile (void) int main (int argc, char* argv []) /* Assembler main program */ { - int I; + /* Program long options */ + static const LongOpt OptTab[] = { + { "--auto-import", 0, OptAutoImport }, + { "--cpu", 1, OptCPU }, + { "--debug-info", 0, OptDebugInfo }, + { "--feature", 1, OptFeature }, + { "--help", 0, OptHelp }, + { "--ignore-case", 0, OptIgnoreCase }, + { "--include-dir", 1, OptIncludeDir }, + { "--listing", 0, OptListing }, + { "--pagelength", 1, OptPageLength }, + { "--smart", 0, OptSmart }, + { "--target", 1, OptTarget }, + { "--verbose", 0, OptVerbose }, + { "--version", 0, OptVersion }, + }; - /* Set the program name */ - ProgName = argv [0]; + int I; - /* We must have a file name */ - if (argc < 2) { - Usage (); - } + /* Initialize the cmdline module */ + InitCmdLine (&argc, &argv, "ca65"); /* Enter the base lexical level. We must do that here, since we may * define symbols using -D. @@ -523,61 +522,69 @@ int main (int argc, char* argv []) /* Check the parameters */ I = 1; - while (I < argc) { + while (I < ArgCount) { /* Get the argument */ - const char* Arg = argv [I]; + const char* Arg = ArgVec [I]; /* Check for an option */ if (Arg [0] == '-') { switch (Arg [1]) { case '-': - LongOption (&I, argv); + LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0])); break; - case 'g': - OptDebugInfo (Arg); + case 'g': + OptDebugInfo (Arg, 0); break; + case 'h': + OptHelp (Arg, 0); + break; + case 'i': - OptIgnoreCase (Arg); + OptIgnoreCase (Arg, 0); break; case 'l': - OptListing (Arg); + OptListing (Arg, 0); break; case 'o': - OutFile = GetArg (&I, argv, 2); + OutFile = GetArg (&I, 2); break; case 's': - OptSmart (Arg); + OptSmart (Arg, 0); break; + case 't': + OptTarget (Arg, GetArg (&I, 2)); + break; + case 'v': - OptVerbose (Arg); + OptVerbose (Arg, 0); break; case 'D': - DefineSymbol (GetArg (&I, argv, 2)); + DefineSymbol (GetArg (&I, 2)); break; case 'I': - OptIncludeDir (Arg, GetArg (&I, argv, 2)); + OptIncludeDir (Arg, GetArg (&I, 2)); break; case 'U': - OptAutoImport (Arg); + OptAutoImport (Arg, 0); break; case 'V': - OptVersion (Arg); + OptVersion (Arg, 0); break; case 'W': - WarnLevel = atoi (GetArg (&I, argv, 2)); + WarnLevel = atoi (GetArg (&I, 2)); break; default: @@ -588,10 +595,11 @@ int main (int argc, char* argv []) } else { /* Filename. Check if we already had one */ if (InFile) { - fprintf (stderr, "Don't know what to do with `%s'\n", Arg); - Usage (); + fprintf (stderr, "%s: Don't know what to do with `%s'\n", + ProgName, Arg); + exit (EXIT_FAILURE); } else { - InFile = Arg; + InFile = Arg; } } @@ -601,10 +609,13 @@ int main (int argc, char* argv []) /* Do we have an input file? */ if (InFile == 0) { - fprintf (stderr, "No input file\n"); + fprintf (stderr, "%s: No input files\n", ProgName); exit (EXIT_FAILURE); } + /* Intialize the target translation tables */ + TgtTranslateInit (); + /* Initialize the scanner, open the input file */ InitScanner (InFile); @@ -629,8 +640,11 @@ int main (int argc, char* argv []) SegCheck (); } + /* If we didn't have an errors, index the line infos */ + MakeLineInfoIndex (); + /* Dump the data */ - if (Verbose >= 2) { + if (Verbosity >= 2) { SymDump (stdout); SegDump (); }