da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/***********************************************************************
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* This software is part of the ast package *
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz* Copyright (c) 1986-2009 AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* and is licensed under the *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Common Public License, Version 1.0 *
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin* by AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* A copy of the License is available at *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Information and Software Systems Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* AT&T Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Florham Park NJ *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Glenn Fowler <gsf@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin***********************************************************************/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Glenn Fowler
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * AT&T Research
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * preprocessor library control interface
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define ppiskey(t,v,p) (p=t,v>=p->value&&value<=(p+elementsof(t)-2)->value)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * set option value
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * initialization files have lowest precedence
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin r = p == &pp.state ? &pp.ro_state : p == &pp.mode ? &pp.ro_mode : &pp.ro_option;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!(pp.mode & INIT) || !(pp.in->type == IN_FILE) || !(*r & op))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin debug((-7, "set(%s)=%s", p == &pp.state ? "state" : p == &pp.mode ? "mode" : "option", p == &pp.state ? ppstatestr(*p) : p == &pp.mode ? ppmodestr(*p) : ppoptionstr(*p)));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * initialize hash table with keywords from key
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chininithash(register Hash_table_t* tab, register struct ppkeyword* key)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* s;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return ppkeyword table name given value
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* s;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register struct ppkeyword* p;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (dir && ppiskey(directives, value, p) || !dir && (ppiskey(options, value, p) || ppiskey(predicates, value, p) || ppiskey(variables, value, p)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return s + !ppisid(*s);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(PANIC, "no keyword table name for value=%d", value);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return "UNKNOWN";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * add to the include maps
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(1, "%s: input file name required for %s ignore", file, dirname(INCLUDE));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (*s == c)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((fd = ppsearch(file, INC_LOCAL, SEARCH_INCLUDE)) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pp.state |= (COMPILE|FILEPOP|HEADER|JOINING|STRIP|NOSPACE|PASSEOF);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pp.state |= (COMPILE|FILEPOP|HEADER|STRIP|NOSPACE|PASSEOF);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (dp->name && (c = strlen(dp->name)) && !strncmp(dp->name, fp->name, c) && fp->name[c] == '/')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case '\n':
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*FALLTHROUGH*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(3, "%s unexpected in %s map list", pptokstr(pp.token, 0), dirname(INCLUDE));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return non-0 if file is identical to fd
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return !stat(file, &a) && !fstat(fd, &b) && a.st_dev == b.st_dev && a.st_ino == b.st_ino;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * compare up to pp.truncate chars
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * NOTE: __STD* and symbols containing ' ' are not truncated
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return !strchr(b, ' ') && !strneq(b, "__STD", 5) ? strncmp(a, b, pp.truncate) : strcmp(a, b);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * hash up to pp.truncate chars
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * NOTE: __STD* and symbols containing ' ' are not truncated
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic unsigned int
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return memhash(a, (n = strlen(a)) > pp.truncate && !strchr(a, ' ') && !strneq(a, "__STD", 5) ? pp.truncate : n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * append context to debug trace
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * reset include guard
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * reset macro definition
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * pp operations
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * NOTE: PP_INIT must be done before the first pplex() call
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * PP_DONE must be done after the last pplex() call
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * PP_INIT-PP_DONE must be done for each new PP_INPUT
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* p;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* s;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pp.lastop = (pp.lastop->next = newof(0, struct oplist, 1, 0));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pp.firstop = pp.lastop = newof(0, struct oplist, 1, 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (!pp.c)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!pp.c && (dp->c || dp->name && SAMEID(&dp->id, &st)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (*p && *p != c)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *s++ = *p++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *s++ = '/';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*p && *++p && *p != c)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (*p && *p != c)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *s++ = *p++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *s++ = '/';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(3, "preprocessor not compiled with compatibility dialect enabled [COMPATIBLE]");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (*s)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*FALLTHROUGH*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((pp.state & (NOTEXT|HIDDEN)) == HIDDEN && pplastout() != '\n')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(3, "preprocessor not compiled with checkpoint enabled [CHECKPOINT]");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!pp.hosted && ((dp->type & TYPE_HOSTED) || dp->name && SAMEID(&dp->id, &st)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * context initialization
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * out of malloc is fatal
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * initialize the error message interface
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * initialize pplex tables
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * fixed macro stack size -- room for improvement
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * initial include/if control stack
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * validate modes
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if (!(pp.state & WARN) && !(pp.arg_style & STYLE_gnu))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * create the hash tables
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pp.dirtab = hashalloc(REFONE, HASH_name, "directives", 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pp.prdtab = hashalloc(REFALL, HASH_name, "predicates", 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pp.strtab = hashalloc(REFALL, HASH_name, "strings", 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * mark macros that are builtin predicates
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the remaining entry names must be allocated
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * compose, push and read the builtin initialization script
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s %s:%s \"/#<assert> /\" \"/assert /%s #/\"\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s %s:%s \"/#<unassert> /\" \"/unassert /%s #/\"\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (ppsearch(pp.ppdefault, T_STRING, SEARCH_EXISTS) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!(pp.ppdefault = pathprobe(pp.path, NiL, "C", pp.pass, pp.probe ? pp.probe : PPPROBE, 0)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(1, "cannot determine default definitions for %s", pp.probe ? pp.probe : PPPROBE);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sp, "#%s #%s\n", dirname(DEFINE), pp.firstop->value);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sp, "#%s %s\n", dirname(DEFINE), pp.firstop->value);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sp, "#%s %-.*s %s\n", dirname(DEFINE), s - pp.firstop->value, pp.firstop->value, s + 1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sp, "#%s %s 1\n", dirname(DEFINE), pp.firstop->value);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sp, "#%s %s:%-.*s %s\n", dirname(PRAGMA), pp.pass, s - pp.firstop->value, pp.firstop->value, s + 1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sp, "#%s %s:%s\n", dirname(PRAGMA), pp.pass, pp.firstop->value);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.firstop->value);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sp, "#%s %s\n", dirname(UNDEF), pp.firstop->value);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s %s:%s\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s %s:%s\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s !#%s(%s)\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s !#%s(%s) || #%s(%s)\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s #%s(%s)\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s %s:%s\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s %s:%s\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s __STRICT__ 1\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s __STDPP__ 1\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s %s:no%s\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s __STDPP__directive #(%s)\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sp, "#%s %s%s%s #(%s)\n" , dirname(DEFINE), t, s, t, s);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s %s:no%s\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#%s %s:no%s\n\
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.ppdefault);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#%s !defined(__STDC__) && (!#option(compatibility) || #option(transition))\n\
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz#%s __STDC__ #(STDC)\n\
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin debug((-9, "\n/* begin initialization */\n%s/* end initialization */", t));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin message((-1, "include directory %s%s%s%s", dp->name, (dp->type & TYPE_VENDOR) ? " [VENDOR]" : "", (dp->type & TYPE_HOSTED) ? " [HOSTED]" : "", dp->c ? " [C]" : ""));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * this is sleazy but at least it's
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * hidden in the library
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((preroot = (struct pplist*)hashget(pp.prdtab, "preroot")))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(1, "directories up to and including %s are for \"...\" include files only", pp.stddirs->name);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pp.symtab = hashalloc(NiL, HASH_name, "symbols", HASH_free, undefine, HASH_set, HASH_ALLOCATE|HASH_BUCKET, 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!pp.pragma)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * push the main input file -- special case for hosted mark
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((t = p = strrchr(s, '.')) && (*++p == 'c' || *p == 'C'))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (c = *++p)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (*++p == c);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin t = s + strlen(s);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *t++ = '.';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *(t + 1) = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pp.column += sfprintf(pp.filedeps.sp, " %s", error_info.file);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), xp->value);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*FALLTHROUGH*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pp.lasttx = pp.lasttx->next = newof(0, struct oplist, 1, 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pp.firsttx = pp.lasttx = newof(0, struct oplist, 1, 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(3, "preprocessor not compiled with macro keyword arguments enabled [MACKEYARGS]");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if (*p != '-')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (n >= 2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (open(pp.outfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(ERROR_SYSTEM|3, "%s: cannot create", pp.outfile);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(3, "preprocessor not compiled with input pool enabled [POOL]");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*p == '-')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((c = (int)hashref(pp.strtab, p)) > 0 && c <= X_last_option)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (*s == '_')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (t = s + strlen(s); t > s && *(t - 1) == '_'; t--);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (*t == '_')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin op = ((key = ppkeyref(pp.symtab, s)) && (key->sym.flags & SYM_LEX)) ? key->lex : T_NOISE;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((pp.lastdir->next->name = ((p = va_arg(ap, char*)) && *p) ? p : NiL) && !stat(p, &st))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (s = p; n = *s; s++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pp.symtab = hashalloc(NiL, HASH_set, tab ? HASH_ALLOCATE : 0, HASH_compare, trunccomp, HASH_hash, trunchash, HASH_name, "truncate", 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin hashlook(pp.symtab, (char*)p, HASH_BUCKET|HASH_INSTALL, NiL);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } while (p = b);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!p || !*p)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!c && ((dp->type & TYPE_VENDOR) || dp->name && SAMEID(&dp->id, &st)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(3, "ppop(%d): preprocessor operation must be done before PP_INIT", op);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error(3, "ppop(%d): invalid preprocessor operation", op);