preproc: Add new %[...] indirection construct
authorH. Peter Anvin <hpa@zytor.com>
Sun, 19 Oct 2008 22:45:05 +0000 (15:45 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Sun, 19 Oct 2008 22:45:05 +0000 (15:45 -0700)
Add a new %[...] construct to support indirect macro expansion.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
preproc.c

index e5b5ab3..447f235 100644 (file)
--- a/preproc.c
+++ b/preproc.c
@@ -159,6 +159,7 @@ enum pp_token_type {
     TOK_NUMBER, TOK_FLOAT, TOK_SMAC_END, TOK_OTHER,
     TOK_INTERNAL_STRING,
     TOK_PREPROC_Q, TOK_PREPROC_QQ,
+    TOK_INDIRECT,              /* %[...] */
     TOK_SMAC_PARAM,            /* MUST BE LAST IN THE LIST!!! */
     TOK_MAX = INT_MAX          /* Keep compiler from reducing the range */
 };
@@ -396,6 +397,7 @@ static Blocks blocks = { NULL, NULL };
 static Token *expand_mmac_params(Token * tline);
 static Token *expand_smacro(Token * tline);
 static Token *expand_id(Token * tline);
+static Token *expand_indirect(Token * tline, int level);
 static Context *get_ctx(const char *name, bool all_contexts);
 static void make_tok_num(Token * tok, int64_t val);
 static void error(int severity, const char *fmt, ...);
@@ -804,6 +806,22 @@ static Token *tokenize(char *line)
                 if (*p)
                     p++;
                 type = TOK_PREPROC_ID;
+           } else if (*p == '[') {
+               int lvl = 1;
+               line += 2;      /* Skip the leading %[ */
+               p++;
+               while (*p) {
+                   if (*p == ']') {
+                       if (!--lvl)
+                           break;
+                   } else if (*p == '%' && p[1] == '[') {
+                       lvl++;
+                   }
+                   p++;
+               }
+               if (*p)
+                   *p++ = '\0';
+               type = TOK_INDIRECT;
            } else if (*p == '?') {
                type = TOK_PREPROC_Q; /* %? */
                p++;
@@ -2446,10 +2464,13 @@ static int do_directive(Token * tline)
                  * called expand_mmac_params(); however, if we're
                  * processing an %elif we must have been in a
                  * non-emitting mode, which would have inhibited
-                 * the normal invocation of expand_mmac_params().  Therefore,
-                 * we have to do it explicitly here.
+                 * the normal invocation of expand_indirect() and
+                * expand_mmac_params().  Therefore, we have to do it
+                * explicitly here.
                  */
-                j = if_condition(expand_mmac_params(tline->next), i);
+               t = expand_indirect(tline->next,0);
+               t = expand_mmac_params(t);
+                j = if_condition(expand_mmac_params(t), i);
                 tline->next = NULL; /* it got freed */
                 istk->conds->state =
                     j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
@@ -3442,15 +3463,8 @@ static Token *expand_mmac_params(Token * tline)
             }
             break;
         case TOK_ID:
-            if (tt->type == TOK_ID || tt->type == TOK_NUMBER) {
-                char *tmp = nasm_strcat(t->text, tt->text);
-                nasm_free(t->text);
-                t->text = tmp;
-                t->next = delete_Token(tt);
-            }
-            break;
         case TOK_NUMBER:
-            if (tt->type == TOK_NUMBER) {
+            if (tt->type == t->type || tt->type == TOK_NUMBER) {
                 char *tmp = nasm_strcat(t->text, tt->text);
                 nasm_free(t->text);
                 t->text = tmp;
@@ -3887,6 +3901,61 @@ static Token *expand_id(Token * tline)
 }
 
 /*
+ * Expand indirect tokens, %[...].
+ */
+static Token *expand_indirect(Token * tline, int level)
+{
+    const int max_indirect_level = 1000;
+    Token *t, *thead, **tp;
+    Token *it;
+    bool skip;
+
+    if (level >= max_indirect_level) {
+       error(ERR_NONFATAL, "interminable indirect expansion");
+    } else {
+       thead = NULL;
+       for (tp = &tline; (t = *tp); thead = t, tp = &t->next) {
+           if (t->type != TOK_INDIRECT)
+               continue;
+           it = tokenize(t->text);
+           it = expand_indirect(it, level+1);
+           it = expand_smacro(it);
+           while (it) {
+               skip = false;
+               switch (thead ? thead->type : TOK_NONE) {
+               case TOK_WHITESPACE:
+                   skip = (it->type == TOK_WHITESPACE);
+                   break;
+
+               case TOK_ID:
+               case TOK_NUMBER:
+                   if (it->type == thead->type || it->type == TOK_NUMBER) {
+                       char *tmp = nasm_strcat(thead->text, it->text);
+                       thead->text = tmp;
+                       skip = true;
+                   }
+                   break;
+                   
+               default:
+                   break;
+               }
+
+               if (skip) {
+                   it = delete_Token(it);
+               } else {
+                   *tp = thead = it;
+                   tp = &it->next;
+                   it = it->next;
+               }
+           }
+           *tp = t->next;
+           delete_Token(t);
+       }
+    }
+    return tline;
+}
+
+/*
  * Determine whether the given line constitutes a multi-line macro
  * call, and return the MMacro structure called if so. Doesn't have
  * to check for an initial label - that's taken care of in
@@ -4428,8 +4497,10 @@ static char *pp_getline(void)
          * anything.
          */
         if (!defining && !(istk->conds && !emitting(istk->conds->state))
-            && !(istk->mstk && !istk->mstk->in_progress))
+            && !(istk->mstk && !istk->mstk->in_progress)) {
+           tline = expand_indirect(tline,0);
             tline = expand_mmac_params(tline);
+       }
 
         /*
          * Check the line to see if it's a preprocessor directive.