#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
#include <time.h>
-#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"
#include "options.h"
"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"
" --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;
- }
}
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;
}
/* Do we have a value given? */
if (*P != '=') {
if (*P != '\0') {
- InvSym (Def);
+ InvDef (Def);
}
Val = 0;
} else {
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 */
-static void OptAutoImport (const char* Opt)
+static void OptAutoImport (const char* Opt, const char* Arg)
/* Mark unresolved symbols as imported */
{
AutoImport = 1;
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;
-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;
-static void OptListing (const char* Opt)
+static void OptListing (const char* Opt, const char* Arg)
/* Create a listing file */
{
Listing = 1;
}
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;
-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,
-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);
}
}
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 ();
}
/* Write debug symbols if requested */
WriteDbgSyms ();
+ /* Write line infos if requested */
+ WriteLineInfo ();
+
/* Write an updated header and close the file */
ObjClose ();
}
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.
/* 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);
+ case 'l':
+ 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:
} 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;
}
}
/* 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);
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 ();
}