[nasm:nasm-2.16.xx] preproc: add options for a base prefix to %num(), add %hex()

nasm-bot for H. Peter Anvin hpa at zytor.com
Fri Oct 13 17:54:04 PDT 2023


Commit-ID:  dcac46d973ad6ecc47ca9b6ad96ece087fd82613
Gitweb:     http://repo.or.cz/w/nasm.git?a=commitdiff;h=dcac46d973ad6ecc47ca9b6ad96ece087fd82613
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Fri, 13 Oct 2023 17:50:55 -0700
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Fri, 13 Oct 2023 17:50:55 -0700

preproc: add options for a base prefix to %num(), add %hex()

Make it possible to add a base prefix to %num().

Add the %hex() function, producing hexadecimal values that are
nevertheless valid NASM numeric constants.

Signed-off-by: H. Peter Anvin <hpa at zytor.com>


---
 asm/preproc.c   | 79 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 doc/nasmdoc.src | 26 ++++++++++++++-----
 2 files changed, 87 insertions(+), 18 deletions(-)

diff --git a/asm/preproc.c b/asm/preproc.c
index 0e0195ee..85c19890 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -206,14 +206,15 @@ typedef Token *(*ExpandSMacro)(const SMacro *s, Token **params, int nparams);
  * if SPARM_GREEDY is set.
  */
 enum sparmflags {
-    SPARM_PLAIN     =  0,
-    SPARM_EVAL      =  1,   /* Evaluate as a numeric expression (=) */
-    SPARM_STR       =  2,   /* Convert to quoted string ($) */
-    SPARM_NOSTRIP   =  4,   /* Don't strip braces (!) */
-    SPARM_GREEDY    =  8,   /* Greedy final parameter (+) */
-    SPARM_VARADIC   = 16,   /* Any number of separate arguments */
-    SPARM_OPTIONAL  = 32,   /* Optional argument */
-    SPARM_CONDQUOTE = 64    /* With SPARM_STR, don't re-quote a string */
+    SPARM_PLAIN     =   0,
+    SPARM_EVAL      =   1,  /* Evaluate as a numeric expression (=) */
+    SPARM_STR       =   2,  /* Convert to quoted string ($) */
+    SPARM_NOSTRIP   =   4,  /* Don't strip braces (!) */
+    SPARM_GREEDY    =   8,  /* Greedy final parameter (+) */
+    SPARM_VARADIC   =  16,  /* Any number of separate arguments */
+    SPARM_OPTIONAL  =  32,  /* Optional argument */
+    SPARM_CONDQUOTE =  64,  /* With SPARM_STR, don't re-quote a string */
+    SPARM_HEX       = 128   /* With SPARM_EVAL, generate hexadecimal numbers */
 };
 
 struct smac_param {
@@ -650,6 +651,7 @@ static Token *expand_smacro(Token * tline);
 static Token *expand_id(Token * tline);
 static Context *get_ctx(const char *name, const char **namep);
 static Token *make_tok_num(Token *next, int64_t val);
+static Token *make_tok_hex(Token *next, int64_t val);
 static int64_t get_tok_num(const Token *t, bool *err);
 static Token *make_tok_qstr(Token *next, const char *str);
 static Token *make_tok_qstr_len(Token *next, const char *str, size_t len);
@@ -5924,7 +5926,11 @@ static SMacro *expand_one_smacro(Token ***tpp)
                     nasm_nonfatal("non-constant expression in parameter %d of %s `%s'",
                                   i+1, mtype, m->name);
                 } else {
-                    params[i] = make_tok_num(NULL, reloc_value(evalresult));
+                    int64_t v = reloc_value(evalresult);
+                    if (flags & SPARM_HEX)
+                        params[i] = make_tok_hex(NULL, v);
+                    else
+                        params[i] = make_tok_num(NULL, v);
                 }
             }
 
@@ -7215,12 +7221,13 @@ stdmac_num(const SMacro *s, Token **params, int nparam)
     unsigned int i;
     int nd;
     unsigned int base;
-    char numstr[256];
+    char numstr[262];
     char * const endstr = numstr + sizeof numstr - 1;
-    const int maxlen = sizeof numstr - 3;
+    const int maxlen = sizeof numstr - 5;
     const int maxbase = sizeof num_digits - 1;
     char *p;
     bool moredigits;
+    char decorate;
 
     (void)nparam;
 
@@ -7231,6 +7238,28 @@ stdmac_num(const SMacro *s, Token **params, int nparam)
     dparm  = parm[1];
     bparm  = parm[2];
 
+    decorate = 0;
+    if (bparm < 0) {
+        bparm = -bparm;
+        switch (bparm) {
+        case 2:
+            decorate = 'b';
+            break;
+        case 8:
+            decorate = 'q';
+            break;
+        case 10:
+            decorate = 'd';
+            break;
+        case 16:
+            decorate = 'x';
+            break;
+        default:
+            bparm = -bparm;     /* Error out below */
+            break;
+        }
+    }
+
     if (bparm < 2 || bparm > maxbase) {
         nasm_nonfatal("invalid base %"PRId64" given to %s()",
                       bparm, s->name);
@@ -7252,14 +7281,26 @@ stdmac_num(const SMacro *s, Token **params, int nparam)
         nd = dparm;
     }
 
+    /* Are we supposed to generate an empty string for zero? */
+    if (!nd && !n)
+        decorate = 0;
+
     p = endstr;
     *p = '\0';
     *--p = '\'';
 
+    /*
+     * Note that the actual maximum number of digits can never exceed 64,
+     * so even if moredigits is set it cannot cause string overrun.
+     */
     while (nd-- > 0 || (moredigits && n)) {
         *--p = num_digits[n % base];
         n /= base;
     }
+    if (decorate) {
+        *--p = decorate;
+        *--p = '0';
+    }
     *--p = '\'';
 
     return new_Token(NULL, TOKEN_STR, p, endstr - p);
@@ -7307,6 +7348,7 @@ static void pp_add_magic_stdmac(void)
         { "%abs",       false, 1, SPARM_EVAL, stdmac_abs },
         { "%count",     false, 1, SPARM_VARADIC, stdmac_count },
         { "%eval",      false, 1, SPARM_EVAL|SPARM_VARADIC, stdmac_join },
+        { "%hex",       false, 1, SPARM_EVAL|SPARM_HEX|SPARM_VARADIC, stdmac_join },
         { "%str",       false, 1, SPARM_GREEDY|SPARM_STR, stdmac_join },
         { "%strcat",    false, 1, SPARM_STR|SPARM_CONDQUOTE|SPARM_VARADIC, stdmac_strcat },
         { "%strlen",    false, 1, SPARM_STR|SPARM_CONDQUOTE, stdmac_strlen },
@@ -8002,9 +8044,22 @@ static Token *make_tok_num(Token *next, int64_t val)
     return next;
 }
 
+/* Create a numeric token as unsigned hexadecimal */
+static Token *make_tok_hex(Token *next, int64_t val)
+{
+    char numbuf[32];
+    int len;
+    uint64_t uval = val;
+
+    len = snprintf(numbuf, sizeof numbuf, "%#"PRIx64, uval);
+    next = new_Token(next, TOKEN_NUM, numbuf, len);
+
+    return next;
+}
+
 /*
  * Do the inverse of make_tok_num(). This only needs to be able
- * to parse the output of make_tok_num().
+ * to parse the output of make_tok_num() or make_tok_hex().
  */
 static int64_t get_tok_num(const Token *t, bool *err)
 {
diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src
index ddf8b630..3b5ea462 100644
--- a/doc/nasmdoc.src
+++ b/doc/nasmdoc.src
@@ -2919,6 +2919,14 @@ The expressions passed to \c{%eval()} are \i{critical expressions},
 see \k{crit}.
 
 
+\C{f_hex} \i\c{%hex()} Function
+
+Equivalent to \i\c\{%eval()}, except that the results generated are
+given as hexadecimal. A \c{0x} prefix is added unless the value is
+zero, equivalent to the C \c{printf("%#x")} format. See also the
+\c{%num()} function, (\k{f_num}).
+
+
 \S{f_is} \i\c{%is()} Family Functions
 
 Each \i\c{%if} family directive (see \k{condasm}) has an equivalent
@@ -2948,16 +2956,23 @@ argument to the conditional using \c{\{\}}:
 
 The \c{%num()} function evaluates its arguments as expressions, and
 then produces a quoted string encoding the first argument as an
-\e{unsigned} integer. The second argument is the desired number of
-digits (max 253, default -1), and the second argument is the encoding
-base (from 2 to 64, default 10.)
+\e{unsigned} 64-bit integer.
+
+The second argument is the desired number of digits (max 255, default
+-1).
+
+The third argument is the encoding base (from 2 to 64, default 10); if
+the base is given as -2, -8, -10, or -16, then \c{0b}, \c{0q}, \c{0d}
+or \c{0x} is prepended, respectively; all other negative values are
+disallowed.
 
 Only the first argument is required.
 
 If the number of digits is negative, NASM will add additional digits
-if needed, if positive the string is truncated to the number of digits
+if needed; if positive the string is truncated to the number of digits
 specified. 0 is treated as -1, except that the input number 0
-generates an empty string (thus, the first digit will never be zero.)
+always generates an empty string (thus, the first digit will never be
+zero), even if the base given is negative.
 
 The full 64-symbol set used is, in order:
 
@@ -2967,7 +2982,6 @@ If a \e{signed} number needs to be converted to a string, use
 \c{%abs()}, \c{%cond()}, and \c{%strcat()} to format the signed number
 string to your specific output requirements.
 
-
 \S{f_sel} \i\c{%sel()} Function
 
 The \c{%sel()} function evaluates its first argument as an


More information about the Nasm-commits mailing list