]> git.sur5r.net Git - cc65/commitdiff
Support for preprocessing info file via cpp or m4.
authorAIDA Shinra <shinra@j10n.org>
Sun, 10 Jun 2018 16:53:35 +0000 (01:53 +0900)
committerAIDA Shinra <shinra@j10n.org>
Sun, 10 Jun 2018 16:53:35 +0000 (01:53 +0900)
doc/da65.sgml
src/da65/main.c
src/da65/scanner.c
src/da65/scanner.h

index a8e32e1c851aab07b74061d70a0b875a9b60dbce..df4b05060dbe52404a3c4897a790583f781ce5f4 100644 (file)
@@ -53,6 +53,7 @@ Short options:
   -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
 
@@ -70,6 +71,7 @@ Long options:
   --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
@@ -205,6 +207,17 @@ Here is a description of all the command line options:
   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>
 
@@ -299,9 +312,10 @@ anything). Each attribute is terminated by a semicolon.
 
 <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>
index 1454d01fb831bf1b3ff158bb874f072e85209f54..6ce5f32afb2288dfa2e3f78e67277f045c33a33d 100644 (file)
@@ -82,6 +82,7 @@ static void Usage (void)
             "  -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"
@@ -98,6 +99,7 @@ static void Usage (void)
             "  --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",
@@ -312,6 +314,15 @@ static void OptStartAddr (const char* Opt, const char* Arg)
 
 
 
+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 */
 {
@@ -539,6 +550,7 @@ int main (int argc, char* argv [])
         { "--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              },
@@ -589,6 +601,10 @@ int main (int argc, char* argv [])
                     OptStartAddr (Arg, GetArg (&I, 2));
                     break;
 
+                case 's':
+                    OptSyncLines (Arg, 0);
+                    break;
+
                 case 'V':
                     OptVersion (Arg, 0);
                     break;
index 8dc8d393a77fb389fa86fa87828b56ef938a4525..567b513485d69d8acd8a8be4886ab8bf350e241b 100644 (file)
@@ -41,6 +41,8 @@
 /* common */
 #include "chartype.h"
 #include "xsprintf.h"
+#include "xmalloc.h"
+#include "strbuf.h"
 
 /* ld65 */
 #include "global.h"
@@ -72,7 +74,10 @@ static int              C               = ' ';
 static unsigned         InputLine       = 1;
 static unsigned         InputCol        = 0;
 static FILE*            InputFile       = 0;
+static char*            InputSrcName    = 0;
 
+/* Options */
+unsigned char           InfoSyncLines   = 0;
 
 
 /*****************************************************************************/
@@ -91,7 +96,8 @@ void InfoWarning (const char* Format, ...)
     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);
 }
 
 
@@ -106,7 +112,9 @@ void InfoError (const char* Format, ...)
     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);
 }
 
 
@@ -149,17 +157,171 @@ static unsigned DigitVal (int C)
 
 
 
+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;
@@ -198,11 +360,7 @@ Again:
 
     /* Decimal number? */
     if (IsDigit (C)) {
-        InfoIVal = 0;
-        while (IsDigit (C)) {
-            InfoIVal = InfoIVal * 10 + DigitVal (C);
-            NextChar ();
-        }
+        InfoIVal = GetDecimalToken ();
         InfoTok = INFOTOK_INTCON;
         return;
     }
@@ -248,38 +406,31 @@ Again:
         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");
             }
@@ -288,8 +439,13 @@ Again:
             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) {
@@ -298,6 +454,21 @@ Again:
             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;
@@ -484,15 +655,19 @@ void InfoSetName (const char* Name)
 /* 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 */
 
 
 
index f7f090fad4ab56426c6307a096f4f39bcaa5b860..1dcecf68fc3295e860156afc18c8aeb46e64c03e 100644 (file)
@@ -137,6 +137,8 @@ extern long             InfoIVal;
 extern unsigned         InfoErrorLine;
 extern unsigned         InfoErrorCol;
 
+/* Options */
+extern unsigned char    InfoSyncLines;
 
 
 /*****************************************************************************/