Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#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);
        fixlex();
        iniths();
        genline();
        process(&tr);
        flushout();
        fflush(stderr);
        exits(nerrs? "errors" : 0);
        return 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, Notinmacro);
                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;

        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:
                return;

        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>", Notinmacro);
                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);
}