Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * common code for all the assemblers
 */

void
pragpack(void)
{
        while(getnsc() != '\n')
                ;
}

void
pragvararg(void)
{
        while(getnsc() != '\n')
                ;
}

void
pragfpround(void)
{
        while(getnsc() != '\n')
                ;
}

void
pragprofile(void)
{
        while(getnsc() != '\n')
                ;
}

void
pragincomplete(void)
{
        while(getnsc() != '\n')
                ;
}

/*
 * real allocs
 */
void*
alloc(long n)
{
        void *p;

        while((uintptr)hunk & MAXALIGN) {
                hunk++;
                nhunk--;
        }
        while(nhunk < n)
                gethunk();
        p = hunk;
        nhunk -= n;
        hunk += n;
        return p;
}

void*
allocn(void *p, long on, long n)
{
        void *q;

        q = (uchar*)p + on;
        if(q != hunk || nhunk < n) {
                while(nhunk < on+n)
                        gethunk();
                memmove(hunk, p, on);
                p = hunk;
                hunk += on;
                nhunk -= on;
        }
        hunk += n;
        nhunk -= n;
        return p;
}

void
setinclude(char *p)
{
        int i;

        if(p == 0)
                return;
        for(i=1; i < ninclude; i++)
                if(strcmp(p, include[i]) == 0)
                        return;

        if(ninclude >= nelem(include)) {
                yyerror("ninclude too small %d", nelem(include));
                exits("ninclude");
        }
        include[ninclude++] = p;
}

void
errorexit(void)
{

        if(outfile)
                remove(outfile);
        exits("error");
}

void
pushio(void)
{
        Io *i;

        i = iostack;
        if(i == I) {
                yyerror("botch in pushio");
                errorexit();
        }
        i->p = fi.p;
        i->c = fi.c;
}

void
newio(void)
{
        Io *i;
        static int pushdepth = 0;

        i = iofree;
        if(i == I) {
                pushdepth++;
                if(pushdepth > 1000) {
                        yyerror("macro/io expansion too deep");
                        errorexit();
                }
                i = alloc(sizeof(*i));
        } else
                iofree = i->link;
        i->c = 0;
        i->f = -1;
        ionext = i;
}

void
newfile(char *s, int f)
{
        Io *i;

        i = ionext;
        i->link = iostack;
        iostack = i;
        i->f = f;
        if(f < 0)
                i->f = open(s, 0);
        if(i->f < 0) {
                yyerror("%ca: %r: %s", thechar, s);
                errorexit();
        }
        fi.c = 0;
        linehist(s, 0);
}

Sym*
slookup(char *s)
{

        strcpy(symb, s);
        return lookup();
}

Sym*
lookup(void)
{
        Sym *s;
        long h;
        char *p;
        int c, l;

        h = 0;
        for(p=symb; c = *p; p++)
                h = h+h+h + c;
        l = (p - symb) + 1;
        if(h < 0)
                h = ~h;
        h %= NHASH;
        c = symb[0];
        for(s = hash[h]; s != S; s = s->link) {
                if(s->name[0] != c)
                        continue;
                if(memcmp(s->name, symb, l) == 0)
                        return s;
        }
        s = alloc(sizeof(*s));
        s->name = alloc(l);
        memmove(s->name, symb, l);

        s->link = hash[h];
        hash[h] = s;
        syminit(s);
        return s;
}

long
yylex(void)
{
        int c, c1;
        char *cp;
        Sym *s;

        c = peekc;
        if(c != IGN) {
                peekc = IGN;
                goto l1;
        }
l0:
        c = GETC();

l1:
        if(c == EOF) {
                peekc = EOF;
                return -1;
        }
        if(isspace(c)) {
                if(c == '\n') {
                        lineno++;
                        return ';';
                }
                goto l0;
        }
        if(isalpha(c))
                goto talph;
        if(isdigit(c))
                goto tnum;
        switch(c)
        {
        case '\n':
                lineno++;
                return ';';

        case '#':
                domacro();
                goto l0;

        case '.':
                c = GETC();
                if(isalpha(c)) {
                        cp = symb;
                        *cp++ = '.';
                        goto aloop;
                }
                if(isdigit(c)) {
                        cp = symb;
                        *cp++ = '.';
                        goto casedot;
                }
                peekc = c;
                return '.';

        talph:
        case '_':
        case '@':
                cp = symb;

        aloop:
                *cp++ = c;
                c = GETC();
                if(isalpha(c) || isdigit(c) || c == '_' || c == '$')
                        goto aloop;
                *cp = 0;
                peekc = c;
                s = lookup();
                if(s->macro) {
                        newio();
                        cp = ionext->b;
                        macexpand(s, cp);
                        pushio();
                        ionext->link = iostack;
                        iostack = ionext;
                        fi.p = cp;
                        fi.c = strlen(cp);
                        if(peekc != IGN) {
                                cp[fi.c++] = peekc;
                                cp[fi.c] = 0;
                                peekc = IGN;
                        }
                        goto l0;
                }
                if(s->type == 0)
                        s->type = LNAME;
                if(s->type == LNAME ||
                   s->type == LVAR ||
                   s->type == LLAB) {
                        yylval.sym = s;
                        return s->type;
                }
                yylval.lval = s->value;
                return s->type;

        tnum:
                cp = symb;
                if(c != '0')
                        goto dc;
                *cp++ = c;
                c = GETC();
                c1 = 3;
                if(c == 'x' || c == 'X') {
                        c1 = 4;
                        c = GETC();
                } else
                if(c < '0' || c > '7')
                        goto dc;
                yylval.lval = 0;
                for(;;) {
                        if(c >= '0' && c <= '9') {
                                if(c > '7' && c1 == 3)
                                        break;
                                yylval.lval <<= c1;
                                yylval.lval += c - '0';
                                c = GETC();
                                continue;
                        }
                        if(c1 == 3)
                                break;
                        if(c >= 'A' && c <= 'F')
                                c += 'a' - 'A';
                        if(c >= 'a' && c <= 'f') {
                                yylval.lval <<= c1;
                                yylval.lval += c - 'a' + 10;
                                c = GETC();
                                continue;
                        }
                        break;
                }
                goto ncu;

        dc:
                for(;;) {
                        if(!isdigit(c))
                                break;
                        *cp++ = c;
                        c = GETC();
                }
                if(c == '.')
                        goto casedot;
                if(c == 'e' || c == 'E')
                        goto casee;
                *cp = 0;
                if(sizeof(yylval.lval) == sizeof(vlong))
                        yylval.lval = strtoll(symb, nil, 10);
                else
                        yylval.lval = strtol(symb, nil, 10);

        ncu:
                while(c == 'U' || c == 'u' || c == 'l' || c == 'L')
                        c = GETC();
                peekc = c;
                return LCONST;

        casedot:
                for(;;) {
                        *cp++ = c;
                        c = GETC();
                        if(!isdigit(c))
                                break;
                }
                if(c == 'e' || c == 'E')
                        goto casee;
                goto caseout;

        casee:
                *cp++ = 'e';
                c = GETC();
                if(c == '+' || c == '-') {
                        *cp++ = c;
                        c = GETC();
                }
                while(isdigit(c)) {
                        *cp++ = c;
                        c = GETC();
                }

        caseout:
                *cp = 0;
                peekc = c;
                if(FPCHIP) {
                        yylval.dval = atof(symb);
                        return LFCONST;
                }
                yyerror("assembler cannot interpret fp constants");
                yylval.lval = 1L;
                return LCONST;

        case '"':
                memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval));
                cp = yylval.sval;
                c1 = 0;
                for(;;) {
                        c = escchar('"');
                        if(c == EOF)
                                break;
                        if(c1 < sizeof(yylval.sval))
                                *cp++ = c;
                        c1++;
                }
                if(c1 > sizeof(yylval.sval))
                        yyerror("string constant too long");
                return LSCONST;

        case '\'':
                c = escchar('\'');
                if(c == EOF)
                        c = '\'';
                if(escchar('\'') != EOF)
                        yyerror("missing '");
                yylval.lval = c;
                return LCONST;

        case '/':
                c1 = GETC();
                if(c1 == '/') {
                        for(;;) {
                                c = GETC();
                                if(c == '\n')
                                        goto l1;
                                if(c == EOF) {
                                        yyerror("eof in comment");
                                        errorexit();
                                }
                        }
                }
                if(c1 == '*') {
                        for(;;) {
                                c = GETC();
                                while(c == '*') {
                                        c = GETC();
                                        if(c == '/')
                                                goto l0;
                                }
                                if(c == EOF) {
                                        yyerror("eof in comment");
                                        errorexit();
                                }
                                if(c == '\n')
                                        lineno++;
                        }
                }
                break;

        default:
                return c;
        }
        peekc = c1;
        return c;
}

int
getc(void)
{
        int c;

        c = peekc;
        if(c != IGN) {
                peekc = IGN;
                return c;
        }
        c = GETC();
        if(c == '\n')
                lineno++;
        if(c == EOF) {
                yyerror("End of file");
                errorexit();
        }
        return c;
}

int
getnsc(void)
{
        int c;

        for(;;) {
                c = getc();
                if(!isspace(c) || c == '\n')
                        return c;
        }
}

void
unget(int c)
{

        peekc = c;
        if(c == '\n')
                lineno--;
}

int
escchar(int e)
{
        int c, l;

loop:
        c = getc();
        if(c == '\n') {
                yyerror("newline in string");
                return EOF;
        }
        if(c != '\\') {
                if(c == e)
                        return EOF;
                return c;
        }
        c = getc();
        if(c >= '0' && c <= '7') {
                l = c - '0';
                c = getc();
                if(c >= '0' && c <= '7') {
                        l = l*8 + c-'0';
                        c = getc();
                        if(c >= '0' && c <= '7') {
                                l = l*8 + c-'0';
                                return l;
                        }
                }
                peekc = c;
                return l;
        }
        switch(c)
        {
        case '\n':      goto loop;
        case 'n':       return '\n';
        case 't':       return '\t';
        case 'b':       return '\b';
        case 'r':       return '\r';
        case 'f':       return '\f';
        case 'a':       return 0x07;
        case 'v':       return 0x0b;
        case 'z':       return 0x00;
        }
        return c;
}

void
pinit(char *f)
{
        int i;
        Sym *s;

        lineno = 1;
        newio();
        newfile(f, -1);
        pc = 0;
        peekc = IGN;
        sym = 1;
        for(i=0; i<NSYM; i++) {
                h[i].type = 0;
                h[i].sym = S;
        }
        for(i=0; i<NHASH; i++)
                for(s = hash[i]; s != S; s = s->link)
                        s->macro = 0;
}

int
filbuf(void)
{
        Io *i;

loop:
        i = iostack;
        if(i == I)
                return EOF;
        if(i->f < 0)
                goto pop;
        fi.c = read(i->f, i->b, BUFSIZ) - 1;
        if(fi.c < 0) {
                close(i->f);
                linehist(0, 0);
                goto pop;
        }
        fi.p = i->b + 1;
        return i->b[0];

pop:
        iostack = i->link;
        i->link = iofree;
        iofree = i;
        i = iostack;
        if(i == I)
                return EOF;
        fi.p = i->p;
        fi.c = i->c;
        if(--fi.c < 0)
                goto loop;
        return *fi.p++;
}

void
yyerror(char *a, ...)
{
        char buf[200];
        va_list arg;

        /*
         * hack to intercept message from yaccpar
         */
        if(strcmp(a, "syntax error") == 0) {
                yyerror("syntax error, last name: %s", symb);
                return;
        }
        prfile(lineno);
        va_start(arg, a);
        vseprint(buf, buf+sizeof(buf), a, arg);
        va_end(arg);
        print("%s\n", buf);
        nerrors++;
        if(nerrors > 10) {
                print("too many errors\n");
                errorexit();
        }
}

void
prfile(long l)
{
        int i, n;
        Hist a[HISTSZ], *h;
        long d;

        n = 0;
        for(h = hist; h != H; h = h->link) {
                if(l < h->line)
                        break;
                if(h->name) {
                        if(h->offset == 0) {
                                if(n >= 0 && n < HISTSZ)
                                        a[n] = *h;
                                n++;
                                continue;
                        }
                        if(n > 0 && n < HISTSZ)
                                if(a[n-1].offset == 0) {
                                        a[n] = *h;
                                        n++;
                                } else
                                        a[n-1] = *h;
                        continue;
                }
                n--;
                if(n >= 0 && n < HISTSZ) {
                        d = h->line - a[n].line;
                        for(i=0; i<n; i++)
                                a[i].line += d;
                }
        }
        if(n > HISTSZ)
                n = HISTSZ;
        for(i=0; i<n; i++)
                print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
}

void
ieeedtod(Ieee *ieee, double native)
{
        double fr, ho, f;
        int exp;

        if(native < 0) {
                ieeedtod(ieee, -native);
                ieee->h |= 0x80000000L;
                return;
        }
        if(native == 0) {
                ieee->l = 0;
                ieee->h = 0;
                return;
        }
        fr = frexp(native, &exp);
        f = 2097152L;           /* shouldnt use fp constants here */
        fr = modf(fr*f, &ho);
        ieee->h = ho;
        ieee->h &= 0xfffffL;
        ieee->h |= (exp+1022L) << 20;
        f = 65536L;
        fr = modf(fr*f, &ho);
        ieee->l = ho;
        ieee->l <<= 16;
        ieee->l |= (long)(fr*f);
}