[nasm:nasm-2.16.xx] preproc: factor expand_one_smacro() even more

nasm-bot for H. Peter Anvin hpa at zytor.com
Mon Oct 16 03:00:04 PDT 2023


Commit-ID:  78bde7562d477698e3b3e5929b74475f09d9e77b
Gitweb:     http://repo.or.cz/w/nasm.git?a=commitdiff;h=78bde7562d477698e3b3e5929b74475f09d9e77b
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Mon, 16 Oct 2023 02:03:56 -0700
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Mon, 16 Oct 2023 02:03:56 -0700

preproc: factor expand_one_smacro() even more

Separate out counting and parsing smacro parameters into separate
functions. This not only makes the code *way* easier to read, but
these can be re-used e.g. for %map().

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


---
 asm/preproc.c | 359 ++++++++++++++++++++++++++++++++--------------------------
 1 file changed, 196 insertions(+), 163 deletions(-)

diff --git a/asm/preproc.c b/asm/preproc.c
index 013ab733..52a24ce5 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -5861,6 +5861,198 @@ expand_smacro_with_params(SMacro *m, Token *mstart, Token **params,
     return tline;
 }
 
+/*
+ * Count the arguments to an smacro call. Returns 0 if the token following
+ * is not a left paren.
+ */
+static int count_smacro_args(Token *t)
+{
+    int nparam;
+    int paren, brackets;
+
+    t = skip_white(t);
+
+    if (!tok_is(t, '('))
+        return 0;
+
+    paren = 1;
+    nparam = 1;
+    brackets = 0;
+
+    while (paren) {
+        t = t->next;
+
+        if (!t) {
+            nasm_nonfatal("macro call expects terminating `)'");
+            return 0;
+        }
+
+        switch (t->type) {
+        case ',':
+            if (!brackets && paren == 1)
+                nparam++;
+            break;
+
+        case '{':
+            brackets++;
+            break;
+
+        case '}':
+            if (brackets > 0)
+                brackets--;
+            break;
+
+        case '(':
+            if (!brackets)
+                paren++;
+            break;
+
+        case ')':
+            if (!brackets)
+                paren--;
+            break;
+
+        default:
+            break;          /* Normal token */
+        }
+    }
+
+    return nparam;
+}
+
+/*
+ * Collect the arguments to an smacro call. The size of the array must have
+ * been previously counted. It *is* permitted to call this with an nparam
+ * value that is too small for the macro in question; in that case the
+ * parameters are treated as missing optional arguments, even if they
+ * are not optional in the macro specification.
+ *
+ * *nparamp is adjusted if some arguments got merged as greedy or entered
+ * as optional/empty.
+ *
+ * Moves *tp to point to the final ) token.
+ */
+static Token **parse_smacro_args(Token **tp, int *nparamp, const SMacro *m)
+{
+    Token **phead, **pep;
+    int white = 0;
+    int brackets = 0;
+    int paren;
+    bool bracketed = false;
+    bool bad_bracket = false;
+    int i;
+    enum sparmflags flags;
+    const struct smac_param *mparm;
+    Token *t = *tp;
+    int nparam = *nparamp;
+    Token **params;
+    /* Is it a macro or a preprocessor function? Used for diagnostics. */
+    const char * const mtype = m->name[0] == '%' ? "function" : "macro";
+
+    nasm_assert(tok_is(t, '('));
+
+    if (nparam > m->nparam) {
+        if (m->params[m->nparam-1].flags & SPARM_GREEDY)
+            *nparamp = nparam = m->nparam;
+    } else if (nparam < m->nparam) {
+        *nparamp = nparam = m->nparam; /* Missing optional arguments = empty */
+    }
+    paren = 1;
+    nasm_newn(params, nparam);
+    i = 0;
+    mparm = m->params;
+    flags = mparm->flags;
+    phead = pep = &params[i];
+    *pep = NULL;
+
+    while (paren) {
+        bool skip;
+
+        t = t->next;
+
+        if (!t)
+            nasm_nonfatal("%s `%s' call expects terminating `)'",
+                          mtype, m->name);
+
+        skip = false;
+
+        switch (t->type) {
+        case TOKEN_WHITESPACE:
+            if (!(flags & SPARM_NOSTRIP)) {
+                if (brackets || *phead)
+                    white++;    /* Keep interior whitespace */
+                skip = true;
+            }
+            break;
+
+        case ',':
+            if (!brackets && paren == 1 && !(flags & SPARM_GREEDY)) {
+                i++;
+                nasm_assert(i < nparam);
+                phead = pep = &params[i];
+                *pep = NULL;
+                bracketed = false;
+                skip = true;
+                if (!(flags & SPARM_VARADIC)) {
+                    mparm++;
+                    flags = mparm->flags;
+                }
+            }
+            break;
+
+        case '{':
+            if (!bracketed) {
+                bracketed = !*phead && !(flags & SPARM_NOSTRIP);
+                skip = bracketed;
+            }
+            brackets++;
+            break;
+
+        case '}':
+            if (brackets > 0) {
+                if (!--brackets)
+                    skip = bracketed;
+            }
+            break;
+
+        case '(':
+            if (!brackets)
+                paren++;
+            break;
+
+        case ')':
+            if (!brackets) {
+                paren--;
+                if (!paren) {
+                    skip = true;
+                    i++;    /* Found last argument */
+                }
+            }
+            break;
+
+        default:
+            break;          /* Normal token */
+        }
+
+        if (!skip) {
+            Token *tt;
+
+            bad_bracket |= bracketed && !brackets;
+
+            if (white) {
+                *pep = tt = new_White(NULL);
+                pep = &tt->next;
+                white = 0;
+            }
+            *pep = tt = dup_Token(NULL, t);
+            pep = &tt->next;
+        }
+    }
+
+    *tp = t;
+    return params;
+}
+
 /*
  * Expand *one* single-line macro instance. If the first token is not
  * a macro at all, it is simply copied to the output and the pointer
@@ -5877,11 +6069,10 @@ expand_smacro_with_params(SMacro *m, Token *mstart, Token **params,
 static SMacro *expand_one_smacro(Token ***tpp)
 {
     Token **params = NULL;
-    const char *mname, *mtype;
+    const char *mname;
     Token *mstart = **tpp;
     Token *tline  = mstart;
     SMacro *head, *m;
-    int i;
     Token *tafter, **tep;
     int nparam = 0;
 
@@ -5944,61 +6135,12 @@ static SMacro *expand_one_smacro(Token ***tpp)
          * substitute for the parameters when we expand. What a
          * pain.
          */
-        Token *t;
-        int paren, brackets;
 
         tline = tline->next;
         tline = skip_white(tline);
-        if (!tok_is(tline, '(')) {
-            /*
-             * This macro wasn't called with parameters: ignore
-             * the call. (Behaviour borrowed from gnu cpp.)
-             */
+        nparam = count_smacro_args(tline);
+        if (!nparam)
             goto not_a_macro;
-        }
-
-        paren = 1;
-        nparam = 1;
-        brackets = 0;
-        t = tline;              /* tline points to leading ( */
-
-        while (paren) {
-            t = t->next;
-
-            if (!t) {
-                nasm_nonfatal("macro call expects terminating `)'");
-                goto not_a_macro;
-            }
-
-            switch (t->type) {
-            case ',':
-                if (!brackets && paren == 1)
-                    nparam++;
-                break;
-
-            case '{':
-                brackets++;
-                break;
-
-            case '}':
-                if (brackets > 0)
-                    brackets--;
-                break;
-
-            case '(':
-                if (!brackets)
-                    paren++;
-                break;
-
-            case ')':
-                if (!brackets)
-                    paren--;
-                break;
-
-            default:
-                break;          /* Normal token */
-            }
-        }
 
         /*
          * Look for a macro matching in both name and parameter count.
@@ -6033,117 +6175,8 @@ static SMacro *expand_one_smacro(Token ***tpp)
     if (m->in_progress && !m->recursive)
         goto not_a_macro;
 
-    /* Is it a macro or a preprocessor function? Used for diagnostics. */
-    mtype = m->name[0] == '%' ? "function" : "macro";
-
     if (nparam) {
-        /* Extract parameters */
-        Token **phead, **pep;
-        int white = 0;
-        int brackets = 0;
-        int paren;
-        bool bracketed = false;
-        bool bad_bracket = false;
-        enum sparmflags flags;
-        const struct smac_param *mparm;
-
-        if (nparam > m->nparam) {
-            if (m->params[m->nparam-1].flags & SPARM_GREEDY)
-                nparam = m->nparam;
-        } else if (nparam < m->nparam) {
-            nparam = m->nparam; /* Missing optional arguments = empty */
-        }
-        paren = 1;
-        nasm_newn(params, nparam);
-        i = 0;
-        mparm = m->params;
-        flags = mparm->flags;
-        phead = pep = &params[i];
-        *pep = NULL;
-
-        while (paren) {
-            bool skip;
-
-            tline = tline->next;
-
-            if (!tline)
-                nasm_nonfatal("%s `%s' call expects terminating `)'",
-                              mtype, m->name);
-
-            skip = false;
-
-            switch (tline->type) {
-            case TOKEN_WHITESPACE:
-                if (!(flags & SPARM_NOSTRIP)) {
-                    if (brackets || *phead)
-                        white++;    /* Keep interior whitespace */
-                    skip = true;
-                }
-                break;
-
-            case ',':
-                if (!brackets && paren == 1 && !(flags & SPARM_GREEDY)) {
-                    i++;
-                    nasm_assert(i < nparam);
-                    phead = pep = &params[i];
-                    *pep = NULL;
-                    bracketed = false;
-                    skip = true;
-                    if (!(flags & SPARM_VARADIC)) {
-                        mparm++;
-                        flags = mparm->flags;
-                    }
-                }
-                break;
-
-            case '{':
-                if (!bracketed) {
-                    bracketed = !*phead && !(flags & SPARM_NOSTRIP);
-                    skip = bracketed;
-                }
-                brackets++;
-                break;
-
-            case '}':
-                if (brackets > 0) {
-                    if (!--brackets)
-                        skip = bracketed;
-                }
-                break;
-
-            case '(':
-                if (!brackets)
-                    paren++;
-                break;
-
-            case ')':
-                if (!brackets) {
-                    paren--;
-                    if (!paren) {
-                        skip = true;
-                        i++;    /* Found last argument */
-                    }
-                }
-                break;
-
-            default:
-                break;          /* Normal token */
-            }
-
-            if (!skip) {
-                Token *t;
-
-                bad_bracket |= bracketed && !brackets;
-
-                if (white) {
-                    *pep = t = new_White(NULL);
-                    pep = &t->next;
-                    white = 0;
-                }
-                *pep = t = dup_Token(NULL, tline);
-                pep = &t->next;
-            }
-        }
+        params = parse_smacro_args(&tline, &nparam, m);
     }
 
     tafter = tline->next;   /* Skip past the macro call */


More information about the Nasm-commits mailing list