]> git.sur5r.net Git - cc65/commitdiff
New .sprintf function
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 10 May 2005 15:42:32 +0000 (15:42 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 10 May 2005 15:42:32 +0000 (15:42 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@3508 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/ca65/nexttok.c
src/ca65/pseudo.c
src/ca65/scanner.c
src/ca65/scanner.h

index 12bed7e4801843be42bf1332e0cf3e74efcdbd0f..139017494b792f6524d3278fcc8b18e924bf86c3 100644 (file)
@@ -37,7 +37,9 @@
 #include <string.h>
 
 /* common */
+#include "chartype.h"
 #include "check.h"
+#include "strbuf.h"
 
 /* ca65 */
 #include "error.h"
@@ -59,6 +61,29 @@ static unsigned RawMode = 0;         /* Raw token mode flag/counter */
 
 
 
+/*****************************************************************************/
+/*                              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 (Tok != TOK_STRCON) {
+        Error ("String constant expected");
+        SkipUntilSep ();
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
+
+
 /*****************************************************************************/
 /*                                          Code                                    */
 /*****************************************************************************/
@@ -135,9 +160,7 @@ static void FuncConcat (void)
     while (1) {
 
        /* Next token must be a string */
-       if (Tok != TOK_STRCON) {
-           Error ("String constant expected");
-           SkipUntilSep ();
+        if (!LookAtStrCon ()) {
            return;
        }
 
@@ -248,9 +271,7 @@ static void FuncIdent (void)
     ConsumeLParen ();
 
     /* The function expects a string argument */
-    if (Tok != TOK_STRCON) {
-        Error ("String constant expected");
-        SkipUntilSep ();
+    if (!LookAtStrCon ()) {
         return;
     }
 
@@ -410,6 +431,216 @@ 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 */
+{
+    char        Format[sizeof (SVal)];              /* User given format */
+    const char* F = Format;                         /* User format pointer */
+    StrBuf      R = AUTO_STRBUF_INITIALIZER;        /* Result string */
+    StrBuf      F1 = AUTO_STRBUF_INITIALIZER;       /* One format spec from F */
+    StrBuf      R1 = AUTO_STRBUF_INITIALIZER;       /* One result */
+    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;
+    }
+    strcpy (Format, 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 (*F == '\0') {
+            break;
+        }
+
+        /* Check for a format specifier */
+        if (*F != '%') {
+            /* No format specifier, just copy */
+            SB_AppendChar (&R, *F++);
+            continue;
+        }
+        if (*++F == '%') {
+            /* %% */
+            SB_AppendChar (&R, '%');
+            ++F;
+            continue;
+        }
+        if (*F == '\0') {
+            InvalidFormatString ();
+            break;
+        }
+
+        /* Since a format specifier follows, we do expect anotehr 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 (*F != '\0' && !Done) {
+            switch (*F) {
+                case '-': /* FALLTHROUGH */
+                case '+': /* FALLTHROUGH */
+                case ' ': /* FALLTHROUGH */
+                case '#': /* FALLTHROUGH */
+                case '0': SB_AppendChar (&F1, *F++);    break;
+                default:  Done = 1;                     break;
+            }
+        }
+
+        /* We do only support a numerical width field */
+        while (IsDigit (*F)) {
+            SB_AppendChar (&F1, *F++);
+        }
+
+        /* Precision - only positive numerical fields supported */
+        if (*F == '.') {
+            SB_AppendChar (&F1, *F++);
+            while (IsDigit (*F)) {
+                SB_AppendChar (&F1, *F++);
+            }
+        }
+
+        /* Length modifiers aren't supported, so read the conversion specs */
+        switch (*F) {
+
+            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, *F++);
+                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, *F++);
+                SB_Terminate (&F1);
+
+                /* The argument must be a string constant */
+                if (!LookAtStrCon ()) {
+                    /* Make it one */
+                    strcpy (SVal, "**undefined**");
+                }
+
+                /* Format this argument according to the spec */
+                SB_Printf (&R1, SB_GetConstBuf (&F1), 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, *F++);
+                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");
+                if (*F) {
+                    /* Don't skip beyond end of string */
+                    ++F;
+                }
+                break;
+        }
+
+    }
+
+    /* The length of the final result may not exceed the size of a string */
+    if (SB_GetLen (&R) >= sizeof (SVal)) {
+        Error ("Resulting string is too long");
+        SB_Cut (&R, sizeof (SVal) - 1);
+    }
+
+    /* 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 (Tok != TOK_RPAREN) {
+       Error ("`)' expected");
+    } else {
+       Tok = TOK_STRCON;
+       memcpy (SVal, SB_GetConstBuf (&R), SB_GetLen (&R) + 1);
+    }
+
+
+    /* Delete the string buffers */
+    DoneStrBuf (&R);
+    DoneStrBuf (&F1);
+    DoneStrBuf (&R1);
+}
+
+
+
 static void FuncString (void)
 /* Handle the .STRING function */
 {
@@ -477,6 +708,10 @@ void NextTok (void)
                FuncRight ();
                break;
 
+            case TOK_SPRINTF:
+                FuncSPrintF ();
+                break;
+
            case TOK_STRING:
                FuncString ();
                break;
index 1ed6272128a0e04982e523e5a6ac281fbefcb9b7..85aef7d8b43ff8cecee579ad9f1954f9e364770a 100644 (file)
@@ -1773,7 +1773,8 @@ static CtrlDesc CtrlCmdTab [] = {
     { ccNone,          DoSegment       },
     { ccNone,                  DoSetCPU        },
     { ccNone,           DoUnexpected    },      /* .SIZEOF */
-    { ccNone,          DoSmart         },
+    { ccNone,          DoSmart         },                  
+    { ccNone,           DoUnexpected    },      /* .SPRINTF */
     { ccNone,          DoUnexpected    },      /* .STRAT */
     { ccNone,                  DoUnexpected    },      /* .STRING */
     { ccNone,          DoUnexpected    },      /* .STRLEN */
index f07be47b74955395fc735981c1db523cb362fa26..69846d9c5eb5e8c4934515e99200656f9dbe22d8 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2004 Ullrich von Bassewitz                                       */
+/* (C) 1998-2005 Ullrich von Bassewitz                                       */
 /*               Römerstraße 52                                              */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
@@ -241,6 +241,7 @@ struct DotKeyword {
     { ".SHR",          TOK_SHR         },
     { ".SIZEOF",        TOK_SIZEOF      },
     { ".SMART",                TOK_SMART       },
+    { ".SPRINTF",       TOK_SPRINTF     },
     { ".STRAT",                TOK_STRAT       },
     { ".STRING",       TOK_STRING      },
     { ".STRLEN",       TOK_STRLEN      },
index 637ae3816b7c6610bf89e7f8c88f128ff05cc8ec..dedbeb047362abdb7426f5ff1256745774456c33 100644 (file)
@@ -228,6 +228,7 @@ enum Token {
     TOK_SETCPU,
     TOK_SIZEOF,
     TOK_SMART,
+    TOK_SPRINTF,
     TOK_STRAT,
     TOK_STRING,
     TOK_STRLEN,