#include <u.h>#include <libc.h>#include <stdio.h>#include "cpp.h" #define OUTS 16384char outbuf[OUTS];char *outp = outbuf;Source *cursource;int nerrs;struct token nltoken = { NL, 0, 0, 0, 1, (uchar*)"\n" };char *curtime;int incdepth;int ifdepth;int ifsatisfied[NIF];int skipping; intmain(int argc, char **argv){ Tokenrow tr; long t; char ebuf[BUFSIZ]; setbuf(stderr, ebuf); t = time(NULL); curtime = ctime(t); maketokenrow(3, &tr); expandlex(); setup(argc, argv); iniths(); genline(); process(&tr); flushout(); fflush(stderr); exits(nerrs? "errors" : 0);} voidprocess(Tokenrow *trp){ int anymacros = 0; for (;;) { if (trp->tp >= trp->lp) { trp->tp = trp->lp = trp->bp; outp = outbuf; anymacros |= gettokens(trp, 1); trp->tp = trp->bp; } if (trp->tp->type == END) { if (--incdepth>=0) { if (cursource->ifdepth) error(ERROR, "Unterminated conditional in #include"); unsetsource(); cursource->line += cursource->lineinc; trp->tp = trp->lp; genline(); continue; } if (ifdepth) error(ERROR, "Unterminated #if/#ifdef/#ifndef"); break; } if (trp->tp->type==SHARP) { trp->tp += 1; control(trp); } else if (!skipping && anymacros) expandrow(trp, NULL); if (skipping) setempty(trp); puttokens(trp); anymacros = 0; cursource->line += cursource->lineinc; if (cursource->lineinc>1) { genline(); } }} voidcontrol(Tokenrow *trp){ Nlist *np; Token *tp; Dir *d; Once n; tp = trp->tp; if (tp->type!=NAME) { if (tp->type==NUMBER) goto kline; if (tp->type != NL) error(ERROR, "Unidentifiable control line"); return; /* else empty line */ } if ((np = lookup(tp, 0))==NULL || (np->flag&ISKW)==0 && !skipping) { error(WARNING, "Unknown preprocessor control %t", tp); return; } if (skipping) { if ((np->flag&ISKW)==0) return; switch (np->val) { case KENDIF: if (--ifdepth<skipping) skipping = 0; --cursource->ifdepth; setempty(trp); return; case KIFDEF: case KIFNDEF: case KIF: if (++ifdepth >= NIF) error(FATAL, "#if too deeply nested"); ++cursource->ifdepth; return; case KELIF: case KELSE: if (ifdepth<=skipping) break; return; default: return; } } switch (np->val) { case KDEFINE: dodefine(trp); break; case KUNDEF: tp += 1; if (tp->type!=NAME || trp->lp - trp->bp != 4) { error(ERROR, "Syntax error in #undef"); break; } if ((np = lookup(tp, 0))) { if (np->flag&ISUNCHANGE) { error(ERROR, "#defined token %t can't be undefined", tp); return; } np->flag &= ~ISDEFINED; } break; case KPRAGMA: tp += 1; if (tp->type!=NAME || tp->len < 4 || memcmp(tp->t, "once", 4) != 0) return; if (nblocked >= NONCE) error(FATAL, "#pragma once list max length exceeded"); d = dirfstat(cursource->fd); if (d == nil) error(FATAL, "Out of memory from dirfstat"); n.qid = d->qid; n.type = d->type; n.dev = d->dev; incblocked[nblocked++] = n; free(d); break; case KIFDEF: case KIFNDEF: case KIF: if (++ifdepth >= NIF) error(FATAL, "#if too deeply nested"); ++cursource->ifdepth; ifsatisfied[ifdepth] = 0; if (eval(trp, np->val)) ifsatisfied[ifdepth] = 1; else skipping = ifdepth; break; case KELIF: if (ifdepth==0) { error(ERROR, "#elif with no #if"); return; } if (ifsatisfied[ifdepth]==2) error(ERROR, "#elif after #else"); if (eval(trp, np->val)) { if (ifsatisfied[ifdepth]) skipping = ifdepth; else { skipping = 0; ifsatisfied[ifdepth] = 1; } } else skipping = ifdepth; break; case KELSE: if (ifdepth==0 || cursource->ifdepth==0) { error(ERROR, "#else with no #if"); return; } if (ifsatisfied[ifdepth]==2) error(ERROR, "#else after #else"); if (trp->lp - trp->bp != 3) error(ERROR, "Syntax error in #else"); skipping = ifsatisfied[ifdepth]? ifdepth: 0; ifsatisfied[ifdepth] = 2; break; case KENDIF: if (ifdepth==0 || cursource->ifdepth==0) { error(ERROR, "#endif with no #if"); return; } --ifdepth; --cursource->ifdepth; if (trp->lp - trp->bp != 3) error(WARNING, "Syntax error in #endif"); break; case KERROR: trp->tp = tp+1; error(ERROR, "#error directive: %r", trp); break; case KWARNING: trp->tp = tp+1; error(WARNING, "#warning directive: %r", trp); break; case KLINE: trp->tp = tp+1; expandrow(trp, "<line>"); tp = trp->bp+2; kline: if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp || (tp+3==trp->lp && ((tp+1)->type!=STRING)||*(tp+1)->t=='L')){ error(ERROR, "Syntax error in #line"); return; } cursource->line = atol((char*)tp->t)-1; if (cursource->line<0 || cursource->line>=32768) error(WARNING, "#line specifies number out of range"); tp = tp+1; if (tp+1<trp->lp) cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0); return; case KDEFINED: error(ERROR, "Bad syntax for control line"); break; case KINCLUDE: doinclude(trp); trp->lp = trp->bp; return; case KEVAL: eval(trp, np->val); break; default: error(ERROR, "Preprocessor control `%t' not yet implemented", tp); break; } setempty(trp); return;} void *dorealloc(void *ptr, int size){ void *p = realloc(ptr, size); if (p==NULL) error(FATAL, "Out of memory from realloc"); return p;} void *domalloc(int size){ void *p = malloc(size); if (p==NULL) error(FATAL, "Out of memory from malloc"); return p;} voiddofree(void *p){ free(p);} voiderror(enum errtype type, char *string, ...){ va_list ap; char *cp, *ep; Token *tp; Tokenrow *trp; Source *s; int i; void *p; fprintf(stderr, "cpp: "); for (s=cursource; s; s=s->next) if (*s->filename) fprintf(stderr, "%s:%d ", s->filename, s->line); va_start(ap, string); for (ep=string; *ep; ep++) { if (*ep=='%') { switch (*++ep) { case 's': cp = va_arg(ap, char *); fprintf(stderr, "%s", cp); break; case 'd': i = va_arg(ap, int); fprintf(stderr, "%d", i); break; case 'p': p = va_arg(ap, void *); fprintf(stderr, "%p", p); break; case 't': tp = va_arg(ap, Token *); fprintf(stderr, "%.*s", tp->len, tp->t); break; case 'r': trp = va_arg(ap, Tokenrow *); for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) { if (tp>trp->tp && tp->wslen) fputc(' ', stderr); fprintf(stderr, "%.*s", tp->len, tp->t); } break; default: fputc(*ep, stderr); break; } } else fputc(*ep, stderr); } va_end(ap); fputc('\n', stderr); if (type==FATAL) exits("error"); if (type!=WARNING) nerrs = 1; fflush(stderr);}
#include <u.h>
#include <libc.h>
#include <stdio.h>
#include "cpp.h"
#define OUTS 16384
char outbuf[OUTS];
char *outp = outbuf;
Source *cursource;
int nerrs;
struct token nltoken = { NL, 0, 0, 0, 1, (uchar*)"\n" };
char *curtime;
int incdepth;
int ifdepth;
int ifsatisfied[NIF];
int skipping;
int
main(int argc, char **argv)
{
Tokenrow tr;
long t;
char ebuf[BUFSIZ];
setbuf(stderr, ebuf);
t = time(NULL);
curtime = ctime(t);
maketokenrow(3, &tr);
expandlex();
setup(argc, argv);
iniths();
genline();
process(&tr);
flushout();
fflush(stderr);
exits(nerrs? "errors" : 0);
}
void
process(Tokenrow *trp)
{
int anymacros = 0;
for (;;) {
if (trp->tp >= trp->lp) {
trp->tp = trp->lp = trp->bp;
outp = outbuf;
anymacros |= gettokens(trp, 1);
trp->tp = trp->bp;
}
if (trp->tp->type == END) {
if (--incdepth>=0) {
if (cursource->ifdepth)
error(ERROR,
"Unterminated conditional in #include");
unsetsource();
cursource->line += cursource->lineinc;
trp->tp = trp->lp;
genline();
continue;
}
if (ifdepth)
error(ERROR, "Unterminated #if/#ifdef/#ifndef");
break;
}
if (trp->tp->type==SHARP) {
trp->tp += 1;
control(trp);
} else if (!skipping && anymacros)
expandrow(trp, NULL);
if (skipping)
setempty(trp);
puttokens(trp);
anymacros = 0;
cursource->line += cursource->lineinc;
if (cursource->lineinc>1) {
genline();
}
}
}
void
control(Tokenrow *trp)
{
Nlist *np;
Token *tp;
Dir *d;
Once n;
tp = trp->tp;
if (tp->type!=NAME) {
if (tp->type==NUMBER)
goto kline;
if (tp->type != NL)
error(ERROR, "Unidentifiable control line");
return; /* else empty line */
}
if ((np = lookup(tp, 0))==NULL || (np->flag&ISKW)==0 && !skipping) {
error(WARNING, "Unknown preprocessor control %t", tp);
return;
}
if (skipping) {
if ((np->flag&ISKW)==0)
return;
switch (np->val) {
case KENDIF:
if (--ifdepth<skipping)
skipping = 0;
--cursource->ifdepth;
setempty(trp);
return;
case KIFDEF:
case KIFNDEF:
case KIF:
if (++ifdepth >= NIF)
error(FATAL, "#if too deeply nested");
++cursource->ifdepth;
return;
case KELIF:
case KELSE:
if (ifdepth<=skipping)
break;
return;
default:
return;
}
}
switch (np->val) {
case KDEFINE:
dodefine(trp);
break;
case KUNDEF:
tp += 1;
if (tp->type!=NAME || trp->lp - trp->bp != 4) {
error(ERROR, "Syntax error in #undef");
break;
}
if ((np = lookup(tp, 0))) {
if (np->flag&ISUNCHANGE) {
error(ERROR, "#defined token %t can't be undefined", tp);
return;
}
np->flag &= ~ISDEFINED;
}
break;
case KPRAGMA:
tp += 1;
if (tp->type!=NAME || tp->len < 4 || memcmp(tp->t, "once", 4) != 0)
return;
if (nblocked >= NONCE)
error(FATAL, "#pragma once list max length exceeded");
d = dirfstat(cursource->fd);
if (d == nil)
error(FATAL, "Out of memory from dirfstat");
n.qid = d->qid;
n.type = d->type;
n.dev = d->dev;
incblocked[nblocked++] = n;
free(d);
break;
case KIFDEF:
case KIFNDEF:
case KIF:
if (++ifdepth >= NIF)
error(FATAL, "#if too deeply nested");
++cursource->ifdepth;
ifsatisfied[ifdepth] = 0;
if (eval(trp, np->val))
ifsatisfied[ifdepth] = 1;
else
skipping = ifdepth;
break;
case KELIF:
if (ifdepth==0) {
error(ERROR, "#elif with no #if");
return;
}
if (ifsatisfied[ifdepth]==2)
error(ERROR, "#elif after #else");
if (eval(trp, np->val)) {
if (ifsatisfied[ifdepth])
skipping = ifdepth;
else {
skipping = 0;
ifsatisfied[ifdepth] = 1;
}
} else
skipping = ifdepth;
break;
case KELSE:
if (ifdepth==0 || cursource->ifdepth==0) {
error(ERROR, "#else with no #if");
return;
}
if (ifsatisfied[ifdepth]==2)
error(ERROR, "#else after #else");
if (trp->lp - trp->bp != 3)
error(ERROR, "Syntax error in #else");
skipping = ifsatisfied[ifdepth]? ifdepth: 0;
ifsatisfied[ifdepth] = 2;
break;
case KENDIF:
if (ifdepth==0 || cursource->ifdepth==0) {
error(ERROR, "#endif with no #if");
return;
}
--ifdepth;
--cursource->ifdepth;
if (trp->lp - trp->bp != 3)
error(WARNING, "Syntax error in #endif");
break;
case KERROR:
trp->tp = tp+1;
error(ERROR, "#error directive: %r", trp);
break;
case KWARNING:
trp->tp = tp+1;
error(WARNING, "#warning directive: %r", trp);
break;
case KLINE:
trp->tp = tp+1;
expandrow(trp, "<line>");
tp = trp->bp+2;
kline:
if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp
|| (tp+3==trp->lp && ((tp+1)->type!=STRING)||*(tp+1)->t=='L')){
error(ERROR, "Syntax error in #line");
return;
}
cursource->line = atol((char*)tp->t)-1;
if (cursource->line<0 || cursource->line>=32768)
error(WARNING, "#line specifies number out of range");
tp = tp+1;
if (tp+1<trp->lp)
cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0);
return;
case KDEFINED:
error(ERROR, "Bad syntax for control line");
break;
case KINCLUDE:
doinclude(trp);
trp->lp = trp->bp;
return;
case KEVAL:
eval(trp, np->val);
break;
default:
error(ERROR, "Preprocessor control `%t' not yet implemented", tp);
break;
}
setempty(trp);
return;
}
void *
dorealloc(void *ptr, int size)
{
void *p = realloc(ptr, size);
if (p==NULL)
error(FATAL, "Out of memory from realloc");
return p;
}
void *
domalloc(int size)
{
void *p = malloc(size);
if (p==NULL)
error(FATAL, "Out of memory from malloc");
return p;
}
void
dofree(void *p)
{
free(p);
}
void
error(enum errtype type, char *string, ...)
{
va_list ap;
char *cp, *ep;
Token *tp;
Tokenrow *trp;
Source *s;
int i;
void *p;
fprintf(stderr, "cpp: ");
for (s=cursource; s; s=s->next)
if (*s->filename)
fprintf(stderr, "%s:%d ", s->filename, s->line);
va_start(ap, string);
for (ep=string; *ep; ep++) {
if (*ep=='%') {
switch (*++ep) {
case 's':
cp = va_arg(ap, char *);
fprintf(stderr, "%s", cp);
break;
case 'd':
i = va_arg(ap, int);
fprintf(stderr, "%d", i);
break;
case 'p':
p = va_arg(ap, void *);
fprintf(stderr, "%p", p);
break;
case 't':
tp = va_arg(ap, Token *);
fprintf(stderr, "%.*s", tp->len, tp->t);
break;
case 'r':
trp = va_arg(ap, Tokenrow *);
for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) {
if (tp>trp->tp && tp->wslen)
fputc(' ', stderr);
fprintf(stderr, "%.*s", tp->len, tp->t);
}
break;
default:
fputc(*ep, stderr);
break;
}
} else
fputc(*ep, stderr);
}
va_end(ap);
fputc('\n', stderr);
if (type==FATAL)
exits("error");
if (type!=WARNING)
nerrs = 1;
fflush(stderr);
}