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