Print this page
new smatch

Split Close
Expand all
Collapse all
          --- old/usr/src/tools/smatch/src/pre-process.c
          +++ new/usr/src/tools/smatch/src/pre-process.c
↓ open down ↓ 41 lines elided ↑ open up ↑
  42   42  #include "allocate.h"
  43   43  #include "parse.h"
  44   44  #include "token.h"
  45   45  #include "symbol.h"
  46   46  #include "expression.h"
  47   47  #include "scope.h"
  48   48  
  49   49  static struct ident_list *macros;       // only needed for -dD
  50   50  static int false_nesting = 0;
  51   51  static int counter_macro = 0;           // __COUNTER__ expansion
       52 +static int include_level = 0;
  52   53  
  53   54  #define INCLUDEPATHS 300
  54   55  const char *includepath[INCLUDEPATHS+1] = {
  55   56          "",
  56   57          "/usr/include",
  57   58          "/usr/local/include",
  58   59          NULL
  59   60  };
  60   61  
  61   62  static const char **quote_includepath = includepath;
↓ open down ↓ 78 lines elided ↑ open up ↑
 140  141                          sym->used_in = file_scope;
 141  142                          return 1;
 142  143                  }
 143  144                  return 0;
 144  145          }
 145  146  
 146  147          sparse_error(token->pos, "expected preprocessor identifier");
 147  148          return 0;
 148  149  }
 149  150  
 150      -static void replace_with_defined(struct token *token)
      151 +static void replace_with_bool(struct token *token, bool val)
 151  152  {
 152  153          static const char *string[] = { "0", "1" };
 153      -        int defined = token_defined(token);
 154  154  
 155  155          token_type(token) = TOKEN_NUMBER;
 156      -        token->number = string[defined];
      156 +        token->number = string[val];
 157  157  }
 158  158  
      159 +static void replace_with_defined(struct token *token)
      160 +{
      161 +        replace_with_bool(token, token_defined(token));
      162 +}
      163 +
      164 +static void replace_with_has_builtin(struct token *token)
      165 +{
      166 +        struct symbol *sym = lookup_symbol(token->ident, NS_SYMBOL);
      167 +        replace_with_bool(token, sym && sym->builtin);
      168 +}
      169 +
      170 +static void replace_with_has_attribute(struct token *token)
      171 +{
      172 +        struct symbol *sym = lookup_symbol(token->ident, NS_KEYWORD);
      173 +        replace_with_bool(token, sym && sym->op && sym->op->attribute);
      174 +}
      175 +
      176 +static void expand_line(struct token *token)
      177 +{
      178 +        replace_with_integer(token, token->pos.line);
      179 +}
      180 +
      181 +static void expand_file(struct token *token)
      182 +{
      183 +        replace_with_string(token, stream_name(token->pos.stream));
      184 +}
      185 +
      186 +static void expand_basefile(struct token *token)
      187 +{
      188 +        replace_with_string(token, base_filename);
      189 +}
      190 +
      191 +static time_t t = 0;
      192 +static void expand_date(struct token *token)
      193 +{
      194 +        static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */
      195 +
      196 +        if (!t)
      197 +                time(&t);
      198 +        strftime(buffer, 12, "%b %e %Y", localtime(&t));
      199 +        replace_with_string(token, buffer);
      200 +}
      201 +
      202 +static void expand_time(struct token *token)
      203 +{
      204 +        static char buffer[9]; /* __TIME__: 2 + ':' + 2 + ':' + 2 + '\0' */
      205 +
      206 +        if (!t)
      207 +                time(&t);
      208 +        strftime(buffer, 9, "%T", localtime(&t));
      209 +        replace_with_string(token, buffer);
      210 +}
      211 +
      212 +static void expand_counter(struct token *token)
      213 +{
      214 +        replace_with_integer(token, counter_macro++);
      215 +}
      216 +
      217 +static void expand_include_level(struct token *token)
      218 +{
      219 +        replace_with_integer(token, include_level - 1);
      220 +}
      221 +
 159  222  static int expand_one_symbol(struct token **list)
 160  223  {
 161  224          struct token *token = *list;
 162  225          struct symbol *sym;
 163      -        static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */
 164      -        static time_t t = 0;
 165  226  
 166  227          if (token->pos.noexpand)
 167  228                  return 1;
 168  229  
 169  230          sym = lookup_macro(token->ident);
 170      -        if (sym) {
 171      -                store_macro_pos(token);
      231 +        if (!sym)
      232 +                return 1;
      233 +        store_macro_pos(token);
      234 +        if (sym->expander) {
      235 +                sym->expander(token);
      236 +                return 1;
      237 +        } else {
 172  238                  sym->used_in = file_scope;
 173  239                  return expand(list, sym);
 174  240          }
 175      -        if (token->ident == &__LINE___ident) {
 176      -                replace_with_integer(token, token->pos.line);
 177      -        } else if (token->ident == &__FILE___ident) {
 178      -                replace_with_string(token, stream_name(token->pos.stream));
 179      -        } else if (token->ident == &__DATE___ident) {
 180      -                if (!t)
 181      -                        time(&t);
 182      -                strftime(buffer, 12, "%b %e %Y", localtime(&t));
 183      -                replace_with_string(token, buffer);
 184      -        } else if (token->ident == &__TIME___ident) {
 185      -                if (!t)
 186      -                        time(&t);
 187      -                strftime(buffer, 9, "%T", localtime(&t));
 188      -                replace_with_string(token, buffer);
 189      -        } else if (token->ident == &__COUNTER___ident) {
 190      -                replace_with_integer(token, counter_macro++);
 191      -        }
 192      -        return 1;
 193  241  }
 194  242  
 195  243  static inline struct token *scan_next(struct token **where)
 196  244  {
 197  245          struct token *token = *where;
 198  246          if (token_type(token) != TOKEN_UNTAINT)
 199  247                  return token;
 200  248          do {
 201  249                  token->ident->tainted = 0;
 202  250                  token = token->next;
↓ open down ↓ 304 lines elided ↑ open up ↑
 507  555          static char buffer[512];
 508  556          enum token_type res = combine(left, right, buffer);
 509  557          int n;
 510  558  
 511  559          switch (res) {
 512  560          case TOKEN_IDENT:
 513  561                  left->ident = built_in_ident(buffer);
 514  562                  left->pos.noexpand = 0;
 515  563                  return 1;
 516  564  
 517      -        case TOKEN_NUMBER: {
 518      -                char *number = __alloc_bytes(strlen(buffer) + 1);
 519      -                memcpy(number, buffer, strlen(buffer) + 1);
      565 +        case TOKEN_NUMBER:
 520  566                  token_type(left) = TOKEN_NUMBER;        /* could be . + num */
 521      -                left->number = number;
      567 +                left->number = xstrdup(buffer);
 522  568                  return 1;
 523      -        }
 524  569  
 525  570          case TOKEN_SPECIAL:
 526  571                  if (buffer[2] && buffer[3])
 527  572                          break;
 528  573                  for (n = SPECIAL_BASE; n < SPECIAL_ARG_SEPARATOR; n++) {
 529  574                          if (!memcmp(buffer, combinations[n-SPECIAL_BASE], 3)) {
 530  575                                  left->special = n;
 531  576                                  return 1;
 532  577                          }
 533  578                  }
↓ open down ↓ 310 lines elided ↑ open up ↑
 844  889                          /* This includes the final "/" */
 845  890                          memcpy(m, stream->name, len);
 846  891                          m[len] = 0;
 847  892                          path = m;
 848  893                  }
 849  894                  stream->path = path;
 850  895          }
 851  896          includepath[0] = path;
 852  897  }
 853  898  
      899 +#ifndef PATH_MAX
      900 +#define PATH_MAX 4096   // for Hurd where it's not defined
      901 +#endif
      902 +
 854  903  static int try_include(const char *path, const char *filename, int flen, struct token **where, const char **next_path)
 855  904  {
 856  905          int fd;
 857  906          int plen = strlen(path);
 858  907          static char fullname[PATH_MAX];
 859  908  
 860  909          memcpy(fullname, path, plen);
 861  910          if (plen && path[plen-1] != '/') {
 862  911                  fullname[plen] = '/';
 863  912                  plen++;
 864  913          }
 865  914          memcpy(fullname+plen, filename, flen);
 866  915          if (already_tokenized(fullname))
 867  916                  return 1;
 868  917          fd = open(fullname, O_RDONLY);
 869  918          if (fd >= 0) {
 870      -                char * streamname = __alloc_bytes(plen + flen);
 871      -                memcpy(streamname, fullname, plen + flen);
      919 +                char *streamname = xmemdup(fullname, plen + flen);
 872  920                  *where = tokenize(streamname, fd, *where, next_path);
 873  921                  close(fd);
 874  922                  return 1;
 875  923          }
 876  924          return 0;
 877  925  }
 878  926  
 879  927  static int do_include_path(const char **pptr, struct token **list, struct token *token, const char *filename, int flen)
 880  928  {
 881  929          const char *path;
↓ open down ↓ 23 lines elided ↑ open up ↑
 905  953          struct stat statbuf;
 906  954          const char *ret;
 907  955          char cwd[PATH_MAX];
 908  956          static char buf[PATH_MAX + 1];
 909  957  
 910  958          dp = opendir(".");
 911  959          if (!dp)
 912  960                  return NULL;
 913  961  
 914  962          if (!getcwd(cwd, sizeof(cwd)))
 915      -                return NULL;
      963 +                goto close;
 916  964  
 917  965          while ((entry = readdir(dp))) {
 918  966                  lstat(entry->d_name, &statbuf);
 919  967  
 920  968                  if (strcmp(entry->d_name, look_for) == 0) {
 921  969                          snprintf(buf, sizeof(buf), "%s/%s", cwd, entry->d_name);
      970 +                        closedir(dp);
 922  971                          return buf;
 923  972                  }
 924  973  
 925  974                  if (S_ISDIR(statbuf.st_mode)) {
 926  975                          /* Found a directory, but ignore . and .. */
 927  976                          if (strcmp(".", entry->d_name) == 0 ||
 928  977                              strcmp("..", entry->d_name) == 0 ||
 929  978                              strcmp(skip, entry->d_name) == 0)
 930  979                                  continue;
 931  980  
 932  981                          chdir(entry->d_name);
 933  982                          ret = find_include("", look_for);
 934  983                          chdir("..");
 935      -                        if (ret)
      984 +                        if (ret) {
      985 +                                closedir(dp);
 936  986                                  return ret;
      987 +                        }
 937  988                  }
 938  989          }
      990 +close:
 939  991          closedir(dp);
 940  992  
 941  993          return NULL;
 942  994  }
 943  995  
 944  996  const char *search_dir(const char *stop, const char *look_for)
 945  997  {
 946  998          char cwd[PATH_MAX];
 947  999          int len;
 948 1000          const char *ret;
↓ open down ↓ 26 lines elided ↑ open up ↑
 975 1027          }
 976 1028          return NULL;
 977 1029  }
 978 1030  
 979 1031  static void use_best_guess_header_file(struct token *token, const char *filename, struct token **list)
 980 1032  {
 981 1033          char cwd[PATH_MAX];
 982 1034          char dir_part[PATH_MAX];
 983 1035          const char *file_part;
 984 1036          const char *include_name;
     1037 +        static int cnt;
 985 1038          int len;
 986 1039  
     1040 +        /* Avoid guessing includes recursively. */
     1041 +        if (cnt++ > 1000)
     1042 +                return;
     1043 +
 987 1044          if (!filename || filename[0] == '\0')
 988 1045                  return;
 989 1046  
 990 1047          file_part = filename;
 991 1048          while ((filename = strchr(filename, '/'))) {
 992 1049                  ++filename;
 993 1050                  if (filename[0])
 994 1051                          file_part = filename;
 995 1052          }
 996 1053  
↓ open down ↓ 416 lines elided ↑ open up ↑
1413 1470          return expansion;
1414 1471  
1415 1472  Econcat:
1416 1473          sparse_error(token->pos, "'##' cannot appear at the ends of macro expansion");
1417 1474          return NULL;
1418 1475  Earg:
1419 1476          sparse_error(token->pos, "too many instances of argument in body");
1420 1477          return NULL;
1421 1478  }
1422 1479  
1423      -static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr)
     1480 +static int do_define(struct position pos, struct token *token, struct ident *name,
     1481 +                     struct token *arglist, struct token *expansion, int attr)
1424 1482  {
1425      -        struct token *arglist, *expansion;
1426      -        struct token *left = token->next;
1427 1483          struct symbol *sym;
1428      -        struct ident *name;
1429      -        int ret;
     1484 +        int ret = 1;
1430 1485  
1431      -        if (token_type(left) != TOKEN_IDENT) {
1432      -                sparse_error(token->pos, "expected identifier to 'define'");
1433      -                return 1;
1434      -        }
1435      -
1436      -        name = left->ident;
1437      -
1438      -        arglist = NULL;
1439      -        expansion = left->next;
1440      -        if (!expansion->pos.whitespace) {
1441      -                if (match_op(expansion, '(')) {
1442      -                        arglist = expansion;
1443      -                        expansion = parse_arguments(expansion);
1444      -                        if (!expansion)
1445      -                                return 1;
1446      -                } else if (!eof_token(expansion)) {
1447      -                        warning(expansion->pos,
1448      -                                "no whitespace before object-like macro body");
1449      -                }
1450      -        }
1451      -
1452 1486          expansion = parse_expansion(expansion, arglist, name);
1453 1487          if (!expansion)
1454 1488                  return 1;
1455 1489  
1456      -        ret = 1;
1457 1490          sym = lookup_symbol(name, NS_MACRO | NS_UNDEF);
1458 1491          if (sym) {
1459 1492                  int clean;
1460 1493  
1461 1494                  if (attr < sym->attr)
1462 1495                          goto out;
1463 1496  
1464 1497                  clean = (attr == sym->attr && sym->namespace == NS_MACRO);
1465 1498  
1466 1499                  if (token_list_different(sym->expansion, expansion) ||
1467 1500                      token_list_different(sym->arglist, arglist)) {
1468 1501                          ret = 0;
1469 1502                          if ((clean && attr == SYM_ATTR_NORMAL)
1470 1503                                          || sym->used_in == file_scope) {
1471      -                                warning(left->pos, "preprocessor token %.*s redefined",
     1504 +                                warning(pos, "preprocessor token %.*s redefined",
1472 1505                                                  name->len, name->name);
1473 1506                                  info(sym->pos, "this was the original definition");
1474 1507                          }
1475 1508                  } else if (clean)
1476 1509                          goto out;
1477 1510          }
1478 1511  
1479 1512          if (!sym || sym->scope != file_scope) {
1480      -                sym = alloc_symbol(left->pos, SYM_NODE);
     1513 +                sym = alloc_symbol(pos, SYM_NODE);
1481 1514                  bind_symbol(sym, name, NS_MACRO);
1482 1515                  add_ident(&macros, name);
1483 1516                  ret = 0;
1484 1517          }
1485 1518  
1486 1519          if (!ret) {
1487 1520                  sym->expansion = expansion;
1488 1521                  sym->arglist = arglist;
1489      -                __free_token(token);    /* Free the "define" token, but not the rest of the line */
     1522 +                if (token) /* Free the "define" token, but not the rest of the line */
     1523 +                        __free_token(token);
1490 1524          }
1491 1525  
1492 1526          sym->namespace = NS_MACRO;
1493 1527          sym->used_in = NULL;
1494 1528          sym->attr = attr;
1495 1529  out:
1496 1530          return ret;
1497 1531  }
1498 1532  
     1533 +///
     1534 +// predefine a macro with a printf-formatted value
     1535 +// @name: the name of the macro
     1536 +// @weak: 0/1 for a normal or a weak define
     1537 +// @fmt: the printf format followed by it's arguments.
     1538 +//
     1539 +// The type of the value is automatically infered:
     1540 +// TOKEN_NUMBER if it starts by a digit, TOKEN_IDENT otherwise.
     1541 +// If @fmt is null or empty, the macro is defined with an empty definition.
     1542 +void predefine(const char *name, int weak, const char *fmt, ...)
     1543 +{
     1544 +        struct ident *ident = built_in_ident(name);
     1545 +        struct token *value = &eof_token_entry;
     1546 +        int attr = weak ? SYM_ATTR_WEAK : SYM_ATTR_NORMAL;
     1547 +
     1548 +        if (fmt && fmt[0]) {
     1549 +                static char buf[256];
     1550 +                va_list ap;
     1551 +
     1552 +                va_start(ap, fmt);
     1553 +                vsnprintf(buf, sizeof(buf), fmt, ap);
     1554 +                va_end(ap);
     1555 +
     1556 +                value = __alloc_token(0);
     1557 +                if (isdigit(buf[0])) {
     1558 +                        token_type(value) = TOKEN_NUMBER;
     1559 +                        value->number = xstrdup(buf);
     1560 +                } else {
     1561 +                        token_type(value) = TOKEN_IDENT;
     1562 +                        value->ident = built_in_ident(buf);
     1563 +                }
     1564 +                value->pos.whitespace = 1;
     1565 +                value->next = &eof_token_entry;
     1566 +        }
     1567 +
     1568 +        do_define(value->pos, NULL, ident, NULL, value, attr);
     1569 +}
     1570 +
     1571 +static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr)
     1572 +{
     1573 +        struct token *arglist, *expansion;
     1574 +        struct token *left = token->next;
     1575 +        struct ident *name;
     1576 +
     1577 +        if (token_type(left) != TOKEN_IDENT) {
     1578 +                sparse_error(token->pos, "expected identifier to 'define'");
     1579 +                return 1;
     1580 +        }
     1581 +
     1582 +        name = left->ident;
     1583 +
     1584 +        arglist = NULL;
     1585 +        expansion = left->next;
     1586 +        if (!expansion->pos.whitespace) {
     1587 +                if (match_op(expansion, '(')) {
     1588 +                        arglist = expansion;
     1589 +                        expansion = parse_arguments(expansion);
     1590 +                        if (!expansion)
     1591 +                                return 1;
     1592 +                } else if (!eof_token(expansion)) {
     1593 +                        warning(expansion->pos,
     1594 +                                "no whitespace before object-like macro body");
     1595 +                }
     1596 +        }
     1597 +
     1598 +        return do_define(left->pos, token, name, arglist, expansion, attr);
     1599 +}
     1600 +
1499 1601  static int handle_define(struct stream *stream, struct token **line, struct token *token)
1500 1602  {
1501 1603          return do_handle_define(stream, line, token, SYM_ATTR_NORMAL);
1502 1604  }
1503 1605  
1504 1606  static int handle_weak_define(struct stream *stream, struct token **line, struct token *token)
1505 1607  {
1506 1608          return do_handle_define(stream, line, token, SYM_ATTR_WEAK);
1507 1609  }
1508 1610  
↓ open down ↓ 36 lines elided ↑ open up ↑
1545 1647  static int handle_undef(struct stream *stream, struct token **line, struct token *token)
1546 1648  {
1547 1649          return do_handle_undef(stream, line, token, SYM_ATTR_NORMAL);
1548 1650  }
1549 1651  
1550 1652  static int handle_strong_undef(struct stream *stream, struct token **line, struct token *token)
1551 1653  {
1552 1654          return do_handle_undef(stream, line, token, SYM_ATTR_STRONG);
1553 1655  }
1554 1656  
1555      -static int preprocessor_if(struct stream *stream, struct token *token, int true)
     1657 +static int preprocessor_if(struct stream *stream, struct token *token, int cond)
1556 1658  {
1557 1659          token_type(token) = false_nesting ? TOKEN_SKIP_GROUPS : TOKEN_IF;
1558 1660          free_preprocessor_line(token->next);
1559 1661          token->next = stream->top_if;
1560 1662          stream->top_if = token;
1561      -        if (false_nesting || true != 1)
     1663 +        if (false_nesting || cond != 1)
1562 1664                  false_nesting++;
1563 1665          return 0;
1564 1666  }
1565 1667  
1566 1668  static int handle_ifdef(struct stream *stream, struct token **line, struct token *token)
1567 1669  {
1568 1670          struct token *next = token->next;
1569 1671          int arg;
1570 1672          if (token_type(next) == TOKEN_IDENT) {
1571 1673                  arg = token_defined(next);
↓ open down ↓ 47 lines elided ↑ open up ↑
1619 1721  
1620 1722          while (!eof_token(p = scan_next(list))) {
1621 1723                  switch (state) {
1622 1724                  case 0:
1623 1725                          if (token_type(p) != TOKEN_IDENT)
1624 1726                                  break;
1625 1727                          if (p->ident == &defined_ident) {
1626 1728                                  state = 1;
1627 1729                                  beginning = list;
1628 1730                                  break;
     1731 +                        } else if (p->ident == &__has_builtin_ident) {
     1732 +                                state = 4;
     1733 +                                beginning = list;
     1734 +                                break;
     1735 +                        } else if (p->ident == &__has_attribute_ident) {
     1736 +                                state = 6;
     1737 +                                beginning = list;
     1738 +                                break;
1629 1739                          }
1630 1740                          if (!expand_one_symbol(list))
1631 1741                                  continue;
1632 1742                          if (token_type(p) != TOKEN_IDENT)
1633 1743                                  break;
1634 1744                          token_type(p) = TOKEN_ZERO_IDENT;
1635 1745                          break;
1636 1746                  case 1:
1637 1747                          if (match_op(p, '(')) {
1638 1748                                  state = 2;
↓ open down ↓ 10 lines elided ↑ open up ↑
1649 1759                                  state = 0;
1650 1760                          replace_with_defined(p);
1651 1761                          *beginning = p;
1652 1762                          break;
1653 1763                  case 3:
1654 1764                          state = 0;
1655 1765                          if (!match_op(p, ')'))
1656 1766                                  sparse_error(p->pos, "missing ')' after \"defined\"");
1657 1767                          *list = p->next;
1658 1768                          continue;
     1769 +
     1770 +                // __has_builtin(x) or __has_attribute(x)
     1771 +                case 4: case 6:
     1772 +                        if (match_op(p, '(')) {
     1773 +                                state++;
     1774 +                        } else {
     1775 +                                sparse_error(p->pos, "missing '(' after \"__has_%s\"",
     1776 +                                        state == 4 ? "builtin" : "attribute");
     1777 +                                state = 0;
     1778 +                        }
     1779 +                        *beginning = p;
     1780 +                        break;
     1781 +                case 5: case 7:
     1782 +                        if (token_type(p) != TOKEN_IDENT) {
     1783 +                                sparse_error(p->pos, "identifier expected");
     1784 +                                state = 0;
     1785 +                                break;
     1786 +                        }
     1787 +                        if (!match_op(p->next, ')'))
     1788 +                                sparse_error(p->pos, "missing ')' after \"__has_%s\"",
     1789 +                                        state == 5 ? "builtin" : "attribute");
     1790 +                        if (state == 5)
     1791 +                                replace_with_has_builtin(p);
     1792 +                        else
     1793 +                                replace_with_has_attribute(p);
     1794 +                        state = 8;
     1795 +                        *beginning = p;
     1796 +                        break;
     1797 +                case 8:
     1798 +                        state = 0;
     1799 +                        *list = p->next;
     1800 +                        continue;
1659 1801                  }
1660 1802                  list = &p->next;
1661 1803          }
1662 1804  
1663 1805          p = constant_expression(*where, &expr);
1664 1806          if (!eof_token(p))
1665 1807                  sparse_error(p->pos, "garbage at end: %s", show_token_sequence(p, 0));
1666 1808          value = get_expression_value(expr);
1667 1809          return value != 0;
1668 1810  }
↓ open down ↓ 293 lines elided ↑ open up ↑
1962 2104  }
1963 2105  
1964 2106  /*
1965 2107   * We ignore #line for now.
1966 2108   */
1967 2109  static int handle_line(struct stream *stream, struct token **line, struct token *token)
1968 2110  {
1969 2111          return 1;
1970 2112  }
1971 2113  
1972      -/*
1973      - * Ignore "#ident".
1974      - */
1975 2114  static int handle_ident(struct stream *stream, struct token **line, struct token *token)
1976 2115  {
1977 2116          return 1;
1978 2117  }
1979 2118  
1980 2119  static int handle_nondirective(struct stream *stream, struct token **line, struct token *token)
1981 2120  {
1982 2121          sparse_error(token->pos, "unrecognized preprocessor line '%s'", show_token_sequence(token, 0));
1983 2122          return 1;
1984 2123  }
↓ open down ↓ 29 lines elided ↑ open up ↑
2014 2153                  { "split_include", handle_split_include },
2015 2154                  { "argv_include",  handle_argv_include },
2016 2155          }, special[] = {
2017 2156                  { "ifdef",      handle_ifdef },
2018 2157                  { "ifndef",     handle_ifndef },
2019 2158                  { "else",       handle_else },
2020 2159                  { "endif",      handle_endif },
2021 2160                  { "if",         handle_if },
2022 2161                  { "elif",       handle_elif },
2023 2162          };
     2163 +        static struct {
     2164 +                const char *name;
     2165 +                void (*expander)(struct token *);
     2166 +        } dynamic[] = {
     2167 +                { "__LINE__",           expand_line },
     2168 +                { "__FILE__",           expand_file },
     2169 +                { "__BASE_FILE__",      expand_basefile },
     2170 +                { "__DATE__",           expand_date },
     2171 +                { "__TIME__",           expand_time },
     2172 +                { "__COUNTER__",        expand_counter },
     2173 +                { "__INCLUDE_LEVEL__",  expand_include_level },
     2174 +        };
2024 2175  
2025 2176          for (i = 0; i < ARRAY_SIZE(normal); i++) {
2026 2177                  struct symbol *sym;
2027 2178                  sym = create_symbol(stream, normal[i].name, SYM_PREPROCESSOR, NS_PREPROCESSOR);
2028 2179                  sym->handler = normal[i].handler;
2029 2180                  sym->normal = 1;
2030 2181          }
2031 2182          for (i = 0; i < ARRAY_SIZE(special); i++) {
2032 2183                  struct symbol *sym;
2033 2184                  sym = create_symbol(stream, special[i].name, SYM_PREPROCESSOR, NS_PREPROCESSOR);
2034 2185                  sym->handler = special[i].handler;
2035 2186                  sym->normal = 0;
2036 2187          }
     2188 +        for (i = 0; i < ARRAY_SIZE(dynamic); i++) {
     2189 +                struct symbol *sym;
     2190 +                sym = create_symbol(stream, dynamic[i].name, SYM_NODE, NS_MACRO);
     2191 +                sym->expander = dynamic[i].expander;
     2192 +        }
2037 2193  
2038 2194          counter_macro = 0;
2039 2195  }
2040 2196  
2041 2197  static void handle_preprocessor_line(struct stream *stream, struct token **line, struct token *start)
2042 2198  {
2043 2199          int (*handler)(struct stream *, struct token **, struct token *);
2044 2200          struct token *token = start->next;
2045 2201          int is_normal = 1;
2046 2202  
↓ open down ↓ 61 lines elided ↑ open up ↑
2108 2264                  case TOKEN_STREAMEND:
2109 2265                          if (stream->top_if) {
2110 2266                                  nesting_error(stream);
2111 2267                                  sparse_error(stream->top_if->pos, "unterminated preprocessor conditional");
2112 2268                                  stream->top_if = NULL;
2113 2269                                  false_nesting = 0;
2114 2270                          }
2115 2271                          if (!stream->dirty)
2116 2272                                  stream->constant = CONSTANT_FILE_YES;
2117 2273                          *list = next->next;
     2274 +                        include_level--;
2118 2275                          continue;
2119 2276                  case TOKEN_STREAMBEGIN:
2120 2277                          *list = next->next;
     2278 +                        include_level++;
2121 2279                          continue;
2122 2280  
2123 2281                  default:
2124 2282                          dirty_stream(stream);
2125 2283                          if (false_nesting) {
2126 2284                                  *list = next->next;
2127 2285                                  __free_token(next);
2128 2286                                  continue;
2129 2287                          }
2130 2288  
↓ open down ↓ 41 lines elided ↑ open up ↑
2172 2330          do_preprocess(&token);
2173 2331  
2174 2332          // Drop all expressions from preprocessing, they're not used any more.
2175 2333          // This is not true when we have multiple files, though ;/
2176 2334          // clear_expression_alloc();
2177 2335          preprocessing = 0;
2178 2336  
2179 2337          return token;
2180 2338  }
2181 2339  
     2340 +static int is_VA_ARGS_token(struct token *token)
     2341 +{
     2342 +        return (token_type(token) == TOKEN_IDENT) &&
     2343 +                (token->ident == &__VA_ARGS___ident);
     2344 +}
     2345 +
2182 2346  static void dump_macro(struct symbol *sym)
2183 2347  {
2184 2348          int nargs = sym->arglist ? sym->arglist->count.normal : 0;
2185 2349          struct token *args[nargs];
2186 2350          struct token *token;
2187 2351  
2188 2352          printf("#define %s", show_ident(sym->ident));
2189 2353          token = sym->arglist;
2190 2354          if (token) {
2191 2355                  const char *sep = "";
2192 2356                  int narg = 0;
2193 2357                  putchar('(');
2194 2358                  for (; !eof_token(token); token = token->next) {
2195 2359                          if (token_type(token) == TOKEN_ARG_COUNT)
2196 2360                                  continue;
2197      -                        printf("%s%s", sep, show_token(token));
     2361 +                        if (is_VA_ARGS_token(token))
     2362 +                                printf("%s...", sep);
     2363 +                        else
     2364 +                                printf("%s%s", sep, show_token(token));
2198 2365                          args[narg++] = token;
2199      -                        sep = ", ";
     2366 +                        sep = ",";
2200 2367                  }
2201 2368                  putchar(')');
2202 2369          }
2203      -        putchar(' ');
2204 2370  
2205 2371          token = sym->expansion;
2206      -        while (!eof_token(token)) {
     2372 +        while (token_type(token) != TOKEN_UNTAINT) {
2207 2373                  struct token *next = token->next;
     2374 +                if (token->pos.whitespace)
     2375 +                        putchar(' ');
2208 2376                  switch (token_type(token)) {
2209      -                case TOKEN_UNTAINT:
     2377 +                case TOKEN_CONCAT:
     2378 +                        printf("##");
2210 2379                          break;
     2380 +                case TOKEN_STR_ARGUMENT:
     2381 +                        printf("#");
     2382 +                        /* fall-through */
     2383 +                case TOKEN_QUOTED_ARGUMENT:
2211 2384                  case TOKEN_MACRO_ARGUMENT:
2212 2385                          token = args[token->argnum];
2213 2386                          /* fall-through */
2214 2387                  default:
2215 2388                          printf("%s", show_token(token));
2216      -                        if (next->pos.whitespace)
2217      -                                putchar(' ');
2218 2389                  }
2219 2390                  token = next;
2220 2391          }
2221 2392          putchar('\n');
2222 2393  }
2223 2394  
2224 2395  void dump_macro_definitions(void)
2225 2396  {
2226 2397          struct ident *name;
2227 2398  
2228 2399          FOR_EACH_PTR(macros, name) {
2229 2400                  struct symbol *sym = lookup_macro(name);
2230 2401                  if (sym)
2231 2402                          dump_macro(sym);
2232 2403          } END_FOR_EACH_PTR(name);
2233 2404  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX