]> git.sur5r.net Git - cc65/commitdiff
Redoing the pragma stuff
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sun, 29 Sep 2002 21:09:47 +0000 (21:09 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sun, 29 Sep 2002 21:09:47 +0000 (21:09 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@1413 b7a2c559-68d2-44c3-8de9-860c34a00d81

12 files changed:
src/cc65/asmstmt.c
src/cc65/hexval.c [new file with mode: 0644]
src/cc65/hexval.h [new file with mode: 0644]
src/cc65/make/gcc.mak
src/cc65/make/watcom.mak
src/cc65/pragma.c
src/cc65/pragma.h
src/cc65/preproc.c
src/cc65/scanner.c
src/cc65/scanner.h
src/cc65/scanstrbuf.c [new file with mode: 0644]
src/cc65/scanstrbuf.h [new file with mode: 0644]

index 25ab944fcdf4df5d50948f19ef146478ba4f6039..f3bad160136462909984009a76fa84b76659dd97 100644 (file)
@@ -373,7 +373,9 @@ void AsmStatement (void)
     NextToken ();
 
     /* Need left parenthesis */
-    ConsumeLParen ();
+    if (!ConsumeLParen ()) {
+        return;
+    }
 
     /* String literal */
     if (CurTok.Tok != TOK_SCONST) {
diff --git a/src/cc65/hexval.c b/src/cc65/hexval.c
new file mode 100644 (file)
index 0000000..21c8ef8
--- /dev/null
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                   hexval.c                                */
+/*                                                                           */
+/*                     Convert hex digits to numeric values                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2002      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@cc65.org                                                 */
+/*                                                                           */
+/*                                                                           */
+/* 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.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+/* common */
+#include "chartype.h"
+
+/* cc65 */
+#include "error.h"
+#include "hexval.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned HexVal (int C)
+/* Convert a hex digit into a value. The function will emit an error for
+ * invalid hex digits.
+ */
+{
+    if (!IsXDigit (C)) {
+       Error ("Invalid hexadecimal digit: `%c'", C);
+    }
+    if (IsDigit (C)) {
+       return C - '0';
+    } else {
+               return toupper (C) - 'A' + 10;
+    }
+}
+
+
+
diff --git a/src/cc65/hexval.h b/src/cc65/hexval.h
new file mode 100644 (file)
index 0000000..edba95b
--- /dev/null
@@ -0,0 +1,60 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                   hexval.h                                */
+/*                                                                           */
+/*                     Convert hex digits to numeric values                  */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2002      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@cc65.org                                                 */
+/*                                                                           */
+/*                                                                           */
+/* 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.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef HEXVAL_H
+#define HEXVAL_H
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+unsigned HexVal (int C);
+/* Convert a hex digit into a value. The function will emit an error for 
+ * invalid hex digits.
+ */
+
+
+
+/* End of hexval.h */
+#endif
+
+
+
+
+
index a22ae93e5f6fd8ff08e59eafde69f1dee71be295..9d33f33870ad6e6efbba17abfb1870ccf49533a4 100644 (file)
@@ -56,6 +56,7 @@ OBJS =        anonname.o      \
        function.o      \
        global.o        \
        goto.o          \
+        hexval.o        \
        ident.o         \
        incpath.o       \
        input.o         \
@@ -70,6 +71,7 @@ OBJS =        anonname.o      \
        pragma.o        \
        reginfo.o       \
        scanner.o       \
+        scanstrbuf.o    \
        segments.o      \
        stdfunc.o       \
        stmt.o          \
index 5fb562d4ca2bff906e72839261d7bc070cc96932..72bb310877315b7ff66bac45cc3e9269140de008 100644 (file)
@@ -101,6 +101,7 @@ OBJS =      anonname.obj    \
        function.obj    \
        global.obj      \
        goto.obj        \
+        hexval.obj      \
        ident.obj       \
        incpath.obj     \
        input.obj       \
@@ -115,6 +116,7 @@ OBJS =      anonname.obj    \
        pragma.obj      \
        reginfo.obj     \
        scanner.obj     \
+        scanstrbuf.obj  \
        segments.obj    \
        stdfunc.obj     \
        stmt.obj        \
@@ -179,7 +181,8 @@ FILE exprnode.obj
 FILE funcdesc.obj
 FILE function.obj
 FILE global.obj
-FILE goto.obj
+FILE goto.obj            
+FILE hexval.obj
 FILE ident.obj
 FILE incpath.obj
 FILE input.obj
@@ -194,6 +197,7 @@ FILE preproc.obj
 FILE pragma.obj
 FILE reginfo.obj
 FILE scanner.obj
+FILE scanstrbuf.obj
 FILE segments.obj
 FILE stdfunc.obj
 FILE stmt.obj
index 5103063c32ad11b16dd20621473d4788c1def29a..21203944f731f814ab4b2e6c5b33bf060f248387 100644 (file)
@@ -46,6 +46,7 @@
 #include "global.h"
 #include "litpool.h"
 #include "scanner.h"
+#include "scanstrbuf.h"
 #include "segments.h"
 #include "symtab.h"
 #include "pragma.h"
@@ -70,7 +71,7 @@ typedef enum {
     PR_RODATASEG,
     PR_SIGNEDCHARS,
     PR_STATICLOCALS,
-    PR_ZPSYM,      
+    PR_ZPSYM,
     PR_COUNT
 } pragma_t;
 
@@ -99,6 +100,17 @@ static const struct Pragma {
 
 
 
+static void PragmaErrorSkip (void)
+/* Called in case of an error, skips tokens until the closing paren or a
+ * semicolon is reached.
+ */
+{
+    static const token_t TokenList[] = { TOK_RPAREN, TOK_SEMI };
+    SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
+}
+
+
+
 static int CmpKey (const void* Key, const void* Elem)
 /* Compare function for bsearch */
 {
@@ -119,36 +131,30 @@ static pragma_t FindPragma (const char* Key)
 
 
 
-static void StringPragma (void (*Func) (const char*))
+static void StringPragma (StrBuf* B, void (*Func) (const char*))
 /* Handle a pragma that expects a string parameter */
 {
-    if (CurTok.Tok != TOK_SCONST) {
-       Error ("String literal expected");
-    } else {
-       /* Get the string */
-       const char* Name = GetLiteral (CurTok.IVal);
+    StrBuf S;
 
+    if (SB_GetString (B, &S)) {
                /* Call the given function with the string argument */
-       Func (Name);
-
-       /* Reset the string pointer, removing the string from the pool */
-       ResetLiteralPoolOffs (CurTok.IVal);
+       Func (SB_GetConstBuf (&S));
+    } else {
+       Error ("String literal expected");
     }
-
-    /* Skip the string (or error) token */
-    NextToken ();
 }
 
 
 
-static void SegNamePragma (segment_t Seg)
+static void SegNamePragma (StrBuf* B, segment_t Seg)
 /* Handle a pragma that expects a segment name parameter */
 {
-    if (CurTok.Tok != TOK_SCONST) {
-       Error ("String literal expected");
-    } else {
-       /* Get the segment name */
-       const char* Name = GetLiteral (CurTok.IVal);
+    StrBuf S;
+
+    if (SB_GetString (B, &S)) {
+
+        /* Get the string */
+        const char* Name = SB_GetConstBuf (&S);
 
        /* Check if the name is valid */
        if (ValidSegName (Name)) {
@@ -163,17 +169,14 @@ static void SegNamePragma (segment_t Seg)
 
        }
 
-       /* Reset the string pointer, removing the string from the pool */
-       ResetLiteralPoolOffs (CurTok.IVal);
+    } else {
+       Error ("String literal expected");
     }
-
-    /* Skip the string (or error) token */
-    NextToken ();
 }
 
 
 
-static void CharMapPragma (void)
+static void CharMapPragma (StrBuf* B)
 /* Change the character map */
 {
     unsigned Index, C;
@@ -207,36 +210,61 @@ static void CharMapPragma (void)
 
 
 
-static void FlagPragma (unsigned char* Flag)
+static void FlagPragma (StrBuf* B, unsigned char* Flag)
 /* Handle a pragma that expects a boolean paramater */
 {
-    /* Read a constant integer expression */
-    ExprDesc Val;
-    ConstIntExpr (&Val);
-
-    /* Store the value into the flag parameter */
-    *Flag = (Val.ConstVal != 0);
+    ident Ident;
+
+    if (SB_Peek (B) == '0') {
+        SB_Skip (B);
+        *Flag = 0;
+    } else if (SB_Peek (B) == '1') {
+        SB_Skip (B);
+        *Flag = 1;
+    } else if (SB_GetSym (B, Ident)) {
+        if (strcmp (Ident, "true") == 0 || strcmp (Ident, "on") == 0) {
+            *Flag = 1;
+        } else if (strcmp (Ident, "false") == 0 || strcmp (Ident, "off") == 0) {
+            *Flag = 0;
+        } else {
+            Error ("Pragma argument must be one of `on', `off', `true' or `false'");
+        }
+    } else {
+        Error ("Invalid pragma argument");
+    }
 }
 
 
 
-void DoPragma (void)
-/* Handle pragmas */
+static void ParsePragma (void)
+/* Parse the contents of the _Pragma statement */
 {
     pragma_t Pragma;
+    ident    Ident;
 
-    /* Skip the token itself */
+    /* Create a string buffer from the string literal */
+    StrBuf B = AUTO_STRBUF_INITIALIZER;
+    GetLiteralStrBuf (&B, CurTok.IVal);
+
+    /* Reset the string pointer, effectivly clearing the string from the
+     * string table. Since we're working with one token lookahead, this
+     * will fail if the next token is also a string token, but that's a
+     * syntax error anyway, because we expect a right paren.
+     */
+    ResetLiteralPoolOffs (CurTok.IVal);
+
+    /* Skip the string token */
     NextToken ();
 
-    /* Identifier must follow */
-    if (CurTok.Tok != TOK_IDENT) {
-       Error ("Identifier expected");
-       return;
+    /* Get the pragma name from the string */
+    SB_SkipWhite (&B);
+    if (!SB_GetSym (&B, Ident)) {
+        Error ("Invalid pragma");
+        return;
     }
 
-    /* Search for the name, then skip the identifier */
-    Pragma = FindPragma (CurTok.Ident);
-    NextToken ();
+    /* Search for the name */
+    Pragma = FindPragma (Ident);
 
     /* Do we know this pragma? */
     if (Pragma == PR_ILLEGAL) {
@@ -244,60 +272,111 @@ void DoPragma (void)
                 * for unknown pragmas, however, we're allowed to warn - and we will
                 * do so. Otherwise one typo may give you hours of bug hunting...
                 */
-               Warning ("Unknown #pragma `%s'", CurTok.Ident);
+               Warning ("Unknown pragma `%s'", Ident);
                return;
     }
 
     /* Check for an open paren */
-    ConsumeLParen ();
+    SB_SkipWhite (&B);
+    if (SB_Get (&B) != '(') {
+        Error ("'(' expected");
+        return;
+    }
+
+    /* Skip white space before the argument */
+    SB_SkipWhite (&B);
 
     /* Switch for the different pragmas */
     switch (Pragma) {
 
-       case PR_BSSSEG:
-           SegNamePragma (SEG_BSS);
-           break;
+       case PR_BSSSEG:
+           SegNamePragma (&B, SEG_BSS);
+           break;
 
-       case PR_CHARMAP:
-           CharMapPragma ();
-           break;
+       case PR_CHARMAP:
+           CharMapPragma (&B);
+           break;
 
-       case PR_CHECKSTACK:
-           FlagPragma (&CheckStack);
-           break;
+       case PR_CHECKSTACK:
+           FlagPragma (&B, &CheckStack);
+           break;
 
-       case PR_CODESEG:
-           SegNamePragma (SEG_CODE);
-           break;
+       case PR_CODESEG:
+           SegNamePragma (&B, SEG_CODE);
+           break;
 
-       case PR_DATASEG:
-           SegNamePragma (SEG_DATA);
-           break;
+       case PR_DATASEG:
+           SegNamePragma (&B, SEG_DATA);
+           break;
 
-       case PR_REGVARADDR:
-           FlagPragma (&AllowRegVarAddr);
-           break;
+       case PR_REGVARADDR:
+           FlagPragma (&B, &AllowRegVarAddr);
+           break;
 
-       case PR_RODATASEG:
-           SegNamePragma (SEG_RODATA);
-           break;
+       case PR_RODATASEG:
+           SegNamePragma (&B, SEG_RODATA);
+           break;
 
-       case PR_SIGNEDCHARS:
-           FlagPragma (&SignedChars);
-           break;
+       case PR_SIGNEDCHARS:
+           FlagPragma (&B, &SignedChars);
+           break;
 
-       case PR_STATICLOCALS:
-           FlagPragma (&StaticLocals);
-           break;
+       case PR_STATICLOCALS:
+           FlagPragma (&B, &StaticLocals);
+           break;
 
-       case PR_ZPSYM:
-           StringPragma (MakeZPSym);
-           break;
+       case PR_ZPSYM:
+           StringPragma (&B, MakeZPSym);
+           break;
 
-       default:
+       default:
                    Internal ("Invalid pragma");
     }
 
+    /* Closing paren expected */
+    SB_SkipWhite (&B);
+    if (SB_Get (&B) != ')') {
+        Error ("')' expected");
+        return;
+    }
+
+    /* Make sure nothing follows */
+    SB_SkipWhite (&B);
+    if (SB_Peek (&B) != '\0') {
+        Error ("Unexpected input following pragma directive");
+    }
+}
+
+
+
+void DoPragma (void)
+/* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */
+{
+    /* Skip the token itself */
+    NextToken ();
+
+    /* We expect an opening paren */
+    if (!ConsumeLParen ()) {
+       return;
+    }
+
+    /* String literal */
+    if (CurTok.Tok != TOK_SCONST) {
+
+       /* Print a diagnostic */
+       Error ("String literal expected");
+
+       /* Try some smart error recovery: Skip tokens until we reach the
+        * enclosing paren, or a semicolon.
+        */
+               PragmaErrorSkip ();
+
+    } else {
+
+       /* Parse the _Pragma statement */
+       ParsePragma ();
+    }
+
     /* Closing paren needed */
     ConsumeRParen ();
 }
index 82026b35c465756f274140c4976c865607659935..86ef28697bbcac8993128e5157e9235b26f6a7d9 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2001 Ullrich von Bassewitz                                       */
+/* (C) 1998-2002 Ullrich von Bassewitz                                       */
 /*               Wacholderweg 14                                             */
 /*               D-70597 Stuttgart                                           */
 /* EMail:        uz@cc65.org                                                 */
 
 
 /*****************************************************************************/
-/*                                  code                                    */
+/*                                  Code                                    */
 /*****************************************************************************/
 
 
 
 void DoPragma (void);
-/* Handle pragmas */
+/* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */
 
 
 
index 67aaeee62170e541059aeed2e5aa013924103073..60c8417e88dda5b5010f228154a42ad0b6ae81c6 100644 (file)
@@ -9,6 +9,7 @@
 /* common */
 #include "chartype.h"
 #include "check.h"
+#include "inline.h"
 #include "print.h"
 #include "xmalloc.h"
 
@@ -62,9 +63,6 @@ static char mlinebuf [LINESIZE];
 static char* mline = mlinebuf;
 static char* mptr;
 
-/* Flag: Expand macros in this line */
-static int ExpandMacros = 1;
-
 
 
 /*****************************************************************************/
@@ -142,15 +140,19 @@ static pptoken_t FindPPToken (const char* Ident)
 
 
 
-static void keepch (char c)
+#ifdef HAVE_INLINE
+INLINE void KeepChar (char c)
 /* Put character c into translation buffer. */
 {
     *mptr++ = c;
 }
+#else
+#define KeepChar(c)     *mptr++ = (c)
+#endif
 
 
 
-static void keepstr (const char* S)
+static void KeepStr (const char* S)
 /* Put string str into translation buffer. */
 {
     unsigned Len = strlen (S);
@@ -160,6 +162,43 @@ static void keepstr (const char* S)
 
 
 
+static void Stringize (const char* S)
+/* Stringize the given string: Add double quotes at start and end and preceed
+ * each occurance of " and \ by a backslash.
+ */
+{
+    KeepChar ('\"');
+    /* Replace any characters inside the string may not be part of a string
+     * unescaped.
+     */
+    while (*S) {
+        switch (*S) {
+            case '\"':
+            case '\\':
+                KeepChar ('\\');
+            /* FALLTHROUGH */
+            default:
+                KeepChar (*S);
+                break;
+        }
+        ++S;
+    }
+    KeepChar ('\"');
+}
+
+
+
+static void SwapLineBuffers (void)
+/* Swap both line buffers */
+{
+    /* Swap mline and line */
+    char* p = line;
+    line = mline;
+    mline = p;
+}
+
+
+
 static void OldStyleComment (void)
 /* Remove an old style C comment from line. */
 {
@@ -236,7 +275,7 @@ static char* CopyQuotedString (char* Target)
     /* Copy the characters inside the string */
     while (CurC != '\0' && CurC != Quote) {
                /* Keep an escaped char */
-       if (CurC == '\\') {
+       if (CurC == '\\') {
            *Target++ = CurC;
            NextChar ();
        }
@@ -298,41 +337,27 @@ static void ExpandMacroArgs (Macro* M)
            Replacement = FindMacroArg (M, Ident);
            if (Replacement) {
                /* Macro arg, keep the replacement */
-               keepstr (Replacement);
+               KeepStr (Replacement);
            } else {
                /* No macro argument, keep the original identifier */
-               keepstr (Ident);
+               KeepStr (Ident);
            }
        } else if (CurC == '#' && IsIdent (NextC)) {
                    NextChar ();
            SymName (Ident);
            Replacement = FindMacroArg (M, Ident);
                    if (Replacement) {
-               keepch ('\"');
-                /* We have to escape any characters inside replacement that
-                 * may not be part of a string unescaped.
-                 */
-                while (*Replacement) {
-                    switch (*Replacement) {
-                        case '\"':
-                        case '\\':
-                            keepch ('\\');
-                        /* FALLTHROUGH */
-                        default:
-                            keepch (*Replacement);
-                            break;
-                    }
-                    ++Replacement;
-                }
-               keepch ('\"');
+                /* Make a valid string from Replacement */
+                Stringize (Replacement);
            } else {
-               keepch ('#');
-               keepstr (Ident);
+                /* No replacement - keep the input */
+               KeepChar ('#');
+               KeepStr (Ident);
            }
        } else if (IsQuote (CurC)) {
            mptr = CopyQuotedString (mptr);
        } else {
-           *mptr++ = CurC;
+           KeepChar (CurC);
            NextChar ();
        }
     }
@@ -408,7 +433,7 @@ static int MacroCall (Macro* M)
                    --ParCount;
                }
                *B++ = CurC;
-               NextChar ();
+               NextChar ();
            }
        } else if (IsBlank (CurC)) {
            /* Squeeze runs of blanks */
@@ -461,7 +486,7 @@ static void ExpandMacro (Macro* M)
        }
     } else {
        /* Just copy the replacement text */
-       keepstr (M->Replacement);
+       KeepStr (M->Replacement);
     }
 }
 
@@ -570,7 +595,7 @@ static int Pass1 (const char* From, char* To)
     done = 1;
     while (CurC != '\0') {
        if (IsBlank (CurC)) {
-           keepch (' ');
+           KeepChar (' ');
            SkipBlank ();
                } else if (IsIdent (CurC)) {
            SymName (Ident);
@@ -585,15 +610,15 @@ static int Pass1 (const char* From, char* To)
                }
                if (!IsIdent (CurC)) {
                    PPError ("Identifier expected");
-                   *mptr++ = '0';
+                   KeepChar ('0');
                } else {
                    SymName (Ident);
-                   *mptr++ = IsMacro (Ident)? '1' : '0';
+                   KeepChar (IsMacro (Ident)? '1' : '0');
                    if (HaveParen) {
                        SkipBlank();
                        if (CurC != ')') {
                            PPError ("`)' expected");
-                       } else {
+                       } else {
                            NextChar ();
                        }
                    }
@@ -602,22 +627,22 @@ static int Pass1 (const char* From, char* To)
                if (MaybeMacro (Ident[0])) {
                    done = 0;
                }
-               keepstr (Ident);
+               KeepStr (Ident);
            }
        } else if (IsQuote (CurC)) {
            mptr = CopyQuotedString (mptr);
        } else if (CurC == '/' && NextC == '*') {
-           keepch (' ');
+           KeepChar (' ');
            OldStyleComment ();
        } else if (ANSI == 0 && CurC == '/' && NextC == '/') {
-           keepch (' ');
+           KeepChar (' ');
            NewStyleComment ();
        } else {
-           *mptr++ = CurC;
+           KeepChar (CurC);
            NextChar ();
        }
     }
-    keepch ('\0');
+    KeepChar ('\0');
     return done;
 }
 
@@ -639,7 +664,7 @@ static int Pass2 (const char* From, char* To)
     /* Loop substituting macros */
     no_chg = 1;
     while (CurC != '\0') {
-       /* If we have an identifier, check if it's a macro */
+       /* If we have an identifier, check if it's a macro */
        if (IsIdent (CurC)) {
            SymName (Ident);
            M = FindMacro (Ident);
@@ -647,12 +672,12 @@ static int Pass2 (const char* From, char* To)
                ExpandMacro (M);
                no_chg = 0;
            } else {
-               keepstr (Ident);
+               KeepStr (Ident);
            }
        } else if (IsQuote (CurC)) {
            mptr = CopyQuotedString (mptr);
        } else {
-           *mptr++ = CurC;
+           KeepChar (CurC);
            NextChar ();
        }
     }
@@ -661,28 +686,28 @@ static int Pass2 (const char* From, char* To)
 
 
 
-static void TranslateLine (void)
+static void PreprocessLine (void)
 /* Translate one line. */
 {
-    int cnt;
-    int Done;
+    unsigned I;
 
-    Done = Pass1 (line, mline);
-    if (ExpandMacros == 0) {
-       Done = 1;
-       ExpandMacros = 1;       /* Reset to default */
-    }
-    cnt = 5;
-    do {
+    /* Trim whitespace and remove comments. The function returns false if no
+     * identifiers were found that may be macros. If this is the case, no
+     * macro substitution is performed.
+     */
+    int Done = Pass1 (line, mline);
+
+    /* Repeatedly expand macros in the line */
+    for (I = 0; I < 5; ++I) {
        /* Swap mline and line */
-               char* p = line;
-       line = mline;
-       mline = p;
-       if (Done)
-           break;
-       Done = Pass2 (line, mline);
-       keepch ('\0');
-    } while (--cnt);
+        SwapLineBuffers ();
+       if (Done) {
+           break;
+        }
+        /* Perform macro expansion */
+       Done = Pass2 (line, mline);
+       KeepChar ('\0');
+    }
 
     /* Reinitialize line parsing */
     InitLine (line);
@@ -741,18 +766,18 @@ static int DoIf (int Skip)
 
     /* Make sure the line infos for the tokens won't get removed */
     if (sv1.LI) {
-       UseLineInfo (sv1.LI);
+       UseLineInfo (sv1.LI);
     }
     if (sv2.LI) {
-       UseLineInfo (sv2.LI);
+       UseLineInfo (sv2.LI);
     }
 
     /* Remove the #if from the line and add two semicolons as sentinels */
     SkipBlank ();
     S = line;
     while (CurC != '\0') {
-       *S++ = CurC;
-       NextChar ();
+       *S++ = CurC;
+       NextChar ();
     }
     *S++ = ';';
     *S++ = ';';
@@ -765,7 +790,7 @@ static int DoIf (int Skip)
     Preprocessing = 1;
 
     /* Expand macros in this line */
-    TranslateLine ();
+    PreprocessLine ();
 
     /* Prime the token pump (remove old tokens from the stream) */
     NextToken ();
@@ -838,7 +863,7 @@ static void DoInclude (void)
      */
     mptr = mline;
     while (CurC != '\0' && CurC != RTerm) {
-       *mptr++ = CurC;
+       KeepChar (CurC);
        NextChar ();
     }
     *mptr = '\0';
@@ -878,11 +903,35 @@ static void DoError (void)
 
 
 
+static void DoPragma (void)
+/* Handle a #pragma line by converting the #pragma preprocessor directive into
+ * the _Pragma() compiler operator.
+ */
+{
+    /* Skip blanks following the #pragma directive */
+    SkipBlank ();
+
+    /* Copy the remainder of the line into mline removing comments and ws */
+    Pass1 (lptr, mline);
+
+    /* Convert the directive into the operator */
+    mptr = line;
+    KeepStr ("_Pragma (");
+    Stringize (mline);
+    KeepChar (')');
+    *mptr = '\0';
+
+    /* Initialize reading from line */
+    InitLine (line);
+}
+
+
+
 void Preprocess (void)
 /* Preprocess a line */
 {
-    int        Skip;
-    ident      Directive;
+    int        Skip;
+    ident      Directive;
 
     /* Skip white space at the beginning of the line */
     SkipBlank ();
@@ -911,22 +960,22 @@ void Preprocess (void)
                                }
                                break;
 
-                   case PP_ELIF:
-                       if (IfIndex >= 0) {
-                           if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {
-
-                               /* Handle as #else/#if combination */
-                               if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
-                                   Skip = !Skip;
-                               }
-                               IfStack[IfIndex] |= IFCOND_ELSE;
-                               Skip = DoIf (Skip);
-
-                               /* #elif doesn't need a terminator */
-                               IfStack[IfIndex] &= ~IFCOND_NEEDTERM;
-                           } else {
-                               PPError ("Duplicate #else/#elif");
-                           }
+                   case PP_ELIF:
+                       if (IfIndex >= 0) {
+                           if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {
+
+                               /* Handle as #else/#if combination */
+                               if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
+                                   Skip = !Skip;
+                               }
+                               IfStack[IfIndex] |= IFCOND_ELSE;
+                               Skip = DoIf (Skip);
+
+                               /* #elif doesn't need a terminator */
+                               IfStack[IfIndex] &= ~IFCOND_NEEDTERM;
+                           } else {
+                               PPError ("Duplicate #else/#elif");
+                           }
                        } else {
                            PPError ("Unexpected #elif");
                        }
@@ -952,7 +1001,7 @@ void Preprocess (void)
                            /* Remove any clauses on top of stack that do not
                             * need a terminating #endif.
                             */
-                           while (IfIndex >= 0 && (IfStack[IfIndex] & IFCOND_NEEDTERM) == 0) {
+                           while (IfIndex >= 0 && (IfStack[IfIndex] & IFCOND_NEEDTERM) == 0) {
                                --IfIndex;
                            }
 
@@ -991,20 +1040,18 @@ void Preprocess (void)
                        break;
 
                            case PP_LINE:
-                       /* Not allowed in strict ANSI mode */
+                       /* Not allowed in strict ANSI mode */
                        if (!Skip && ANSI) {
                            PPError ("Preprocessor directive expected");
                            ClearLine ();
-                       }
-                       break;
+                       }
+                       break;
 
                            case PP_PRAGMA:
-                       if (!Skip) {
-                           /* Don't expand macros in this line */
-                           ExpandMacros = 0;
-                           /* #pragma is handled on the scanner level */
-                           goto Done;
-                       }
+                       if (!Skip) {
+                            DoPragma ();
+                            goto Done;
+                       }
                        break;
 
                            case PP_UNDEF:
@@ -1017,7 +1064,7 @@ void Preprocess (void)
                        PPError ("Preprocessor directive expected");
                        ClearLine ();
                }
-           }
+           }
 
        }
        if (NextLine () == 0) {
@@ -1026,11 +1073,12 @@ void Preprocess (void)
            }
            return;
        }
-       SkipBlank ();
+       SkipBlank ();
     }
 
+    PreprocessLine ();
+
 Done:
-    TranslateLine ();
     Print (stdout, 2, "line: %s\n", line);
 }
 
index 6de50ed32873da8a4e14b57ea30f026922886650..b6321780e21f346c3b5355b4fd99da84d3f681e4 100644 (file)
@@ -48,6 +48,7 @@
 #include "error.h"
 #include "function.h"
 #include "global.h"
+#include "hexval.h"
 #include "ident.h"
 #include "input.h"
 #include "litpool.h"
@@ -79,6 +80,7 @@ static const struct Keyword {
     unsigned char   Tok;       /* The token */
     unsigned char   Type;              /* Token type */
 } Keywords [] = {
+    { "_Pragma",        TOK_PRAGMA,     TT_C    },
     { "__A__",         TOK_A,          TT_C    },
     { "__AX__",                TOK_AX,         TT_C    },
     { "__EAX__",               TOK_EAX,        TT_C    },
@@ -226,21 +228,6 @@ static void UnknownChar (char C)
 
 
 
-static unsigned HexVal (int c)
-/* Convert a hex digit into a value */
-{
-    if (!IsXDigit (c)) {
-       Error ("Invalid hexadecimal digit: `%c'", c);
-    }
-    if (IsDigit (c)) {
-       return c - '0';
-    } else {
-               return toupper (c) - 'A' + 10;
-    }
-}
-
-
-
 static void SetTok (int tok)
 /* Set NextTok.Tok and bump line ptr */
 {
@@ -780,18 +767,6 @@ void NextToken (void)
            SetTok (TOK_COMP);
            break;
 
-        case '#':
-           /* Skip it and following whitespace */
-           do {
-               NextChar ();
-           } while (CurC == ' ');
-           if (!IsSym (token) || strcmp (token, "pragma") != 0) {
-               /* OOPS - should not happen */
-               Error ("Preprocessor directive expected");
-           }
-           NextTok.Tok = TOK_PRAGMA;
-           break;
-
        default:
                    UnknownChar (CurC);
 
@@ -825,104 +800,110 @@ void SkipTokens (const token_t* TokenList, unsigned TokenCount)
 
 
 
-void Consume (token_t Token, const char* ErrorMsg)
+int Consume (token_t Token, const char* ErrorMsg)
 /* Eat token if it is the next in the input stream, otherwise print an error
- * message.
+ * message. Returns true if the token was found and false otherwise.
  */
 {
     if (CurTok.Tok == Token) {
        NextToken ();
+        return 1;
     } else {
                Error (ErrorMsg);
+        return 0;
     }
 }
 
 
 
-void ConsumeColon (void)
+int ConsumeColon (void)
 /* Check for a colon and skip it. */
 {
-    Consume (TOK_COLON, "`:' expected");
+    return Consume (TOK_COLON, "`:' expected");
 }
 
 
 
-void ConsumeSemi (void)
+int ConsumeSemi (void)
 /* Check for a semicolon and skip it. */
 {
     /* Try do be smart about typos... */
     if (CurTok.Tok == TOK_SEMI) {
-       NextToken ();
+       NextToken ();
+        return 1;
     } else {
        Error ("`;' expected");
        if (CurTok.Tok == TOK_COLON || CurTok.Tok == TOK_COMMA) {
            NextToken ();
        }
+        return 0;
     }
 }
 
 
 
-void ConsumeComma (void)
+int ConsumeComma (void)
 /* Check for a comma and skip it. */
 {
     /* Try do be smart about typos... */
     if (CurTok.Tok == TOK_COMMA) {
-       NextToken ();
+       NextToken ();
+        return 1;
     } else {
        Error ("`,' expected");
        if (CurTok.Tok == TOK_SEMI) {
            NextToken ();
        }
+        return 0;
     }
 }
 
 
 
-void ConsumeLParen (void)
+int ConsumeLParen (void)
 /* Check for a left parenthesis and skip it */
 {
-    Consume (TOK_LPAREN, "`(' expected");
+    return Consume (TOK_LPAREN, "`(' expected");
 }
 
 
 
-void ConsumeRParen (void)
+int ConsumeRParen (void)
 /* Check for a right parenthesis and skip it */
 {
-    Consume (TOK_RPAREN, "`)' expected");
+    return Consume (TOK_RPAREN, "`)' expected");
 }
 
 
 
-void ConsumeLBrack (void)
+int ConsumeLBrack (void)
 /* Check for a left bracket and skip it */
 {
-    Consume (TOK_LBRACK, "`[' expected");
+    return Consume (TOK_LBRACK, "`[' expected");
 }
 
 
 
-void ConsumeRBrack (void)
+int ConsumeRBrack (void)
 /* Check for a right bracket and skip it */
 {
-    Consume (TOK_RBRACK, "`]' expected");
+    return Consume (TOK_RBRACK, "`]' expected");
 }
 
 
 
-void ConsumeLCurly (void)
+int ConsumeLCurly (void)
 /* Check for a left curly brace and skip it */
 {
-    Consume (TOK_LCURLY, "`{' expected");
+    return Consume (TOK_LCURLY, "`{' expected");
 }
 
 
 
-void ConsumeRCurly (void)
+int ConsumeRCurly (void)
 /* Check for a right curly brace and skip it */
 {
-    Consume (TOK_RCURLY, "`}' expected");
+    return Consume (TOK_RCURLY, "`}' expected");
 }
 
 
index e78446efbe2efa370e875c237f2730fe6e46aee6..8bf668691b00763696e64de1678376a0c67cdc69 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2001 Ullrich von Bassewitz                                       */
+/* (C) 1998-2002 Ullrich von Bassewitz                                       */
 /*               Wacholderweg 14                                             */
 /*               D-70597 Stuttgart                                           */
 /* EMail:        uz@musoftware.de                                            */
@@ -210,36 +210,36 @@ void SkipTokens (const token_t* TokenList, unsigned TokenCount);
  * This routine is used for error recovery.
  */
 
-void Consume (token_t Token, const char* ErrorMsg);
+int Consume (token_t Token, const char* ErrorMsg);
 /* Eat token if it is the next in the input stream, otherwise print an error
- * message.
+ * message. Returns true if the token was found and false otherwise.
  */
 
-void ConsumeColon (void);
+int ConsumeColon (void);
 /* Check for a colon and skip it. */
 
-void ConsumeSemi (void);
+int ConsumeSemi (void);
 /* Check for a semicolon and skip it. */
 
-void ConsumeComma (void);
+int ConsumeComma (void);
 /* Check for a comma and skip it. */
 
-void ConsumeLParen (void);
+int ConsumeLParen (void);
 /* Check for a left parenthesis and skip it */
 
-void ConsumeRParen (void);
+int ConsumeRParen (void);
 /* Check for a right parenthesis and skip it */
 
-void ConsumeLBrack (void);
+int ConsumeLBrack (void);
 /* Check for a left bracket and skip it */
 
-void ConsumeRBrack (void);
+int ConsumeRBrack (void);
 /* Check for a right bracket and skip it */
 
-void ConsumeLCurly (void);
+int ConsumeLCurly (void);
 /* Check for a left curly brace and skip it */
 
-void ConsumeRCurly (void);
+int ConsumeRCurly (void);
 /* Check for a right curly brace and skip it */
 
 
diff --git a/src/cc65/scanstrbuf.c b/src/cc65/scanstrbuf.c
new file mode 100644 (file)
index 0000000..82418f7
--- /dev/null
@@ -0,0 +1,211 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 scanstrbuf.c                              */
+/*                                                                           */
+/*                     Small scanner for input from a StrBuf                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2002      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@cc65.org                                                 */
+/*                                                                           */
+/*                                                                           */
+/* 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.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+/* common */
+#include "chartype.h"
+
+/* cc65 */
+#include "error.h"
+#include "hexval.h"
+#include "ident.h"
+#include "scanstrbuf.h"
+
+
+
+/*****************************************************************************/
+/*                               Helper functions                            */
+/*****************************************************************************/
+
+
+
+static char ParseChar (StrBuf* B)
+/* Parse a character. Converts \n into EOL, etc. */
+{
+    unsigned I;
+    int C;
+
+    /* Check for escape chars */
+    if ((C = SB_Get (B)) == '\\') {
+       switch (SB_Get (B)) {
+           case 'b':
+               C = '\b';
+               break;
+           case 'f':
+               C = '\f';
+               break;
+           case 'r':
+               C = '\r';
+               break;
+           case 'n':
+               C = '\n';
+               break;
+           case 't':
+               C = '\t';
+               break;
+           case '\"':
+               C = '\"';
+               break;
+           case '\'':
+               C = '\'';
+               break;
+           case '\\':
+               C = '\\';
+               break;
+           case 'x':
+           case 'X':
+               /* Hex character constant */
+                       C = HexVal (SB_Get (B)) << 4;
+                       C |= HexVal (SB_Get (B));
+               break;
+           case '0':
+               /* Octal constant */
+                C = 0;
+                goto Octal;
+           case '1':
+                /* Octal constant */
+                C = 1;
+Octal:          I = 0;
+                       while (SB_Peek (B) >= '0' && SB_Peek (B) <= '7' && I++ < 4) {
+                    C = (C << 3) | (SB_Get (B) - '0');
+               }
+               break;
+           default:
+               Error ("Illegal character constant");
+               C = ' ';
+               break;
+       }
+    }
+
+    /* Return the character */
+    return C;
+}
+
+
+
+
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void SB_SkipWhite (StrBuf* B)
+/* Skip whitespace in the string buffer */
+{
+    while (IsBlank (SB_Peek (B))) {
+        SB_Skip (B);
+    }
+}
+
+
+
+int SB_GetSym (StrBuf* B, char* S)
+/* Get a symbol from the string buffer. S must be able to hold MAX_IDENTLEN
+ * characters. Returns 1 if a symbol was found and 0 otherwise.
+ */
+{
+    if (IsIdent (SB_Peek (B))) {
+        unsigned I = 0;
+        char C = SB_Peek (B);
+        do {
+            if (I < MAX_IDENTLEN) {
+                ++I;
+                *S++ = C;
+            }
+            SB_Skip (B);
+            C = SB_Peek (B);
+        } while (IsIdent (C) || IsDigit (C));
+        *S = '\0';
+       return 1;
+    } else {
+       return 0;
+    }
+}
+
+
+
+int SB_GetString (StrBuf* B, StrBuf* S)
+/* Get a string from the string buffer. S will be initialized by the function
+ * and will return the correctly terminated string on return. The function
+ * returns 1 if a string was found and 0 otherwise.
+ */
+{
+    char C;
+
+    /* Initialize S */
+    *S = AUTO_STRBUF_INITIALIZER;
+    if (SB_Peek (B) == '\"') {
+
+        /* String follows, be sure to concatenate strings */
+        while (SB_Peek (B) == '\"') {
+
+            /* Skip the quote char */
+            SB_Skip (B);
+
+            /* Read the actual string contents */
+            while ((C = SB_Peek (B)) != '\"') {
+                if (C == '\0') {
+                    Error ("Unexpected end of string");
+                    break;
+                }
+                SB_AppendChar (S, ParseChar (B));
+            }
+
+            /* Skip the closing quote char if there was one */
+            SB_Skip (B);
+
+            /* Skip white space, read new input */
+            SB_SkipWhite (B);
+        }
+
+        /* Terminate the string */
+        SB_Terminate (S);
+
+        /* Success */
+        return 1;
+
+    } else {
+
+        /* Not a string */
+        SB_Terminate (S);
+        return 0;
+    }
+}
+
+
+
diff --git a/src/cc65/scanstrbuf.h b/src/cc65/scanstrbuf.h
new file mode 100644 (file)
index 0000000..9bd9714
--- /dev/null
@@ -0,0 +1,75 @@
+/*****************************************************************************/
+/*                                                                           */
+/*                                 scanstrbuf.h                              */
+/*                                                                           */
+/*                     Small scanner for input from a StrBuf                 */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 2002      Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@cc65.org                                                 */
+/*                                                                           */
+/*                                                                           */
+/* 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.                                                          */
+/*                                                                           */
+/*****************************************************************************/
+
+
+
+#ifndef SCANSTRBUF_H
+#define SCANSTRBUF_H
+
+
+
+/* common */
+#include "strbuf.h"
+
+
+
+/*****************************************************************************/
+/*                                  Code                                    */
+/*****************************************************************************/
+
+
+
+void SB_SkipWhite (StrBuf* B);
+/* Skip whitespace in the string buffer */
+
+int SB_GetSym (StrBuf* B, char* S);
+/* Get a symbol from the string buffer. S must be able to hold MAX_IDENTLEN
+ * characters. Returns 1 if a symbol was found and 0 otherwise.
+ */
+
+int SB_GetString (StrBuf* B, StrBuf* S);
+/* Get a string from the string buffer. S will be initialized by the function
+ * and will return the correctly terminated string on return. The function
+ * returns 1 if a string was found and 0 otherwise.
+ */
+
+
+
+
+/* End of scanstrbuf.h */
+#endif
+
+
+
+
+