Subversion Repositories planix.SVN

Rev

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

#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <mach.h>
#define Extern extern
#include "acid.h"

static int fsize[] =
{
        ['A'] 4,
        ['B'] 4,
        ['C'] 1,
        ['D'] 4,
        ['F'] 8,
        ['G'] 8,
        ['O'] 4,
        ['Q'] 4,
        ['R'] 4,
        ['S'] 4,
        ['U'] 4,
        ['V'] 8,
        ['W'] 8,
        ['X'] 4,
        ['Y'] 8,
        ['Z'] 8,
        ['a'] 4,
        ['b'] 1,
        ['c'] 1,
        ['d'] 2,
        ['f'] 4,
        ['g'] 4,
        ['o'] 2,
        ['q'] 2,
        ['r'] 2,
        ['s'] 4,
        ['u'] 2,
        ['x'] 2,
        ['3'] 10,
        ['8'] 10,
};

int
fmtsize(Value *v)
{
        int ret;

        switch(v->fmt) {
        default:
                return  fsize[v->fmt];
        case 'i':
        case 'I':
                if(v->type != TINT || machdata == 0)
                        error("no size for i fmt pointer ++/--");
                ret = (*machdata->instsize)(cormap, v->ival);
                if(ret < 0) {
                        ret = (*machdata->instsize)(symmap, v->ival);
                        if(ret < 0)
                                error("%r");
                }
                return ret;
        }
}

void
chklval(Node *lp)
{
        if(lp->op != ONAME)
                error("need l-value");
}

void
olist(Node *n, Node *res)
{
        expr(n->left, res);
        expr(n->right, res);
}

void
oeval(Node *n, Node *res)
{
        expr(n->left, res);
        if(res->type != TCODE)
                error("bad type for eval");
        expr(res->cc, res);
}

void
ocast(Node *n, Node *res)
{
        if(n->sym->lt == 0)
                error("%s is not a complex type", n->sym->name);

        expr(n->left, res);
        res->comt = n->sym->lt;
        res->fmt = 'a';
}

void
oindm(Node *n, Node *res)
{
        Map *m;
        Node l;

        m = cormap;
        if(m == 0)
                m = symmap;
        expr(n->left, &l);
        if(l.type != TINT)
                error("bad type for *");
        if(m == 0)
                error("no map for *");
        indir(m, l.ival, l.fmt, res);
        res->comt = l.comt;
}

void
oindc(Node *n, Node *res)
{
        Map *m;
        Node l;

        m = symmap;
        if(m == 0)
                m = cormap;
        expr(n->left, &l);
        if(l.type != TINT)
                error("bad type for @");
        if(m == 0)
                error("no map for @");
        indir(m, l.ival, l.fmt, res);
        res->comt = l.comt;
}

void
oframe(Node *n, Node *res)
{
        char *p;
        Node *lp;
        uvlong ival;
        Frtype *f;

        p = n->sym->name;
        while(*p && *p == '$')
                p++;
        lp = n->left;
        if(localaddr(cormap, p, lp->sym->name, &ival, rget) < 0)
                error("colon: %r");

        res->ival = ival;
        res->op = OCONST;
        res->fmt = 'X';
        res->type = TINT;

        /* Try and set comt */
        for(f = n->sym->local; f; f = f->next) {
                if(f->var == lp->sym) {
                        res->comt = f->type;
                        res->fmt = 'a';
                        break;
                }
        }
}

void
oindex(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);

        if(r.type != TINT)
                error("bad type for []");

        switch(l.type) {
        default:
                error("lhs[] has bad type");
        case TINT:
                indir(cormap, l.ival+(r.ival*fsize[l.fmt]), l.fmt, res);
                res->comt = l.comt;
                res->fmt = l.fmt;
                break;
        case TLIST:
                nthelem(l.l, r.ival, res);
                break;
        case TSTRING:
                res->ival = 0;
                if(r.ival >= 0 && r.ival < l.string->len) {
                        int xx8;        /* to get around bug in vc */
                        xx8 = r.ival;
                        res->ival = l.string->string[xx8];
                }
                res->op = OCONST;
                res->type = TINT;
                res->fmt = 'c';
                break;
        }
}

void
oappend(Node *n, Node *res)
{
        Value *v;
        Node r, l;
        int  empty;

        expr(n->left, &l);
        expr(n->right, &r);
        if(l.type != TLIST)
                error("must append to list");
        empty = (l.l == nil && (n->left->op == ONAME));
        append(res, &l, &r);
        if(empty) {
                v = n->left->sym->v;
                v->type = res->type;
                v->Store = res->Store;
                v->comt = res->comt;
        }
}

void
odelete(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        if(l.type != TLIST)
                error("must delete from list");
        if(r.type != TINT)
                error("delete index must be integer");

        delete(l.l, r.ival, res);
}

void
ohead(Node *n, Node *res)
{
        Node l;

        expr(n->left, &l);
        if(l.type != TLIST)
                error("head needs list");
        res->op = OCONST;
        if(l.l) {
                res->type = l.l->type;
                res->Store = l.l->Store;
        }
        else {
                res->type = TLIST;
                res->l = 0;
        }
}

void
otail(Node *n, Node *res)
{
        Node l;

        expr(n->left, &l);
        if(l.type != TLIST)
                error("tail needs list");
        res->op = OCONST;
        res->type = TLIST;
        if(l.l)
                res->l = l.l->next;
        else
                res->l = 0;
}

void
oconst(Node *n, Node *res)
{
        res->op = OCONST;
        res->type = n->type;
        res->Store = n->Store;
        res->comt = n->comt;
}

void
oname(Node *n, Node *res)
{
        Value *v;

        v = n->sym->v;
        if(v->set == 0)
                error("%s used but not set", n->sym->name);
        res->op = OCONST;
        res->type = v->type;
        res->Store = v->Store;
        res->comt = v->comt;
}

void
octruct(Node *n, Node *res)
{
        res->op = OCONST;
        res->type = TLIST;
        res->l = construct(n->left);
}

void
oasgn(Node *n, Node *res)
{
        Node *lp, r;
        Value *v;

        lp = n->left;
        switch(lp->op) {
        case OINDM:
                windir(cormap, lp->left, n->right, res);
                break;
        case OINDC:
                windir(symmap, lp->left, n->right, res);
                break;
        default:
                chklval(lp);
                v = lp->sym->v;
                expr(n->right, &r);
                v->set = 1;
                v->type = r.type;
                v->Store = r.Store;
                res->op = OCONST;
                res->type = v->type;
                res->Store = v->Store;
                res->comt = v->comt;
        }
}

void
oadd(Node *n, Node *res)
{
        Node l, r;

        if(n->right == nil){            /* unary + */
                expr(n->left, res);
                return;
        }
        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = l.fmt;
        res->op = OCONST;
        res->type = TFLOAT;
        switch(l.type) {
        default:
                error("bad lhs type +");
        case TINT:
                switch(r.type) {
                case TINT:
                        res->type = TINT;
                        res->ival = l.ival+r.ival;
                        break;
                case TFLOAT:
                        res->fval = l.ival+r.fval;
                        break;
                default:
                        error("bad rhs type +");
                }
                break;
        case TFLOAT:
                switch(r.type) {
                case TINT:
                        res->fval = l.fval+r.ival;
                        break;
                case TFLOAT:
                        res->fval = l.fval+r.fval;
                        break;
                default:
                        error("bad rhs type +");
                }
                break;
        case TSTRING:
                if(r.type == TSTRING) {
                        res->type = TSTRING;
                        res->fmt = 's';
                        res->string = stradd(l.string, r.string); 
                        break;
                }
                if(r.type == TINT) {
                        res->type = TSTRING;
                        res->fmt = 's';
                        res->string = straddrune(l.string, r.ival);
                        break;
                }
                error("bad rhs for +");
        case TLIST:
                res->type = TLIST;
                switch(r.type) {
                case TLIST:
                        res->l = addlist(l.l, r.l);
                        break;
                default:
                        r.left = 0;
                        r.right = 0;
                        res->l = addlist(l.l, construct(&r));
                        break;
                }
        }
}

void
osub(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = l.fmt;
        res->op = OCONST;
        res->type = TFLOAT;
        switch(l.type) {
        default:
                error("bad lhs type -");
        case TINT:
                switch(r.type) {
                case TINT:
                        res->type = TINT;
                        res->ival = l.ival-r.ival;
                        break;
                case TFLOAT:
                        res->fval = l.ival-r.fval;
                        break;
                default:
                        error("bad rhs type -");
                }
                break;
        case TFLOAT:
                switch(r.type) {
                case TINT:
                        res->fval = l.fval-r.ival;
                        break;
                case TFLOAT:
                        res->fval = l.fval-r.fval;
                        break;
                default:
                        error("bad rhs type -");
                }
                break;
        }
}

void
omul(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = l.fmt;
        res->op = OCONST;
        res->type = TFLOAT;
        switch(l.type) {
        default:
                error("bad lhs type *");
        case TINT:
                switch(r.type) {
                case TINT:
                        res->type = TINT;
                        res->ival = l.ival*r.ival;
                        break;
                case TFLOAT:
                        res->fval = l.ival*r.fval;
                        break;
                default:
                        error("bad rhs type *");
                }
                break;
        case TFLOAT:
                switch(r.type) {
                case TINT:
                        res->fval = l.fval*r.ival;
                        break;
                case TFLOAT:
                        res->fval = l.fval*r.fval;
                        break;
                default:
                        error("bad rhs type *");
                }
                break;
        }
}

void
odiv(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = l.fmt;
        res->op = OCONST;
        res->type = TFLOAT;
        switch(l.type) {
        default:
                error("bad lhs type /");
        case TINT:
                switch(r.type) {
                case TINT:
                        res->type = TINT;
                        if(r.ival == 0)
                                error("zero divide");
                        res->ival = l.ival/r.ival;
                        break;
                case TFLOAT:
                        if(r.fval == 0)
                                error("zero divide");
                        res->fval = l.ival/r.fval;
                        break;
                default:
                        error("bad rhs type /");
                }
                break;
        case TFLOAT:
                switch(r.type) {
                case TINT:
                        res->fval = l.fval/r.ival;
                        break;
                case TFLOAT:
                        res->fval = l.fval/r.fval;
                        break;
                default:
                        error("bad rhs type /");
                }
                break;
        }
}

void
omod(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = l.fmt;
        res->op = OCONST;
        res->type = TINT;
        if(l.type != TINT || r.type != TINT)
                error("bad expr type %");
        res->ival = l.ival%r.ival;
}

void
olsh(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = l.fmt;
        res->op = OCONST;
        res->type = TINT;
        if(l.type != TINT || r.type != TINT)
                error("bad expr type <<");
        res->ival = l.ival<<r.ival;
}

void
orsh(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = l.fmt;
        res->op = OCONST;
        res->type = TINT;
        if(l.type != TINT || r.type != TINT)
                error("bad expr type >>");
        res->ival = (uvlong)l.ival>>r.ival;
}

void
olt(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);

        res->fmt = l.fmt;
        res->op = OCONST;
        res->type = TINT;
        switch(l.type) {
        default:
                error("bad lhs type <");
        case TINT:
                switch(r.type) {
                case TINT:
                        res->ival = l.ival < r.ival;
                        break;
                case TFLOAT:
                        res->ival = l.ival < r.fval;
                        break;
                default:
                        error("bad rhs type <");
                }
                break;
        case TFLOAT:
                switch(r.type) {
                case TINT:
                        res->ival = l.fval < r.ival;
                        break;
                case TFLOAT:
                        res->ival = l.fval < r.fval;
                        break;
                default:
                        error("bad rhs type <");
                }
                break;
        }
}

void
ogt(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = 'D';
        res->op = OCONST;
        res->type = TINT;
        switch(l.type) {
        default:
                error("bad lhs type >");
        case TINT:
                switch(r.type) {
                case TINT:
                        res->ival = l.ival > r.ival;
                        break;
                case TFLOAT:
                        res->ival = l.ival > r.fval;
                        break;
                default:
                        error("bad rhs type >");
                }
                break;
        case TFLOAT:
                switch(r.type) {
                case TINT:
                        res->ival = l.fval > r.ival;
                        break;
                case TFLOAT:
                        res->ival = l.fval > r.fval;
                        break;
                default:
                        error("bad rhs type >");
                }
                break;
        }
}

void
oleq(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = 'D';
        res->op = OCONST;
        res->type = TINT;
        switch(l.type) {
        default:
                error("bad expr type <=");
        case TINT:
                switch(r.type) {
                case TINT:
                        res->ival = l.ival <= r.ival;
                        break;
                case TFLOAT:
                        res->ival = l.ival <= r.fval;
                        break;
                default:
                        error("bad expr type <=");
                }
                break;
        case TFLOAT:
                switch(r.type) {
                case TINT:
                        res->ival = l.fval <= r.ival;
                        break;
                case TFLOAT:
                        res->ival = l.fval <= r.fval;
                        break;
                default:
                        error("bad expr type <=");
                }
                break;
        }
}

void
ogeq(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = 'D';
        res->op = OCONST;
        res->type = TINT;
        switch(l.type) {
        default:
                error("bad lhs type >=");
        case TINT:
                switch(r.type) {
                case TINT:
                        res->ival = l.ival >= r.ival;
                        break;
                case TFLOAT:
                        res->ival = l.ival >= r.fval;
                        break;
                default:
                        error("bad rhs type >=");
                }
                break;
        case TFLOAT:
                switch(r.type) {
                case TINT:
                        res->ival = l.fval >= r.ival;
                        break;
                case TFLOAT:
                        res->ival = l.fval >= r.fval;
                        break;
                default:
                        error("bad rhs type >=");
                }
                break;
        }
}

void
oeq(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = 'D';
        res->op = OCONST;
        res->type = TINT;
        res->ival = 0;
        switch(l.type) {
        default:
                break;
        case TINT:
                switch(r.type) {
                case TINT:
                        res->ival = l.ival == r.ival;
                        break;
                case TFLOAT:
                        res->ival = l.ival == r.fval;
                        break;
                default:
                        break;
                }
                break;
        case TFLOAT:
                switch(r.type) {
                case TINT:
                        res->ival = l.fval == r.ival;
                        break;
                case TFLOAT:
                        res->ival = l.fval == r.fval;
                        break;
                default:
                        break;
                }
                break;
        case TSTRING:
                if(r.type == TSTRING) {
                        res->ival = scmp(r.string, l.string);
                        break;
                }
                break;
        case TLIST:
                if(r.type == TLIST) {
                        res->ival = listcmp(l.l, r.l);
                        break;
                }
                break;
        }
        if(n->op == ONEQ)
                res->ival = !res->ival;
}


void
oland(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = l.fmt;
        res->op = OCONST;
        res->type = TINT;
        if(l.type != TINT || r.type != TINT)
                error("bad expr type &");
        res->ival = l.ival&r.ival;
}

void
oxor(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = l.fmt;
        res->op = OCONST;
        res->type = TINT;
        if(l.type != TINT || r.type != TINT)
                error("bad expr type ^");
        res->ival = l.ival^r.ival;
}

void
olor(Node *n, Node *res)
{
        Node l, r;

        expr(n->left, &l);
        expr(n->right, &r);
        res->fmt = l.fmt;
        res->op = OCONST;
        res->type = TINT;
        if(l.type != TINT || r.type != TINT)
                error("bad expr type |");
        res->ival = l.ival|r.ival;
}

void
ocand(Node *n, Node *res)
{
        Node l, r;

        res->op = OCONST;
        res->type = TINT;
        res->ival = 0;
        res->fmt = 'D';
        expr(n->left, &l);
        if(bool(&l) == 0)
                return;
        expr(n->right, &r);
        if(bool(&r) == 0)
                return;
        res->ival = 1;
}

void
onot(Node *n, Node *res)
{
        Node l;

        res->op = OCONST;
        res->type = TINT;
        res->ival = 0;
        expr(n->left, &l);
        res->fmt = l.fmt;
        if(bool(&l) == 0)
                res->ival = 1;
}

void
ocor(Node *n, Node *res)
{
        Node l, r;

        res->op = OCONST;
        res->type = TINT;
        res->ival = 0;
        res->fmt = 'D';
        expr(n->left, &l);
        if(bool(&l)) {
                res->ival = 1;
                return;
        }
        expr(n->right, &r);
        if(bool(&r)) {
                res->ival = 1;
                return;
        }
}

void
oeinc(Node *n, Node *res)
{
        Value *v;

        chklval(n->left);
        v = n->left->sym->v;
        res->op = OCONST;
        res->type = v->type;
        switch(v->type) {
        case TINT:
                if(n->op == OEDEC)
                        v->ival -= fmtsize(v);
                else
                        v->ival += fmtsize(v);
                break;                  
        case TFLOAT:
                if(n->op == OEDEC)
                        v->fval--;
                else
                        v->fval++;
                break;
        default:
                error("bad type for pre --/++");
        }
        res->Store = v->Store;
}

void
opinc(Node *n, Node *res)
{
        Value *v;

        chklval(n->left);
        v = n->left->sym->v;
        res->op = OCONST;
        res->type = v->type;
        res->Store = v->Store;
        switch(v->type) {
        case TINT:
                if(n->op == OPDEC)
                        v->ival -= fmtsize(v);
                else
                        v->ival += fmtsize(v);
                break;                  
        case TFLOAT:
                if(n->op == OPDEC)
                        v->fval--;
                else
                        v->fval++;
                break;
        default:
                error("bad type for post --/++");
        }
}

void
ocall(Node *n, Node *res)
{
        Lsym *s;
        Rplace *rsav;

        res->op = OCONST;               /* Default return value */
        res->type = TLIST;
        res->l = 0;

        chklval(n->left);
        s = n->left->sym;

        if(n->builtin && !s->builtin){
                error("no builtin %s", s->name);
                return;
        }
        if(s->builtin && (n->builtin || s->proc == 0)) {
                (*s->builtin)(res, n->right);
                return;
        }
        if(s->proc == 0)
                error("no function %s", s->name);

        rsav = ret;
        call(s->name, n->right, s->proc->left, s->proc->right, res);
        ret = rsav;
}

void
ofmt(Node *n, Node *res)
{
        expr(n->left, res);
        res->fmt = n->right->ival;
}

void
owhat(Node *n, Node *res)
{
        res->op = OCONST;               /* Default return value */
        res->type = TLIST;
        res->l = 0;
        whatis(n->sym);
}

void (*expop[])(Node*, Node*) =
{
        [ONAME]         oname,
        [OCONST]        oconst,
        [OMUL]          omul,
        [ODIV]          odiv,
        [OMOD]          omod,
        [OADD]          oadd,
        [OSUB]          osub,
        [ORSH]          orsh,
        [OLSH]          olsh,
        [OLT]           olt,
        [OGT]           ogt,
        [OLEQ]          oleq,
        [OGEQ]          ogeq,
        [OEQ]           oeq,
        [ONEQ]          oeq,
        [OLAND]         oland,
        [OXOR]          oxor,
        [OLOR]          olor,
        [OCAND]         ocand,
        [OCOR]          ocor,
        [OASGN]         oasgn,
        [OINDM]         oindm,
        [OEDEC]         oeinc,
        [OEINC]         oeinc,
        [OPINC]         opinc,
        [OPDEC]         opinc,
        [ONOT]          onot,
        [OIF]           0,
        [ODO]           0,
        [OLIST]         olist,
        [OCALL]         ocall,
        [OCTRUCT]       octruct,
        [OWHILE]        0,
        [OELSE]         0,
        [OHEAD]         ohead,
        [OTAIL]         otail,
        [OAPPEND]       oappend,
        [ORET]          0,
        [OINDEX]        oindex,
        [OINDC]         oindc,
        [ODOT]          odot,
        [OLOCAL]        0,
        [OFRAME]        oframe,
        [OCOMPLEX]      0,
        [ODELETE]       odelete,
        [OCAST]         ocast,
        [OFMT]          ofmt,
        [OEVAL]         oeval,
        [OWHAT]         owhat,
};