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>89#include <scc/cstd.h>10#include <scc/scc.h>11#include "cc1.h"1213struct ifstate {14 unsigned char done;15 unsigned char enabled;16 unsigned char iselse;17};1819static unsigned ncmdlines;20static Symbol *symline, *symfile;21static struct ifstate ifstate[NR_COND];22static int cppoff;23static struct items dirinclude;2425unsigned cppctx;26int disexpand;2728void29defdefine(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 };3738 if (!val)39 val = "";40 if (strlen(fmt) + strlen(name) + strlen(val) > INPUTSIZ) {41 errorp("macro definition '%s' too big", name);42 return;43 }4445 sprintf(buffer, fmt, name, val);46 lineno = ++ncmdlines;4748 addinput(IPARAM, buffer, FAIL);49 cpp();50 delinput();51}5253void54undefmacro(char *s)55{56 killsym(lookup(NS_CPP, s, NOALLOC));57}5859void60icpp(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 };8081 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);8586 for (bp = list; bp->name; ++bp)87 defdefine(bp->name, bp->value, "built-in");8889 symline = lookup(NS_CPP, "__LINE__", ALLOC);90 symfile = lookup(NS_CPP, "__FILE__", ALLOC);9192 ncmdlines = 0;93}9495static char *96appendpar(Macro *mp, char *s, int len)97{98 char *arg;99 int siz = mp->argsiz;100101 if (len+1 > INT_MAX - siz) {102 error("too long argument invoking macro \"%s\"",103 mp->sym->name);104 }105106 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}111112static void113paren(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 }139140unterminated:141 error("unterminated argument list invoking macro \"%s\"",142 mp->sym->name);143}144145static int146cppspace(int c)147{148 return c == ' ' || c == '\t' || c == '\v' ||149 c == '\n' || c == '\f' || c == '\r';150}151152static char *153parameter(Macro *mp, int n)154{155 int siz;156 char *s, *begin, *end;157158 mp->arg = NULL;159 mp->argsiz = 0;160161 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;179180 while (begin < end && cppspace(*begin))181 begin++;182 while (end > begin && cppspace(end[-1]))183 end--;184185 siz = end - begin;186 s = memcpy(xmalloc(siz + 1), begin, siz);187 s[siz] = '\0';188189 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 }200201unterminated:202 error("unterminated argument list invoking macro \"%s\"",203 mp->sym->name);204}205206static int207parsepars(Macro *mp)208{209 int c, n;210 char *name;211212 if (mp->npars == -1)213 return 1;214 if (ahead() != '(')215 return 0;216217 input->p++;218 name = mp->sym->name;219220 if (mp->npars == 0 && ahead() == ')') {221 input->p++;222 return 1;223 }224225 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++;231232 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;239240 if (n == mp->npars)241 return 1;242243 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 }249250 error("macro \"%s\" received %d arguments, but it takes %d",251 mp->sym->name, n, mp->npars);252}253254static int255concatoper(char *def, char *cur)256{257 char *s;258259 for (s = cur + 4; cppspace(*s); ++s)260 ;261 if (*s == CONCAT)262 return 1;263264 for (s = cur; s > def && cppspace(s[-1]); --s)265 ;266 if (s > def && s[-1] == CONCAT)267 return 1;268269 return 0;270}271272static int273stringoper(char **bpp, int *sizep, char *arg)274{275 int c, esc, delim, siz;276 char *bp;277278 bp = *bpp;279 siz = *sizep;280281 if (siz < 3)282 return 0;283284 esc = delim = 0;285286 *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 }297298 if (c == '"') {299 if (siz < 4)300 return 0;301 *bp++ = '\\';302 siz--;303 } else {304 if (siz < 3)305 return 0;306 }307308 *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;319320 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++ = '"';341342 *bpp = bp;343 *sizep = siz;344345 return 1;346}347348static int349expandarg(char *arg, char *def, char *curdef, char *buf, int bufsiz)350{351 int siz;352 char *s = buf;353354 /* gives priority to concatenation operators */355 if (concatoper(def, curdef)) {356 char *p;357 int c;358359 /*360 * ignore NOEXPAND and EXPAND because ## has361 * precedence over macro expansion, and we just362 * want the argument as it is363 */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};376377 /*378 * Here we have to deal with a special case,379 * because the recursive input expansion deals380 * correctly with the hideset manipulation,381 * but once the macro expansion is flattened in382 * a buffer associated to the macro expansion383 * all the hideset information is lost. To solve384 * this problem we have to add annotation tokens385 * to maintain this information and avoid expanding386 * macros hidden due to the recursive hidesets387 */388 addinput(IPARAM, arg, FAIL);389 for (siz = 0; ; siz += n) {390 yyspace = noex[0] = ex[0] = '\0';391 if (next() == EOFTOK)392 break;393394 if (yytoken == IDEN) {395 Symbol *sym = yylval.cppsym;396 if (disexpand || sym && sym->hide) {397 noex[0] = NOEXPAND;398 ex[0] = EXPAND;399 }400 }401402 n = snprintf(buf, bufsiz, "%s%s%s%s",403 yyspace ? " " : "", noex, yytext, ex);404405 if (n < 0 || n == bufsiz)406 return -1;407408 buf += n;409 bufsiz -= n;410 }411 delinput();412 }413414 DBG("MACRO parameter '%s' expanded to '%s'", arg, s);415416 return siz;417}418419static int420copymacro(Macro *mp)421{422 int delim, c, esc;423 char *s, *p, *arg, *bp;424 int size, bufsiz;425426 if (mp->sym == symfile)427 return sprintf(mp->buffer, "\"%s\" ", filenam);428 if (mp->sym == symline)429 return sprintf(mp->buffer, "%d ", lineno);430431 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 else449 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;471472 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';493494 return bp - mp->buffer;495496expansion_too_long:497 error("macro expansion of \"%s\" too long", mp->sym->name);498}499500/*501 * Functions to deal with macro hidesets. Yes, this sucks, a lot,502 * but before blaming me read503 * https://www.spinellis.gr/blog/20060626/cpp.algo.pdf504 * It is not my fault.505 */506static void507addhideset(Symbol *sym)508{509 Symbol **set, **p;510511 set = input->hideset;512 for (p = set; p < &set[NR_MACROARG-1] && *p; ++p) {513 if (*p == sym)514 return;515 }516517 if (p == &set[NR_MACROARG])518 error("too complex macro expansion");519520 *p = sym;521 DBG("MACRO Adding %s to hideset of %s",522 sym->name, input->macro->sym->name);523}524525static void526hide(Symbol *sym)527{528 DBG("SYM: hidding symbol %s %d", sym->name, sym->hide);529 sym->hide = 1;530}531532static void533unhide(Symbol *sym)534{535 DBG("SYM: unhidding symbol %s %d", sym->name, sym->hide);536 sym->hide = 0;537}538539void540unsethideset(Input *ip)541{542 Symbol **p;543544 for (p = ip->hideset; *p; ++p)545 unhide(*p);546}547548void549sethideset(Input *ip)550{551 Symbol **p;552553 for (p = ip->hideset; *p; ++p)554 hide(*p);555}556557void558delmacro(Macro *mp)559{560 int i;561 Symbol **p;562563 if (!mp)564 return;565566 if (mp->arglist) {567 for (i = 0; i < mp->npars; i++)568 free(mp->arglist[i]);569 }570571 free(mp->arglist);572 free(mp);573}574575Macro *576newmacro(Symbol *sym)577{578 Macro *mp;579580 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);585586 return mp;587}588589static void590intersect(Symbol **dst, Symbol **set)591{592 Symbol *sym, **cur, **p;593594 for (cur = dst; sym = *cur; ++cur) {595 for (p = set; *p && *p != sym; ++p)596 ;597 if (*p)598 *dst++ = sym;599 }600601 while (dst != cur)602 *dst++ = NULL;603}604605int606expand(Symbol *sym)607{608 int spc, siz;609 Macro *mp;610611 DBG("MACRO '%s' detected disexpand=%d hide=%d",612 sym->name, disexpand, sym->hide);613614 if (disexpand || sym->hide || sym->token != IDEN)615 return 0;616617 spc = yyspace;618 mp = newmacro(sym);619 mp->fname = filenam;620 memcpy(mp->hideset, input->hideset, sizeof(mp->hideset));621622 if (!parsepars(mp)) {623 delmacro(mp);624 return 0;625 }626627 if (mp->npars != -1)628 intersect(mp->hideset, input->hideset);629 addinput(IMACRO, mp, FAIL);630 addhideset(sym);631 hide(sym);632633 mp->buffer = input->line;634 mp->bufsiz = INPUTSIZ-1;635636 siz = copymacro(mp);637 mp->buffer[siz] = '\0';638 yyspace = spc;639640 DBG("MACRO '%s' expanded to :'%s'", mp->sym->name, mp->buffer);641642 return 1;643}644645static int646getpars(Symbol *args[NR_MACROARG])647{648 int n, c;649 Symbol *sym;650651 if (*input->p != '(')652 return -1;653654 /* skip the '(' */655 next();656 next();657 if (yytoken == ')')658 return 0;659660 n = 0;661 do {662 if (n == NR_MACROARG) {663 cpperror("too many parameters in macro");664 return NR_MACROARG;665 }666667 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 }676677 if (!install(NS_MACROPAR, sym)) {678 errorp("duplicated macro parameter '%s'", sym->name);679 } else {680 sym->flags |= SUSED;681 args[n++] = sym;682 }683684 if (accept(ELLIPSIS))685 break;686687 } while (accept(','));688689 if (yytoken != ')') {690 cpperror("expected ')' at the end of macro argument list");691 return NR_MACROARG;692 }693694 return n;695}696697static int698getdefs(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;703704 while (cppspace(*input->p))705 ++input->p;706707 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;713714 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 }733734 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 }746747 if (prevc == 0 && token == CONCAT)748 goto wrong_concat;749750 if (prevc == STRINGIZE && !ispar) {751 cpperror("'#' is not followed by a macro parameter");752 return 0;753 }754755 if (len >= bufsiz) {756 cpperror("macro too long");757 return 0;758 }759760 memcpy(bp, s, len);761 bp += len;762 bufsiz -= len;763 prevc = token;764 }765766end_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;775776wrong_concat:777 cpperror("'##' cannot appear at either ends of a macro expansion");778 return 0;779}780781static void782define(void)783{784 int n;785 Symbol *sym,*args[NR_MACROARG];786 char buff[LINESIZ+1];787 unsigned flags = SDECLARED|SSTRING;788789 if (cppoff)790 return;791792 namespace = NS_CPP;793 next();794795 if (yytoken != IDEN) {796 cpperror("macro names must be identifiers");797 return;798 }799 sym = yylval.sym;800801 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;806807 sprintf(buff, "%02d#", n);808 if (!getdefs(args, n, buff+3, LINESIZ-3))809 goto delete;810811 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 }819820 sym->u.s = xstrdup(buff);821 DBG("MACRO '%s' defined as '%s'", sym->name, buff);822 return;823824delete:825 killsym(sym);826}827828void829incdir(char *dir)830{831 if (!dir || *dir == '\0')832 die("cc1: incorrect -I flag");833 newitem(&dirinclude, dir);834}835836static int837includefile(char *dir, char *file, size_t filelen)838{839 size_t dirlen;840 char path[FILENAME_MAX];841842 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';856857 return addinput(IFILE, path, NOFAIL);858}859860static char *861cwd(char *buf)862{863 char *p, *s = filenam;864 size_t len;865866 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}874875static void876include(void)877{878 char dir[FILENAME_MAX], file[FILENAME_MAX], *p, **bp;879 size_t filelen;880 int n;881882 if (cppoff)883 return;884885 disexpand = 0;886 namespace = NS_IDEN;887 next();888889 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';898899 input->begin = input->p = p+1;900 if (next() != '\n')901 goto trailing_characters;902903 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';912913 if (next() != '\n')914 goto trailing_characters;915916 if (includefile(cwd(dir), file, filelen))917 goto its_done;918 break;919 default:920 goto bad_include;921 }922923 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);929930its_done:931 return;932933trailing_characters:934 cpperror("trailing characters after preprocessor directive");935 return;936937too_long:938 cpperror("too long file name in #include");939 return;940941bad_include:942 cpperror("#include expects \"FILENAME\" or <FILENAME>");943 return;944}945946static void947line(void)948{949 long n;950 char *endp, *fname;951952 if (cppoff)953 return;954955 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 }962963 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}977978static void979pragma(void)980{981 if (cppoff)982 return;983 next();984 warn("ignoring pragma '%s'", yytext);985 *input->p = '\0';986 next();987}988989static void990usererr(void)991{992 if (cppoff)993 return;994 cpperror("#error %s", input->p);995 exit(EXIT_FAILURE);996 next();997}9989991000Node *1001defined(void)1002{1003 Symbol *sym;1004 int paren;10051006 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 else1014 sym = one;1015 disexpand = 0;1016 next();1017 if (paren)1018 expect(')');1019 return constnode(sym);1020}10211022static void1023ifclause(int negate, int isifdef)1024{1025 Symbol *sym;1026 unsigned n;1027 int enabled, done;1028 Node *expr;10291030 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);10341035 if (n > 0 && !ifstate[n-1].enabled) {1036 done = 1;1037 enabled = 0;1038 goto disabled;1039 }10401041 namespace = NS_CPP;1042 next();10431044 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 }10651066 if (negate)1067 enabled = !enabled;1068 done = enabled;10691070disabled: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}10771078static void1079cppif(void)1080{1081 DBG("CPP line=%u if cppctx=%d", lineno, cppctx);1082 disexpand = 0;1083 ifclause(0, 0);1084}10851086static void1087ifdef(void)1088{1089 DBG("CPP line=%u ifdef cppctx=%d", lineno, cppctx);1090 ifclause(0, 1);1091}10921093static void1094ifndef(void)1095{1096 DBG("CPP line=%u ifndef cppctx=%d", lineno, cppctx);1097 ifclause(1, 1);1098}10991100static void1101cppelse(void)1102{1103 DBG("CPP line=%u else cppctx=%d", lineno, cppctx);11041105 if (cppctx == 0 || ifstate[cppctx-1].iselse) {1106 cpperror("#else without #ifdef/ifndef");1107 return;1108 }11091110 /*1111 * If we are disabled by a upper ifdef then ifclause() already1112 * marked us as disabled and done. So if we are done then we1113 * disable cpp because or ifclause was true, or it was disabled1114 * 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;11251126 next();1127}11281129static void1130elif(void)1131{1132 DBG("CPP line=%u elif cppctx=%d", lineno, cppctx);11331134 if (cppctx == 0 || ifstate[cppctx-1].iselse) {1135 cpperror("#elif without #ifdef/ifndef");1136 return;1137 }11381139 /*1140 * If we are disabled by a upper ifdef then ifclause() already1141 * marked us as disabled and done. So if we are done then we1142 * disable cpp because or ifclause was true, or it was disabled1143 * by the upper. If we are not done, then we have to evaluate1144 * 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}11551156static void1157endif(void)1158{1159 DBG("CPP line=%u endif cppctx=%d", lineno, cppctx);11601161 if (cppctx == 0)1162 error("#endif without #if");11631164 if (cppctx > 1)1165 cppoff = !ifstate[cppctx - 2].enabled;1166 else1167 cppoff = 0;11681169 --cppctx;1170 DBG("CPP endif updates cppctx=%d", cppctx);1171 next();1172}11731174static void1175undef(void)1176{1177 if (cppoff)1178 return;11791180 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}11891190int1191cpp(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;12131214 for (p = input->p; cppspace(*p); ++p)1215 ;12161217 if (*p != '#') {1218 if (cppoff)1219 *input->p = '\0';1220 return cppoff;1221 }1222 input->p = p+1;12231224 disexpand = 1;1225 lexmode = CPPMODE;1226 ns = namespace;1227 namespace = NS_CPPCLAUSES;1228 next();1229 namespace = NS_IDEN;12301231 if (yytoken == '\n')1232 goto ret;12331234 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 }12401241 DBG("CPP %s", yytext);12421243 /*1244 * create a new context to avoid polish the current context,1245 * and to get all the symbols freed at the end1246 */1247 pushctx();1248 (*bp->fun)();1249 popctx();12501251 /*1252 * #include changes the content of input->line, so the correctness1253 * of the line must be checked in the own include(), and we have1254 * to skip this tests. For the same reason include() is the only1255 * function which does not prepare the next token1256 */1257 if (bp->token == INCLUDE)1258 goto ret;12591260 if (yytoken != '\n' && yytoken != EOFTOK && !cppoff)1261 cpperror("trailing characters after preprocessor directive");12621263ret:1264 disexpand = 0;1265 lexmode = CCMODE;1266 namespace = ns;12671268 /*1269 * at this point we know that the cpp line is processed, and any error1270 * is generated but as next is called we cannot be sure that input is1271 * valid anymore, but in case of begin valid we want to discard any1272 * pending input in the current line1273 */1274 if (input)1275 *input->p = '\0';12761277 return 1;1278}12791280void1281ppragmaln(void)1282{1283 static char file[FILENAME_MAX];1284 static unsigned nline;1285 char *s;12861287 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);12981299 for (s = input->line; isspace(*s); ++s)1300 putchar(*s);1301 yyspace = 0;1302}13031304void1305outcpp(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}