URI:
       cpp.c - scc - simple c99 compiler
  HTML git clone git://git.simple-cc.org/scc
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       cpp.c (23323B)
       ---
            1 #include <assert.h>
            2 #include <ctype.h>
            3 #include <limits.h>
            4 #include <stdio.h>
            5 #include <stdlib.h>
            6 #include <string.h>
            7 #include <time.h>
            8 
            9 #include <scc/cstd.h>
           10 #include <scc/scc.h>
           11 #include "cc1.h"
           12 
           13 struct ifstate {
           14         unsigned char done;
           15         unsigned char enabled;
           16         unsigned char iselse;
           17 };
           18 
           19 static unsigned ncmdlines;
           20 static Symbol *symline, *symfile;
           21 static struct ifstate ifstate[NR_COND];
           22 static int cppoff;
           23 static struct items dirinclude;
           24 
           25 unsigned cppctx;
           26 int disexpand;
           27 
           28 void
           29 defdefine(char *name, char *val, char *source)
           30 {
           31         char buffer[INPUTSIZ+1];
           32         char *def, *fmt = "#define %s %s\n";
           33         Symbol *sym = &(Symbol) {
           34                 .name = name,
           35                 .flags = SDECLARED,
           36         };
           37 
           38         if (!val)
           39                 val = "";
           40         if (strlen(fmt) + strlen(name) + strlen(val) > INPUTSIZ) {
           41                 errorp("macro definition '%s' too big", name);
           42                 return;
           43         }
           44 
           45         sprintf(buffer, fmt, name, val);
           46         lineno = ++ncmdlines;
           47 
           48         addinput(IPARAM, buffer, FAIL);
           49         cpp();
           50         delinput();
           51 }
           52 
           53 void
           54 undefmacro(char *s)
           55 {
           56         killsym(lookup(NS_CPP, s, NOALLOC));
           57 }
           58 
           59 void
           60 icpp(void)
           61 {
           62         struct tm *tm;
           63         time_t t;
           64         static char sdate[14], stime[11];
           65         static struct {
           66                 char *name;
           67                 char *value;
           68         } *bp, list[] = {
           69                 {"__STDC__", "1"},
           70                 {"__STDC_HOSTED__", "1"},
           71                 {"__SCC__", "1"},
           72                 {"__DATE__", sdate},
           73                 {"__TIME__", stime},
           74                 {"__STDC_VERSION__", STDC_VERSION},
           75                 {"__LINE__", NULL},
           76                 {"__FILE__", NULL},
           77                 {"__FLT_EVAL_METHOD__", "0"},
           78                 {NULL, NULL}
           79         };
           80 
           81         t = time(NULL);
           82         tm = localtime(&t);
           83         strftime(sdate, sizeof(sdate), "\"%b %d %Y\"", tm);
           84         strftime(stime, sizeof(stime), "\"%H:%M:%S\"", tm);
           85 
           86         for (bp = list; bp->name; ++bp)
           87                 defdefine(bp->name, bp->value, "built-in");
           88 
           89         symline = lookup(NS_CPP, "__LINE__", ALLOC);
           90         symfile = lookup(NS_CPP, "__FILE__", ALLOC);
           91 
           92         ncmdlines = 0;
           93 }
           94 
           95 static char *
           96 appendpar(Macro *mp, char *s, int len)
           97 {
           98         char *arg;
           99         int siz = mp->argsiz;
          100 
          101         if (len+1 > INT_MAX - siz) {
          102                 error("too long argument invoking macro \"%s\"",
          103                       mp->sym->name);
          104         }
          105 
          106         mp->arg = xrealloc(mp->arg, siz + len + 1);
          107         memcpy(mp->arg + siz, s, len);
          108         mp->argsiz = siz += len;
          109         mp->arg[siz] = '\0';
          110 }
          111 
          112 static void
          113 paren(Macro *mp)
          114 {
          115         for (;;) {
          116                 switch (*input->p) {
          117                 case ')':
          118                         appendpar(mp, input->p++, 1);
          119                         return;
          120                 case '(':
          121                         appendpar(mp, input->p++, 1);
          122                         paren(mp);
          123                         break;
          124                 case '"':
          125                 case '\'':
          126                         next();
          127                         assert(yytoken == STRING || yytoken == CONSTANT);
          128                         appendpar(mp, yytext, yylen);
          129                         break;
          130                 case '\0':
          131                         if (!moreinput())
          132                                 goto unterminated;
          133                         continue;
          134                 default:
          135                         appendpar(mp, input->p++, 1);
          136                         break;
          137                 }
          138         }
          139 
          140 unterminated:
          141         error("unterminated argument list invoking macro \"%s\"",
          142               mp->sym->name);
          143 }
          144 
          145 static int
          146 cppspace(int c)
          147 {
          148         return c == ' ' || c == '\t' || c == '\v' ||
          149                c == '\n' || c == '\f' || c == '\r';
          150 }
          151 
          152 static char *
          153 parameter(Macro *mp, int n)
          154 {
          155         int siz;
          156         char *s, *begin, *end;
          157 
          158         mp->arg = NULL;
          159         mp->argsiz = 0;
          160 
          161         for (;;) {
          162                 switch (*input->p) {
          163                 case '"':
          164                 case '\'':
          165                         next();
          166                         assert(yytoken == STRING || yytoken == CONSTANT);
          167                         appendpar(mp, yytext, yylen);
          168                         break;
          169                 case '(':
          170                         appendpar(mp, input->p++, 1);
          171                         paren(mp);
          172                         break;
          173                 case ',':
          174                         if (n+1 == mp->npars)
          175                                 goto append;
          176                 case ')':
          177                         begin = mp->arg;
          178                         end = begin + mp->argsiz;
          179 
          180                         while (begin < end && cppspace(*begin))
          181                                 begin++;
          182                         while (end > begin && cppspace(end[-1]))
          183                                 end--;
          184 
          185                         siz = end - begin;
          186                         s = memcpy(xmalloc(siz + 1), begin, siz);
          187                         s[siz] = '\0';
          188 
          189                         return s;
          190                 case '\0':
          191                         if (!moreinput())
          192                                 goto unterminated;
          193                         continue;
          194                 default:
          195                 append:
          196                         appendpar(mp, input->p++, 1);
          197                         break;
          198                 }
          199         }
          200 
          201 unterminated:
          202         error("unterminated argument list invoking macro \"%s\"",
          203               mp->sym->name);
          204 }
          205 
          206 static int
          207 parsepars(Macro *mp)
          208 {
          209         int c, n;
          210         char *name;
          211 
          212         if (mp->npars == -1)
          213                 return 1;
          214         if (ahead() != '(')
          215                 return 0;
          216 
          217         input->p++;
          218         name = mp->sym->name;
          219 
          220         if (mp->npars == 0 && ahead() == ')') {
          221                 input->p++;
          222                 return 1;
          223         }
          224 
          225         disexpand = 1;
          226         for (n = 0; n < NR_MACROARG; ) {
          227                 mp->arglist = xrealloc(mp->arglist, (n+1)*sizeof(char *));
          228                 mp->arglist[n] = parameter(mp, n);
          229                 DBG("MACRO fetched arg '%s'", mp->arglist[n]);
          230                 n++;
          231 
          232                 c = *input->p++;
          233                 if (c == ')')
          234                         break;
          235                 if (c != ',')
          236                         error("incorrect macro function-alike invocation of \"%s\"", name);
          237         }
          238         disexpand = 0;
          239 
          240         if (n == mp->npars)
          241                 return 1;
          242 
          243         if (n == mp->npars-1 && mp->sym->flags & SVARIADIC) {
          244                 DBG("MACRO defaulted __VA_ARGS__ to \"\"");
          245                 mp->arglist = xrealloc(mp->arglist, (n+1)*sizeof(char *));
          246                 mp->arglist[n] = xstrdup("");
          247                 return 1;
          248         }
          249 
          250         error("macro \"%s\" received %d arguments, but it takes %d",
          251               mp->sym->name, n, mp->npars);
          252 }
          253 
          254 static int
          255 concatoper(char *def, char *cur)
          256 {
          257         char *s;
          258 
          259         for (s = cur + 4; cppspace(*s); ++s)
          260                 ;
          261         if (*s == CONCAT)
          262                 return 1;
          263 
          264         for (s = cur; s > def && cppspace(s[-1]); --s)
          265                 ;
          266         if (s > def && s[-1] == CONCAT)
          267                 return 1;
          268 
          269         return 0;
          270 }
          271 
          272 static int
          273 stringoper(char **bpp, int *sizep, char *arg)
          274 {
          275         int c, esc, delim, siz;
          276         char *bp;
          277 
          278         bp = *bpp;
          279         siz = *sizep;
          280 
          281         if (siz < 3)
          282                 return 0;
          283 
          284         esc = delim = 0;
          285 
          286         *bp++ = '"';
          287         while ((c = *arg++) != '\0') {
          288                 switch (c) {
          289                 case '\'':
          290                 case '"':
          291                         if (!esc) {
          292                                 if (!delim)
          293                                         delim = c;
          294                                 else if (delim == c)
          295                                         delim = 0;
          296                         }
          297 
          298                         if (c == '"') {
          299                                 if (siz < 4)
          300                                         return 0;
          301                                 *bp++ = '\\';
          302                                 siz--;
          303                         } else {
          304                                 if (siz < 3)
          305                                         return 0;
          306                         }
          307 
          308                         *bp++ = c;
          309                         siz--;
          310                         break;
          311                 case '\\':
          312                         if (!delim)
          313                                 goto copy;
          314                         if (siz < 4)
          315                                 return 0;
          316                         *bp++ = '\\';
          317                         *bp++ = '\\';
          318                         siz -= 2;
          319 
          320                         if (!esc) {
          321                                 esc = 1;
          322                                 continue;
          323                         }
          324                         break;
          325                 default:
          326                         if (!delim && cppspace(c)) {
          327                                 while (cppspace(*arg))
          328                                         ++arg;
          329                                 c = ' ';
          330                         }
          331                 copy:
          332                         if (siz < 3)
          333                                 return 0;
          334                         *bp++ = c;
          335                         siz--;
          336                         break;
          337                 }
          338                 esc = 0;
          339         }
          340         *bp++ = '"';
          341 
          342         *bpp = bp;
          343         *sizep = siz;
          344 
          345         return 1;
          346 }
          347 
          348 static int
          349 expandarg(char *arg, char *def, char *curdef, char *buf, int bufsiz)
          350 {
          351         int siz;
          352         char *s = buf;
          353 
          354         /* gives priority to concatenation operators */
          355         if (concatoper(def, curdef)) {
          356                 char *p;
          357                 int c;
          358 
          359                 /*
          360                  * ignore NOEXPAND and EXPAND because ## has
          361                  * precedence over macro expansion, and we just
          362                  * want the argument as it is
          363                  */
          364                 for (siz = 0, p = arg; (c = *p) != '\0'; p++) {
          365                         if (c == NOEXPAND || c == EXPAND)
          366                                 continue;
          367                         if (siz == bufsiz - 1)
          368                                 return -1;
          369                         *buf++ = c;
          370                         siz++;
          371                 }
          372                 *buf = '\0';
          373         } else {
          374                 int n;
          375                 char noex[2] = {0, 0}, ex[2] = {0, 0};
          376 
          377                 /*
          378                  * Here we have to deal with a special case,
          379                  * because the recursive input expansion deals
          380                  * correctly with the hideset manipulation,
          381                  * but once the macro expansion is flattened in
          382                  * a buffer associated to the macro expansion
          383                  * all the hideset information is lost. To solve
          384                  * this problem we have to add annotation tokens
          385                  * to maintain this information and avoid expanding
          386                  * macros hidden due to the recursive hidesets
          387                  */
          388                 addinput(IPARAM, arg, FAIL);
          389                 for (siz = 0; ; siz += n) {
          390                         yyspace = noex[0] = ex[0] = '\0';
          391                         if (next() == EOFTOK)
          392                                 break;
          393 
          394                         if (yytoken == IDEN) {
          395                                 Symbol *sym = yylval.cppsym;
          396                                 if (disexpand || sym && sym->hide) {
          397                                         noex[0] = NOEXPAND;
          398                                         ex[0] = EXPAND;
          399                                 }
          400                         }
          401 
          402                         n = snprintf(buf, bufsiz, "%s%s%s%s",
          403                                      yyspace ? " " : "", noex, yytext, ex);
          404 
          405                         if (n < 0 || n == bufsiz)
          406                                 return -1;
          407 
          408                         buf += n;
          409                         bufsiz -= n;
          410                 }
          411                 delinput();
          412         }
          413 
          414         DBG("MACRO parameter '%s' expanded to '%s'", arg, s);
          415 
          416         return siz;
          417 }
          418 
          419 static int
          420 copymacro(Macro *mp)
          421 {
          422         int delim, c, esc;
          423         char *s, *p, *arg, *bp;
          424         int size, bufsiz;
          425 
          426         if (mp->sym == symfile)
          427                 return sprintf(mp->buffer, "\"%s\" ", filenam);
          428         if (mp->sym == symline)
          429                 return sprintf(mp->buffer, "%d ", lineno);
          430 
          431         bp = mp->buffer;
          432         bufsiz = mp->bufsiz;
          433         for (s = mp->def; c = *s; ++s) {
          434                 switch (c) {
          435                 case '\'':
          436                         delim = '\'';
          437                         goto search_delim;
          438                 case '\"':
          439                         delim = '"';
          440                 search_delim:
          441                         esc = 0;
          442                         p = s;
          443                         for (++s; c = *s; ++s) {
          444                                 if (c == '\\' && !esc)
          445                                         esc = 1;
          446                                 else if (c == delim &&!esc)
          447                                         break;
          448                                 else
          449                                         esc = 0;
          450                         }
          451                         size = s - p + 1;
          452                         if (size > bufsiz)
          453                                 goto expansion_too_long;
          454                         memcpy(bp, p, size);
          455                         bufsiz -= size;
          456                         bp += size;
          457                         break;
          458                 case CONCAT:
          459                         /* token concatenation operator */
          460                         DBG("MACRO concat");
          461                         while (cppspace(bp[-1]))
          462                                 --bp, ++bufsiz;
          463                         while (cppspace(s[1]))
          464                                 ++s;
          465                         break;
          466                 case STRINGIZE:
          467                         /* stringfier operator */
          468                         DBG("MACRO stringize");
          469                         arg = mp->arglist[atoi(s += 2)];
          470                         s += 2;
          471 
          472                         if (!stringoper(&bp, &bufsiz, arg))
          473                                 goto expansion_too_long;
          474                         break;
          475                 case MACROPAR:
          476                         /* parameter substitution */
          477                         arg = mp->arglist[atoi(s+1)];
          478                         size = expandarg(arg, mp->def, s, bp, bufsiz);
          479                         if (size < 0)
          480                                 goto expansion_too_long;
          481                         bp += size;
          482                         bufsiz -= size;
          483                         s += 3;
          484                         break;
          485                 default:
          486                         if (bufsiz-- == 0)
          487                                 goto expansion_too_long;
          488                         *bp++ = c;
          489                         break;
          490                 }
          491         }
          492         *bp = '\0';
          493 
          494         return bp - mp->buffer;
          495 
          496 expansion_too_long:
          497         error("macro expansion of \"%s\" too long", mp->sym->name);
          498 }
          499 
          500 /*
          501  * Functions to deal with macro hidesets. Yes, this sucks, a lot,
          502  * but before blaming me read
          503  * https://www.spinellis.gr/blog/20060626/cpp.algo.pdf
          504  * It is not my fault.
          505  */
          506 static void
          507 addhideset(Symbol *sym)
          508 {
          509         Symbol **set, **p;
          510 
          511         set = input->hideset;
          512         for (p = set; p < &set[NR_MACROARG-1] && *p; ++p) {
          513                 if (*p == sym)
          514                         return;
          515         }
          516 
          517         if (p == &set[NR_MACROARG])
          518                 error("too complex macro expansion");
          519 
          520         *p = sym;
          521         DBG("MACRO Adding %s to hideset of %s",
          522             sym->name, input->macro->sym->name);
          523 }
          524 
          525 static void
          526 hide(Symbol *sym)
          527 {
          528         DBG("SYM: hidding symbol %s %d", sym->name, sym->hide);
          529         sym->hide = 1;
          530 }
          531 
          532 static void
          533 unhide(Symbol *sym)
          534 {
          535         DBG("SYM: unhidding symbol %s %d", sym->name, sym->hide);
          536         sym->hide = 0;
          537 }
          538 
          539 void
          540 unsethideset(Input *ip)
          541 {
          542         Symbol **p;
          543 
          544         for (p = ip->hideset; *p; ++p)
          545                 unhide(*p);
          546 }
          547 
          548 void
          549 sethideset(Input *ip)
          550 {
          551         Symbol **p;
          552 
          553         for (p = ip->hideset; *p; ++p)
          554                 hide(*p);
          555 }
          556 
          557 void
          558 delmacro(Macro *mp)
          559 {
          560         int i;
          561         Symbol **p;
          562 
          563         if (!mp)
          564                 return;
          565 
          566         if (mp->arglist) {
          567                 for (i = 0; i < mp->npars; i++)
          568                         free(mp->arglist[i]);
          569         }
          570 
          571         free(mp->arglist);
          572         free(mp);
          573 }
          574 
          575 Macro *
          576 newmacro(Symbol *sym)
          577 {
          578         Macro *mp;
          579 
          580         mp = memset(xmalloc(sizeof(*mp)), 0, sizeof(*mp));
          581         mp->sym = sym;
          582         mp->def = sym->u.s + 3;
          583         if (sym->u.s)
          584                 mp->npars = atoi(sym->u.s);
          585 
          586         return mp;
          587 }
          588 
          589 static void
          590 intersect(Symbol **dst, Symbol **set)
          591 {
          592         Symbol *sym, **cur, **p;
          593 
          594         for (cur = dst; sym = *cur; ++cur) {
          595                 for (p = set; *p && *p != sym; ++p)
          596                         ;
          597                 if (*p)
          598                         *dst++ = sym;
          599         }
          600 
          601         while (dst != cur)
          602                 *dst++ = NULL;
          603 }
          604 
          605 int
          606 expand(Symbol *sym)
          607 {
          608         int spc, siz;
          609         Macro *mp;
          610 
          611         DBG("MACRO '%s' detected disexpand=%d hide=%d",
          612             sym->name, disexpand, sym->hide);
          613 
          614         if (disexpand || sym->hide || sym->token != IDEN)
          615                 return 0;
          616 
          617         spc = yyspace;
          618         mp = newmacro(sym);
          619         mp->fname = filenam;
          620         memcpy(mp->hideset, input->hideset, sizeof(mp->hideset));
          621 
          622         if (!parsepars(mp)) {
          623                 delmacro(mp);
          624                 return 0;
          625         }
          626 
          627         if (mp->npars != -1)
          628                 intersect(mp->hideset, input->hideset);
          629         addinput(IMACRO, mp, FAIL);
          630         addhideset(sym);
          631         hide(sym);
          632 
          633         mp->buffer = input->line;
          634         mp->bufsiz = INPUTSIZ-1;
          635 
          636         siz = copymacro(mp);
          637         mp->buffer[siz] = '\0';
          638         yyspace = spc;
          639 
          640         DBG("MACRO '%s' expanded to :'%s'", mp->sym->name, mp->buffer);
          641 
          642         return 1;
          643 }
          644 
          645 static int
          646 getpars(Symbol *args[NR_MACROARG])
          647 {
          648         int n, c;
          649         Symbol *sym;
          650 
          651         if (*input->p != '(')
          652                 return -1;
          653 
          654         /* skip the '(' */
          655         next();
          656         next();
          657         if (yytoken == ')')
          658                 return 0;
          659 
          660         n = 0;
          661         do {
          662                 if (n == NR_MACROARG) {
          663                         cpperror("too many parameters in macro");
          664                         return NR_MACROARG;
          665                 }
          666 
          667                 if (yytoken == ELLIPSIS) {
          668                         sym = newsym(NS_MACROPAR, "__VA_ARGS__");
          669                 } else if (yytoken == IDEN) {
          670                         sym = yylval.sym;
          671                         next();
          672                 } else {
          673                         cpperror("macro arguments must be identifiers");
          674                         return NR_MACROARG;
          675                 }
          676 
          677                 if (!install(NS_MACROPAR, sym)) {
          678                         errorp("duplicated macro parameter '%s'", sym->name);
          679                 } else {
          680                         sym->flags |= SUSED;
          681                         args[n++] = sym;
          682                 }
          683 
          684                 if (accept(ELLIPSIS))
          685                         break;
          686 
          687         } while (accept(','));
          688 
          689         if (yytoken != ')') {
          690                 cpperror("expected ')' at the end of macro argument list");
          691                 return NR_MACROARG;
          692         }
          693 
          694         return n;
          695 }
          696 
          697 static int
          698 getdefs(Symbol *args[NR_MACROARG], int nargs, char *buffer, size_t bufsiz)
          699 {
          700         Symbol **argp;
          701         char c, *bp, *s, *p;
          702         int len, id, token, prevc, ispar;
          703 
          704         while (cppspace(*input->p))
          705                 ++input->p;
          706 
          707         bp = buffer;
          708         for (prevc = 0; (c = *input->p) != '\n' && c != '\0'; ++input->p) {
          709                 len = 1;
          710                 ispar = 0;
          711                 s = &c;
          712                 token = c;
          713 
          714                 if (c == '#') {
          715                         if (input->p[1] == '#') {
          716                                 c = token = CONCAT;
          717                                 ++input->p;
          718                         } else {
          719                                 c = token = STRINGIZE;
          720                                 while (cppspace(input->p[1]))
          721                                         ++input->p;
          722                         }
          723                 } else if (c == '"' || c == '\'' || c == '_' || isalpha(c)) {
          724                         next();
          725                         assert(yytoken == STRING ||
          726                                yytoken == CONSTANT ||
          727                                yytoken == IDEN);
          728                         token = yytoken;
          729                         s = yytext;
          730                         len = yylen;
          731                         --input->p;
          732                 }
          733 
          734                 if (token == IDEN && nargs > 0) {
          735                         for (argp = args; argp < &args[nargs]; ++argp) {
          736                                 if (*argp == yylval.sym) {
          737                                         id = argp - args;
          738                                         sprintf(yytext,
          739                                                 "%c%02d%c", MACROPAR, id, MACROPAR);
          740                                         ispar = 1;
          741                                         yylen = len = 4;
          742                                         break;
          743                                 }
          744                         }
          745                 }
          746 
          747                 if (prevc == 0 && token == CONCAT)
          748                         goto wrong_concat;
          749 
          750                 if (prevc == STRINGIZE && !ispar) {
          751                         cpperror("'#' is not followed by a macro parameter");
          752                         return 0;
          753                 }
          754 
          755                 if (len >= bufsiz) {
          756                         cpperror("macro too long");
          757                         return 0;
          758                 }
          759 
          760                 memcpy(bp, s, len);
          761                 bp += len;
          762                 bufsiz -= len;
          763                 prevc = token;
          764         }
          765 
          766 end_loop:
          767         if ((yytoken = c) == '\0')
          768                 yytoken = EOFTOK;
          769         if (prevc == CONCAT)
          770                 goto wrong_concat;
          771         for ( ; bp > buffer && cppspace(bp[-1]); --bp);
          772                 ;
          773         *bp = '\0';
          774         return 1;
          775 
          776 wrong_concat:
          777         cpperror("'##' cannot appear at either ends of a macro expansion");
          778         return 0;
          779 }
          780 
          781 static void
          782 define(void)
          783 {
          784         int n;
          785         Symbol *sym,*args[NR_MACROARG];
          786         char buff[LINESIZ+1];
          787         unsigned flags = SDECLARED|SSTRING;
          788 
          789         if (cppoff)
          790                 return;
          791 
          792         namespace = NS_CPP;
          793         next();
          794 
          795         if (yytoken != IDEN) {
          796                 cpperror("macro names must be identifiers");
          797                 return;
          798         }
          799         sym = yylval.sym;
          800 
          801         namespace = NS_MACROPAR;   /* Avoid polution in NS_CPP */
          802         if ((n = getpars(args)) == NR_MACROARG)
          803                 goto delete;
          804         if (n > 0 && strcmp(args[n-1]->name, "__VA_ARGS__") == 0)
          805                 flags |= SVARIADIC;
          806 
          807         sprintf(buff, "%02d#", n);
          808         if (!getdefs(args, n, buff+3, LINESIZ-3))
          809                 goto delete;
          810 
          811         if (sym->flags & SDECLARED) {
          812                 if (strcmp(sym->u.s, buff) != 0)
          813                         warn("'%s' redefined", sym->name);
          814                 free(sym->u.s);
          815         } else {
          816                 sym = install(NS_CPP, sym);
          817                 sym->flags |= flags;
          818         }
          819 
          820         sym->u.s = xstrdup(buff);
          821         DBG("MACRO '%s' defined as '%s'", sym->name, buff);
          822         return;
          823 
          824 delete:
          825         killsym(sym);
          826 }
          827 
          828 void
          829 incdir(char *dir)
          830 {
          831         if (!dir || *dir == '\0')
          832                 die("cc1: incorrect -I flag");
          833         newitem(&dirinclude, dir);
          834 }
          835 
          836 static int
          837 includefile(char *dir, char *file, size_t filelen)
          838 {
          839         size_t dirlen;
          840         char path[FILENAME_MAX];
          841 
          842         if (!dir) {
          843                 dirlen = 0;
          844                 if (filelen > FILENAME_MAX-1)
          845                         return 0;
          846         } else {
          847                 dirlen = strlen(dir);
          848                 if (dirlen + filelen > FILENAME_MAX-2)
          849                         return 0;
          850                 memcpy(path, dir, dirlen);
          851                 if (dir[dirlen-1] != '/')
          852                         path[dirlen++] = '/';
          853         }
          854         memcpy(path+dirlen, file, filelen);
          855         path[dirlen + filelen] = '\0';
          856 
          857         return addinput(IFILE, path, NOFAIL);
          858 }
          859 
          860 static char *
          861 cwd(char *buf)
          862 {
          863         char *p, *s = filenam;
          864         size_t len;
          865 
          866         if ((p = strrchr(s, '/')) == NULL)
          867                 return NULL;
          868         if ((len = p - s) >= FILENAME_MAX)
          869                 die("cc1: current work directory too long");
          870         memcpy(buf, s, len);
          871         buf[len] = '\0';
          872         return buf;
          873 }
          874 
          875 static void
          876 include(void)
          877 {
          878         char dir[FILENAME_MAX], file[FILENAME_MAX], *p, **bp;
          879         size_t filelen;
          880         int n;
          881 
          882         if (cppoff)
          883                 return;
          884 
          885         disexpand = 0;
          886         namespace = NS_IDEN;
          887         next();
          888 
          889         switch (*yytext) {
          890         case '<':
          891                 if ((p = strchr(input->begin, '>')) == NULL || p[-1] == '<')
          892                         goto bad_include;
          893                 filelen = p - input->begin;
          894                 if (filelen >= FILENAME_MAX)
          895                         goto too_long;
          896                 memcpy(file, input->begin, filelen);
          897                 file[filelen] = '\0';
          898 
          899                 input->begin = input->p = p+1;
          900                 if (next() != '\n')
          901                         goto trailing_characters;
          902 
          903                 break;
          904         case '"':
          905                 if (yylen < 3)
          906                         goto bad_include;
          907                 filelen = yylen-2;
          908                 if (filelen >= FILENAME_MAX)
          909                         goto too_long;
          910                 memcpy(file, yytext+1, filelen);
          911                 file[filelen] = '\0';
          912 
          913                 if (next() != '\n')
          914                         goto trailing_characters;
          915 
          916                 if (includefile(cwd(dir), file, filelen))
          917                         goto its_done;
          918                 break;
          919         default:
          920                 goto bad_include;
          921         }
          922 
          923         n = dirinclude.n;
          924         for (bp = dirinclude.s; n--; ++bp) {
          925                 if (includefile(*bp, file, filelen))
          926                         goto its_done;
          927         }
          928         cpperror("included file '%s' not found", file);
          929 
          930 its_done:
          931         return;
          932 
          933 trailing_characters:
          934         cpperror("trailing characters after preprocessor directive");
          935         return;
          936 
          937 too_long:
          938         cpperror("too long file name in #include");
          939         return;
          940 
          941 bad_include:
          942         cpperror("#include expects \"FILENAME\" or <FILENAME>");
          943         return;
          944 }
          945 
          946 static void
          947 line(void)
          948 {
          949         long n;
          950         char *endp, *fname;
          951 
          952         if (cppoff)
          953                 return;
          954 
          955         disexpand = 0;
          956         next();
          957         n = strtol(yytext, &endp, 10);
          958         if (n <= 0 || n > USHRT_MAX || *endp != '\0') {
          959                 cpperror("first parameter of #line is not a positive integer");
          960                 return;
          961         }
          962 
          963         next();
          964         if (yytoken == '\n') {
          965                 fname = NULL;
          966         } else {
          967                 if (*yytext != '\"' || yylen == 1) {
          968                         cpperror("second parameter of #line is not a valid filename");
          969                         return;
          970                 }
          971                 fname = yylval.sym->u.s;
          972         }
          973         setloc(fname, n - 1);
          974         if (yytoken != '\n')
          975                 next();
          976 }
          977 
          978 static void
          979 pragma(void)
          980 {
          981         if (cppoff)
          982                 return;
          983         next();
          984         warn("ignoring pragma '%s'", yytext);
          985         *input->p = '\0';
          986         next();
          987 }
          988 
          989 static void
          990 usererr(void)
          991 {
          992         if (cppoff)
          993                 return;
          994         cpperror("#error %s", input->p);
          995         exit(EXIT_FAILURE);
          996         next();
          997 }
          998 
          999 
         1000 Node *
         1001 defined(void)
         1002 {
         1003         Symbol *sym;
         1004         int paren;
         1005 
         1006         disexpand = 1;
         1007         next();
         1008         paren = accept('(');
         1009         if (yytoken != IDEN && yytoken != TYPEIDEN)
         1010                 cpperror("operator 'defined' requires an identifier");
         1011         if (yytoken == TYPEIDEN || !(yylval.sym->flags & SDECLARED))
         1012                 sym = zero;
         1013         else
         1014                 sym = one;
         1015         disexpand = 0;
         1016         next();
         1017         if (paren)
         1018                 expect(')');
         1019         return constnode(sym);
         1020 }
         1021 
         1022 static void
         1023 ifclause(int negate, int isifdef)
         1024 {
         1025         Symbol *sym;
         1026         unsigned n;
         1027         int enabled, done;
         1028         Node *expr;
         1029 
         1030         if (cppctx == NR_COND-1)
         1031                 error("too many nesting levels of conditional inclusion");
         1032         n = cppctx++;
         1033         DBG("CPP ifclause updates cppctx=%d", cppctx);
         1034 
         1035         if (n > 0 && !ifstate[n-1].enabled) {
         1036                 done = 1;
         1037                 enabled = 0;
         1038                 goto disabled;
         1039         }
         1040 
         1041         namespace = NS_CPP;
         1042         next();
         1043 
         1044         if (isifdef) {
         1045                 if (yytoken != IDEN) {
         1046                         cpperror("no macro name given in #%s directive",
         1047                                  (negate) ? "ifndef" : "ifdef");
         1048                         return;
         1049                 }
         1050                 sym = yylval.sym;
         1051                 next();
         1052                 enabled = (sym->flags & SDECLARED) != 0;
         1053                 if (!enabled)
         1054                         killsym(sym);
         1055         } else {
         1056                 /* TODO: catch recovery here */
         1057                 if ((expr = iconstexpr()) == NULL) {
         1058                         cpperror("parameter of #if is not an integer constant expression");
         1059                         return;
         1060                 }
         1061                 DBG("CPP if expr=%d", expr->sym->u.i);
         1062                 enabled = expr->sym->u.i != 0;
         1063                 freetree(expr);
         1064         }
         1065 
         1066         if (negate)
         1067                 enabled = !enabled;
         1068         done = enabled;
         1069 
         1070 disabled:
         1071         cppoff = !enabled;
         1072         DBG("CPP if result=%d", enabled);
         1073         ifstate[n].done = done;
         1074         ifstate[n].enabled = enabled;
         1075         ifstate[n].iselse = 0;
         1076 }
         1077 
         1078 static void
         1079 cppif(void)
         1080 {
         1081         DBG("CPP line=%u if cppctx=%d", lineno, cppctx);
         1082         disexpand = 0;
         1083         ifclause(0, 0);
         1084 }
         1085 
         1086 static void
         1087 ifdef(void)
         1088 {
         1089         DBG("CPP line=%u ifdef cppctx=%d", lineno, cppctx);
         1090         ifclause(0, 1);
         1091 }
         1092 
         1093 static void
         1094 ifndef(void)
         1095 {
         1096         DBG("CPP line=%u ifndef cppctx=%d", lineno, cppctx);
         1097         ifclause(1, 1);
         1098 }
         1099 
         1100 static void
         1101 cppelse(void)
         1102 {
         1103         DBG("CPP line=%u else cppctx=%d", lineno, cppctx);
         1104 
         1105         if (cppctx == 0 || ifstate[cppctx-1].iselse) {
         1106                 cpperror("#else without #ifdef/ifndef");
         1107                 return;
         1108         }
         1109 
         1110         /*
         1111          * If we are disabled by a upper ifdef then ifclause() already
         1112          * marked us as disabled and done. So if we are done then we
         1113          * disable cpp because or ifclause was true, or it was disabled
         1114          * by the upper. If we are not done, then it is our turn.
         1115          */
         1116         if (ifstate[cppctx-1].done) {
         1117                 ifstate[cppctx-1].enabled = 0;
         1118                 cppoff = 1;
         1119         } else {
         1120                 ifstate[cppctx-1].done = 1;
         1121                 ifstate[cppctx-1].enabled = 1;
         1122                 cppoff = 0;
         1123         }
         1124         ifstate[cppctx-1].iselse = 1;
         1125 
         1126         next();
         1127 }
         1128 
         1129 static void
         1130 elif(void)
         1131 {
         1132         DBG("CPP line=%u elif cppctx=%d", lineno, cppctx);
         1133 
         1134         if (cppctx == 0 || ifstate[cppctx-1].iselse) {
         1135                 cpperror("#elif without #ifdef/ifndef");
         1136                 return;
         1137         }
         1138 
         1139         /*
         1140          * If we are disabled by a upper ifdef then ifclause() already
         1141          * marked us as disabled and done. So if we are done then we
         1142          * disable cpp because or ifclause was true, or it was disabled
         1143          * by the upper. If we are not done, then we have to evaluate
         1144          * the if condition.
         1145          */
         1146         if (ifstate[cppctx-1].done) {
         1147                 ifstate[cppctx-1].enabled = 0;
         1148                 cppoff = 1;
         1149         } else {
         1150                 --cppctx;
         1151                 DBG("elif updates cppctx=%d", cppctx);
         1152                 cppif();
         1153         }
         1154 }
         1155 
         1156 static void
         1157 endif(void)
         1158 {
         1159         DBG("CPP line=%u endif cppctx=%d", lineno, cppctx);
         1160 
         1161         if (cppctx == 0)
         1162                 error("#endif without #if");
         1163 
         1164         if (cppctx > 1)
         1165                 cppoff = !ifstate[cppctx - 2].enabled;
         1166         else
         1167                 cppoff = 0;
         1168 
         1169         --cppctx;
         1170         DBG("CPP endif updates cppctx=%d", cppctx);
         1171         next();
         1172 }
         1173 
         1174 static void
         1175 undef(void)
         1176 {
         1177         if (cppoff)
         1178                 return;
         1179 
         1180         namespace = NS_CPP;
         1181         next();
         1182         if (yytoken != IDEN) {
         1183                 error("no macro name given in #undef directive");
         1184                 return;
         1185         }
         1186         killsym(yylval.sym);
         1187         next();
         1188 }
         1189 
         1190 int
         1191 cpp(void)
         1192 {
         1193         static struct {
         1194                 unsigned char token;
         1195                 void (*fun)(void);
         1196         } *bp, clauses [] = {
         1197                 {DEFINE, define},
         1198                 {INCLUDE, include},
         1199                 {LINE, line},
         1200                 {IFDEF, ifdef},
         1201                 {IF, cppif},
         1202                 {ELIF, elif},
         1203                 {IFNDEF, ifndef},
         1204                 {ELSE, cppelse},
         1205                 {ENDIF, endif},
         1206                 {UNDEF, undef},
         1207                 {PRAGMA, pragma},
         1208                 {ERROR, usererr},
         1209                 {0, NULL}
         1210         };
         1211         int ns;
         1212         char *p;
         1213 
         1214         for (p = input->p; cppspace(*p); ++p)
         1215                 ;
         1216 
         1217         if (*p != '#') {
         1218                 if (cppoff)
         1219                         *input->p = '\0';
         1220                 return cppoff;
         1221         }
         1222         input->p = p+1;
         1223 
         1224         disexpand = 1;
         1225         lexmode = CPPMODE;
         1226         ns = namespace;
         1227         namespace = NS_CPPCLAUSES;
         1228         next();
         1229         namespace = NS_IDEN;
         1230 
         1231         if (yytoken == '\n')
         1232                 goto ret;
         1233 
         1234         for (bp = clauses; bp->token && bp->token != yytoken; ++bp)
         1235                 ;
         1236         if (!bp->token) {
         1237                 errorp("incorrect preprocessor directive '%s'", yytext);
         1238                 goto ret;
         1239         }
         1240 
         1241         DBG("CPP %s", yytext);
         1242 
         1243         /*
         1244          * create a new context to avoid polish the current context,
         1245          * and to get all the symbols freed at the end
         1246          */
         1247         pushctx();
         1248         (*bp->fun)();
         1249         popctx();
         1250 
         1251         /*
         1252          * #include changes the content of input->line, so the correctness
         1253          * of the line must be checked in the own include(), and we have
         1254          * to skip this tests. For the same reason include() is the only
         1255          * function which does not prepare the next token
         1256          */
         1257         if (bp->token == INCLUDE)
         1258                 goto ret;
         1259 
         1260         if (yytoken != '\n' && yytoken != EOFTOK && !cppoff)
         1261                 cpperror("trailing characters after preprocessor directive");
         1262 
         1263 ret:
         1264         disexpand = 0;
         1265         lexmode = CCMODE;
         1266         namespace = ns;
         1267 
         1268         /*
         1269          * at this point we know that the cpp line is processed, and any error
         1270          * is generated but as next is called we cannot be sure that input is
         1271          * valid anymore, but in case of begin valid we want to discard any
         1272          * pending input in the current line
         1273          */
         1274         if (input)
         1275                 *input->p = '\0';
         1276 
         1277         return 1;
         1278 }
         1279 
         1280 void
         1281 ppragmaln(void)
         1282 {
         1283         static char file[FILENAME_MAX];
         1284         static unsigned nline;
         1285         char *s;
         1286 
         1287         putchar('\n');
         1288         if (strcmp(file, filenam)) {
         1289                 strcpy(file, filenam);
         1290                 s = "#line %u \"%s\"\n";
         1291         } else if (nline+1 != lineno) {
         1292                 s = "#line %u\n";
         1293         } else {
         1294                 s = "";
         1295         }
         1296         nline = lineno;
         1297         printf(s, nline, file);
         1298 
         1299         for (s = input->line; isspace(*s); ++s)
         1300                 putchar(*s);
         1301         yyspace = 0;
         1302 }
         1303 
         1304 void
         1305 outcpp(void)
         1306 {
         1307         for (next(); yytoken != EOFTOK; next()) {
         1308                 if (onlyheader)
         1309                         continue;
         1310                 printf("%s%s", yyspace ? " " : "", yytext);
         1311                 yyspace = 0;
         1312         }
         1313         putchar('\n');
         1314 }