More automation in the preprocessor conditionals handling
authorH. Peter Anvin <hpa@zytor.com>
Wed, 12 Sep 2007 04:18:37 +0000 (04:18 +0000)
committerH. Peter Anvin <hpa@zytor.com>
Wed, 12 Sep 2007 04:18:37 +0000 (04:18 +0000)
Further automate the production of preprocessor conditionals.  Now the
code automatically folds if/elif and the negatives.

pptok.pl
preproc.c

index 759a9a0..9a00ea2 100755 (executable)
--- a/pptok.pl
+++ b/pptok.pl
@@ -17,9 +17,9 @@ while (defined($line = <IN>)) {
     $line =~ s/\s*\#.*$//;     # Remove comments and trailing whitespace
     next if ($line eq '');
     
-    if ($line =~ /^(\%.*)\*$/) {
+    if ($line =~ /^\%(.*)\*$/) {
        push(@cctok, $1);
-    } elsif ($line =~ /^(\%.*)$/) {
+    } elsif ($line =~ /^\%(.*)$/) {
        push(@pptok, $1);
     } elsif ($line =~ /^\*(.*)$/) {
        push(@cond, $1);
@@ -29,16 +29,29 @@ close(IN);
 
 @cctok = sort @cctok;
 @cond = sort @cond;
+@pptok = sort @pptok;
+
+# Generate the expanded list including conditionals.  The conditionals
+# are at the beginning, padded to a power of 2, with the inverses
+# interspersed; this allows a simple mask to pick out the condition.
 
-# Generate the expanded list including conditionals
+while ((scalar @cond) & (scalar @cond)-1) {
+    push(@cond, undef);
+}
+
+@cptok = ();
 foreach $ct (@cctok) {
     foreach $cc (@cond) {
-       push(@pptok, $ct.$cc);
-       push(@pptok, $ct.'n'.$cc);
+       if (defined($cc)) {
+           push(@cptok, $ct.$cc);
+           push(@cptok, $ct.'n'.$cc);
+       } else {
+           push(@cptok, undef, undef);
+       }
     }
 }
-
-@pptok = sort @pptok;
+$first_uncond = $pptok[0];
+@pptok = (@cptok, @pptok);
 
 open(OUT, "> $out") or die "$0: cannot open: $out\n";
 print OUT "/* Automatically generated from $in by $0 */\n";
@@ -50,21 +63,44 @@ print OUT "\n";
 #
 if ($what eq 'h') {
     print OUT "enum preproc_token {\n";
+    $n = 0;
     foreach $pt (@pptok) {
-       (my $px = $pt) =~ s/\%//g;
-       print OUT "    PP_\U$px\E,\n";
+       if (defined($pt)) {
+           printf OUT "    %-16s = %3d,\n", "PP_\U$pt\E", $n;
+       }
+       $n++;
     }
-    print OUT "    PP_INVALID = -1\n";
+    printf OUT "    %-16s = %3d\n", 'PP_INVALID', -1;
     print OUT "};\n";
     print OUT "\n";
 
-    $first_cc = $cond[0];
-    $last_cc  = $cond[(scalar @cond)-1];
+    print  OUT "enum pp_conditional {\n";
+    $n = 0;
+    foreach $cc (@cond) {
+       if (defined($cc)) {
+           printf OUT "    %-16s = %3d,\n", "PPC_IF\U$cc\E", $n;
+       }
+       $n += 2;
+    }
+    print  OUT "};\n\n";
+    
+    printf OUT "#define PP_COND(x)     ((enum pp_conditional)((x) & 0x%x))\n",
+       (scalar(@cond)-1) << 1;
+    print  OUT "#define PP_IS_COND(x)  ((unsigned int)(x) < PP_\U$first_uncond\E)\n";
+    print  OUT "#define PP_NEGATIVE(x) ((x) & 1)\n";
+    print  OUT "\n";
 
     foreach $ct (@cctok) {
-       (my $cx = $ct) =~ s/\%//g;
-       print OUT "#define IS_PP_\U$cx\E(x) ((x) >= PP_\U$cx$first_cc\E && ";
-       print OUT "(x) <= PP_\U$cx$last_cc\E)\n";
+       print OUT "#define CASE_PP_\U$ct\E";
+       $pref = " \\\n";
+       foreach $cc (@cond) {
+           if (defined($cc)) {
+               print OUT "$pref\tcase PP_\U${ct}${cc}\E: \\\n";
+               print OUT "\tcase PP_\U${ct}N${cc}\E";
+               $pref = ":\\\n";
+           }
+       }
+       print OUT "\n";         # No colon or newline on the last one
     }
 }
 
@@ -75,10 +111,12 @@ if ($what eq 'c') {
     my %tokens = ();
     my @tokendata = ();
 
+    my $n = 0;
     foreach $pt (@pptok) {
-       (my $px = $pt) =~ s/\%//g;
-       $tokens{$pt} = scalar @tokendata;
-       push(@tokendata, $pt);
+       if (defined($pt)) {
+           $tokens{'%'.$pt} = $n;
+       }
+       $n++;
     }
 
     my @hashinfo = gen_perfect_hash(\%tokens);
@@ -104,10 +142,13 @@ if ($what eq 'c') {
     print OUT "\n";
 
     # Note that this is global.
-    printf OUT "const char * const pp_directives[%d] = {\n",
-       scalar(@tokendata);
-    foreach $d (@tokendata) {
-       print OUT "    \"$d\",\n";
+    printf OUT "const char * const pp_directives[%d] = {\n", scalar(@pptok);
+    foreach $d (@pptok) {
+       if (defined($d)) {
+           print OUT "    \"%$d\",\n";
+       } else {
+           print OUT "    NULL,\n";
+       }
     }
     print OUT  "};\n";
     
@@ -149,7 +190,7 @@ if ($what eq 'c') {
     print OUT  "    }\n";
     print OUT  "\n";
     printf OUT "    ix = hash1[k1 & 0x%x] + hash2[k2 & 0x%x];\n", $n-1, $n-1;
-    printf OUT "    if (ix >= %d)\n", scalar(@tokendata);
+    printf OUT "    if (ix >= %d)\n", scalar(@pptok);
     print OUT  "        return PP_INVALID;\n";
     print OUT  "\n";
 
index 68aea7e..fa2a953 100644 (file)
--- a/preproc.c
+++ b/preproc.c
@@ -137,16 +137,18 @@ struct Context {
  * mechanism as an alternative to trying to find a sensible type of
  * quote to use on the filename we were passed.
  */
+enum pp_token_type {
+    TOK_NONE = 0, TOK_WHITESPACE, TOK_COMMENT, TOK_ID,
+    TOK_PREPROC_ID, TOK_STRING,
+    TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_SMAC_PARAM,
+    TOK_INTERNAL_STRING
+};
+
 struct Token {
     Token *next;
     char *text;
     SMacro *mac;                /* associated macro for TOK_SMAC_END */
-    int type;
-};
-enum {
-    TOK_WHITESPACE = 1, TOK_COMMENT, TOK_ID, TOK_PREPROC_ID, TOK_STRING,
-    TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_SMAC_PARAM,
-    TOK_INTERNAL_STRING
+    enum pp_token_type type;
 };
 
 /*
@@ -274,8 +276,7 @@ static int inverse_ccs[] = {
 /* If this is a an IF, ELIF, ELSE or ENDIF keyword */
 static int is_condition(enum preproc_token arg)
 {
-    return IS_PP_IF(arg) || IS_PP_ELIF(arg) ||
-       (arg == PP_ELSE) || (arg == PP_ENDIF);
+    return PP_IS_COND(arg) || (arg == PP_ELSE) || (arg == PP_ENDIF);
 }
 
 /* For TASM compatibility we need to be able to recognise TASM compatible
@@ -383,7 +384,7 @@ static void make_tok_num(Token * tok, int32_t val);
 static void error(int severity, const char *fmt, ...);
 static void *new_Block(size_t size);
 static void delete_Blocks(void);
-static Token *new_Token(Token * next, int type, char *text, int txtlen);
+static Token *new_Token(Token * next, enum pp_token_type type, char *text, int txtlen);
 static Token *delete_Token(Token * t);
 
 /*
@@ -683,7 +684,7 @@ static char *read_line(void)
 static Token *tokenize(char *line)
 {
     char *p = line;
-    int type;
+    enum pp_token_type type;
     Token *list = NULL;
     Token *t, **tail = &list;
 
@@ -862,7 +863,7 @@ static void delete_Blocks(void)
  *  back to the caller.  It sets the type and text elements, and
  *  also the mac and next elements to NULL.
  */
-static Token *new_Token(Token * next, int type, char *text, int txtlen)
+static Token *new_Token(Token * next, enum pp_token_type type, char *text, int txtlen)
 {
     Token *t;
     int i;
@@ -1269,26 +1270,25 @@ static void count_mmac_params(Token * t, int *nparam, Token *** params)
  *
  * We must free the tline we get passed.
  */
-static int if_condition(Token * tline, int i)
+static int if_condition(Token * tline, enum preproc_token ct)
 {
-    int j, casesense;
+    enum pp_conditional i = PP_COND(ct);
+    int j;
     Token *t, *tt, **tptr, *origline;
     struct tokenval tokval;
     expr *evalresult;
+    enum pp_token_type needtype;
 
     origline = tline;
 
     switch (i) {
-    case PP_IFCTX:
-    case PP_ELIFCTX:
-    case PP_IFNCTX:
-    case PP_ELIFNCTX:
+    case PPC_IFCTX:
         j = FALSE;              /* have we matched yet? */
         while (cstk && tline) {
             skip_white_(tline);
             if (!tline || tline->type != TOK_ID) {
                 error(ERR_NONFATAL,
-                      "`%s' expects context identifiers", pp_directives[i]);
+                      "`%s' expects context identifiers", pp_directives[ct]);
                 free_tlist(origline);
                 return -1;
             }
@@ -1296,15 +1296,9 @@ static int if_condition(Token * tline, int i)
                 j = TRUE;
             tline = tline->next;
         }
-        if (i == PP_IFNCTX || i == PP_ELIFNCTX)
-            j = !j;
-        free_tlist(origline);
-        return j;
+       break;
 
-    case PP_IFDEF:
-    case PP_ELIFDEF:
-    case PP_IFNDEF:
-    case PP_ELIFNDEF:
+    case PPC_IFDEF:
         j = FALSE;              /* have we matched yet? */
         while (tline) {
             skip_white_(tline);
@@ -1312,27 +1306,17 @@ static int if_condition(Token * tline, int i)
                            (tline->type != TOK_PREPROC_ID ||
                             tline->text[1] != '$'))) {
                 error(ERR_NONFATAL,
-                      "`%s' expects macro identifiers", pp_directives[i]);
-                free_tlist(origline);
-                return -1;
+                      "`%s' expects macro identifiers", pp_directives[ct]);
+               goto fail;
             }
             if (smacro_defined(NULL, tline->text, 0, NULL, 1))
                 j = TRUE;
             tline = tline->next;
         }
-        if (i == PP_IFNDEF || i == PP_ELIFNDEF)
-            j = !j;
-        free_tlist(origline);
-        return j;
+       break;
 
-    case PP_IFIDN:
-    case PP_ELIFIDN:
-    case PP_IFNIDN:
-    case PP_ELIFNIDN:
-    case PP_IFIDNI:
-    case PP_ELIFIDNI:
-    case PP_IFNIDNI:
-    case PP_ELIFNIDNI:
+    case PPC_IFIDN:
+    case PPC_IFIDNI:
         tline = expand_smacro(tline);
         t = tt = tline;
         while (tok_isnt_(tt, ","))
@@ -1340,20 +1324,16 @@ static int if_condition(Token * tline, int i)
         if (!tt) {
             error(ERR_NONFATAL,
                   "`%s' expects two comma-separated arguments",
-                  pp_directives[i]);
-            free_tlist(tline);
-            return -1;
+                  pp_directives[ct]);
+           goto fail;
         }
         tt = tt->next;
-        casesense = (i == PP_IFIDN || i == PP_ELIFIDN ||
-                     i == PP_IFNIDN || i == PP_ELIFNIDN);
         j = TRUE;               /* assume equality unless proved not */
         while ((t->type != TOK_OTHER || strcmp(t->text, ",")) && tt) {
             if (tt->type == TOK_OTHER && !strcmp(tt->text, ",")) {
                 error(ERR_NONFATAL, "`%s': more than one comma on line",
-                      pp_directives[i]);
-                free_tlist(tline);
-                return -1;
+                      pp_directives[ct]);
+               goto fail;
             }
             if (t->type == TOK_WHITESPACE) {
                 t = t->next;
@@ -1372,7 +1352,7 @@ static int if_condition(Token * tline, int i)
                 tt->text[0] = t->text[0];
                 tt->text[strlen(tt->text) - 1] = t->text[0];
             }
-            if (mstrcmp(tt->text, t->text, casesense) != 0) {
+            if (mstrcmp(tt->text, t->text, i == PPC_IFIDN) != 0) {
                 j = FALSE;      /* found mismatching tokens */
                 break;
             }
@@ -1382,16 +1362,9 @@ static int if_condition(Token * tline, int i)
         }
         if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt)
             j = FALSE;          /* trailing gunk on one end or other */
-        if (i == PP_IFNIDN || i == PP_ELIFNIDN ||
-            i == PP_IFNIDNI || i == PP_ELIFNIDNI)
-            j = !j;
-        free_tlist(tline);
-        return j;
+       break;
 
-    case PP_IFMACRO:
-    case PP_ELIFMACRO:
-    case PP_IFNMACRO:
-    case PP_ELIFNMACRO:
+    case PPC_IFMACRO:
         {
             int found = 0;
             MMacro searching, *mmac;
@@ -1401,8 +1374,8 @@ static int if_condition(Token * tline, int i)
             tline = expand_id(tline);
             if (!tok_type_(tline, TOK_ID)) {
                 error(ERR_NONFATAL,
-                      "`%s' expects a macro name", pp_directives[i]);
-                return -1;
+                      "`%s' expects a macro name", pp_directives[ct]);
+               goto fail;
             }
             searching.name = nasm_strdup(tline->text);
             searching.casesense = (i == PP_MACRO);
@@ -1418,7 +1391,7 @@ static int if_condition(Token * tline, int i)
             } else if (!tok_type_(tline, TOK_NUMBER)) {
                 error(ERR_NONFATAL,
                       "`%s' expects a parameter count or nothing",
-                      pp_directives[i]);
+                      pp_directives[ct]);
             } else {
                 searching.nparam_min = searching.nparam_max =
                     readnum(tline->text, &j);
@@ -1434,7 +1407,7 @@ static int if_condition(Token * tline, int i)
                 else if (!tok_type_(tline, TOK_NUMBER))
                     error(ERR_NONFATAL,
                           "`%s' expects a parameter count after `-'",
-                          pp_directives[i]);
+                          pp_directives[ct]);
                 else {
                     searching.nparam_max = readnum(tline->text, &j);
                     if (j)
@@ -1463,67 +1436,36 @@ static int if_condition(Token * tline, int i)
                 mmac = mmac->next;
             }
             nasm_free(searching.name);
-            free_tlist(origline);
-            if (i == PP_IFNMACRO || i == PP_ELIFNMACRO)
-                found = !found;
-            return found;
+           j = found;
+           break;
         }
 
-    case PP_IFID:
-    case PP_ELIFID:
-    case PP_IFNID:
-    case PP_ELIFNID:
-    case PP_IFNUM:
-    case PP_ELIFNUM:
-    case PP_IFNNUM:
-    case PP_ELIFNNUM:
-    case PP_IFSTR:
-    case PP_ELIFSTR:
-    case PP_IFNSTR:
-    case PP_ELIFNSTR:
+    case PPC_IFID:
+       needtype = TOK_ID;
+       goto iftype;
+    case PPC_IFNUM:
+       needtype = TOK_NUMBER;
+       goto iftype;
+    case PPC_IFSTR:
+       needtype = TOK_STRING;
+       goto iftype;
+
+    iftype:
         tline = expand_smacro(tline);
         t = tline;
         while (tok_type_(t, TOK_WHITESPACE))
             t = t->next;
         j = FALSE;              /* placate optimiser */
         if (t)
-            switch (i) {
-            case PP_IFID:
-            case PP_ELIFID:
-            case PP_IFNID:
-            case PP_ELIFNID:
-                j = (t->type == TOK_ID);
-                break;
-            case PP_IFNUM:
-            case PP_ELIFNUM:
-            case PP_IFNNUM:
-            case PP_ELIFNNUM:
-                j = (t->type == TOK_NUMBER);
-                break;
-            case PP_IFSTR:
-            case PP_ELIFSTR:
-            case PP_IFNSTR:
-            case PP_ELIFNSTR:
-                j = (t->type == TOK_STRING);
-                break;
-            }
-        if (i == PP_IFNID || i == PP_ELIFNID ||
-            i == PP_IFNNUM || i == PP_ELIFNNUM ||
-            i == PP_IFNSTR || i == PP_ELIFNSTR)
-            j = !j;
-        free_tlist(tline);
-        return j;
+           j = t->type == needtype;
+       break;
 
-    case PP_IF:
-    case PP_IFN:
-    case PP_ELIF:
-    case PP_ELIFN:
+    case PPC_IF:
         t = tline = expand_smacro(tline);
         tptr = &t;
         tokval.t_type = TOKEN_INVALID;
         evalresult = evaluate(ppscan, tptr, &tokval,
                               NULL, pass | CRITICAL, error, NULL);
-        free_tlist(tline);
         if (!evalresult)
             return -1;
         if (tokval.t_type)
@@ -1531,20 +1473,24 @@ static int if_condition(Token * tline, int i)
                   "trailing garbage after expression ignored");
         if (!is_simple(evalresult)) {
             error(ERR_NONFATAL,
-                  "non-constant value given to `%s'", pp_directives[i]);
-            return -1;
+                  "non-constant value given to `%s'", pp_directives[ct]);
+           goto fail;
         }
         j = reloc_value(evalresult) != 0;
-        if (i == PP_IFN || i == PP_ELIFN)
-            j = !j;
         return j;
     default:
         error(ERR_FATAL,
               "preprocessor directive `%s' not yet implemented",
-              pp_directives[i]);
-        free_tlist(origline);
-        return -1;              /* yeah, right */
+              pp_directives[ct]);
+       goto fail;
     }
+
+    free_tlist(origline);
+    return j ^ PP_NEGATIVE(ct);
+    
+fail:
+    free_tlist(origline);
+    return -1;
 }
 
 /*
@@ -1957,24 +1903,7 @@ static int do_directive(Token * tline)
         free_tlist(origline);
         break;
 
-    case PP_IF:
-    case PP_IFCTX:
-    case PP_IFDEF:
-    case PP_IFID:
-    case PP_IFIDN:
-    case PP_IFIDNI:
-    case PP_IFMACRO:
-    case PP_IFN:
-    case PP_IFNCTX:
-    case PP_IFNDEF:
-    case PP_IFNID:
-    case PP_IFNIDN:
-    case PP_IFNIDNI:
-    case PP_IFNMACRO:
-    case PP_IFNNUM:
-    case PP_IFNSTR:
-    case PP_IFNUM:
-    case PP_IFSTR:
+    CASE_PP_IF:
         if (istk->conds && !emitting(istk->conds->state))
             j = COND_NEVER;
         else {
@@ -1989,24 +1918,7 @@ static int do_directive(Token * tline)
         istk->conds = cond;
         return DIRECTIVE_FOUND;
 
-    case PP_ELIF:
-    case PP_ELIFCTX:
-    case PP_ELIFDEF:
-    case PP_ELIFID:
-    case PP_ELIFIDN:
-    case PP_ELIFIDNI:
-    case PP_ELIFMACRO:
-    case PP_ELIFN:
-    case PP_ELIFNCTX:
-    case PP_ELIFNDEF:
-    case PP_ELIFNID:
-    case PP_ELIFNIDN:
-    case PP_ELIFNIDNI:
-    case PP_ELIFNMACRO:
-    case PP_ELIFNNUM:
-    case PP_ELIFNSTR:
-    case PP_ELIFNUM:
-    case PP_ELIFSTR:
+    CASE_PP_ELIF:
         if (!istk->conds)
             error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
         if (emitting(istk->conds->state)
@@ -2961,6 +2873,8 @@ static Token *expand_mmac_params(Token * tline)
                 t->next = delete_Token(tt);
             }
             break;
+       default:
+           break;
         }
 
     return thead;