diff --git a/asm.c b/asm.c new file mode 100644 index 0000000..5c07cac --- /dev/null +++ b/asm.c @@ -0,0 +1,50 @@ +#include "yo.h" + +char* instname[] = { + [INOP] = "nop", + [IADDW] = "addw", + [ISUBW] = "subw", + [IMULW] = "mulw", + [IRET] = "ret", + [IMOVW] = "movw", + [IMOVM] = "movm", + [ILEA] = "lea", + [ICALL] = "call", + [IJMP] = "jmp", + [PCALL] = "pcall", + [IFRAME] = "frame", + [IARRAY] = "array", + [ISLICE] = "slice", + [ILEN] = "len", + [IBEQW] = "beqw", + [IBNEQW] = "bneqw", + [ILTW] = "lt", + [ILEQW] = "leq", + [IEQW] = "eq", +}; + +void +asminst(FILE *f, Inst *in) +{ + for(; in; in=in->next) + instconv(f, in); +} + +void +asmexport(FILE *f, Sym *pkg, Decl **arr, int n) +{ + fprintf(f, "\tpackage\t"); + fprintf(f, "%s\n", pkg->name); + fprintf(f, "\texported %d\n", n); + for(int i = 0; i < n; ++i){ + Decl *d = arr[i]; + switch(d->store){ + default: + break; + // case Dfn: + // fprintf(f, "\tlink\t%u,%u,\"",d->desc->id, d->pc->pc); + // fprintf(f, "%s\"\n", d->sym->name); + // break; + } + } +} \ No newline at end of file diff --git a/assert.c b/assert.c new file mode 100644 index 0000000..780164c --- /dev/null +++ b/assert.c @@ -0,0 +1,465 @@ +#include "yo.h" + +void assertexpr(Node *n); + +Decl *fndecls; +Node **labstk; +int loopdep; +int maxloopdep; + +static void +pushloop(void) +{ + if(loopdep >= maxloopdep) + maxloopdep += MaxScope; + loopdep += 1; +} + +static Type* +typeofslice(Type *t) +{ + Type *p = t; + while(p && p->kind == Tslice) + p = p->tof; + assert(p && p->kind == Tarray); + return p; +} + +void +elemfields(Node *n) +{ + Decl *d = nil; + Type *t = n->ty; + Node *e = nil; + + switch(t->kind){ + case Tstruct: + d = t->ids; + for(e = n->l; e != nil; e = e->r){ + e->l->ty = d->ty; + assertexpr(e->l); + d = d->next; + } + break; + case Tarray: + for(e = n->l; e != nil; e = e->r){ + e->l->ty = t->tof; + assertexpr(e->l); + } + break; + default: + assert(0); + } +} + +Decl* +tupfields(Node *n) +{ + Decl *h = nil; + Decl *d = h; + Decl **last = &h; + for(; n; n=n->r){ + d = mkdecl(Dfield, n->l->ty); + *last = d; + last = &d->next; + } + return h; +} + +void +dasinfer(Node *n, Type *t) +{ + switch(n->op){ + case Otup: + n->ty = t; + n = n->l; + Decl *p = t->ids; + for(; p&&n; p=p->next){ + if(p->store != Dfield) + continue; + dasinfer(n->l, p->ty); + n = n->r; + } + for(;p; p=p->next){ + if(p->store == Dfield) + break; + } + assert(n==nil && p==nil); + return; + case Oname: + n->decl->ty = t; + n->ty = t; + sharelocal(n->decl); + return; + default: + assert(0); + } +} + +void +assertexpr(Node *n) +{ + if(n == nil) + return; + if(n->op == Oseq){ + for(; n && n->op==Oseq; n=n->r){ + assertexpr(n->l); + n->ty = tnone; + } + if(n == nil) + return; + } + + Type *t = nil; + Decl *d = nil; + Node * l = n->l, *r = n->r; + if(n->op != Odas) + assertexpr(l); + if(n->op != Ocall &&n->op != Odas && n->op != Odot && n->op != Oindex && n->op != Oindex) + assertexpr(r); + switch(n->op){ + case Opkg: break; + case Oseq: n->ty = tnone; break; + case Ostruct: + case Oarray: + n->ty = isvalidty(n->ty); + break; + case Oeq: case Oneq: case Olt: + case Oleq: case Ogt: case Ogeq: + n->ty = tbool; + break; + case Oconst: + assert(n->ty != nil); + break; + case Omul: case Oadd: case Osub: + /* TODO : match type or can addable */ + assertexpr(l); + assertexpr(r); + assert(eqtype(l->ty, r->ty)); + n->ty = l->ty; + break; + case Olen: + l->ty = isvalidty(l->ty); + assert(l->ty->kind==Tarray||l->ty->kind==Tslice); + n->ty = tint; + break; + case Oas: + if(r->op == Oname) + assert(r->decl->store != Dtype); + assert(eqtype(l->ty, r->ty)); + n->ty = l->ty = r->ty; + break; + case Odas: + assertexpr(r); + dasdecl(l); + dasinfer(l, r->ty); + assert(eqtype(l->ty, r->ty)); + n->ty = l->ty = r->ty; + usetype(n->ty); + if(r->op == Oname) + assert(r->decl->store != Dtype); + break; + case Oxref: + t = l->ty; + assert(t->kind == Tptr); + n->ty = usetype(t->tof); + break; + case Oref: + t = l->ty; + assert(l->op == Oname); + n->ty = usetype(mktype(Tref, IBY2WD, t, nil)); + break; + case Odot: + t = l->ty; + switch(t->kind){ + case Tpkg: + assert(r->op == Oname); + d = isinpkg(t->ids, r->decl->sym); + assert(d != nil); + r->decl = d; + r->ty = n->ty = d->ty; + break; + case Tstruct: + d = isinids(t->ids, r->decl->sym); + assert(d != nil); + d->ty = usetype(isvalidty(d->ty)); + r->decl = d; + n->ty = d->ty; + break; + default: + assert(0); + } + break; + case Oname: + assert((d = n->decl) != nil); + if(d->store == Dunbound){ + Sym *s = d->sym; + assert((d = s->decl) != nil); + s->unbound = nil; + n->decl = d; + } + assert(n->ty = d->ty = usetype(d->ty)); + switch(d->store){ + case Darg: case Dfn: case Dlocal: case Dfield: + case Dtype: case Dglobal: case Dpkg: + break; + default: + assert(0); + } + break; + case Oslice: + t = usetype(l->ty); + if(t->kind == Tslice) + t = typeofslice(t); + assert(t->kind == Tarray); + n->ty = mktype(Tslice, ArrHead, t, nil); + break; + case Oindex: + t = l->ty; + if(t->kind == Tslice) + t = t->tof; + assert(t->kind == Tarray || t->kind == Tslice); + assertexpr(r); + if(r->op == Oconst) + assert(r->val < t->len); + n->ty = t->tof; + break; + case Otup: + d = tupfields(l); + n->ty = usetype(mktype(Ttup, 0, nil, d)); + break; + case Ocall: + assertexpr(r); + t = l->ty; + if(l->op==Opkg) + return; + usetype(t); + n->ty = t->tof; + break; + default: + assert(0); + } +} + +void +assertvar(Node *n) +{ + Type *t = isvalidty(n->ty); + Decl *last = n->l->decl; + for(Decl *d = n->decl; d != last->next; d=d->next){ + assert(d->store != Dtype); + d->ty = t; + } +} + +Node* +assertstmt(Type *ret, Node *n) +{ + Decl *d = nil; + Node *top = n, *last = nil, *l = nil, *r=nil; + + for(; n; n=n->r){ + l = n->l; + r = n->r; + switch(n->op){ + case Oseq: + n->l = assertstmt(ret, l); + break; + case Ovardecl: + vardecled(n); + assertvar(n); + return top; + case Oret: + assertexpr(l); + if(l == nil) + assert(ret == tnone); + else if(ret == tnone) + assert(l->ty == tnone); + else + assert(eqtype(ret, l->ty)); + return top; + case Oif: + n->l = l = assertstmt(ret, l); + assert(l->ty == tbool); + r->l = assertstmt(ret, r->l); + n = r; + break; + case Ofor: + assertexpr(l); + assert(l->ty == tbool); + pushloop(); + r->r = assertstmt(ret, r->r); + r->l = assertstmt(ret, r->l); + loopdep -= 1; + return top; + case Oscope: + pushscope(n, Sother); + assertstmt(ret, n->l); + n->r = assertstmt(ret, n->r); + d = popscope(); + fndecls = concatdecl(fndecls,d); + return top; + default: + assertexpr(n); + if(last == nil) + return n; + last->r = n; + return top; + } + last = n; + } + return top; +} + +Decl* +assertfndecl(Node* n) +{ + Decl *d = n->l->decl; + d->store = Dfn; + d->init = n; + Type *t = n->ty; + t = isvalidty(t); + n->ty = d->ty = t = usetype(t); + d->offset = idoffsets(t->ids, 56, IBY2WD); + d->locals = nil; + n->decl = d; + return d; +} + +void +assertfn(Decl *d) +{ + Node *n = d->init; + fndecls = nil; + repushids(d->ty->ids); + n->r = assertstmt(n->ty->tof, n->r); + d->locals = concatdecl(popids(d->ty->ids), fndecls); + fndecls = nil; +} + +void +gdecl(Node *n) +{ + for(;;n=n->r){ + if(n==nil) + return; + if(n->op != Oseq) + break; + gdecl(n->l); + } + switch(n->op){ + case Oexport: + gdecl(n->l); + nexport += 1; + break; + case Ovardecl: + vardecled(n); + nvar += 1; + break; + case Ostrdecl: + structdecled(n); + ntype += 1; + break; + case Ofn: + fndecled(n); + nfn += 1; + break; + default: + assert(0); + } +} + +void +varassert(Node *n) +{ + Type *t = isvalidty(n->ty); + Decl *last = n->l->decl; + for(Decl *ids = n->decl; ids != last->next; ids=ids->next){ + ids->ty = t; + } +} + +void +gassert(Node *n) +{ + for(; ; n=n->r){ + if(n==nil) + return; + if(n->op != Oseq) + break; + gassert(n->l); + } + switch(n->op){ + case Oexport: + gassert(n->l); + break; + case Ostrdecl: + repushids(n->ty->ids); + gassert(n->l); + assert(popids(n->ty->ids) == nil); + break; + case Ofn: + assertexpr(n->l); + assertfndecl(n); + break; + case Ovardecl: + varassert(n); + bindsize(n->ty); + break; + case Ofielddecl: + bindsize(n->ty); + break; + default: + assert(0); + } + return; +} + +void +gentry(Node *tree) +{ + static int ivar = 0; + static int ifn = 0; + static int iexport = 0; + static int itype = 0; + + for(; tree; tree=tree->r){ + assert(tree->op == Oseq); + Node *n = tree->l; + Decl *d = nil; + int exp = 0; +redo: + switch(n->op){ + case Oexport: + n = n->l; + exp = 1; + goto redo; + break; + case Ostrdecl: + types[itype++]=d=n->ty->decl; + break; + case Ofn: + fns[ifn++]=d=n->decl; + break; + case Ovardecl: + vars[ivar++]=d=n->decl; + break; + default: + break; + } + if(exp) + exports[iexport++] = d; + } +} + +Sym* +assertpkgdecl(Node **trees, int n) +{ + Sym *s = trees[0]->l->decl->sym; + for(int i = 1; i < n; ++i){ + Sym *ss = trees[i]->l->decl->sym; + assert(s->len == ss->len); + assert(memcmp(s->name, ss->name, s->len)==0); + } + return s; +} \ No newline at end of file diff --git a/com.c b/com.c new file mode 100644 index 0000000..0557a2a --- /dev/null +++ b/com.c @@ -0,0 +1,767 @@ +#include "yo.h" + +static Node* ecom(Node *nto, Node *n); + +static Inst **breaks; +static Inst **conts; +static Node **bcsps; +static int scp; +static Node *scps[MaxScope]; + +static void +pushscp(Node *n) +{ + assert(scp < MaxScope); + scps[scp++] = n; +} + +static void +popscp(void) +{ + scp -= 1; +} + +static Node* +curscp(void) +{ + if(scp == 0) return nil; + else return scps[scp-1]; +} + +static Node* +sumark(Node *n) +{ + if(n == nil) + return nil; + Node *l = n->l; + Node *r = n->r; + n->temps = 0; + n->addable = Rcant; + if(l){ + sumark(l); + n->temps = l->temps; + } + if(r){ + sumark(r); + if(r->temps == n->temps) n->temps++; + else if(r->temps > n->temps) n->temps = r->temps; + } + switch(n->op){ + case Oindex: + n->addable = Radr; + break; + case Oxref: + switch(l->addable){ + case Rreg: n->addable = Radr; break; + case Rareg: n->addable = Rreg; break; + case Raadr: n->addable = Radr; break; + default: break; + } + break; + case Oadr: + switch(l->addable){ + case Rreg: n->addable = Rareg; break; + case Radr: n->addable = Raadr; break; + default: break; + } + break; + case Oname: + switch(n->decl->store){ + case Dtype: break; + case Darg: + case Dlocal: n->addable = Rreg; break; + case Dpkg: + case Dfn: n->addable = Rpc; break; + case Dglobal: n->addable = Rreg; break; + default: + assert(0); + } + break; + case Oconst: + switch(n->ty->kind){ + case Tbool: + case Tint: n->addable = Rconst; break; + default: assert(0); + } + break; + case Omul: + case Oadd: + case Osub: + if(r->addable == Rconst){ + switch(l->addable){ + case Rcant: + case Rconst: break; + case Rareg: n->addable = Rareg; break; + case Rreg: + case Raadr: n->addable = Raadr; break; + case Radr: n->addable = Rreg; break; + default: assert(0); + } + } + break; + default: + break; + } + if(n->addable < Rcant) n->temps = 0; + else if(n->temps == 0) n->temps = 1; + return n; +} + +static void +arrcom(Node *nto, Node *n) +{ + Node sz = {.op=Oconst,.val=0,.addable=Rconst,.ty=tint}; + Node toff = {0}, tadd={0}, tadr={0}, fake={0}, *e=nil; + toff.op = Oconst; + toff.ty = tint; + tadr.op = Oadr; + tadr.l = nto; + tadr.ty = tint; + tadd.op = Oadd; + tadd.l = &tadr; + tadd.r = &toff; + tadd.ty = tint; + fake.op = Oxref; + fake.l = &tadd; + sumark(&fake); + assert(fake.addable < Rcant); + + fake.ty = n->ty->tof; + genmove(nto->ty, nto, nto); + toff.val += IBY2WD; sz.val = nto->ty->len; + genmove(tint, &sz, &fake); + toff.val += IBY2WD; sz.val = nto->ty->len; + genmove(tint, &sz, &fake); + toff.val += IBY2WD; sz.val = nto->ty->tof->size; + genmove(tint, &sz, &fake); + for(e = n->l; e != nil; e = e->r){ + toff.val += nto->ty->tof->size; + ecom(&fake, e->l); + } +} + +static int +tupblk0(Node *n, Decl **dd) +{ + Decl *d = nil; + switch(n->op){ + case Otup: + for(n = n->l; n; n=n->r) + if(tupblk0(n->l, dd) == 0) + return 0; + return 1; + case Oname: + if(n->decl == nil) + return 0; + d = *dd; + if(d && d->next != n->decl) + return 0; + int nid = n->decl->nid; + if(d == nil && nid == 1) + return 0; + if(d != nil && nid != 0) + return 0; + *dd = n->decl; + return 1; + } + return 0; +} + +static Node* +tupblk(Node *n) +{ + if(n->op != Otup) + return nil; + Decl *d = nil; + if(tupblk0(n, &d) == 0) + return nil; + while(n->op == Otup) + n = n->l->l; + assert(n->op == Oname); + return n; +} + +static void +tuplcom(Node *n, Node *nto) +{ + Decl *d = nil; + Node toff = {0}, tadd={0}, tadr={0}, fake={0}, tas={0}, *e=nil, *as; + toff.op = Oconst; + toff.ty = tint; + tadr.op = Oadr; + tadr.l = n; + tadr.ty = tint; + tadd.op = Oadd; + tadd.l = &tadr; + tadd.r = &toff; + tadd.ty = tint; + fake.op = Oxref; + fake.l = &tadd; + sumark(&fake); + assert(fake.addable < Rcant); + d = nto->ty->ids; + for(e = nto->l; e != nil; e = e->r){ + as = e->l; + if(as->op != Oname || as->decl != nildecl){ + toff.val = d->offset; + fake.ty = d->ty; + if(as->addable < Rcant) + genmove(d->ty, &fake, as); + else{ + tas.op = Oas; + tas.ty = d->ty; + tas.l = as; + tas.r = &fake; + tas.addable = Rcant; + ecom(nil, &tas); + } + } + d = d->next; + } +} + +static void +tuplrcom(Node *n, Node *nto) +{ + Decl *de = nto->ty->ids; + Node *s = nil, *d = nil, tas ={0}; + for(s=n->l, d=nto->l; s!=nil&&d!=nil; s=s->r, d=d->r){ + if(d->l->op != Oname || d->l->decl != nil){ + tas.op = Oas; + tas.ty = de->ty; + tas.l = d->l; + tas.r = s->l; + sumark(&tas); + ecom(nil, &tas); + } + de = de->next; + } + assert(s == nil &&d == nil); +} + +static void +tupcom(Node *nto, Node *n) +{ + Decl *d = nil; + Node toff = {0}, tadd={0}, tadr={0}, fake={0}, *e=nil; + toff.op = Oconst; + toff.ty = tint; + tadr.op = Oadr; + tadr.l = nto; + tadr.ty = tint; + tadd.op = Oadd; + tadd.l = &tadr; + tadd.r = &toff; + tadd.ty = tint; + fake.op = Oxref; + fake.l = &tadd; + sumark(&fake); + assert(fake.addable < Rcant); + d = n->ty->ids; + for(e = n->l; e != nil; e = e->r){ + toff.val = d->offset; + fake.ty = d->ty; + ecom(&fake, e->l); + d = d->next; + } +} + +static Node* +eacom(Node *n, Node *reg, Node *t) +{ + Node *l = n->l; + if(n->op != Oxref){ + Node *tmp = talloc(reg, n->ty, t); + ecom(tmp, n); + return reg; + } + if(l->op==Oadd && l->r->op == Oconst){ + if(l->l->op == Oadr){ + l->l->l = eacom(l->l->l, reg, t); + sumark(n); + assert(n->addable < Rcant); + return n; + }else + assert(0); + }else if(l->op == Oadr){ + assert(0); + }else{ + talloc(reg, l->ty, t); + ecom(reg, l); + n->l = reg; + n->addable = Radr; + } + return n; +} + +static void +assertcall(Decl *i, Node *j) +{ + assert((i==nil) == (j==nil)); + for(; i && j && j->op==Oseq; i=i->next, j=j->r){ + assert(eqtype(i->ty, j->l->ty)); + } + assert((j==nil) == (i==nil)); +} + +static void +callcom(int op, Node *n, Node *ret) +{ + Node *args = n->r, *fn = n->l; + Node tadd = {0}, pass={0}, toff={0}, frame={0}; + assertcall(fn->ty->ids, args); + talloc(&frame, tint, nil); + toff.op = Oconst; + toff.addable = Rconst; + toff.ty = tint; + tadd.op = Oadd; + tadd.addable = Raadr; + tadd.l = &frame; + tadd.r = &toff; + tadd.ty = tint; + pass.op = Oxref; + pass.ty = tint; + pass.op = Oxref; + pass.addable = Radr; + pass.l = &tadd; + + Inst *in = genrawop(IFRAME, nil, nil, &frame); + in->sm = Adesc; + in->s.decl = fn->decl; + + Decl *d = fn->ty->ids; + int off = 0; + for(Node *a = args; a; a=a->r, d=d->next){ + off = d->offset; + toff.val = off; + pass.ty = d->ty; + ecom(&pass, a->l); + } + + /* pass return value */ + if(ret && ret->ty != tnone){ + toff.val = REGRET * IBY2WD; + pass.ty = fn->ty->tof; + in = genrawop(ILEA, ret, nil, &pass); + } + + if(fn->op != Opkg){ + in = genrawop(ICALL, &frame, nil, nil); + in->dm = Apc; + in->d.decl = fn->decl; + }else{ + in = genrawop(PCALL, &frame, nil, nil); + in->mm = Aimm; + in->m.offset = fn->decl->pc->m.reg; + in->dm = Aimm; + in->d.offset = fn->decl->pc->pc; + } + tfree(&frame); +} + +static Node* +rewrite(Node *n) +{ + if(n == nil) + return nil; + Type *t = nil; + Decl *d = nil; + Node *l = n->l, *r = n->r; + switch(n->op){ + case Opkg: return n; + case Oexport: n = n->l; break; + case Odas: n->op = Oas; return rewrite(n); + case Odot: + d = r->decl; + switch(d->store){ + case Dpkg: return r; + case Dfield: break; + case Dfn: + assert(r->l == nil); + n->op = Oname; + n->decl = d; + n->r = nil; + n->l = nil; + return n; + default: + assert(0); + } + r->op = Oconst; + r->val = d->offset; + r->ty = tint; + n->l = mkunray(Oadr, l); + n->l->ty = tint; + n->op = Oadd; + n = mkunray(Oxref, n); + n->ty = n->l->ty; + n->l->ty = tint; + n->l = rewrite(n->l); + return n; + case Oslice: + if(r->l == nil) + r->l = mkconst(0); + if(r->r == nil) + r->r = mkconst(t->len); + n->l = rewrite(n->l); + n->r = rewrite(n->r); + break; + case Oindex: + t = n->ty; + n->r = mkn(Omul, mkconst(IBY2WD), n->r); + n->r->ty = tint; + n->op = Oadd; + n->ty = tint; + n = mkunray(Oxref, n); + n->ty = t; + break; + default: + n->l = rewrite(l); + n->r = rewrite(r); + break; + } + return n; +} + +static Node* +simplifiy(Node *n) +{ + if(n==nil) + return nil; + return rewrite(n); +} + +static int +tupaliased(Node *n, Node *e) +{ + for(;;){ + if(e == nil) return 0; + if(e->op == Oname && e->decl == n->decl) return 1; + if(tupaliased(n, e->l)) return 1; + e = e->r; + } +} + +static int +tupsaliased(Node *n, Node *e) +{ + for(;;){ + if(n == nil) return 0; + if(n->op == Oname && tupaliased(n, e)) return 1; + if(tupsaliased(n->l, e)) return 1; + n = n->r; + } +} + +static int +swaprelop(int op) +{ + switch(op){ + case Oeq: return Oneq; + case Oneq: return Oeq; + case Olt: return Ogt; + case Ogt: return Olt; + case Ogeq: return Oleq; + case Oleq: return Ogeq; + default: assert(0); + } +} + +static Inst* +cmpcom(Node *nto, Node *n) +{ + Node tl={0}, tr={0}; + Node *l = n->l; + Node *r = n->r; + int op = n->op; + Inst *i; + + switch(op){ + case Ogt: + case Ogeq: + op = swaprelop(op); + Node *t = l; + l = r; + r = t; + } + if(r->addable < Ralways){ + if(l->addable >= Rcant) + l = eacom(l, &tl, nil); + }else if(l->temps <= r->temps){ + r = ecom(talloc(&tr, r->ty, nil), r); + if(l->addable >= Rcant) + l = eacom(l, &tl, nil); + }else{ + l = eacom(l, &tl, nil); + r = eacom(l, talloc(&tr, r->ty, nil), r); + } + i = genop(op, l, r, nto); + tfree(&tl); + tfree(&tr); + return i; +} + +static Inst* +brcom(Node *n, int ift, Inst *b) +{ + Inst *bb = nil; + int op = n->op; + Node nto={0}; + Node f = (Node){.op=Oconst,.val=!ift,.addable=Rconst,.ty=tbool}; + + sumark(n); + if(op != Oconst){ + cmpcom(talloc(&nto, tbool, nil), n); + bb = genrawop(IBEQW, &nto, &f, nil); + }else{ + bb = genrawop(IBEQW, &f, n, nil); + } + bb->branch = b; + tfree(&nto); + return bb; +} + +static Node* +ecom(Node *nto, Node *n) +{ + Node *l = n->l; Node *r = n->r; + Node tr={0},tl={0},tt={0},*tn=nil; + int op = n->op; + + if(n->addable < Rcant){ + if(nto) + genmove(n->ty, n, nto); + return nto; + } + switch(op){ + case Oas: + if(l->op == Oslice) + assert(0); + if(l->op == Otup){ + if(tupsaliased(r, l) == 0){ + if((tn = tupblk(l))){ + tn->ty = n->ty; + ecom(tn, r); + if(nto) + genmove(n->ty, tn, nto); + break; + } + if((tn = tupblk(r))){ + tn->ty = n->ty; + ecom(tn, l); + if(nto) + genmove(n->ty, tn, nto); + break; + } + if(nto==nil && r->op == Otup){ + tuplrcom(r, l); + break; + } + } + if(r->addable >= Ralways||r->op!=Oname + ||tupaliased(r, l)){ + talloc(&tr, n->ty, nil); + ecom(&tr, r); + r = &tr; + } + tuplcom(r, n->l); + if(nto) + genmove(n->ty, r, nto); + tfree(&tr); + break; + } + if(l->addable >= Rcant) + l = eacom(l, &tl, nto); + ecom(l, r); + if(nto) + genmove(nto->ty, l, nto); + tfree(&tl); + tfree(&tr); + break; + case Olen: genrawop(ILEN, n->l, nil, nto); break; + case Oarray: arrcom(nto, n); break; + case Ostruct: tupcom(nto, n); break; + case Oslice: + if(l->addable >= Rcant) + l = eacom(l, &tl, nto); + if(r->l->addable >= Rcant) + r->l = ecom(talloc(&tr,r->l->ty,nil), r->l); + if(r->r->addable >= Rcant) + r->r = ecom(talloc(&tt,r->r->ty,nil), r->r); + genmove(n->ty, l, nto); + genrawop(ISLICE, r->l, r->r, nto); + tfree(&tl); + tfree(&tr); + tfree(&tt); + break; + case Otup: + if((tn = tupblk(n)) != nil){ + tn->ty = n->ty; + genmove(n->ty, tn, nto); + break; + } + tupcom(nto, n); + break; + case Oxref: + n = eacom(n, &tl, nto); + genmove(n->ty, n, nto); + tfree(&tl); + break; + case Oref: + genrawop(ILEA, l, nil, nto); + break; + case Ocall: + callcom(op, n, nto); + break; + case Oeq: + case Oneq: + case Olt: + case Oleq: + case Ogt: + case Ogeq: + if(nto) + cmpcom(nto, n); + break; + case Omul: + case Oadd: + case Osub: + if(nto==nil) + break; + if(l->addable < Ralways){ + if(r->addable >= Rcant) + r = eacom(r, &tr, nto); + }else if(r->temps <= l->temps){ + l = ecom(talloc(&tl, l->ty, nto), l); + if(r->addable >= Rcant) + r = eacom(r, &tr, nil); + }else{ + r = eacom(r, &tr, nto); + l = ecom(talloc(&tl, l->ty, nil), l); + } + if(sameaddr(nto, l)) + genop(op, r, nil, nto); + else if(sameaddr(nto, r)) + genop(op, l, nil, nto); + else + genop(op, r, l, nto); + tfree(&tl); + tfree(&tr); + break; + } + return nto; +} + +static void +scom(Node *n) +{ + Inst *p, *pp; + Node *l, *r; + + for(; n; n = n->r){ + l = n->l; + r = n->r; + switch(n->op){ + case Ovardecl: + return; + case Oscope: + pushscp(n); + scom(n->l); + scom(n->r); + popscp(); + return; + case Oif: + pushblock(); + pushblock(); + p = brcom(l, 1, nil); + tfreenow(); + popblock(); + scom(r->l); + if(r->r){ + pp = p; + p = genrawop(IJMP, nil, nil, nil); + ipatch(pp, nextinst()); + scom(r->r); + } + ipatch(p, nextinst()); + popblock(); + return; + case Ofor: + pushblock(); + pp = nextinst(); + n->l = l = simplifiy(n->l); + sumark(l); + p = brcom(l, 1, nil); + tfreenow(); + popblock(); + assert(loopdep < maxloopdep); + breaks[loopdep] = nil; + conts[loopdep] = nil; + bcsps[loopdep] = curscp(); + loopdep += 1; + scom(n->r->l); + loopdep -= 1; + ipatch(conts[loopdep], nextinst()); + if(n->r->r){ + pushblock(); + scom(n->r->r); + popblock(); + } + repushblock(lastinst->block); + ipatch(genrawop(IJMP,nil,nil,nil),pp); + popblock(); + ipatch(p, nextinst()); + ipatch(breaks[loopdep], nextinst()); + return; + case Oret: + pushblock(); + if(n->l){ + Node ret={0}; + n->l = simplifiy(n->l); + sumark(n->l); + ecom(retalloc(&ret, n->l), n->l); + tfreenow(); + } + genrawop(IRET, nil, nil, nil); + popblock(); + break; + case Oseq: + scom(n->l); + break; + default: + pushblock(); + n = simplifiy(n); + sumark(n); + ecom(nil, n); + tfreenow(); + popblock(); + return; + } + } +} + +void +fncom(Decl *d) +{ + Node *n = d->init; + d->pc = nextinst(); + tinit(); + + loopdep = scp = 0; + breaks = new(sizeof(breaks[0]) * maxloopdep); + conts = new(sizeof(conts[0]) * maxloopdep); + bcsps = new(sizeof(bcsps[0]) * maxloopdep); + for(Node *p=n->r; p; p=p->r){ + if(p->op != Oseq){ + scom(p); + break; + }else + scom(p->l); + } + free(breaks); + free(conts); + free(bcsps); + + Decl *locs = concatdecl(d->locals, tdecls()); + d->offset += idoffsets(locs, d->offset, IBY2WD); + d->locals = locs; + printf("%d\n", d->offset); +} diff --git a/dat.h b/dat.h new file mode 100644 index 0000000..bf0ca6f --- /dev/null +++ b/dat.h @@ -0,0 +1,273 @@ +enum TypeKind +{ + Tnone, + Tint, + Tbool, + Tstring, + Tany, + Ttup, + Tid, + Tfn, + Tstruct, + Tarray, + Tslice, + Tptr, + Tref, + Tpfn, + Tpkg, + Tend, +}; + +enum NodeOp +{ + Onone, + Oadd, + Osub, + Olt, + Ogt, + Oneq, + Oeq, + Oleq, + Ogeq, + Omul, + Oconst, + Oindex, + Oadr, + Otup, + Ofn, + Opkg, + Orange, + Otypedecl, + Ostrdecl, + Oname, + Ofor, + Oif, + Oret, + Oref, + Oxref, + Oseq, + Oscope, + Ocall, + Odas, + Oas, + Odot, + Olen, + Oslice, + Ofielddecl, + Ovardecl, + Ovardecli, + Oimport, + Oexport, + Opkgdecl, + Oarray, + Ostruct, + Oend, +}; + +enum +{ + Aimm, /* immediate */ + Amp, /* global */ + Ampind, /* global indirect */ + Afp, /* activation frame */ + Afpind, /* frame indirect */ + Apc, /* branch */ + Adesc, /* type descriptor immediate */ + Aoff, /* offset in module description table */ + Anoff, /* above encoded as -ve */ + Aerr, /* error */ + Anone, /* no operand */ + Aldt, /* linkage descriptor table immediate */ + Aend +}; + +enum +{ + Rreg, /* v(fp) */ + Rmreg, /* v(mp) */ + Roff, /* $v */ + Rnoff, /* $v encoded as -ve */ + Rdesc, /* $v */ + Rdescp, /* $v */ + Rconst, /* $v */ + Ralways, /* preceeding are always addressable */ + Radr, /* v(v(fp)) */ + Rmadr, /* v(v(mp)) */ + Rcant, /* following are not quite addressable */ + Rpc, /* branch address */ + Rmpc, /* cross module branch address */ + Rareg, /* $v(fp) */ + Ramreg, /* $v(mp) */ + Raadr, /* $v(v(fp)) */ + Ramadr, /* $v(v(mp)) */ + Rldt, /* $v */ + Rend +}; + +enum +{ + Dtype, + Dlocal, + Dglobal, + Dconst, + Darg, + Dfield, + Dfn, + Dpkg, + Dundef, + Dunbound, + Dwundef, +}; + +enum +{ + TopScope = 0, + MaxScope = 128, + ScopeNil = 1, + ScopeGlobal = 2, + + Sother = 0, + Sloop, + Sscope, +}; + +enum LexToken +{ + Leof = -1, + Lnone = 0, + Lfn = sizeof(char)+1, + Llen, + Ltid, + Lid, + Lconst, + Lsconst, + Lret, + Ldas, + Ltype, + Lvar, + Lstruct, + Lstring, + Lfor, + Lif, + Lelse, + Lexport, + Limport, + Lpackage, + Leq, + Lneq, + Lleq, + Lgeq, +}; + +typedef struct Lexer Lexer; +typedef struct Node Node; +typedef struct Type Type; +typedef struct Decl Decl; +typedef struct Inst Inst; +typedef struct Addr Addr; +typedef struct Sym Sym; +typedef struct Token Token; +typedef struct Import Import; + +struct Sym +{ + int tok; + char *name; + int len; + Decl *decl; + Decl *unbound; +}; + +struct Decl +{ + Sym *sym; + int nid; + int scope; + int das; + Type *ty; + Decl *next; + Decl *old; + Decl *dot; + Node *init; + int store; + int offset; + int tref; + Inst *pc; + Decl *locals; + Decl *link; + int flag; +}; + +struct Lexer +{ + int tok; + int next; + int cur; + int eof; + Sym *sym; + FILE *f; + WORD val; +}; + +struct Type +{ + int kind; + int size; + int len; + int offset; + Decl *decl; + Type *tof; + Decl *ids; +}; + +struct Node +{ + u8 op; + u8 addable; + u8 temps; + Node *l, *r; + Type *ty; + int val; + Decl *decl; +}; + +struct Addr +{ + i32 reg; + i32 offset; + Decl *decl; +}; + +struct Inst +{ + u8 op; + u8 sm; /* operand addressing modes */ + u8 mm; + u8 dm; + Addr s; /* operands */ + Addr m; + Addr d; + Inst *next; + Inst *branch; + int block; + u32 pc; +}; + +struct Token +{ + int kind; + union{ + Sym *sym; + int num; + Decl *ids; + Node *node; + Type *type; + }; +}; + +struct Import +{ + Sym *sym; + Sym *path; + Decl *decls; +}; \ No newline at end of file diff --git a/decl.c b/decl.c new file mode 100644 index 0000000..b7c7bc7 --- /dev/null +++ b/decl.c @@ -0,0 +1,315 @@ +#include "yo.h" + +Decl *nildecl; +Decl *truedecl; +Decl *falsedecl; +Decl *_decl; +static Decl *scopes[MaxScope] = {0}; +static Decl *tails[MaxScope] = {0}; +static Node *scopenode[MaxScope] = {0}; +static int scopekind[MaxScope] = {0}; +static int scope; + +static void freeloc(Decl *d); +static void recdecl(Node *n ,int store, int *id); +static int recmark(Node *n, int id); + +void +declstart(void) +{ + scope = ScopeNil; + scopes[scope] = nil; + tails[scope] = nil; + + nildecl = mkdecl(Dglobal, tany); + nildecl->sym = enter("nil", 0); + installids(Dglobal, nildecl); + + _decl = mkdecl(Dglobal, tany); + _decl->sym = enter("_", Lid); + installids(Dglobal, _decl); + + truedecl = mkdecl(Dglobal, tbool); + truedecl->sym = enter("true", Lconst); + installids(Dglobal, truedecl); + + falsedecl = mkdecl(Dglobal, tbool); + falsedecl->sym = enter("false", Lconst); + installids(Dglobal, falsedecl); + + scope = ScopeGlobal; + scopes[scope] = nil; + tails[scope] = nil; +} + +Decl* +popids(Decl *d) +{ + for(; d; d=d->next){ + if(d->sym){ + d->sym->decl = d->old; + d->old = nil; + } + } + return popscope(); +} + +void +repushids(Decl *d) +{ + assert(scope < MaxScope); + scope++; + scopes[scope] = nil; + tails[scope] = nil; + scopenode[scope] = nil; + scopekind[scope] = Sother; + + for(; d; d=d->next){ + if(d->scope != scope + && (d->scope != ScopeGlobal||scope != ScopeGlobal +1)) + assert(0); + Sym *s = d->sym; + if(s != nil){ + if(s->decl != nil && s->decl->scope >= scope) + d->old = s->decl->old; + else + d->old = s->decl; + s->decl = d; + } + } +} + +void +pushscope(Node *scp, int kind) +{ + assert(scope+1 < MaxScope); + scope += 1; + scopes[scope] = nil; + tails[scope] = nil; + scopenode[scope] = scp; + scopekind[scope] = kind; +} + +Decl* +popscope(void) +{ + for(Decl *p=scopes[scope]; p; p=p->next){ + if(p->sym){ + p->sym->decl = p->old; + p->old = nil; + } + if(p->store == Dlocal) + freeloc(p); + } + return scopes[scope--]; +} + +void +installids(int store, Decl *ids) +{ + if(ids == nil) + return; + Decl *last = nil; + for(Decl *d = ids; d; d=d->next){ + d->scope = scope; + if(d->store == Dundef) + d->store = store; + Sym *s = d->sym; + if(s){ + if(s->decl && s->decl->scope >= scope){ + assert(0); + }else + d->old = s->decl; + s->decl = d; + } + last = d; + } + Decl *d = tails[scope]; + if(d == nil) + scopes[scope] = ids; + else + d->next = ids; + tails[scope] = last; +} + +void +fielddecled(Node *n) +{ + for(; n; n=n->r) + switch(n->op){ + case Oseq: fielddecled(n->l); break; + case Ofielddecl: installids(Dfield, n->decl); return; + case Ostrdecl: structdecled(n); return; + default: assert(0); + } +} + +void +structdecled(Node *n) +{ + Decl *d = n->ty->decl; + installids(Dtype, d); + pushscope(nil, Sother); + fielddecled(n->l); + n->ty->ids = popscope(); +} + +void +fndecled(Node *n) +{ + Node *l = n->l; + assert(l->op == Oname); + Decl *d = l->decl->sym->decl; + assert(d == nil); + d = mkids(l->decl->sym, n->ty, nil); + installids(Dfn, d); + l->decl = d; + pushscope(nil, Sother); + installids(Darg, n->ty->ids); + n->ty->ids = popscope(); +} + +void +vardecled(Node *n) +{ + int store = Dlocal; + if(scope == ScopeGlobal) + store = Dglobal; + Decl *ids = n->decl; + installids(store, ids); + Type *t = n->ty; + for(; ids; ids=ids->next) + ids->ty = t; +} + +void +dasdecl(Node *n) +{ + int store = 0; + if(scope == ScopeGlobal) + store = Dglobal; + else + store = Dlocal; + int id = 0; + recdecl(n, store, &id); + if(store == Dlocal && id > 1) + recmark(n, id); +} + +Node* +vardecl(Decl *ids, Type *t) +{ + Node *n = mkn(Ovardecl, mkn(Oseq, nil, nil), nil); + n->decl = ids; + n->ty = t; + return n; +} + +Node* +mkdeclname(Decl *d) +{ + Node *n = mkn(Oname, nil, nil); + n->decl = d; + n->ty = d->ty; + return n; +} + +Node* +varinit(Decl *ids, Node *e) +{ + Node *n = mkdeclname(ids); + if(ids->next == nil) + return mkn(Oas, n, e); + return mkn(Oas, n, varinit(ids->next, e)); +} + +Decl* +concatdecl(Decl *d1, Decl *d2) +{ + if(d1 == nil) + return d2; + Decl *t = d1; + for(; t->next; t=t->next) + ; + t->next = d2; + return d1; +} + +int +decllen(Decl*d) +{ + int l = 0; + for(;d;d=d->next) + ++l; + return l; +} + +int +sharelocal(Decl *d) +{ + if(d->store != Dlocal) + return 0; + Type *t = d->ty; + for(Decl *dd = fndecls; dd; dd=dd->next){ + assert(d != dd); + Type *tt = dd->ty; + if(dd->store != Dlocal || dd->link || dd->tref != 0) + continue; + if(t->size == tt->size){ + d->link = dd; + dd->tref = 1; + return 1; + } + } + return 0; +} + +static void +freeloc(Decl *d) +{ + if(d->link) + d->link->tref = 0; +} + +static void +recdecl(Node *n ,int store, int *id) +{ + Decl *d; + + switch(n->op){ + case Otup: + for(n = n->l; n; n=n->r) + recdecl(n->l, store, id); + return; + case Oname: + assert(n->decl != nil); + d = mkids(n->decl->sym, nil, nil); + installids(store, d); + // old = d->old; assert(old == nil); warn shadwoing + n->decl = d; + d->das = 1; + if(*id >= 0) + *id += 1; + return; + default: + assert(0); + } +} + +static int +recmark(Node *n, int id) +{ + switch(n->op){ + case Otup: + for(n = n->l; n; n = n->r) + id = recmark(n->l, id); + break; + case Oname: + n->decl->nid = id; + id = 0; + break; + default: + assert(0); + } + return id; +} diff --git a/dis.c b/dis.c new file mode 100644 index 0000000..74da130 --- /dev/null +++ b/dis.c @@ -0,0 +1,91 @@ +#include "yo.h" + +static int dismode[Aend] = { + /* Aimm */ AIMM, + /* Amp */ AMP, + /* Ampind */ AMP|AIND, + /* Afp */ AFP, + /* Afpind */ AFP|AIND, + /* Apc */ AIMM, + /* Adesc */ AIMM, + /* Aoff */ AIMM, + /* Anoff */ AIMM, + /* Aerr */ AXXX, + /* Anone */ AXXX, + /* Aldt */ AIMM, +}; + +static int disregmode[Aend] = { + /* Aimm */ AXIMM, + /* Amp */ AXINM, + /* Ampind */ AXNON, + /* Afp */ AXINF, + /* Afpind */ AXNON, + /* Apc */ AXIMM, + /* Adesc */ AXIMM, + /* Aoff */ AXIMM, + /* Anoff */ AXIMM, + /* Aerr */ AXNON, + /* Anone */ AXNON, + /* Aldt */ AXIMM, +}; + +void +wr1(FILE *f, u8 v) +{ + fwrite(&v, 1, 1, f); +} +void +wr2(FILE *f, u16 v) +{ + fwrite(&v, 1, 2, f); +} +void +wr4(FILE *f, u32 v) +{ + fwrite(&v, 1, 4, f); +} + +void +disaddr(FILE* f, u32 m, Addr *a) +{ + u32 val = 0; + switch(m){ + case Anone: + return; + case Aimm: + val = a->offset; + break; + case Afp: + val = a->reg; + break; + case Afpind: + wr2(f, a->reg); + wr2(f, a->offset); + return; + case Adesc: + val = a->offset+a->reg; + break; + case Apc: + val = a->offset; + break; + default: + assert(0); + } + wr4(f, val); +} + +int +disinst(FILE *f, Inst *in) +{ + int n = 0; + for(; in != nil; in = in->next){ + n += 1; + wr1(f, in->op); + wr1(f, SRC(dismode[in->sm]) | DST(dismode[in->dm]) | disregmode[in->mm]); + disaddr(f, in->mm, &in->m); + disaddr(f, in->sm, &in->s); + disaddr(f, in->dm, &in->d); + } + return n; +} \ No newline at end of file diff --git a/exports.c b/exports.c new file mode 100644 index 0000000..4d22976 --- /dev/null +++ b/exports.c @@ -0,0 +1,105 @@ +#include "yo.h" + +static FILE *f; + +static int +retlen(Type *t) +{ + if(t == tnone) + return 0; + if(t->kind != Ttup) + return 1; + return decllen(t->ids); +} + +static void +tyexported(Decl **arr, int n) +{ + for(int i = 0; i < n; ++i){ + Decl *d = arr[i]; + if(isexported(d)==0) + continue; + Type *t = d->ty; + int l = decllen(t->ids); + fprintf(f, "type .%s struct %d %d\n", + d->sym->name, t->size,l); + for(Decl *dd=t->ids; dd;dd=dd->next){ + Type *tt = dd->ty; + fprintf(f,"\t%s %s %d %d %d\n", + dd->sym->name, + tt->decl->sym->name, + tt->kind, + tt->size, + dd->offset); + } + } +} + +static void +fnexported(Decl **arr, int n) +{ + for(int i = 0; i < n; ++i){ + Decl *d = arr[i]; + if(isexported(d)==0) + continue; + Type *t = d->ty; + fprintf(f, "fn .%s %d %d %d %d\n", + d->sym->name, d->offset, d->pc->pc, + decllen(t->ids), + retlen(t->tof)); + fprintf(f, "\t%d\n", t->size); + for(Decl *dd=t->ids; dd;dd=dd->next){ + Type *tt = dd->ty; + fprintf(f,"\t%s %d %d %d\n", + tt->decl->sym->name, + tt->kind, + tt->size, + dd->offset); + } + t = t->tof; + bindsize(t); + fprintf(f, "\t%d\n", t->size); + if(t->kind==Ttup){ + for(Decl *dd=t->ids; dd;dd=dd->next){ + Type *tt = dd->ty; + fprintf(f,"\t%s %d %d %d\n", + tt->decl->sym->name, + tt->kind, + tt->size, + dd->offset); + } + }else + fprintf(f,"\t%s %d %d %d\n", + t->decl->sym->name, + t->kind, + t->size, + t->decl->offset); + } +} +void +genexports(char *name) +{ + f = fopen(name, "w+"); + assert(f != nil); + + fprintf(f, "%s\n", pkgname->name); + tyexported(types, ntype); + fnexported(fns, nfn); + fprintf(f, "\n"); + fclose(f); +} + +void +genbin(char *name) +{ + f = fopen(name, "w+"); + // fprintf(f, "%s\n", pkgname->name); + // fprintf(f, "%d\n", nimport); + // for(int i = 0; i < nimport; ++i){ + // fprintf(f, "%d %s %s\n", i, imports[i].path->name, imports[i].sym->name); + // } + + wr4(f, ninst); + disinst(f, firstinst); + fclose(f); +} \ No newline at end of file diff --git a/fib.yo b/fib.yo new file mode 100644 index 0000000..e1f4480 --- /dev/null +++ b/fib.yo @@ -0,0 +1,13 @@ +package a + +fn main() int { + x := fib(10); + return x; +}; + +fn fib(n int) int{ + if n <= 1 { + return n; + }; + return fib(n-1) + fib(n-2); +}; diff --git a/file.c b/file.c new file mode 100644 index 0000000..07be08a --- /dev/null +++ b/file.c @@ -0,0 +1,48 @@ +#include "yo.h" +#include +#include +#include + +char* +getpath(void) +{ + char buf[8192] = {0}; + + char *dir = getcwd(buf, sizeof(buf)); + int l = strlen(dir); + char *d = new(l+1); + memcpy(d, dir, l); + d[l] = 0; + return d; +} + +int +issufix(char *a, char *sufix) +{ + int l = strlen(sufix); + char *p = strrchr(a, '.'); + return p && strlen(p)==l && memcmp(p,sufix,l)==0; +} + +char** +getfiles(char *path, char *sufix) +{ + DIR *d; + struct dirent *p; + char **s; + + int j = 1; + s = new(sizeof(char*)); + d = opendir(path); + while((p=readdir(d)) != NULL){ + if(issufix(p->d_name, sufix)){ + s = realloc(s, (j+1)*sizeof(void*)); + int l = strlen(p->d_name); + s[j-1] = memcpy(new(l+1), p->d_name, l+1); + s[j++] = nil; + } + } + nsrc = j - 1; + closedir(d); + return s; +} \ No newline at end of file diff --git a/fn.h b/fn.h new file mode 100644 index 0000000..b0d2de9 --- /dev/null +++ b/fn.h @@ -0,0 +1,119 @@ +/* lex.c parse.c */ +void lexinit(void); +void lexstart(char*); +Sym* enter(char *name, int tok); +Token peek(int *arr); +Token try(int *arr); +Token want(int *arr); +Token lex(void); +void importdef(Sym *file); +Sym* dotsym(void); +void unlex(Token tok); +int isimported(Sym *path); +int isexported(Decl *d); +Node *parse(char*); +Node** parsefiles(char **srcs, int n); + +/* node.c */ +void* new(int s); +Node* mkn(int op, Node *l, Node *r); +Node* mkconst(int v); +Node* dupn(Node *n); +Node* retalloc(Node *n, Node *nn); +Node* mkname(Sym *s); +Decl* mkids(Sym *s, Type *t, Decl *next); +Node* mkunray(int op, Node *l); +Node* mksconst(Sym *s); +Node* mkscope(Node *body); +Node* mkbool(int v); + +/* com.c */ +void fncom(Decl *); + +/* assert.c */ +void gassert(Node *n); +void gdecl(Node *n); +void gbind(Node *n); +void assertfn(Decl *d); +void gentry(Node *tree); + +/* type.c */ +void typeinit(void); +void typestart(void); +Decl* mkdecl(int store, Type *t); +Type* mktype(int kind, int size, Type *tof, Decl *args); +Decl* typeids(Decl *ids, Type *t); +Type* usetype(Type *t); +Type* asserttype(Type *t); +int eqtype(Type *t1, Type *t2); +int eqtup(Type *t1, Type *t2); +Node* structdecl(Decl *id, Node *f); +void bindtypes(Type *t); +Type* mkidtype(Sym *s); +Node* fielddecl(int store, Decl *ids); +Type* isvalidty(Type *t); +Decl* isinids(Decl *ids, Sym *s); +Decl* isinpkg(Decl *ids, Sym *s); +int bindsize(Type *t); + +/* decl.c */ +Node* fndecl(Node *n, Type *t, Node *body); +Inst* nextinst(void); +Inst* mkinst(void); +void installids(int store, Decl *ids); +void fndecled(Node *n); +void declstart(void); +void pushscope(Node *n, int kind); +void repushids(Decl *d); +Decl* popids(Decl *d); +Decl* popscope(void); +int resolvedesc(int l, Decl *d); +Decl* resolveldts(Decl *d, Decl **dd); +void dasdecl(Node *n); +Decl* concatdecl(Decl *d1, Decl *d2); +Inst* genmove(Type *t, Node *s, Node *d); +int align(int off); +Node* vardecl(Decl *ids, Type *t); +void vardecled(Node *n); +Node* varinit(Decl *ids, Node *e); +void structdecled(Node *n); +int decllen(Decl*d); +int sharelocal(Decl *d); + +/* dis.c */ +int disinst(FILE *out, Inst *in); +void wr1(FILE *f, u8 v); +void wr4(FILE *f, u32 v); +void disaddr(FILE* f, u32 m, Addr *a); + +/* gen.c */ +void genstart(void); +Inst* genop(int op, Node *s, Node *m, Node *d); +Inst* genrawop(int op, Node *s, Node *m, Node *d); +Addr genaddr(Node *n); +void instconv(FILE *f, Inst *i); +int sameaddr(Node *n, Node *m); +Node* talloc(Node *n, Type *t, Node *nok); +void tfree(Node *n); +void tfreenow(void); +int resolvepcs(Inst *inst); +Decl* tdecls(void); +void tinit(void); +int idoffsets(Decl *id, long offset, int al); +int pushblock(void); +void repushblock(int b); +void popblock(void); +void ipatch(Inst *b, Inst *d); + +/* asm */ +void asminst(FILE *f, Inst *in); +void asmexport(FILE *f, Sym *pkg, Decl **arr, int n); +void genexports(char *); +void genbin(char *); + +/* file.c */ +char* getpath(void); +int issufix(char *a, char *sufix); +char** getfiles(char *path, char *sufix); +Node** parsefiles(char **srcs, int n); +Sym* assertpkgdecl(Node **trees, int n); \ No newline at end of file diff --git a/gen.c b/gen.c new file mode 100644 index 0000000..02e964f --- /dev/null +++ b/gen.c @@ -0,0 +1,478 @@ +#include "yo.h" + +static int addrmode[Rend] = +{ + /* Rreg */ Afp, + /* Rmreg */ Amp, + /* Roff */ Aoff, + /* Rnoff */ Anoff, + /* Rdesc */ Adesc, + /* Rdescp */ Adesc, + /* Rconst */ Aimm, + /* Ralways */ Aerr, + /* Radr */ Afpind, + /* Rmadr */ Ampind, + /* Rcant */ Aerr, + /* Rpc */ Apc, + /* Rmpc */ Aerr, + /* Rareg */ Aerr, + /* Ramreg */ Aerr, + /* Raadr */ Aerr, + /* Ramadr */ Aerr, + /* Rldt */ Aldt, +}; + +static int blockstklen; +static Inst zinst; +static Decl *wtemp; +static Node *ntoz; +static int ntemp; + +int *blockstk; +int blockdep; +int nblock; +int blocks; + +Node retnode; +Inst *lastinst, *firstinst; + +int +pushblock(void) +{ + if(blockdep >= blockstklen){ + blockstklen = blockdep += 32; + blockstk = realloc(blockstk, blockstklen*sizeof(blockstk)); + } + blockstk[blockdep++] = blocks; + return blocks = nblock++; +} + +void +repushblock(int b) +{ + blockstk[blockdep++] = blocks; + blocks = b; +} + +void +popblock(void) +{ + blocks = blockstk[--blockdep]; +} + +Inst* +nextinst(void) +{ + Inst *in = lastinst->next; + if(in) + return in; + in = new(sizeof(Inst)); + *in = zinst; + lastinst->next = in; + return in; +} + + +Inst* +mkinst(void) +{ + Inst *in = lastinst->next; + if(in == nil){ + in = new(sizeof(Inst)); + *in = zinst; + lastinst->next = in; + } + lastinst = in; + assert(blocks >= 0); + in->block = blocks; + return in; +} + +void +tinit(void) +{ + wtemp = nil; +} + +void +genstart(void) +{ + ntoz = nil; + Decl *d = mkdecl(Dlocal, tint); + d->sym = enter(".ret", 0); + d->offset = IBY2WD * REGRET; + + zinst = (Inst){0}; + zinst.op = INOP; + zinst.sm = Anone; + zinst.dm = Anone; + zinst.mm = Anone; + + firstinst = new(sizeof(Inst)); + *firstinst = zinst; + lastinst = firstinst; + + retnode.op = Oname; + retnode.addable = Rreg; + retnode.ty = tint; + retnode.decl = d; + + blocks = -1; + blockdep = 0; + nblock = 0; +} + +Addr +genaddr(Node *n) +{ + Addr a = {0}; + if(n == nil) + return a; + switch(n->addable){ + case Rareg: + a = genaddr(n->l); + if(n->op == Oadd) + a.reg += n->r->val; + break; + case Rreg: + if(n->decl) + a.decl = n->decl; + else + a = genaddr(n->l); + break; + case Rconst: + a.offset = n->val; + break; + case Radr: + a = genaddr(n->l); + break; + case Raadr: + a = genaddr(n->l); + if(n->op == Oadd) + a.offset += n->r->val; + break; + default: + assert(0); + } + return a; +} + +int +sameaddr(Node *n, Node *m) +{ + if(n->addable != m->addable) + return 0; + Addr a = genaddr(n); + Addr b = genaddr(m); + return a.offset==b.offset && a.reg==b.reg && a.decl == b.decl; +} + +Inst* +genmove(Type *t, Node *s, Node *d) +{ + static u8 mvtab[] = { + [Tptr] = IMOVW, + [Tint] = IMOVW, + [Tbool] = IMOVW, + [Ttup] = IMOVM, + [Tarray] = IARRAY, + [Tslice] = IMOVM, + [Tstruct] = IMOVM, + }; + Inst *in = nil; + Addr reg = {0}; + int regm = Anone; + u8 op = mvtab[t->kind]; + assert(op!=0); + switch(t->kind){ + case Tarray: + case Tslice: + case Tstruct: + case Ttup: + assert(t->size != 0); + regm = Aimm; + reg.offset = t->size; + break; + } + in = mkinst(); + in->op = op; + if(s){ + in->s = genaddr(s); + in->sm = addrmode[s->addable]; + } + in->m = reg; + in->mm = regm; + if(d){ + in->d = genaddr(d); + in->dm = addrmode[d->addable]; + } + return in; +} + +Inst* +genrawop(int op, Node *s, Node *m, Node *d) +{ + Inst *in = mkinst(); + in->op = op; + if(s){ + in->s = genaddr(s); + in->sm = addrmode[s->addable]; + } + if(m){ + in->m = genaddr(m); + in->mm = addrmode[m->addable]; + assert(in->mm != Ampind); + assert(in->mm != Afpind); + } + if(d){ + in->d = genaddr(d); + in->dm = addrmode[d->addable]; + } + return in; +} + +Inst* +genop(int op, Node *s, Node *m, Node *d) +{ + static u8 disoptab[Oend][Tend] = + { + [Olt] = {[Tint]=ILTW,[Tbool]=ILTW}, + [Oeq] = {[Tint]=IEQW,[Tbool]=IEQW}, + [Oleq] ={[Tint]=ILEQW,[Tbool]=ILEQW}, + [Oadd] = {[Tint]=IADDW,}, + [Osub] = {[Tint]=ISUBW,}, + [Omul] = {[Tint]=IMULW,}, + }; + Inst *in = mkinst(); + int iop = disoptab[op][d->ty->kind]; + in->op = iop; + if(s){ + in->s = genaddr(s); + in->sm = addrmode[s->addable]; + } + if(m){ + in->m = genaddr(m); + in->mm = addrmode[m->addable]; + assert(in->mm != Ampind); + assert(in->mm != Afpind); + } + if(d){ + in->d = genaddr(d); + in->dm = addrmode[d->addable]; + } + return in; +} + +void +addprint(FILE *f, int am, Addr *a) +{ + switch(am){ + case Anone: + return; + case Afp: + fprintf(f, "%u(fp)", a->reg); + break; + case Aimm: + fprintf(f, "$%u", a->offset); + break; + case Afpind: + fprintf(f, "%u(%u(fp))", a->offset, a->reg); + break; + case Adesc: + fprintf(f, "$%u", a->offset+a->reg); + break; + case Apc: + fprintf(f, "$%u", a->reg+a->offset); + break; + case Amp: + fprintf(f, "%u(mp)",a->reg); + break; + case Aldt: + fprintf(f, "$%u", a->reg); + break; + default: + assert(0); + } + return; +} + +void +instconv(FILE *f, Inst *in) +{ + char *comma = ""; + + if(in == nil) + return; + char* op = instname[in->op]; + fprintf(f, "\t%s\t", op); + if(op == INOP) + return; + if(in->sm != Anone){ + addprint(f, in->sm, &in->s); + comma = ", "; + } + if(in->mm != Anone){ + fprintf(f, "%s", comma); + addprint(f, in->mm, &in->m); + comma = ", "; + } + if(in->dm != Anone){ + fprintf(f, "%s", comma); + addprint(f, in->dm, &in->d); + comma = ""; + } + fprintf(f, "\n"); +} + +Node* +talloc(Node *n, Type *t, Node *nok) +{ + Decl *ok = nok == nil ? nil : nok->decl; + + if(ok==nil||ok->tref==0) + ok = nil; + *n = (Node){0}; + n->op = Oname; + n->addable = Rreg; + n->ty = t; + if(ok != nil + &&ok->ty->kind == t->kind + &&ok->ty->size == t->size){ + ok->tref++; + n->decl = ok; + return n; + } + for(Decl *d = wtemp; d != nil; d = d->next){ + if(d->tref == 1 + && d->ty->kind == t->kind + && d->ty->size == t->size){ + d->tref++; + n->decl = d; + return n; + } + } + char buf[64] = {0}; + sprintf(buf, ".t%d", ntemp++); + Decl *d = mkdecl(Dlocal, t); + d->sym = enter(buf, 0); + d->tref = 2; + n->decl = d; + d->next = wtemp; + wtemp = d; + + return n; +} + +void +tfree(Node *n) +{ + if(n == nil || n->decl == nil || n->decl->tref == 0) + return; + assert(n->decl->tref > 1); + if(--n->decl->tref == 1){ + return; + } +} + +void +tfreenow(void) +{ + assert(ntoz == nil); +} + +int +align(int off) +{ + while(off % IBY2WD) + off++; + return off; +} + +int +idoffsets(Decl *id, long offset, int al) +{ + if(id==nil || id->flag) + return align(offset); + for(; id; id = id->next){ + id->flag = 1; + if(id->store == Dlocal && id->link){ + if(id->link->flag == 0) + idoffsets(id->link, offset, al); + id->offset = id->link->offset; + continue; + } + offset = align(offset); + id->offset = offset; + offset += id->ty->size; + if(id->nid == 0 && (id->next == nil || id->next->nid != 0)) + offset = align(offset); + } + return align(offset); +} + +Decl* +tdecls(void) +{ + for(Decl *d = wtemp; d; d=d->next) + assert(d->tref == 1); + return wtemp; +} + +int +resolvepcs(Inst *inst) +{ + int pc = 0; + for(Inst *in=inst; in; in=in->next){ + Decl *d = in->s.decl; + if(d){ + in->s.reg += d->offset; + } + d = in->m.decl; + if(d){ + in->m.reg += d->offset; + } + d = in->d.decl; + if(d){ + if(in->dm == Apc){ + in->d.offset = d->pc->pc; + }else{ + in->d.reg += d->offset; + } + } + in->pc = pc++; + } + for(Inst *in=inst; in; in=in->next){ + Decl *d =in->s.decl; + if(d && in->sm == Apc) + in->s.offset = d->pc->pc; + d = in->d.decl; + if(d != nil && in->dm == Apc) + in->d.offset = d->pc->pc; + if(in->branch){ + in->dm = Apc; + in->d.offset = in->branch->pc; + } + } + return pc; +} + +int +idindices(Decl *id) +{ + int i = 0; + for(; id; id=id->next){ + usetype(id->ty); + id->offset = i++; + } + return i; +} + +void +ipatch(Inst *b, Inst *d) +{ + Inst *n; + for(; b; b = n){ + n = b->branch; + b->branch = d; + } +} \ No newline at end of file diff --git a/isa.h b/isa.h new file mode 100644 index 0000000..5042bb6 --- /dev/null +++ b/isa.h @@ -0,0 +1,70 @@ +/* instructions */ +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef int8_t i8; +typedef int16_t i16; +typedef uint32_t u32; +typedef int32_t i32; + +typedef u8 byte; +typedef intptr_t WORD; + +enum +{ + INOP, + IARRAY, + ISLICE, + IFRAME, + ICALL, + IJMP, + PCALL, + IRET, + IREF, + ILEN, + ILEA, + IADDW, + ISUBW, + IMULW, + IMULB, + IMOVW, + IMOVM, + ILTW, + IEQW, + ILEQW, + IBEQW, + IBNEQW, + IEND, +}; + +enum +{ + AMP = 0x00, /* Src/Dst op addressing */ + AFP = 0x01, + AIMM = 0x02, + AXXX = 0x03, + AIND = 0x04, + AMASK = 0x07, + AOFF = 0x08, + AVAL = 0x10, + + ARM = 0xC0, /* Middle op addressing */ + AXNON = 0x00, + AXIMM = 0x40, + AXINF = 0x80, + AXINM = 0xC0, + + IBY2WD = sizeof(WORD), + REGRET = 4, + + StrSize = 256, + ArrHead = IBY2WD * 4, +}; + +#define SRC(x) ((x)<<3) +#define DST(x) ((x)<<0) +#define USRC(x) (((x)>>3)&AMASK) +#define UDST(x) ((x)&AMASK) +#define UXSRC(x) ((x)&(AMASK<<3)) +#define UXDST(x) ((x)&(AMASK<<0)) diff --git a/lex.c b/lex.c new file mode 100644 index 0000000..6e7138b --- /dev/null +++ b/lex.c @@ -0,0 +1,323 @@ +#include "yo.h" + +#define isend(x) (*(x)==0) + +static void popimport(void); + +typedef struct +{ + char *name; + int tok; +}Keywd; + +static Keywd keywd[] = { + {"len", Llen}, + {"return", Lret}, + {"fn", Lfn}, + {"for", Lfor}, + {"if", Lif}, + {"else", Lelse}, + {"var", Lvar}, + {"type", Ltype}, + {"struct", Lstruct}, + {"export", Lexport}, + {"import", Limport}, + {"package", Lpackage}, +}; + +static int bstack; +static FILE *bin; +static Token un; +FILE *bins[1024]; + +static Sym **syms; +static int nsym; +static int isym; +static int ineof; + +static int +Getc(void) +{ + if(ineof) + return EOF; + int c = fgetc(bin); + if(c == EOF) + ineof = 1; + return c; +} + +static void +Ungetc(int c) +{ + if(ineof) + return; + ungetc(c, bin); +} + +static int +isident(int c) +{ + return isdigit(c) || isalpha(c) || c == '_'; +} + +static Token +lexstr(void) +{ + char id[StrSize + 1]; + char *p = id; + int i = 0; + for(;;){ + int c = Getc(); + assert(c != EOF); + if(c == '\"') + break; + assert(i++ < StrSize); + *p++ = c; + } + *p = '\0'; + Sym *sym = new(sizeof(Sym)); + sym->len = i; + sym->name = new(p - id + 1); + memcpy(sym->name, id, p-id+1); + return (Token){.kind=Lsconst, .sym=sym}; +} + +static Token +lexid(void) +{ + char id[StrSize + 1]; + char *p = id; + int i = 0, c = Getc(); + for(;;){ + assert(i++ < StrSize); + *p++ = c; *p = '\0'; + c = Getc(); + if(c==EOF|| isident(c) == 0){ + Ungetc(c); + break; + } + } + Sym *sym = enter(id, Lid); + Token tok = (Token){.kind=sym->tok}; + if(tok.kind == Lid ||tok.kind == Ltid || tok.kind==Lconst) + tok.sym = sym; + return tok; +} + +static Token +lexnum(void) +{ + int v = Getc() - '0'; + for(;;){ + int c = Getc(); + if(c==EOF || isdigit(c) == 0){ + Ungetc(c); + break; + } + v = v * 10 + c - '0'; + } + return (Token){.kind=Lconst, .num=v}; +} + +static Token +lexing(void) +{ + for(;;){ + int c = Getc(); + if(c == EOF){ + popimport(); + if(bstack == -1) + return (Token){.kind=Leof}; + return (Token){.kind=Leof}; + } + if(isspace(c) || c =='\n') + continue; + if(isdigit(c)){ + Ungetc(c); + return lexnum(); + } + if(isident(c)){ + Ungetc(c); + return lexid(); + } + switch(c){ + case '\"': + return lexstr(); + case '(': case ')': case '[': case ']': + case '}': case '{': case ',': case ';': + return (Token){.kind=c}; + case '!': + if((c = Getc()) == '=') + return (Token){.kind=Lneq}; + Ungetc(c); + return (Token){.kind='!'}; + case '=': + if((c = Getc()) == '=') + return (Token){.kind=Leq}; + Ungetc(c); + return (Token){.kind='='}; + case '>': + if((c = Getc()) == '=') + return (Token){.kind=Lgeq}; + Ungetc(c); + return (Token){.kind='>'}; + case '<': + if((c = Getc()) == '=') + return (Token){.kind=Lleq}; + Ungetc(c); + return (Token){.kind='<'}; + case '.': + return (Token){.kind=c}; + case ':': + if((c = Getc()) == '=') + return (Token){.kind=Ldas}; + Ungetc(c); + return (Token){.kind=':'}; + case '+':case '-': case '*': case '&': + return (Token){.kind=c}; + default: + assert(0); + } + } +} + +void +unlex(Token tok) +{ + un = tok; +} + +Token +lex(void) +{ + if(un.kind != EOF){ + Token t = un; + un = (Token){.kind = EOF}; + return t; + } + Token t = lexing(); + if(t.kind == EOF){ + return (Token){.kind=EOF}; + } + return t; +} + +Token +peek(int *arr) +{ + Token t = lex(); + unlex(t); + while(!isend(arr)) + if(*arr++ == t.kind) + return t; + return (Token){.kind=Lnone}; +} + +Token +try(int *arr) +{ + Token t = lex(); + while(!isend(arr)) + if(t.kind == *arr++) + return t; + unlex(t); + return (Token){.kind=Lnone}; +} + +Token +want(int *arr) +{ + Token t = lex(); + while(!isend(arr)) + if(t.kind == *arr++) + return t; + assert(0); +} + +void +lexinit(void) +{ + bstack = -1; + for(int i = 0; i < elem(keywd); ++i){ + enter(keywd[i].name, keywd[i].tok); + } +} + +Sym* +dotsym(void) +{ + char id[StrSize + 1]; + char *p = id; + int c; + while(isspace(c=Getc())) + ; + int i = 0; + for(;;){ + assert(i++ < StrSize); + *p++ = c; *p = '\0'; + c = Getc(); + if(c==EOF||(isident(c)==0&&c!='.')){ + Ungetc(c); + break; + } + } + Sym *s = new(sizeof(Sym)); + s->len = i; + s->name = new(i+1); + memcpy(s->name, id, i+1); + un = (Token){.kind=-1}; + return s; +} + +void +lexstart(char *name) +{ + FILE *f = fopen(name, "r"); + assert(f!=nil); + un = (Token){.kind = EOF}; + ineof = 0; + bin = bins[++bstack] = f; +} + +Sym* +enter(char *name, int tok) +{ + int l = strlen(name); + for(int i = 0; i < isym; ++i){ + Sym *s = syms[i]; + if(s && l==s->len && memcmp(name, s->name, l)==0) + return s; + } + Sym *s = new(sizeof(Sym)); + s->name = new(l+1); + memcpy(s->name, name, l+1); + s->len = l; + if(tok == 0) + tok = Lid; + s->tok = tok; + if(isym + 1 >= nsym){ + nsym += 16; + syms = realloc(syms, nsym*sizeof(Sym*)); + } + return syms[isym++] = s; +} + +static void +popimport(void) +{ + ineof = 0; + fclose(bin); + bstack -= 1; + bin = bins[bstack]; +} + +void +importdef(Sym *file) +{ + char buf[1024]={0}; + sprintf(buf, "%s/exported", file->name); + FILE *b = fopen(buf, "r"); + assert(b != nil); + assert(bstack + 1 < sizeof(bins)); + bin = bins[++bstack] = b; +} \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..d2cb98b --- /dev/null +++ b/main.c @@ -0,0 +1,102 @@ +#include "yo.h" + +int nsrc; +int ninst; +int nimport; +int nfn; +int nexport; +int ntype; +int nvar; +Import *imports; +Decl **fns; +Decl **exports; +Decl **types; +Decl **vars; +Sym *pkgname; +char *path; + +int +streq(char *a, char *b) +{ + if(a==b) + return 1; + for(;*a && *b;){ + if(*a != *b) + return 0; + a += 1; + b += 1; + } + return *a == *b; +} + +int +isimported(Sym *p) +{ + for(int i = 0; i < nimport; ++i){ + if(streq(imports[i].path->name, p->name)) + return 1; + } + return 0; +} + +int +isexported(Decl *d) +{ + for(int i = 0; i < nexport; ++i){ + if(exports[i] == d) + return 1; + } + return 0; +} + +void +buildpkg(char *path, char **srcs, int n) +{ + typestart(); + declstart(); + + Node **trees = parsefiles(srcs, n); + + for(int i = 0; i < n; ++i) + gdecl(trees[i]); + for(int i = 0; i < n; ++i) + gbind(trees[i]); + for(int i = 0; i < n; ++i) + gassert(trees[i]); + maxloopdep = 0; + fns = new(sizeof(Decl*)*(nfn+1)); + vars = new(sizeof(Decl*)*(nvar+1)); + types = new(sizeof(Decl*)*(ntype+1)); + exports = new(sizeof(Decl*)*(nexport+1)); + for(int i = 0; i < n; ++i) + gentry(trees[i]); + for(int i = 0; i < nfn; ++i) + assertfn(fns[i]); + + genstart(); + for(int i = 0; i < nfn; ++i){ + fncom(fns[i]); + } + firstinst = firstinst->next; +} + +int +main(int argc, char **argv) +{ + path = getpath(); + char **srcs = getfiles(path, ".yo"); + if(nsrc == 0) + return; + + lexinit(); + typeinit(); + + buildpkg(path, srcs, nsrc); + + ninst = resolvepcs(firstinst); + + genexports("exported"); + genbin("obj"); + + asminst(stdout, firstinst); +} diff --git a/makefile b/makefile new file mode 100644 index 0000000..9289ede --- /dev/null +++ b/makefile @@ -0,0 +1,19 @@ +CFLAGS= -g -O0 -std=c99 -Wall -Wextra + +SRCS=$(wildcard *.c) +OBJS=$(SRCS:.c=.o) + +com: $(OBJS) + $(CC) $(CFLAGS) -o $@ $^ + make -C ./vm + cp ./vm/run . + +$(OBJS): yo.h isa.h fn.h dat.h + +tests: + ./com fib.yo + ./run obj + +clean: + rm -f com $(OBJS) obj exported run + make clean -C ./vm diff --git a/node.c b/node.c new file mode 100644 index 0000000..76bdde5 --- /dev/null +++ b/node.c @@ -0,0 +1,106 @@ +#include "yo.h" + +Node* +mkscope(Node *body) +{ + Node *n = mkn(Oscope, nil, body); + return n; +} + +Node* +mkunray(int op, Node *l) +{ + Node *n = mkn(op, l, nil); + return n; +} + +Node* +retalloc(Node *n, Node *nn) +{ + if(nn->ty == tnone) + return nil; + *n = (Node){0}; + n->op = Oxref; + n->addable = Radr; + n->l = dupn(&retnode); + n->ty = nn->ty; + return n; +} + +Node* +dupn(Node *n) +{ + Node *nn = new(sizeof(Node)); + *nn = *n; + if(n->l) + nn->l = dupn(nn->l); + if(n->r) + nn->r = dupn(nn->r); + return nn; +} + +void* +new(int s) +{ + void *r = calloc(1, s); + assert(r != 0); + return r; +} + +Node* +mkn(int op, Node *l, Node *r) +{ + Node *n = new(sizeof(Node)); + n->op = op; + n->l = l; + n->r = r; + return n; +} + +Node* +mksconst(Sym *s) +{ + Node *n = mkn(Oconst, NULL, NULL); + n->ty = tstring; + n->decl = mkdecl(Dconst, tstring); + n->decl->sym = s; + return n; +} + +Node* +mkbool(int v) +{ + Node *n = mkn(Oconst, nil, nil); + n->ty = tbool; + n->val = v != 0; + return n; +} + +Node* +mkconst(int v) +{ + Node *n = mkn(Oconst, NULL, NULL); + n->ty = tint; + n->val = v; + return n; +} + +Node* +mkname(Sym *s) +{ + Node *n = mkn(Oname, nil, nil); + if(s->unbound == nil){ + s->unbound = mkdecl(Dunbound, nil); + s->unbound->sym = s; + } + n->decl = s->unbound; + return n; +} + +Node* +fndecl(Node *n, Type *t, Node *body) +{ + Node *fn = mkn(Ofn, n, body); + fn->ty = t; + return fn; +} \ No newline at end of file diff --git a/parse.c b/parse.c new file mode 100644 index 0000000..7554509 --- /dev/null +++ b/parse.c @@ -0,0 +1,917 @@ +#include "yo.h" + +static Node* sourcefile(void); +static Type* parameters(void); +static Node* expr(void); +static Node* exprlist(void); +static Node* topdecl(void); +static Node* decltype(void); +static Node* declvar(void); +static Type* type(void); +static Node* primaryexprs(void); +static void importdecl(void); +static Node* litvalue(void); +static Node* operand(void); +static Node* stmtlist(void); + +Node* +parse(char *name) +{ + lexstart(name); + want((int[]){Lpackage, 0}); + Sym *s = want((int[]){Lid, 0}).sym; + if(pkgname == nil) + pkgname = s; + assert(pkgname==nil || pkgname == s); + importdecl(); + Node *n = sourcefile(); + return n; +} + +Node** +parsefiles(char **srcs, int n) +{ + Node **arr = new(sizeof(Node*)*(n+1)); + for(int i = 0; i < n; ++i){ + arr[i] = parse(srcs[i]); + } + return arr; +} + +static Sym* +trygetpkg(Sym *s) +{ + if(s->decl&&s->decl->ty&&s->decl->ty->kind == Tpkg){ + if(try((int[]){'.',0}).kind != '.') + return nil; + Sym *ss = want((int[]){Lid,0}).sym; + Decl *d = isinpkg(s->decl->ty->ids, ss); + assert(d != nil); + return d->sym; + } + return nil; +} + +static Node* +sconstval(void) +{ + Token t = want((int[]){Lsconst,0}); + return mksconst(t.sym); +} + +static Node* +constval(void) +{ + Node *n; + + Token t = want((int[]){Lconst,0}); + if(t.sym == truedecl->sym){ + n = mkn(Oconst, nil, nil); + n->ty = tbool; + n->val = 1; + }else if(t.sym == falsedecl->sym){ + n = mkn(Oconst, nil, nil); + n->ty = tbool; + n->val = 0; + }else + n = mkconst(t.num); + return n; +} + +static Decl* +ident(void) +{ + Token t = want((int[]){Lid,0}); + return mkids(t.sym, nil, nil); +} + +// identlist = Lid {',' Lid} +static Decl* +identlist(void) +{ + Decl h={0}, *p=&h; + + p = p->next = ident(); + for(;try((int[]){',',0}).kind;){ + p = p->next = ident(); + } + return h.next; +} + +static Node* +name(void) +{ + Sym *s = want((int[]){Lid,0}).sym; + Sym *p = trygetpkg(s); + if(p){ + Node *n = mkn(Opkg,nil,nil); + n->decl = p->decl; + n->ty = p->decl->ty; + return n; + } + return mkname(s); +} + +// argments = '(' exprlist ')' +static Node* +argments(void) +{ + want((int[]){'(',0}); + if(try((int[]){')',0}).kind) + return nil; + Node *n = exprlist(); + if(n->op != Oseq) + n = mkn(Oseq, n, nil); + want((int[]){')',0}); + return n; +} + +static Node* +compoundexpr(void) +{ + Node *n; + + want((int[]){'(',0}); + n = exprlist(); + want((int[]){')',0}); + assert(n->op == Oseq); + return mkn(Otup, n, nil); +} + +static Node* +bltlen(void) +{ + want((int[]){Llen,0}); + want((int[]){'(',0}); + Node *l = name(); + want((int[]){')',0}); + Node *n = mkn(Olen, l, nil); + return n; +} + +// ElementList = KeyedElement { "," KeyedElement } . +// KeyedElement = [ Key ":" ] Element . +// Key = FieldName | Expression | LiteralValue . +// FieldName = identifier . +// Element = Expression | LiteralValue . +static Node* +element(void) +{ + if(peek((int[]){'{',0}).kind) + return litvalue(); + return expr(); +} + +static Node* +elemlist(void) +{ + Node h={0}, *p=&h; + + p = p->r = mkn(Oseq, element(), nil); + while(try((int[]){',',0}).kind) + p = p->r = mkn(Oseq, element(), nil); + return h.r; +} + +// LiteralValue = "{" [ ElementList [ "," ] ] "}" . +static Node* +litvalue(void) +{ + want((int[]){'{',0}); + if(try((int[]){'}', 0}).kind) + return nil; + Node *n = elemlist(); + want((int[]){'}',0}); + return n; +} + +static Node* +compositelit(void) +{ + Token t = want((int[]){Lid,0}); + Node *n = litvalue(); + n = mkn(Ostruct, n, nil); + n->ty = mkidtype(t.sym); + return n; +} + +static int +litlen(Node *n) +{ + int i = 0; + for(; n; n=n->r) + ++i; + return i; +} + +static Node* +arraylit(void) +{ + Type *t = type(); + Node *n = litvalue(); + int l = litlen(n); + if(t->len) + assert(t->len >= l); + else + t->len = l; + n = mkn(Oarray, n, nil); + n->ty = t; + return n; +} + +static Node* +operand(void) +{ + Token t = peek((int[]){Lid,Lstruct,Lsconst,Lconst,Llen,'(','[',0}); + switch(t.kind){ + case '[': return arraylit(); + case '(': return compoundexpr(); + case Lstruct: return compositelit(); + case Lid: return name(); + case Lsconst: return sconstval(); + case Lconst: return constval(); + case Llen: return bltlen(); + default: assert(0); + } +} + +static Node* +index(Node *id) +{ + Node *n=nil, *l=nil, *r=nil; + + want((int[]){'[',0}); + switch(try((int[]){':',']',0}).kind){ + case ']': + assert(0); + case ':': + if(try((int[]){']',0}).kind) + return mkn(Oslice, id, mkn(Oseq, nil, nil)); + n = mkn(Oslice, id, mkn(Oseq, nil, expr())); + break; + default: + l = expr(); + if(peek((int[]){']',0}).kind){ + n = mkn(Oindex, id, l); + break; + } + want((int[]){':',0}); + if(peek((int[]){']',0}).kind){ + n = mkn(Oslice, id, mkn(Oseq, l, nil)); + break; + } + r = expr(); + n = mkn(Oslice, id, mkn(Oseq, l, r)); + } + want((int[]){']',0}); + return n; +} + +static Node* +primaryexprs(void) +{ + Node h={0}, *p=&h; + + p = operand(); + for(;;){ + switch(peek((int[]){'.','(','[',0}).kind){ + case '.': + lex(); + p = mkn(Odot, p, operand()); + break; + case '(': p = mkn(Ocall, p, argments()); break; + case '[': p = index(p); break; + default: return p; + } + } +} + +// unrayexpr = primaryexprs | unray-op unrayexpr +static Node* +unrayexpr(void) +{ + switch(try((int[]){'+','-','*','/','&',0}).kind){ + default: return primaryexprs(); + case '+': + case '-': + case '!': + case '/': + case '^': assert(0); + case '*': return mkn(Oxref, unrayexpr(), nil); + case '&': return mkn(Oref,unrayexpr(), nil); + } +} + +// mul-op = ('*'|'/') primary +static Node* +mulop(void) +{ + int c; + Node *p = unrayexpr(); + while((c = try((int[]){'*','/',0}).kind)) + switch(c){ + case '*': + p = mkn(Omul, p, unrayexpr()); + break; + default: + assert(0); + } + return p; +} + +// add-op = [mul-op] ('+'|'-') expr +static Node* +addop(void) +{ + int c; + Node *p = mulop(); + while((c = try((int[]){'+','-',0}).kind)) + switch(c){ + case '+': p = mkn(Oadd, p, mulop()); break; + case '-': p = mkn(Osub, p, mulop()); break; + default: + assert(0); + } + return p; +} + +static Node* +relop(void) +{ + int c, op; + Node *p = addop(); + while((c = try((int[]){Leq,Lneq,Lgeq,Lleq,'>','<',0}).kind)){ + switch(c){ + case '<': op = Olt; break; + case '>': op = Ogt; break; + case Leq: op = Oeq; break; + case Lneq: op = Oneq; break; + case Lgeq: op = Ogeq; break; + case Lleq: op = Oleq; break; + default: assert(0); + } + p = mkn(op, p, addop()); + } + return p; +} + +static Node* +expr(void) +{ + return relop(); +} + +// exprlist = expr {',' expr } +static Node* +exprlist(void) +{ + Node h={0}, *p=&h; + + p->r = expr(); + if(peek((int[]){',',0}).kind == 0) + return p->r; + p = p->r = mkn(Oseq, p->r, nil); + for(;try((int[]){',',0}).kind;){ + p = p->r = mkn(Oseq, expr(), nil); + } + return h.r; +} + +// estmt = expr +// SimpleStmt = Assignment +Node* +sstmt(void) +{ + Node *r = nil; + Node *l = exprlist(); + switch(try((int[]){'=',Ldas,0}).kind){ + case '=': + r = exprlist(); + return mkn(Oas, l, r); + case Ldas: + r = exprlist(); + return mkn(Odas, l, r); + default: + return l; + } +} + +static Node* +retstmt(void) +{ + want((int[]){Lret,0}); + if(peek((int[]){';',0}).kind) + return mkn(Oret, nil, nil); + Node *n = expr(); + return mkn(Oret, n, nil); +} + +// block = '{' stmtlist '}' +static Node* +block(void) +{ + want((int[]){'{',0}); + Node *n = stmtlist(); + n = mkscope(n); + want((int[]){'}',0}); + return n; +} + +static Node* +ifstmt(void) +{ + Node *n,*l,*p,*r, *c = nil; + + want((int[]){Lif,0}); + l = sstmt(); + if(try((int[]){';',0}).kind) + c = expr(); + p = mkunray(Oseq, block()); + if(c) n = mkn(Oscope, l, mkn(Oif, c, p)); + else n = mkn(Oif, l, p); + + for(c = nil; try((int[]){Lelse,0}).kind; c = nil){ + if(try((int[]){Lif,0}).kind){ + l = sstmt(); + if(try((int[]){';',0}).kind) + c = expr(); + r = mkunray(Oseq, block()); + if(c) p->r = mkn(Oscope, l, mkn(Oif, c, r)); + else p->r = mkn(Oif, l, r); + p = r; + }else + p->r = block(); + } + return n; +} + +// for [ cond | forclause | rangeclause ] block +// ForClause = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] . +static Node * +mkfor(Node *init, Node *cond, Node *post, Node *body) +{ + Node *n; + + n = mkn(Oseq, body, post); + n = mkn(Ofor, cond, n); + if(init) + return mkn(Oscope, init, n); + return n; +} + +static Node* +forstmt(void) +{ + Node *i=nil, *c=nil, *p=nil, *tmp=nil; + + want((int[]){Lfor,0}); + if(peek((int[]){'{',0}).kind) + return mkfor(i, mkbool(1), nil, block()); + + if(peek((int[]){';',0}).kind == 0) + tmp = sstmt(); + if(peek((int[]){'{',0}).kind){ + assert((c = tmp) != nil); + assert(c->op != Odas && c->op != Oas); + return mkfor(nil, c, nil, block()); + } + want((int[]){';',0}); + i = tmp; + tmp = nil; + if(try((int[]){';',0}).kind) + c = mkbool(1); + else if(peek((int[]){'{'}).kind) + assert(0); + else{ + c = expr(); + want((int[]){';',0}); + } + + if(peek((int[]){'{'}).kind) + return mkfor(i, c, nil, block()); + p = sstmt(); + assert(p->op != Odas); + return mkfor(i, c, p, block()); +} + +// stmt = simple-stmt | decl +static Node* +stmt(void) +{ + switch(peek((int[]){Lret,Lif,Lfor,Ltype,Lvar,'{',0}).kind){ + case Lret: return retstmt(); + case Lfor: return forstmt(); + case Lif: return ifstmt(); + case Ltype: return decltype(); + case Lvar: return declvar(); + case '{': return block(); + default: return sstmt(); + } +} + +static Node* +stmtlist(void) +{ + Node h={0}, *p=&h; + + for(;peek((int[]){'}',0}).kind==0;){ + p = p->r = mkn(Oseq, stmt(), nil); + want((int[]){';',0}); + } + return h.r; +} + +// '{' stmtlist '}' +static Node* +fbody(void) +{ + want((int[]){'{',0}); + if((try((int[]){'}',0})).kind) + return nil; + Node *n = stmtlist(); + want((int[]){'}',0}); + return n; +} + +// StructType = "struct" "{" { FieldDecl ";" } "}" . +// FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] . +// EmbeddedField = [ "*" ] TypeName [ TypeArgs ] . +// Tag = string_lit . +static Node* +field(void) +{ + Decl *ids = identlist(); + Decl *t = typeids(ids, type()); + want((int[]){';', 0}); + return fielddecl(Dfield, t); +} + +static Node* +fields(void) +{ + Node h={0}, *p=&h; + + for(;;) + switch(peek((int[]){Lid,Ltid,0}).kind){ + case Lid: + case Ltid: p = p->r = mkn(Oseq, field(), nil); break; + default: return h.r; + } +} + +// [identlist] Type +static Decl* +paramdecl(void) +{ + Decl *ids = identlist(); + Type *t = type(); + return typeids(ids, t); +} + +// paramdecl {"," paramdecl} +static Decl* +paramlist(void) +{ + Decl h={0}, *p = &h; + + p = p->next = paramdecl(); + for(;try((int[]){',',0}).kind==',';) + p = p->next = paramdecl(); + return h.next; +} + +// "(" [parameterlist [ ',' ] ] ")" +static Type* +parameters(void) +{ + Decl h={0}, *p=&h; + + want((int[]){'(',0}); + for(;try((int[]){')',0}).kind==0;) + p = p->next = paramlist(); + return mktype(Tfn, 0, tnone, h.next); +} + +static Type* +arraytype(void) +{ + Type *ty; + Token t; + + want((int[]){'[',0}); + switch((t = try((int[]){Lid,Lconst,0})).kind){ + case Lid: + assert(t.sym->decl == _decl); + want((int[]){']',0}); + ty = mktype(Tarray, 0, type(), nil); + ty->len = 0; + return ty; + case Lconst: + assert(t.num > 0); + want((int[]){']',0}); + ty = mktype(Tarray, 0, type(), nil); + assert((ty->len = t.num) > 0); + return ty; + default : assert(0); + } +} + +static Type* +type(void) +{ + Type h = {0}, *p=&h; + Sym *s; + + Token t = want((int[]){Lid,Ltid,'*','[',0}); + switch(t.kind){ + case '*': + do{ + p = p->tof = mktype(Tptr, IBY2WD, nil, nil); + }while(try((int[]){'*',0}).kind); + p->tof = type(); + return h.tof; + case Lid: + case Ltid: + if((s = trygetpkg(t.sym))) return s->decl->ty; + else return mkidtype(t.sym); + case '[': unlex(t); return arraytype(); + default: assert(0); + } +} + +// type ["," type] +static Decl* +typelist(void) +{ + Decl h={0}, *p=&h; + + p = p->next = mkids(nil, type(), nil); + for(;try((int[]){',',0}).kind==',';) + p = p->next = mkids(nil, type(), nil); + return h.next; +} + +static Type* +tuptype(void) +{ + want((int[]){'(',0}); + Decl *d = typelist(); + want((int[]){')',0}); + assert(d->next != nil); + return mktype(Ttup, 0, nil, d); +} + +static Type* +fnresult(void) +{ + switch(peek((int[]){Lid, Ltid,'[','*','(',0}).kind){ + case '[': + case '*': + case Lid: + case Ltid: return type(); + case '(': return tuptype(); + default: return tnone; + } +} + +// parameters [result] +static Type* +signature(void) +{ + Type *param = parameters(); + param->tof = fnresult(); + return param; +} + +// funcdecl "fn" Lid signature fbody +static Node* +declfn(void) +{ + want((int[]){Lfn,0}); + Node *nm = name(); + Type *s = signature(); + Node *b = fbody(); + Node *n = fndecl(nm, s, b); + return n; +} + +// var-spec = identlist (Type ['=' exprlist] | '=' exprlist ) +// var-decl = Lvar varspec +static Node* +declvar(void) +{ + want((int[]){Lvar,0}); + Decl *d = identlist(); + Type *t = type(); + switch(peek((int[]){';','=',0}).kind){ + case ';': return vardecl(d, t); + default:assert(0); + } +} + +// type-decl = Ltype Lid (Lstruct) '{' fields '}' +static Node* +decltype(void) +{ + want((int[]){Ltype,0}); + Token t = want((int[]){Lid,0}); + Decl *id = mkids(t.sym, 0, nil); + want((int[]){Lstruct,0}); + want((int[]){'{',0}); + Node *f = fields(); + want((int[]){'}',0}); + return structdecl(id, f); +} + +static Node* +decl(void) +{ + switch(peek((int[]){Ltype,Lvar,0}).kind){ + case Ltype: return decltype(); + case Lvar: return declvar(); + default: assert(0); + } +} + +static Node* +declexport(void) +{ + Node *n; + + want((int[]){Lexport,0}); + switch(peek((int[]){Lfn,Lvar,Ltype,0}).kind){ + case Lfn: n=declfn(); break; + case Ltype: n=decltype(); break; + case Lvar: n=declvar(); break; + default: assert(0); + } + return mkn(Oexport, n, nil); +} + +static Node* +topdecl(void) +{ + switch(peek((int[]){Lexport,Lfn,0}).kind){ + case Lexport: return declexport(); + case Lfn: return declfn(); + default: return decl(); + } +} + +// SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } . +static Node* +sourcefile(void) +{ + Node h={0}, *p = &h; + + for(;;){ + switch(peek((int[]){EOF,0}).kind){ + case EOF: return h.r; + default: + p=p->r=mkn(Oseq, topdecl(), nil); + want((int[]){';',0}); + break; + } + } + return h.r; +} + +static Type* +imtype(void) +{ + Type *t = mkidtype(dotsym()); + t->kind = want((int[]){Lconst,0}).num; + t->size = want((int[]){Lconst,0}).num; + t->offset = want((int[]){Lconst,0}).num; + return t; +} + +static Type* +imparam(int n) +{ + if(n == 0) + return nil; + Type *res = mktype(Tpfn, 0, nil, nil); + res->size = want((int[]){Lconst,0}).num; + Decl h, *p=&h; + for(int i = 0; i < n; i++){ + Type *t = imtype(); + Decl *d = mkids(nil, t, nil); + d->offset = t->offset; + p = p->next = d; + } + res->ids = h.next; + return res; +} + +static Type* +imret(int n) +{ + if(n == 0) + return tnone; + if(n == 1){ + want((int[]){Lconst,0}); + want((int[]){Lconst,0}); + return imtype(); + } + Type *res = mktype(Ttup, 0, nil, nil); + res->size = want((int[]){Lconst,0}).num; + res->offset = want((int[]){Lconst,0}).num; + Decl h, *p = &h; + for(int i = 0; i < n; i++){ + p = p->next = mkids(nil, imtype(), nil); + } + res->ids = h.next; + return res; +} + +static Decl* +imdeclfn(void) +{ + want((int[]){Lfn,0}); + Sym *s = dotsym(); + int sz = want((int[]){Lconst,0}).num; + int pc = want((int[]){Lconst,0}).num; + int args = want((int[]){Lconst,0}).num; + int rets = want((int[]){Lconst,0}).num; + Type *t = imparam(args); + t->tof = imret(rets); + Decl *d = mkids(s, t, nil); + d->pc = new(sizeof(Inst)); + d->store = Dpkg; + d->offset = sz; + d->pc->pc = pc; + d->pc->m.reg = nimport; + s->decl = d; + return d; +} + +static Decl* +imstruct(void) +{ + want((int[]){Ltype,0}); + Sym *s = dotsym(); + want((int[]){Lstruct,0}); + Type *t = mktype(Tstruct, 0, nil, nil); + t->size = want((int[]){Lconst,0}).num; + int n = want((int[]){Lconst,0}).num; + Decl *res = mkids(s, t, nil); + res->store = Dtype; + Decl h={0}, *p=&h; + for(int i = 0; i < n; ++i){ + Decl *c = ident(); + c->ty = imtype(); + c->dot = res; + c->store = Dfield; + p = p->next = c; + } + t->ids = h.next; + t->decl = res; + s->decl = res; + return res; +} + +static Decl* +imfields(Import *i) +{ + Decl h, *p=&h, *t; + for(;;){ + switch(peek((int[]){Lfn,Ltype,Leof,0}).kind){ + default : assert(0); + case Leof: return h.next; + case Ltype: t = imstruct(); break; + case Lfn: + t = imdeclfn(); + break; + } + p = p->next = t; + } +} + +static void +entryimport(Import *i, Sym *path) +{ + i->path = path; + Decl *id = ident(); + i->sym = id->sym; + i->decls = imfields(i); + Type *ty = mktype(Tpkg, 0, nil, i->decls); + id->ty = ty; + for(Decl *p=ty->ids; p; p=p->next) + p->dot = id; + installids(Dpkg, id); +} + +static void +importdecl(void) +{ + for(;try((int[]){Limport,0}).kind;){ + Sym *path = want((int[]){Lsconst, 0}).sym; + if(isimported(path)) + return; + imports = realloc(imports, (nimport+1)*sizeof(Import)); + importdef(path); + entryimport(&imports[nimport], path); + nimport += 1; + } +} \ No newline at end of file diff --git a/test/fib.yo b/test/fib.yo new file mode 100644 index 0000000..6f9658a --- /dev/null +++ b/test/fib.yo @@ -0,0 +1,13 @@ +package a + +fn main() int { + x := fib(10); + return x; +}; + +fn fib(n int) int{ + if n <= 1 { + return n; + }; + return fib(n-1) + return fib(n-2); +}; diff --git a/type.c b/type.c new file mode 100644 index 0000000..49a0a79 --- /dev/null +++ b/type.c @@ -0,0 +1,404 @@ +#include "yo.h" + +Sym *anontupsym; +Type *tnone; +Type *tbool; +Type *tint; +Type *tstring; +Type *tany; /* nil ptr */ +Type *tptr; + +Type* +mktype(int kind, int size, Type *tof, Decl *args) +{ + Type *t = new(sizeof(Type)); + t->kind = kind; + t->size = size; + t->tof = tof; + t->ids = args; + return t; +} + +Decl* +mkdecl(int store, Type *t) +{ + Decl *d = new(sizeof(Decl)); + d->store = store; + d->ty = t; + d->nid = 1; + return d; +} + +Decl* +mkids(Sym *s, Type *t, Decl *next) +{ + Decl *d = mkdecl(Dundef, t); + d->next = next; + d->sym = s; + return d; +} + +Type* +mkidtype(Sym *s) +{ + Type *t = mktype(Tid, 0, nil, nil); + if(s->unbound == 0){ + s->unbound = mkdecl(Dunbound, nil); + s->unbound->sym = s; + } + t->decl = s->unbound; + return t; +} + +Node* +structdecl(Decl *id, Node *f) +{ + Node *n = mkn(Ostrdecl, nil, nil); + Type *t = mktype(Tstruct, 0, nil, nil); + id->ty = t; + n->decl = id; + n->l = f; + n->ty = t; + t->decl = id; + return n; +} + +void +typebuiltin(Decl *d, Type *t) +{ + d->ty = t; + t->decl = d; + installids(Dtype, d); +} + +void +typeinit(void) +{ + anontupsym = enter(".tuple", 0); + + tint = mktype(Tint, IBY2WD, nil, nil); + tint->offset = IBY2WD; + + tbool = mktype(Tbool, IBY2WD, nil, nil); + tbool->offset = IBY2WD; + + tnone = mktype(Tnone, 0, nil, nil); + tany = mktype(Tany, IBY2WD, nil, nil); + + + tstring = mktype(Tstring, IBY2WD, nil, nil); + tstring->offset = IBY2WD; +} + +void +typestart(void) +{ + Sym *s; + Decl *d; + + s = enter("int", 0); + d = mkids(s, nil, nil); + typebuiltin(d, tint); + + s = enter("bool", 0); + d = mkids(s, nil, nil); + typebuiltin(d, tbool); + + s = enter("string", 0); + d = mkids(s, nil, nil); + typebuiltin(d, tstring); +} + +Node* +fielddecl(int store, Decl *ids) +{ + Node *n = mkn(Ofielddecl, nil, nil); + n->decl = ids; + for(; ids; ids=ids->next) + ids->store = store; + return n; +} + +Decl* +typeids(Decl *ids, Type *t) +{ + if(ids == nil) + return nil; + ids->ty = t; + for(Decl *id = ids->next; id; id=id->next) + id->ty = t; + return ids; +} + +int +idssize(Decl *d, int off) +{ + for(; d; d=d->next){ + bindsize(d->ty); + off = align(off); + d->offset = off; + off += d->ty->size; + } + return off; +} + +int +bindsize(Type *t) +{ + if(t == nil) + return 0; + switch(t->kind){ + case Tnone: + case Tint: + case Tbool: + break; + case Tslice: t->size=ArrHead; break; + case Tarray: t->size=t->len*bindsize(t->tof)+ArrHead; break; + case Tref: + case Tptr: + t->size = IBY2WD; + bindsize(t->tof); + break; + case Tfn: + t->size = 0; + idssize(t->ids, 56); + bindsize(t->tof); + break; + case Tpkg: + t->size = IBY2WD; + idssize(t->ids,0); + break; + case Tstruct: + case Ttup: + t->size = idssize(t->ids, 0); + t->size = align(t->size); + t->offset = t->size; + break; + default: + assert(0); + } + return t->size; +} + +void +bindtypes(Type *t) +{ + Decl *id = nil; + switch(t->kind){ + case Tnone: + case Tpkg: + case Tpfn: + case Tint: + case Tbool: + break; + case Tslice: + case Tarray: + case Tref: + case Tptr: + bindtypes(t->tof); + break; + case Tid: + id = t->decl->sym->decl; + assert(id != nil); + id->sym->unbound = nil; + t->decl = id; + *t = *id->ty; + break; + case Tfn: + for(id = t->ids; id; id=id->next) + bindtypes(id->ty); + bindtypes(t->tof); + break; + case Ttup: + case Tstruct: + for(id = t->ids; id; id=id->next) + bindtypes(id->ty); + break; + default: + assert(0); + } +} + +void +gbind(Node *n) +{ + for(; ; n=n->r){ + if(n==nil) + return; + if(n->op != Oseq) + break; + gbind(n->l); + } + Decl *d = nil; + switch(n->op){ + case Odas: + case Oas: + case Ovardecl: + case Ofn: break; + case Oexport: gbind(n->l); break; + case Ofielddecl: bindtypes(n->decl->ty); break; + case Ostrdecl: + bindtypes(n->ty); + repushids(n->ty->ids); + gbind(n->l); + d = popids(n->ty->ids); + assert(d == nil); + break; + default: + assert(0); + } +} + +Type* +resolvetype(Type *t) +{ + Decl *d = t->decl; + assert(d->store != Dunbound); + if(d->store != Dtype){ + assert(d->store != Dundef); + assert(d->store != Dwundef); + } + assert(d->ty != nil); + return d->ty; +} + +void +assertstruct(Type *t) +{ + Decl *p = t->decl; + for(Decl *id = t->ids; id; id=id->next){ + assert(id->store == Dfield); + id->dot = p; + } + for(Decl *id = t->ids; id; id=id->next){ + id->dot = p; + id->ty = isvalidty(id->ty); + } +} + +Type* +asserttype(Type *t) +{ + int i = 0; + Decl *id = nil; + switch(t->kind){ + case Tnone: + case Tint: + case Tpkg: + case Tpfn: + case Tbool: + case Tslice: + break; + case Tarray: assert(t->len != 0); + case Tref: + case Tptr: + t->tof = asserttype(t->tof); + break; + case Tid:t = asserttype(resolvetype(t)); break; + case Tstruct: assertstruct(t); break; + case Tfn: + for(id = t->ids; id; id=id->next){ + id->store = Darg; + id->ty = asserttype(id->ty); + } + t->tof = asserttype(t->tof); + break; + case Ttup: + if(t->decl == nil){ + t->decl = mkdecl(Dtype, t); + t->decl->sym = enter(".tuple", 0); + } + for(Decl *id=t->ids; id; id=id->next){ + id->store = Dfield; + if(id->sym == nil){ + char buf[64] = {0}; + sprintf(buf, "t%d", i); + id->sym = enter(buf, 0); + } + i += 1; + id->ty = asserttype(id->ty); + } + break; + default: + assert(0); + } + return t; +} + +Type* +isvalidty(Type *t) +{ + bindtypes(t); + t = asserttype(t); + if(t->kind != Tpkg && t->kind!=Tpfn) + bindsize(t); + return t; +} + +Type* +usetype(Type *t) +{ + if(t == nil) + return nil; + t = isvalidty(t); + return t; +} + +int +eqtup(Type *t1, Type *t2) +{ + Decl *d1 = t1->ids, *d2 = t2->ids; + for(; d1 && d2; d1=d1->next, d2=d2->next){ + if(eqtype(d1->ty, d2->ty) == 0) + return 0; + } + return d1 == d2; +} + +int +eqtype(Type *t1, Type *t2) +{ + if(t1 == t2) + return 1; + if(t1 == nil || t2 == nil) + return 0; + if(t1->kind != t2->kind){ + if(t1->kind != Tptr || t2->kind != Tref) + return 0; + } + switch(t1->kind){ + case Tslice: + return eqtype(t1->tof, t2->tof); + case Tarray: + return t1->len == t2->len && eqtype(t1->tof, t2->tof); + case Tptr: + return eqtype(t1->tof, t2->tof); + case Tnone: + case Tint: + case Tbool: + return 1; + case Ttup: + case Tstruct: + return eqtup(t1, t2); + } + return 0; +} + +Decl* +isinids(Decl *ids, Sym *s) +{ + for(; ids; ids=ids->next) + if(ids->sym == s) + return ids; + return nil; +} + +Decl* +isinpkg(Decl *ids, Sym *s) +{ + for(; ids; ids=ids->next){ + if(ids->sym->len-1 == s->len && memcmp(s->name, ids->sym->name+1, s->len)==0) + return ids; + } + return nil; +} \ No newline at end of file diff --git a/vm/dec.c b/vm/dec.c new file mode 100644 index 0000000..931a5d0 --- /dev/null +++ b/vm/dec.c @@ -0,0 +1,222 @@ +#include "vm.h" +// 000 LO(MP) offset indirect from MP +// 001 LO(FP) offset indirect from FP +// 010 $OP 30 bit immediate +// 011 none no operand +// 100 SO(SO(MP)) double indirect from MP +// 101 SO(SO(FP)) double indirect from FP +// 110 reserved +// 111 reserved + +#define DIND(reg, xxx) (u8*)((*(WORD*)(R.reg+R.PC->xxx.f))+R.PC->xxx.s) + +static void +D09(void) +{ + R.s = R.FP+R.PC->s.ind; + R.d = R.FP+R.PC->d.ind; + R.m = R.d; +} +static void +D0A(void) +{ + R.s = R.FP+R.PC->s.ind; + R.d = (u8*)&R.PC->d.imm; + R.m = R.d; +} +static void +D0B(void) +{ + R.s = R.FP+R.PC->s.ind; +} +static void +D0D(void) +{ + R.s = R.FP+R.PC->s.ind; + R.d = DIND(FP, d); + R.m = R.d; +} +static void +D0F(void) +{ + R.s = R.FP+R.PC->s.ind; +} +static void +D11(void) +{ + R.s = (u8*)&R.PC->s.imm; + R.d = R.FP+R.PC->d.ind; + R.m = R.d; +} +static void +D15(void) +{ + R.s = (u8*)&R.PC->s.imm; + R.d = DIND(FP, d); + R.m = R.d; +} +static void +D1A(void) +{ + R.d = (u8*)&R.PC->d.imm; + R.m = R.d; +} +static void +D1B(void) /* 11 011 */ +{ +} +static void +D29(void) +{ + R.s = DIND(FP, s); + R.d = R.FP+R.PC->d.ind; + R.m = R.d; +} +static void +D2D(void) +{ + R.s = DIND(FP, s); + R.d = DIND(FP, d); + R.m = R.d; +} +static void +D32(void) +{ + R.d = (u8*)&R.PC->d.imm; + R.m = R.d; +} +static void +D49(void) +{ + R.s = R.FP+R.PC->s.ind; + R.d = R.FP+R.PC->d.ind; + R.t = (i16)R.PC->reg; + R.m = &R.t; +} +static void +D4A(void) +{ + R.s = R.FP+R.PC->s.ind; + R.d = (u8*)&R.PC->d.imm; + R.t = (i16)R.PC->reg; + R.m = &R.t; +} +static void +D4D(void) +{ + R.s = R.FP+R.PC->s.ind; + R.d = DIND(FP, d); + R.t = (i16)R.PC->reg; + R.m = &R.t; +} +static void +D51(void) +{ + R.s = (i8*)&R.PC->s.imm; + R.d = R.FP+R.PC->d.ind; + R.t = (i16)R.PC->reg; + R.m = &R.t; +} +static void +D52(void) +{ + R.s = (u8*)&R.PC->s.imm; + R.d = (u8*)&R.PC->d.imm; + R.t = (i16)R.PC->reg; + R.m = &R.t; +} +static void +D55(void) +{ + R.s = (u8*)&R.PC->s.imm; + R.d = DIND(FP, d); + R.t = (i16)R.PC->reg; + R.m = &R.t; +} +static void +D69(void) +{ + R.s = DIND(FP, s); + R.d = R.FP+R.PC->d.ind; + R.t = (i16)R.PC->reg; + R.m = &R.t; +} +static void +D89(void) +{ + R.s = R.FP+R.PC->s.ind; + R.d = R.FP+R.PC->d.ind; + R.m = R.FP+R.PC->reg; +} +static void +D8A(void) +{ + R.s = R.FP+R.PC->s.ind; + R.d = (u8*)&R.PC->d.imm; + R.m = R.FP+R.PC->reg; +} +static void +D8D(void) +{ + R.s = R.FP+R.PC->s.ind; + R.d = DIND(FP, d); + R.m = R.FP+R.PC->reg; +} +static void +D91(void) +{ + R.s = (u8*)&R.PC->s.imm; + R.d = R.FP+R.PC->d.ind; + R.m = R.FP+R.PC->reg; +} +static void +D95(void) +{ + R.s = (u8*)&R.PC->s.imm; + R.d = DIND(FP, d); + R.m = R.FP+R.PC->reg; +} +static void +DA9(void) +{ + R.s = DIND(FP, s); + R.d = R.FP+R.PC->d.ind; + R.m = R.FP+R.PC->reg; +} +static void +DAD(void) +{ + R.s = DIND(FP, s); + R.d = DIND(FP, d); + R.m = R.FP+R.PC->reg; +} + +void (*dec[])(void) = +{ + [0x09] = D09, + [0x0A] = D0A, + [0x0B] = D0B, + [0x0D] = D0D, + [0x0F] = D0F, + [0x11] = D11, + [0x15] = D15, + [0x1B] = D1B, + [0x1A] = D1A, + [0x29] = D29, + [0x2D] = D2D, + [0x32] = D32, + [0x49] = D49, + [0x4A] = D4A, + [0x4D] = D4D, + [0x51] = D51, + [0x52] = D52, + [0x55] = D55, + [0x69] = D69, + [0x89] = D89, + [0x8A] = D8A, + [0x8D] = D8D, + [0x91] = D91, + [0x95] = D95, + [0xA9] = DA9, + [0xAD] = DAD, +}; diff --git a/vm/makefile b/vm/makefile new file mode 100644 index 0000000..a1e0527 --- /dev/null +++ b/vm/makefile @@ -0,0 +1,12 @@ +CFLAGS= -g -O0 -std=c99 -Wall -Wextra -I ../ + +SRCS=$(wildcard *.c) +OBJS=$(SRCS:.c=.o) + +run: $(OBJS) + $(CC) $(CFLAGS) -o $@ $^ + +$(OBJS): vm.h ../isa.h + +clean: + rm -f run $(OBJS) diff --git a/vm/vm.c b/vm/vm.c new file mode 100644 index 0000000..f4b9660 --- /dev/null +++ b/vm/vm.c @@ -0,0 +1,278 @@ +#include "vm.h" + +static u8 end[1]; +u32 ninst; +Inst *inst; +REG R; + +#define OP(fn) void fn(void) +#define B(r) *((i8*)(R.r)) +#define F(r) ((WORD*)(R.r)) +#define A(r) ((Array*)(R.r)) +#define P(r) *((WORD**)(R.r)) +#define W(r) *((WORD*)(R.r)) +#define T(r) *((void**)(R.r)) +#define JMP(r) R.PC = *(Inst**)(R.r) + +void +printbin(u8 x) +{ + u8 arr[8] = { + [0] = x & 128, + [1] = x & 64, + [2] = x & 32, + [3] = x & 16, + [4] = x & 8, + [5] = x & 4, + [6] = x & 2, + [7] = x & 1, + }; + printf("op %x %d: ",x, x); + printf("%d%d ", arr[0]!=0,arr[1]!=0); + printf("%d%d%d ", arr[2]!=0,arr[3]!=0,arr[4]!=0); + printf("%d%d%d\n", arr[5]!=0,arr[6]!=0,arr[7]!=0); +} + +u8 +rd1(FILE *f) +{ + u8 v = 0; + assert(fread(&v, 1, 1, f) == 1); + return v; +} +u16 +rd2(FILE *f) +{ + u16 v = 0; + assert(fread(&v, 1, 2, f) == 2); + return v; +} +u32 +rd4(FILE *f) +{ + u32 v = 0; + assert(fread(&v, 1, 4, f) == 4); + return v; +} + +void +newstack(int sz) +{ + Stack *s = calloc(1, sizeof(s)+sz); + R.EX = s->stack; + R.TS = s->stack + sz; + R.SP = s->fu + sz; + R.FP = s->fu; +} + +void +initprog(int ss) +{ + newstack(ss); + WORD *p = (WORD*)&R.FP[32]; + *p = (WORD)&end; + +} +OP(nop) {} +OP(jmp) {JMP(d);} +OP(lea) {W(d) = (WORD)R.s;} +OP(movw) {W(d) = W(s);} +OP(movm) {memmove(R.d,R.s,W(m));} +OP(addw) {W(d) = W(m) + W(s);} +OP(subw) {W(d) = W(m) - W(s);} +OP(mulw) {W(d) = W(m) * W(s);} +OP(beqw) {if(W(s) == W(m)) JMP(d);} +OP(bneqw) {if(W(s) != W(m)) JMP(d);} +OP(ltw) {W(d) = (W(s) < W(m));} +OP(leqw) {W(d) = (W(s) <= W(m));} +OP(eqw) {W(d) = (W(s) == W(m));} +OP(frame){ + Stack *s; + Frame *f; + int sz; + + sz = W(s); + s = calloc(1, sizeof(Stack) + sz); + s->sz = sz; + s->SP = R.SP; + s->TS = R.TS; + s->EX = R.EX; + f = s->fr; + R.s = f; + R.EX = s; + R.TS = s->stack + sizeof(Stack)+sz; + R.SP = s->fu + sz; + T(d) = R.s; +} +OP(call){ + Frame *f = T(s); + f->lr = R.PC; + f->fp = R.FP; + R.FP = (u8*)f; + JMP(d); +} +OP(ret) { + Frame *f = (Frame*)R.FP; + R.FP = f->fp; + if(R.FP == NULL){ + printf("result %ld\n", W(d)); + exit(0); + } + R.SP = (u8*)f; + R.PC = f->lr; + + u8 *x = (u8*)f-IBY2WD*4; + Stack *s = x; + R.SP = s->SP; + R.TS = s->TS; + R.EX = s->EX; + free(s); +} +OP(len){ + Array *a = A(s); + W(d) = a->len; +} +OP(array){ + WORD *s = R.s; + WORD m = W(m); + WORD *d = R.d; + if(m){ + *d = (WORD)&d[ArrHead/IBY2WD]; + memcpy(d+1, s+1, m-IBY2WD); + }else + assert(0); +} +OP(slice){ + WORD s1 = W(s); + WORD s2 = W(m); + Array *a = A(d); + + if(s2 == -1) + s2 = a->len; + assert(s1 >= 0 && s1 < a->len); + assert(s2 >= 0 && s2 < a->len); + Array d = *a; + d.len = s2 - s1; + d.cap = s2 - s1; + d.arr = a->arr + s1*a->size; + *a = d; +} +static void (*optab[])(void) = { + [INOP] = nop, + [ILEA] = lea, + [IFRAME] = frame, + [ICALL] = call, + [IJMP] = jmp, + [IRET] = ret, + [ILEN] = len, + [ISLICE] = slice, + [IARRAY] = array, + [IADDW] = addw, + [ISUBW] = subw, + [IMOVW] = movw, + [IMULW] = mulw, + [IMOVM] = movm, + [IBEQW] = beqw, + [IBNEQW] = bneqw, + [IEQW] = eqw, + [ILEQW] = leqw, + [ILTW] = ltw, +}; + +void +xec(void) +{ + while(1){ + Inst in = *R.PC; + u8 op = in.op; + if(dec[in.add] == 0){ + printbin(in.add); + exit(1); + } + if(optab[in.op]==0){ + printf("op 0X%x %d\n", in.op, in.op); + exit(1); + } + dec[in.add](); + R.PC++; + optab[op](); + } +} + +void +bpatch(Inst *i) +{ + static int tab[IEND] = { + [ICALL]=1,[IBEQW]=1,[IBNEQW]=1,[IJMP]=1, + }; + if(tab[i->op] == 0) + return; + assert(i->d.imm >= 0 && i->d.imm < ninst); + i->d.imm = (WORD)&inst[i->d.imm]; + return; +} + +void +rdinst(FILE *f, Inst *in) +{ + in->op = rd1(f); + assert(in->op != EOF); + in->add = rd1(f); + switch(in->add & ARM) { + case AXIMM: + case AXINF: + case AXINM: + in->reg = rd4(f); + break; + } + switch(UXSRC(in->add)) { + case SRC(AFP): + case SRC(AMP): + case SRC(AIMM): + in->s.ind = rd4(f); + break; + case SRC(AIND|AFP): + case SRC(AIND|AMP): + in->s.f = rd2(f); + in->s.s = rd2(f); + break; + } + switch(UXDST(in->add)) { + case DST(AFP): + case DST(AMP): + in->d.ind = rd4(f); + break; + case DST(AIMM): + in->d.ind = rd4(f); + bpatch(in); + break; + case DST(AIND|AFP): + case DST(AIND|AMP): + in->d.f = rd2(f); + in->d.s = rd2(f); + break; + } +} + +void +load(char *fname) +{ + FILE *f = fopen(fname, "r"); + assert(f != 0); + initprog(1024); + ninst = rd4(f); + inst = calloc(sizeof(Inst), ninst); + + for(u32 i = 0; i < ninst; ++i){ + rdinst(f, inst+i); + } + R.PC = inst; + fclose(f); +} + +int +main(int argc, char *argv[]) +{ + load(argv[1]); + xec(); +} diff --git a/vm/vm.h b/vm/vm.h new file mode 100644 index 0000000..498aed3 --- /dev/null +++ b/vm/vm.h @@ -0,0 +1,76 @@ +#include "isa.h" +#include +#include +#include +#include +#include + +typedef struct Inst Inst; +typedef union Adr Adr; +typedef struct REG REG; +typedef struct Array Array; +typedef struct Frame Frame; +typedef union Stack Stack; + +union Adr +{ + WORD imm; + WORD ind; + Inst* ins; + struct { + u16 f; /* First */ + u16 s; /* Second */ + }; +}; + +struct Inst +{ + u8 op; + u8 add; + u16 reg; + Adr s; + Adr d; +}; + +struct Frame +{ + Inst *lr; + u8 *fp; +}; + +union Stack +{ + u8 stack[1]; + struct{ + int sz; + u8 *SP; + u8 *TS; + u8 *EX; + union{ + u8 fu[1]; + Frame fr[1]; + }; + }; +}; + +struct REG +{ + Inst *PC; + u8 *FP; + u8 *SP; + u8 *TS; + u8 *EX; + void *s, *d, *m; + int t, dt ,mt; +}; + +struct Array +{ + u8 *arr; + WORD len; + WORD cap; + WORD size; +}; + +extern REG R; +extern void (*dec[])(void); diff --git a/yo.h b/yo.h new file mode 100644 index 0000000..4f3e5d9 --- /dev/null +++ b/yo.h @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include "isa.h" +#include "dat.h" +#include "fn.h" + +#define elem(x) (sizeof(x)/sizeof((x)[0])) +#define nil ((void*)0) + +extern Decl *nildecl; +extern Decl *truedecl; +extern Decl *falsedecl; +extern Decl *_decl; +extern Sym *anontupsym; +extern Type *tnone; +extern Type *tint; +extern Type *tbool; +extern Type *tstring; +extern Type *tany; +extern Node retnode; +extern char* instname[]; + +extern int nimport; +extern int nfn; +extern int nexport; +extern int ntype; +extern int nvar; +extern Import *imports; +extern Decl **fns; +extern Decl **exports; +extern Decl **types; +extern Decl **vars; +extern Inst *lastinst, *firstinst; + +extern Sym *pkgname; +extern char *path; +extern int ninst; +extern int nsrc; +extern Decl *fndecls; +extern int *blockstk; +extern int blockdep; +extern int nblock; +extern int blocks; +extern Decl *fndecls; +extern Node **labstk; +extern int loopdep; +extern int maxloopdep; \ No newline at end of file