]> git.sur5r.net Git - cc65/blobdiff - src/ca65/nexttok.c
Fixed _textcolor definition.
[cc65] / src / ca65 / nexttok.c
index 5be1dfc8a19473ee8c30443ac746686e4ec62a44..54733740e89e552353b852d0a1d09b06aa6916d9 100644 (file)
@@ -1,15 +1,15 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                nexttok.c                                 */
+/*                                 nexttok.c                                 */
 /*                                                                           */
-/*             Get next token and handle token level functions              */
+/*              Get next token and handle token level functions              */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2000-2003 Ullrich von Bassewitz                                       */
-/*               Römerstraße 52                                              */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 2000-2011, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 #include <string.h>
 
 /* common */
+#include "chartype.h"
 #include "check.h"
+#include "strbuf.h"
 
 /* ca65 */
+#include "condasm.h"
 #include "error.h"
 #include "expr.h"
+#include "global.h"
 #include "scanner.h"
 #include "toklist.h"
 #include "nexttok.h"
 
 
 /*****************************************************************************/
-/*                                          Data                                    */
+/*                                   Data                                    */
 /*****************************************************************************/
 
 
 
-static unsigned RawMode = 0;           /* Raw token mode flag/counter */
+static unsigned RawMode = 0;            /* Raw token mode flag/counter */
 
 
 
 /*****************************************************************************/
-/*                                          Code                                    */
+/*                              Error handling                               */
+/*****************************************************************************/
+
+
+
+static int LookAtStrCon (void)
+/* Make sure the next token is a string constant. If not, print an error
+** messages skip the remainder of the line and return false. Otherwise return
+** true.
+*/
+{
+    if (CurTok.Tok != TOK_STRCON) {
+        Error ("String constant expected");
+        SkipUntilSep ();
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                                   Code                                    */
 /*****************************************************************************/
 
 
 
 static TokList* CollectTokens (unsigned Start, unsigned Count)
-/* Read a list of tokens that is terminated by a right paren. For all tokens
- * starting at the one with index Start, and ending at (Start+Count-1), place
- * them into a token list, and return this token list.
- */
+/* Read a list of tokens that is optionally enclosed in curly braces and
+** terminated by a right paren. For all tokens starting at the one with index
+** Start, and ending at (Start+Count-1), place them into a token list, and
+** return this token list.
+*/
 {
+
     /* Create the token list */
     TokList* List = NewTokList ();
 
+    /* Determine if the list is enclosed in curly braces. */
+    token_t Term = GetTokListTerm (TOK_RPAREN);
+
     /* Read the token list */
     unsigned Current = 0;
-    unsigned Parens  = 0;
-    while (Parens != 0 || Tok != TOK_RPAREN) {
-
-       /* Check for end of line or end of input */
-       if (TokIsSep (Tok)) {
-           Error ("Unexpected end of line");
-           return List;
-       }
-
-       /* Collect tokens in the given range */
-       if (Current >= Start && Current < Start+Count) {
-           /* Add the current token to the list */
-           AddCurTok (List);
-       }
-
-       /* Check for and count parenthesii */
-       if (Tok == TOK_LPAREN) {
-           ++Parens;
-       } else if (Tok == TOK_RPAREN) {
-           --Parens;
-       }
-
-       /* Get the next token */
-       ++Current;
-       NextTok ();
+    while (CurTok.Tok != Term) {
+
+        /* Check for end of line or end of input */
+        if (TokIsSep (CurTok.Tok)) {
+            Error ("Unexpected end of line");
+            return List;
+        }
+
+        /* Collect tokens in the given range */
+        if (Current >= Start && Current < Start+Count) {
+            /* Add the current token to the list */
+            AddCurTok (List);
+        }
+
+        /* Get the next token */
+        ++Current;
+        NextTok ();
     }
 
-    /* Eat the closing paren */
-    ConsumeRParen ();
+    /* Eat the terminator token */
+    NextTok ();
+
+    /* If the list was enclosed in curly braces, we do expect now a right paren */
+    if (Term == TOK_RCURLY) {
+        ConsumeRParen ();
+    }
 
     /* Return the list of collected tokens */
     return List;
@@ -114,10 +143,7 @@ static TokList* CollectTokens (unsigned Start, unsigned Count)
 static void FuncConcat (void)
 /* Handle the .CONCAT function */
 {
-    char       Buf[MAX_STR_LEN+1];
-    char*      B;
-    unsigned   Length;
-    unsigned   L;
+    StrBuf      Buf = STATIC_STRBUF_INITIALIZER;
 
     /* Skip it */
     NextTok ();
@@ -126,56 +152,116 @@ static void FuncConcat (void)
     ConsumeLParen ();
 
     /* Concatenate any number of strings */
-    B = Buf;
-    B[0] = '\0';
-    Length = 0;
     while (1) {
 
-       /* Next token must be a string */
-       if (Tok != TOK_STRCON) {
-           Error ("String constant expected");
-           SkipUntilSep ();
-           return;
-       }
-
-       /* Get the length of the string const and check total length */
-       L = strlen (SVal);
-       if (Length + L > MAX_STR_LEN) {
-           Error ("String is too long");
-           /* Try to recover */
-           SkipUntilSep ();
-           return;
-       }
-
-       /* Add the new string */
-       memcpy (B, SVal, L);
-       Length += L;
-       B      += L;
-
-       /* Skip the string token */
-       NextTok ();
-
-       /* Comma means another argument */
-       if (Tok == TOK_COMMA) {
-           NextTok ();
-       } else {
-           /* Done */
-           break;
-       }
+        /* Next token must be a string */
+        if (!LookAtStrCon ()) {
+            SB_Done (&Buf);
+            return;
+        }
+
+        /* Append the string */
+        SB_Append (&Buf, &CurTok.SVal);
+
+        /* Skip the string token */
+        NextTok ();
+
+        /* Comma means another argument */
+        if (CurTok.Tok == TOK_COMMA) {
+            NextTok ();
+        } else {
+            /* Done */
+            break;
+        }
     }
 
-    /* Terminate the string */
-    *B = '\0';
-
     /* We expect a closing parenthesis, but will not skip it but replace it
-     * by the string token just created.
-     */
-    if (Tok != TOK_RPAREN) {
-       Error ("`)' expected");
+    ** by the string token just created.
+    */
+    if (CurTok.Tok != TOK_RPAREN) {
+        Error ("')' expected");
+    } else {
+        CurTok.Tok = TOK_STRCON;
+        SB_Copy (&CurTok.SVal, &Buf);
+        SB_Terminate (&CurTok.SVal);
+    }
+
+    /* Free the string buffer */
+    SB_Done (&Buf);
+}
+
+
+
+static void NoIdent (void)
+/* Print an error message and skip the remainder of the line */
+{
+    Error ("Argument of .IDENT is not a valid identifier");
+    SkipUntilSep ();
+}
+
+
+
+static void FuncIdent (void)
+/* Handle the .IDENT function */
+{
+    StrBuf    Buf = STATIC_STRBUF_INITIALIZER;
+    token_t   Id;
+    unsigned  I;
+
+    /* Skip it */
+    NextTok ();
+
+    /* Left paren expected */
+    ConsumeLParen ();
+
+    /* The function expects a string argument */
+    if (!LookAtStrCon ()) {
+        return;
+    }
+
+    /* Check that the string contains a valid identifier. While doing so,
+    ** determine if it is a cheap local, or global one.
+    */
+    SB_Reset (&CurTok.SVal);
+
+    /* Check for a cheap local symbol */
+    if (SB_Peek (&CurTok.SVal) == LocalStart) {
+        SB_Skip (&CurTok.SVal);
+        Id = TOK_LOCAL_IDENT;
+    } else {
+        Id = TOK_IDENT;
+    }
+
+    /* Next character must be a valid identifier start */
+    if (!IsIdStart (SB_Get (&CurTok.SVal))) {
+        NoIdent ();
+        return;
+    }
+    for (I = SB_GetIndex (&CurTok.SVal); I < SB_GetLen (&CurTok.SVal); ++I) {
+        if (!IsIdChar (SB_AtUnchecked (&CurTok.SVal, I))) {
+            NoIdent ();
+            return;
+        }
+    }
+    if (IgnoreCase) {
+        UpcaseSVal ();
+    }
+
+    /* If anything is ok, save and skip the string. Check that the next token
+    ** is a right paren, then replace the token by an identifier token.
+    */
+    SB_Copy (&Buf, &CurTok.SVal);
+    NextTok ();
+    if (CurTok.Tok != TOK_RPAREN) {
+        Error ("')' expected");
     } else {
-       Tok = TOK_STRCON;
-       strcpy (SVal, Buf);
+        CurTok.Tok = Id;
+        SB_Copy (&CurTok.SVal, &Buf);
+        SB_Terminate (&CurTok.SVal);
     }
+
+    /* Free buffer memory */
+    SB_Done (&Buf);
 }
 
 
@@ -183,8 +269,8 @@ static void FuncConcat (void)
 static void FuncLeft (void)
 /* Handle the .LEFT function */
 {
-    long               Count;
-    TokList*   List;
+    long        Count;
+    TokList*    List;
 
     /* Skip it */
     NextTok ();
@@ -192,11 +278,10 @@ static void FuncLeft (void)
     /* Left paren expected */
     ConsumeLParen ();
 
-    /* Count argument */
+    /* Count argument. Correct negative counts to zero. */
     Count = ConstExpression ();
-    if (Count < 0 || Count > 100) {
-       Error ("Range error");
-       Count = 1;
+    if (Count < 0) {
+        Count = 0;
     }
     ConsumeComma ();
 
@@ -204,12 +289,12 @@ static void FuncLeft (void)
     List = CollectTokens (0, (unsigned) Count);
 
     /* Since we want to insert the list before the now current token, we have
-     * to save the current token in some way and then skip it. To do this, we
-     * will add the current token at the end of the token list (so the list
-     * will never be empty), push the token list, and then skip the current
-     * token. This will replace the current token by the first token from the
-     * list (which will be the old current token in case the list was empty).
-     */
+    ** to save the current token in some way and then skip it. To do this, we
+    ** will add the current token at the end of the token list (so the list
+    ** will never be empty), push the token list, and then skip the current
+    ** token. This will replace the current token by the first token from the
+    ** list (which will be the old current token in case the list was empty).
+    */
     AddCurTok (List);
 
     /* Insert it into the scanner feed */
@@ -224,9 +309,9 @@ static void FuncLeft (void)
 static void FuncMid (void)
 /* Handle the .MID function */
 {
-    long       Start;
-    long               Count;
-    TokList*   List;
+    long        Start;
+    long        Count;
+    TokList*    List;
 
     /* Skip it */
     NextTok ();
@@ -234,19 +319,21 @@ static void FuncMid (void)
     /* Left paren expected */
     ConsumeLParen ();
 
-    /* Start argument */
+    /* Start argument. Since the start argument can get negative with
+    ** expressions like ".tcount(arg)-2", we correct it to zero silently.
+    */
     Start = ConstExpression ();
     if (Start < 0 || Start > 100) {
-       Error ("Range error");
-       Start = 0;
+        Start = 0;
     }
     ConsumeComma ();
 
-    /* Count argument */
+    /* Count argument. Similar as above, we will accept negative counts and
+    ** correct them to zero silently.
+    */
     Count = ConstExpression ();
-    if (Count < 0 || Count > 100) {
-       Error ("Range error");
-       Count = 1;
+    if (Count < 0) {
+        Count = 0;
     }
     ConsumeComma ();
 
@@ -254,12 +341,12 @@ static void FuncMid (void)
     List = CollectTokens ((unsigned) Start, (unsigned) Count);
 
     /* Since we want to insert the list before the now current token, we have
-     * to save the current token in some way and then skip it. To do this, we
-     * will add the current token at the end of the token list (so the list
-     * will never be empty), push the token list, and then skip the current
-     * token. This will replace the current token by the first token from the
-     * list (which will be the old current token in case the list was empty).
-     */
+    ** to save the current token in some way and then skip it. To do this, we
+    ** will add the current token at the end of the token list (so the list
+    ** will never be empty), push the token list, and then skip the current
+    ** token. This will replace the current token by the first token from the
+    ** list (which will be the old current token in case the list was empty).
+    */
     AddCurTok (List);
 
     /* Insert it into the scanner feed */
@@ -274,8 +361,8 @@ static void FuncMid (void)
 static void FuncRight (void)
 /* Handle the .RIGHT function */
 {
-    long               Count;
-    TokList*   List;
+    long        Count;
+    TokList*    List;
 
     /* Skip it */
     NextTok ();
@@ -283,11 +370,10 @@ static void FuncRight (void)
     /* Left paren expected */
     ConsumeLParen ();
 
-    /* Count argument */
+    /* Count argument. Correct negative counts to zero. */
     Count = ConstExpression ();
-    if (Count < 0 || Count > 100) {
-       Error ("Range error");
-       Count = 1;
+    if (Count < 0) {
+        Count = 0;
     }
     ConsumeComma ();
 
@@ -296,26 +382,26 @@ static void FuncRight (void)
 
     /* Delete tokens from the list until Count tokens are remaining */
     while (List->Count > (unsigned) Count) {
-       /* Get the first node */
-       TokNode* T = List->Root;
+        /* Get the first node */
+        TokNode* T = List->Root;
 
-       /* Remove it from the list */
-       List->Root = List->Root->Next;
+        /* Remove it from the list */
+        List->Root = List->Root->Next;
 
-       /* Free the node */
-       FreeTokNode (T);
+        /* Free the node */
+        FreeTokNode (T);
 
-       /* Corrent the token counter */
-       List->Count--;
+        /* Corrent the token counter */
+        List->Count--;
     }
 
     /* Since we want to insert the list before the now current token, we have
-     * to save the current token in some way and then skip it. To do this, we
-     * will add the current token at the end of the token list (so the list
-     * will never be empty), push the token list, and then skip the current
-     * token. This will replace the current token by the first token from the
-     * list (which will be the old current token in case the list was empty).
-     */
+    ** to save the current token in some way and then skip it. To do this, we
+    ** will add the current token at the end of the token list (so the list
+    ** will never be empty), push the token list, and then skip the current
+    ** token. This will replace the current token by the first token from the
+    ** list (which will be the old current token in case the list was empty).
+    */
     AddCurTok (List);
 
     /* Insert it into the scanner feed */
@@ -327,10 +413,214 @@ static void FuncRight (void)
 
 
 
+static void InvalidFormatString (void)
+/* Print an error message and skip the remainder of the line */
+{
+    Error ("Invalid format string");
+    SkipUntilSep ();
+}
+
+
+
+static void FuncSPrintF (void)
+/* Handle the .SPRINTF function */
+{
+    StrBuf      Format = STATIC_STRBUF_INITIALIZER; /* User supplied format */
+    StrBuf      R = STATIC_STRBUF_INITIALIZER;      /* Result string */
+    StrBuf      F1 = STATIC_STRBUF_INITIALIZER;     /* One format spec from F */
+    StrBuf      R1 = STATIC_STRBUF_INITIALIZER;     /* One result */
+    char        C;
+    int         Done;
+    long        IVal;                               /* Integer value */
+
+
+
+    /* Skip the .SPRINTF token */
+    NextTok ();
+
+    /* Left paren expected */
+    ConsumeLParen ();
+
+    /* First argument is a format string. Remember and skip it */
+    if (!LookAtStrCon ()) {
+        return;
+    }
+    SB_Copy (&Format, &CurTok.SVal);
+    NextTok ();
+
+    /* Walk over the format string, generating the function result in R */
+    while (1) {
+
+        /* Get the next char from the format string and check for EOS */
+        if (SB_Peek (&Format) == '\0') {
+            break;
+        }
+
+        /* Check for a format specifier */
+        if (SB_Peek (&Format) != '%') {
+            /* No format specifier, just copy */
+            SB_AppendChar (&R, SB_Get (&Format));
+            continue;
+        }
+        SB_Skip (&Format);
+        if (SB_Peek (&Format) == '%') {
+            /* %% */
+            SB_AppendChar (&R, '%');
+            SB_Skip (&Format);
+            continue;
+        }
+        if (SB_Peek (&Format) == '\0') {
+            InvalidFormatString ();
+            break;
+        }
+
+        /* Since a format specifier follows, we do expect another argument for
+        ** the .sprintf function.
+        */
+        ConsumeComma ();
+
+        /* We will copy the format spec into F1 checking for the things we
+        ** support, and later use xsprintf to do the actual formatting. This
+        ** is easier than adding another printf implementation...
+        */
+        SB_Clear (&F1);
+        SB_AppendChar (&F1, '%');
+
+        /* Check for flags */
+        Done = 0;
+        while ((C = SB_Peek (&Format)) != '\0' && !Done) {
+            switch (C) {
+                case '-': /* FALLTHROUGH */
+                case '+': /* FALLTHROUGH */
+                case ' ': /* FALLTHROUGH */
+                case '#': /* FALLTHROUGH */
+                case '0': SB_AppendChar (&F1, SB_Get (&Format));  break;
+                default:  Done = 1;                               break;
+            }
+        }
+
+        /* We do only support a numerical width field */
+        while (IsDigit (SB_Peek (&Format))) {
+            SB_AppendChar (&F1, SB_Get (&Format));
+        }
+
+        /* Precision - only positive numerical fields supported */
+        if (SB_Peek (&Format) == '.') {
+            SB_AppendChar (&F1, SB_Get (&Format));
+            while (IsDigit (SB_Peek (&Format))) {
+                SB_AppendChar (&F1, SB_Get (&Format));
+            }
+        }
+
+        /* Length modifiers aren't supported, so read the conversion specs */
+        switch (SB_Peek (&Format)) {
+
+            case 'd':
+            case 'i':
+            case 'o':
+            case 'u':
+            case 'X':
+            case 'x':
+                /* Our ints are actually longs, so we use the 'l' modifier when
+                ** calling xsprintf later. Terminate the format string.
+                */
+                SB_AppendChar (&F1, 'l');
+                SB_AppendChar (&F1, SB_Get (&Format));
+                SB_Terminate (&F1);
+
+                /* The argument must be a constant expression */
+                IVal = ConstExpression ();
+
+                /* Format this argument according to the spec */
+                SB_Printf (&R1, SB_GetConstBuf (&F1), IVal);
+
+                /* Append the formatted argument to the result */
+                SB_Append (&R, &R1);
+
+                break;
+
+            case 's':
+                /* Add the format spec and terminate the format */
+                SB_AppendChar (&F1, SB_Get (&Format));
+                SB_Terminate (&F1);
+
+                /* The argument must be a string constant */
+                if (!LookAtStrCon ()) {
+                    /* Make it one */
+                    SB_CopyStr (&CurTok.SVal, "**undefined**");
+                }
+
+                /* Format this argument according to the spec */
+                SB_Printf (&R1, SB_GetConstBuf (&F1), SB_GetConstBuf (&CurTok.SVal));
+
+                /* Skip the string constant */
+                NextTok ();
+
+                /* Append the formatted argument to the result */
+                SB_Append (&R, &R1);
+
+                break;
+
+            case 'c':
+                /* Add the format spec and terminate the format */
+                SB_AppendChar (&F1, SB_Get (&Format));
+                SB_Terminate (&F1);
+
+                /* The argument must be a constant expression */
+                IVal = ConstExpression ();
+
+                /* Check for a valid character range */
+                if (IVal <= 0 || IVal > 255) {
+                    Error ("Char argument out of range");
+                    IVal = ' ';
+                }
+
+                /* Format this argument according to the spec. Be sure to pass
+                ** an int as the char value.
+                */
+                SB_Printf (&R1, SB_GetConstBuf (&F1), (int) IVal);
+
+                /* Append the formatted argument to the result */
+                SB_Append (&R, &R1);
+
+                break;
+
+            default:
+                Error ("Invalid format string");
+                SB_Skip (&Format);
+                break;
+        }
+
+    }
+
+    /* Terminate the result string */
+    SB_Terminate (&R);
+
+    /* We expect a closing parenthesis, but will not skip it but replace it
+    ** by the string token just created.
+    */
+    if (CurTok.Tok != TOK_RPAREN) {
+        Error ("')' expected");
+    } else {
+        CurTok.Tok = TOK_STRCON;
+        SB_Copy (&CurTok.SVal, &R);
+        SB_Terminate (&CurTok.SVal);
+    }
+
+
+    /* Delete the string buffers */
+    SB_Done (&Format);
+    SB_Done (&R);
+    SB_Done (&F1);
+    SB_Done (&R1);
+}
+
+
+
 static void FuncString (void)
 /* Handle the .STRING function */
 {
-    char Buf[MAX_STR_LEN+1];
+    StrBuf Buf = STATIC_STRBUF_INITIALIZER;
 
     /* Skip it */
     NextTok ();
@@ -339,25 +629,46 @@ static void FuncString (void)
     ConsumeLParen ();
 
     /* Accept identifiers or numeric expressions */
-    if (Tok == TOK_IDENT) {
-       /* Save the identifier, then skip it */
-       strcpy (Buf, SVal);
-       NextTok ();
+    if (CurTok.Tok == TOK_LOCAL_IDENT) {
+        /* Save the identifier, then skip it */
+        SB_Copy (&Buf, &CurTok.SVal);
+        NextTok ();
+    } else if (CurTok.Tok == TOK_NAMESPACE || CurTok.Tok == TOK_IDENT) {
+
+        /* Parse a fully qualified symbol name. We cannot use
+        ** ParseScopedSymName here since the name may be invalid.
+        */
+        int NameSpace;
+        do {
+            NameSpace = (CurTok.Tok == TOK_NAMESPACE);
+            if (NameSpace) {
+                SB_AppendStr (&Buf, "::");
+            } else {
+                SB_Append (&Buf, &CurTok.SVal);
+            }
+            NextTok ();
+        } while ((NameSpace != 0 && CurTok.Tok == TOK_IDENT) ||
+                 (NameSpace == 0 && CurTok.Tok == TOK_NAMESPACE));
+
     } else {
-       /* Numeric expression */
-       long Val = ConstExpression ();
-       sprintf (Buf, "%ld", Val);
+        /* Numeric expression */
+        long Val = ConstExpression ();
+        SB_Printf (&Buf, "%ld", Val);
     }
 
     /* We expect a closing parenthesis, but will not skip it but replace it
-     * by the string token just created.
-     */
-    if (Tok != TOK_RPAREN) {
-       Error ("`)' expected");
+    ** by the string token just created.
+    */
+    if (CurTok.Tok != TOK_RPAREN) {
+        Error ("')' expected");
     } else {
-       Tok = TOK_STRCON;
-       strcpy (SVal, Buf);
+        CurTok.Tok = TOK_STRCON;
+        SB_Copy (&CurTok.SVal, &Buf);
+        SB_Terminate (&CurTok.SVal);
     }
+
+    /* Free string memory */
+    SB_Done (&Buf);
 }
 
 
@@ -368,49 +679,59 @@ void NextTok (void)
     /* Get the next raw token */
     NextRawTok ();
 
-    /* In raw mode, pass the token unchanged */
-    if (RawMode == 0) {
+    /* In raw mode, or when output is suppressed via conditional assembly,
+    ** pass the token unchanged.
+    */
+    if (RawMode == 0 && IfCond) {
 
-       /* Execute token handling functions */
-       switch (Tok) {
+        /* Execute token handling functions */
+        switch (CurTok.Tok) {
 
-           case TOK_CONCAT:
-               FuncConcat ();
-               break;
+            case TOK_CONCAT:
+                FuncConcat ();
+                break;
 
-           case TOK_LEFT:
-               FuncLeft ();
-               break;
+            case TOK_LEFT:
+                FuncLeft ();
+                break;
 
-           case TOK_MID:
-               FuncMid ();
-               break;
+            case TOK_MAKEIDENT:
+                FuncIdent ();
+                break;
 
-           case TOK_RIGHT:
-               FuncRight ();
-               break;
+            case TOK_MID:
+                FuncMid ();
+                break;
 
-           case TOK_STRING:
-               FuncString ();
-               break;
+            case TOK_RIGHT:
+                FuncRight ();
+                break;
 
-           default:
-               /* Quiet down gcc */
-               break;
+            case TOK_SPRINTF:
+                FuncSPrintF ();
+                break;
 
-       }
+            case TOK_STRING:
+                FuncString ();
+                break;
+
+            default:
+                /* Quiet down gcc */
+                break;
+
+        }
     }
 }
 
 
 
-void Consume (enum Token Expected, const char* ErrMsg)
+void Consume (token_t Expected, const char* ErrMsg)
 /* Consume Expected, print an error if we don't find it */
 {
-    if (Tok == Expected) {
-       NextTok ();
+    if (CurTok.Tok == Expected) {
+        NextTok ();
     } else {
-       Error (ErrMsg);
+        Error ("%s", ErrMsg);
     }
 }
 
@@ -419,14 +740,12 @@ void Consume (enum Token Expected, const char* ErrMsg)
 void ConsumeSep (void)
 /* Consume a separator token */
 {
-    /* Accept an EOF as separator */
-    if (Tok != TOK_EOF) {
-       if (Tok != TOK_SEP) {
-                   Error ("Unexpected trailing garbage characters");
-           SkipUntilSep ();
-       } else {
-           NextTok ();
-       }
+    /* We expect a separator token */
+    ExpectSep ();
+
+    /* If we are at end of line, skip it */
+    if (CurTok.Tok == TOK_SEP) {
+        NextTok ();
     }
 }
 
@@ -435,7 +754,7 @@ void ConsumeSep (void)
 void ConsumeLParen (void)
 /* Consume a left paren */
 {
-    Consume (TOK_LPAREN, "`(' expected");
+    Consume (TOK_LPAREN, "'(' expected");
 }
 
 
@@ -443,7 +762,7 @@ void ConsumeLParen (void)
 void ConsumeRParen (void)
 /* Consume a right paren */
 {
-    Consume (TOK_RPAREN, "`)' expected");
+    Consume (TOK_RPAREN, "')' expected");
 }
 
 
@@ -451,7 +770,7 @@ void ConsumeRParen (void)
 void ConsumeComma (void)
 /* Consume a comma */
 {
-    Consume (TOK_COMMA, "`,' expected");
+    Consume (TOK_COMMA, "',' expected");
 }
 
 
@@ -459,8 +778,20 @@ void ConsumeComma (void)
 void SkipUntilSep (void)
 /* Skip tokens until we reach a line separator or end of file */
 {
-    while (!TokIsSep (Tok)) {
-       NextTok ();
+    while (!TokIsSep (CurTok.Tok)) {
+        NextTok ();
+    }
+}
+
+
+
+void ExpectSep (void)
+/* Check if we've reached a line separator, and output an error if not. Do
+** not skip the line separator.
+*/
+{
+    if (!TokIsSep (CurTok.Tok)) {
+        ErrorSkip ("Unexpected trailing garbage characters");
     }
 }
 
@@ -468,11 +799,11 @@ void SkipUntilSep (void)
 
 void EnterRawTokenMode (void)
 /* Enter raw token mode. In raw mode, token handling functions are not
- * executed, but the function tokens are passed untouched to the upper
- * layer. Raw token mode is used when storing macro tokens for later
- * use.
- * Calls to EnterRawTokenMode and LeaveRawTokenMode may be nested.
- */
+** executed, but the function tokens are passed untouched to the upper
+** layer. Raw token mode is used when storing macro tokens for later
+** use.
+** Calls to EnterRawTokenMode and LeaveRawTokenMode may be nested.
+*/
 {
     ++RawMode;
 }
@@ -485,6 +816,3 @@ void LeaveRawTokenMode (void)
     PRECONDITION (RawMode > 0);
     --RawMode;
 }
-
-
-