-o name Name the output file
-v Increase verbosity
-F Add formfeeds to the output
+ -s Accept line markers in the info file
-S addr Set the start/load address
-V Print the disassembler version
--mnemonic-column n Specify mnemonic start column
--pagelength n Set the page length for the listing
--start-addr addr Set the start/load address
+ --sync-lines Accept line markers in the info file
--text-column n Specify text start column
--verbose Increase verbosity
--version Print the disassembler version
start address is specified, $10000 minus the size of the input file is used.
+ <label id="option--sync-lines">
+ <tag><tt>-s, --sync-lines</tt></tag>
+
+ Accept line markers in the info file in the following syntax:
+<tscreen><verb>
+#line <lineno> ["<filename>"]
+# <lineno> "<filename>" [<flag>] ...
+</verb></tscreen>
+ This option is intended for preprocessing info files with "cpp" or "m4".
+
+
<label id="option--text-column">
<tag><tt>--text-column n</tt></tag>
<sect1>Comments<p>
-Comments start with a hash mark (<tt/#/); and, extend from the position of
-the mark to the end of the current line. Hash marks inside of strings will
-<em/not/ start a comment, of course.
+Comments start with a hash mark (<tt/#/) or a double slashe (<tt>//</tt>);
+and, extend from the position of the mark to the end of the current line.
+Hash marks or double slashes inside of strings will <em/not/ start a comment,
+of course.
<sect1>Specifying global options<label id="global-options"><p>
" -v\t\t\tIncrease verbosity\n"
" -F\t\t\tAdd formfeeds to the output\n"
" -S addr\t\tSet the start/load address\n"
+ " -s\t\t\tAccept line markers in the info file\n"
" -V\t\t\tPrint the disassembler version\n"
"\n"
"Long options:\n"
" --mnemonic-column n\tSpecify mnemonic start column\n"
" --pagelength n\tSet the page length for the listing\n"
" --start-addr addr\tSet the start/load address\n"
+ " --sync-lines\t\tAccept line markers in the info file\n"
" --text-column n\tSpecify text start column\n"
" --verbose\t\tIncrease verbosity\n"
" --version\t\tPrint the disassembler version\n",
+static void OptSyncLines (const char* Opt attribute ((unused)),
+ const char* Arg attribute ((unused)))
+/* Handle the --sync-lines option */
+{
+ InfoSyncLines = 1;
+}
+
+
+
static void OptTextColumn (const char* Opt, const char* Arg)
/* Handle the --text-column option */
{
{ "--mnemonic-column", 1, OptMnemonicColumn },
{ "--pagelength", 1, OptPageLength },
{ "--start-addr", 1, OptStartAddr },
+ { "--sync-lines", 0, OptSyncLines },
{ "--text-column", 1, OptTextColumn },
{ "--verbose", 0, OptVerbose },
{ "--version", 0, OptVersion },
OptStartAddr (Arg, GetArg (&I, 2));
break;
+ case 's':
+ OptSyncLines (Arg, 0);
+ break;
+
case 'V':
OptVersion (Arg, 0);
break;
/* common */
#include "chartype.h"
#include "xsprintf.h"
+#include "xmalloc.h"
+#include "strbuf.h"
/* ld65 */
#include "global.h"
static unsigned InputLine = 1;
static unsigned InputCol = 0;
static FILE* InputFile = 0;
+static char* InputSrcName = 0;
+/* Options */
+unsigned char InfoSyncLines = 0;
/*****************************************************************************/
xvsprintf (Buf, sizeof (Buf), Format, ap);
va_end (ap);
- Warning ("%s(%u): %s", InfoFile, InfoErrorLine, Buf);
+ fprintf (stderr, "%s(%u): Warning: %s\n",
+ InputSrcName, InfoErrorLine, Buf);
}
xvsprintf (Buf, sizeof (Buf), Format, ap);
va_end (ap);
- Error ("%s(%u): %s", InfoFile, InfoErrorLine, Buf);
+ fprintf (stderr, "%s(%u): Error: %s\n",
+ InputSrcName, InfoErrorLine, Buf);
+ exit (EXIT_FAILURE);
}
+static void SkipBlanks (int SingleLine)
+{
+ while (C != EOF && (!SingleLine || C != '\n') && IsSpace (C)) {
+ NextChar ();
+ }
+}
+
+static long GetDecimalToken ()
+{
+ long Value = 0;
+
+ while (C != EOF && IsDigit (C)) {
+ Value = Value * 10 + DigitVal (C);
+ NextChar ();
+ }
+ return Value;
+}
+
+static int GetEncodedChar (char *Buf, unsigned *IPtr, unsigned Size)
+{
+ char Decoded = 0;
+ int Count;
+
+ if (C == EOF) {
+ return -1;
+ } else if (C != '\\') {
+ Decoded = C;
+ NextChar ();
+ goto Store;
+ }
+ NextChar (); /* consume '\\' */
+ if (C == EOF) {
+ return -1;
+ } else if (IsODigit (C)) {
+ Count = 3;
+ do {
+ Decoded = Decoded * 8 + DigitVal (C);
+ NextChar ();
+ --Count;
+ } while (Count > 0 && C != EOF && IsODigit (C));
+ } else if (C == 'x') {
+ NextChar (); /* consume 'x' */
+ Count = 2;
+ while (Count > 0 && C != EOF && IsXDigit (C)) {
+ Decoded = Decoded * 16 + DigitVal (C);
+ NextChar ();
+ --Count;
+ }
+ } else {
+ switch (C) {
+ case '"': case '\'': case '\\':
+ Decoded = C; break;
+ case 't': Decoded = '\t'; break;
+ case 'r': Decoded = '\r'; break;
+ case 'n': Decoded = '\n'; break;
+ default: return -1;
+ }
+ NextChar ();
+ }
+Store:
+ if (*IPtr < Size - 1) {
+ Buf [(*IPtr)++] = Decoded;
+ }
+ Buf [*IPtr] = 0;
+ return 0;
+}
+
+static void LineMarkerOrComment ()
+/* Handle a line beginning with '#'. Possible interpretations are:
+ * - #line <lineno> ["<filename>"] (C preprocessor input)
+ * - # <lineno> "<filename>" [<flag>]... (gcc preprocessor output)
+ * - #<comment>
+ */
+{
+ unsigned long LineNo = 0;
+ int LineDirective = 0;
+ StrBuf SrcNameBuf = AUTO_STRBUF_INITIALIZER;
+
+ /* Skip the first "# " */
+ NextChar ();
+ SkipBlanks (1);
+
+ /* Check "line" */
+ if (C == 'l') {
+ char MaybeLine [6];
+ unsigned I;
+ for (I = 0; I < sizeof MaybeLine - 1 && C != EOF && IsAlNum (C); ++I) {
+ MaybeLine [I] = C;
+ NextChar ();
+ }
+ MaybeLine [I] = 0;
+ if (strcmp (MaybeLine, "line") != 0) {
+ goto NotMarker;
+ }
+ LineDirective = 1;
+ SkipBlanks (1);
+ }
+
+ /* Get line number */
+ if (C == EOF || !IsDigit (C)) {
+ goto NotMarker;
+ }
+ LineNo = GetDecimalToken ();
+ SkipBlanks (1);
+
+ /* Get the source file name */
+ if (C != '\"') {
+ /* The source file name is missing */
+ if (LineDirective && C == '\n') {
+ /* got #line <lineno> */
+ NextChar ();
+ InputLine = LineNo;
+ goto Last;
+ } else {
+ goto NotMarker;
+ }
+ }
+ NextChar ();
+ while (C != EOF && C != '\n' && C != '\"') {
+ char DecodeBuf [2];
+ unsigned I = 0;
+ if (GetEncodedChar (DecodeBuf, &I, sizeof DecodeBuf) < 0) {
+ goto BadMarker;
+ }
+ SB_AppendBuf (&SrcNameBuf, DecodeBuf, I);
+ }
+ if (C != '\"') {
+ goto BadMarker;
+ }
+ NextChar ();
+
+ /* Ignore until the end of line */
+ while (C != EOF && C != '\n') {
+ NextChar ();
+ }
+
+ /* Accepted a line marker */
+ SB_Terminate (&SrcNameBuf);
+ xfree (InputSrcName);
+ InputSrcName = SB_GetBuf (&SrcNameBuf);
+ SB_Init (&SrcNameBuf);
+ InputLine = (unsigned)LineNo;
+ NextChar ();
+ goto Last;
+
+BadMarker:
+ InfoWarning ("Bad line marker");
+NotMarker:
+ while (C != EOF && C != '\n') {
+ NextChar ();
+ }
+ NextChar ();
+Last:
+ SB_Done (&SrcNameBuf);
+}
+
void InfoNextTok (void)
/* Read the next token from the input stream */
{
unsigned I;
- int Esc;
+ char DecodeBuf [2];
Again:
/* Skip whitespace */
- while (IsSpace (C)) {
- NextChar ();
- }
+ SkipBlanks (0);
/* Remember the current position */
InfoErrorLine = InputLine;
/* Decimal number? */
if (IsDigit (C)) {
- InfoIVal = 0;
- while (IsDigit (C)) {
- InfoIVal = InfoIVal * 10 + DigitVal (C);
- NextChar ();
- }
+ InfoIVal = GetDecimalToken ();
InfoTok = INFOTOK_INTCON;
return;
}
case '\"':
NextChar ();
I = 0;
- while (C != '\"') {
- Esc = (C == '\\');
- if (Esc) {
- NextChar ();
- }
- if (C == EOF || C == '\n') {
- InfoError ("Unterminated string");
- }
- if (Esc) {
- switch (C) {
- case '\"': C = '\"'; break;
- case '\'': C = '\''; break;
- default: InfoError ("Invalid escape char: %c", C);
+ while (C != EOF && C != '\"') {
+ if (GetEncodedChar (InfoSVal, &I, sizeof InfoSVal) < 0) {
+ if (C == EOF) {
+ InfoError ("Unterminated string");
+ } else {
+ InfoError ("Invalid escape char: %c", C);
}
}
- if (I < CFG_MAX_IDENT_LEN) {
- InfoSVal [I++] = C;
- }
- NextChar ();
}
- NextChar ();
- InfoSVal [I] = '\0';
+ if (C != '\"') {
+ InfoError ("Unterminated string");
+ }
+ NextChar ();
InfoTok = INFOTOK_STRCON;
break;
case '\'':
NextChar ();
- if (C == EOF || IsControl (C)) {
+ if (C == EOF || IsControl (C) || C == '\'') {
InfoError ("Invalid character constant");
}
- InfoIVal = C;
- NextChar ();
+ if (GetEncodedChar (DecodeBuf, &I, sizeof DecodeBuf) < 0 || I != 1) {
+ InfoError ("Invalid character constant");
+ }
+ InfoIVal = DecodeBuf [0];
if (C != '\'') {
InfoError ("Unterminated character constant");
}
break;
case '#':
- /* Comment */
- while (C != '\n' && C != EOF) {
+ /* # lineno "sourcefile" or # comment */
+ if (InfoSyncLines && InputCol == 1) {
+ LineMarkerOrComment ();
+ } else {
+ do {
+ NextChar ();
+ } while (C != EOF && C != '\n');
NextChar ();
}
if (C != EOF) {
InfoTok = INFOTOK_EOF;
break;
+ case '/':
+ /* C++ style comment */
+ NextChar ();
+ if (C != '/') {
+ InfoError ("Invalid token `/'");
+ }
+ do {
+ NextChar ();
+ } while (C != '\n' && C != EOF);
+ if (C != EOF) {
+ goto Again;
+ }
+ InfoTok = INFOTOK_EOF;
+ break;
+
case EOF:
InfoTok = INFOTOK_EOF;
break;
/* Set a name for a config file */
{
InfoFile = Name;
+ xfree(InputSrcName);
+ InputSrcName = xstrdup(Name);
}
+#ifdef unused
const char* InfoGetName (void)
/* Get the name of the config file */
{
return InfoFile? InfoFile : "";
}
+#endif /* unused */