From f4b991f953380f43f7a5311f97e83dbfcb40002e Mon Sep 17 00:00:00 2001 From: yoyo Date: Sun, 3 Nov 2024 06:24:26 +0900 Subject: [PATCH] first commit --- asm.c | 50 +++ assert.c | 465 ++++++++++++++++++++++++++ com.c | 767 +++++++++++++++++++++++++++++++++++++++++++ dat.h | 273 ++++++++++++++++ decl.c | 315 ++++++++++++++++++ dis.c | 91 ++++++ exports.c | 105 ++++++ fib.yo | 13 + file.c | 48 +++ fn.h | 119 +++++++ gen.c | 478 +++++++++++++++++++++++++++ isa.h | 70 ++++ lex.c | 323 ++++++++++++++++++ main.c | 102 ++++++ makefile | 19 ++ node.c | 106 ++++++ parse.c | 917 ++++++++++++++++++++++++++++++++++++++++++++++++++++ test/fib.yo | 13 + type.c | 404 +++++++++++++++++++++++ vm/dec.c | 222 +++++++++++++ vm/makefile | 12 + vm/vm.c | 278 ++++++++++++++++ vm/vm.h | 76 +++++ yo.h | 50 +++ 24 files changed, 5316 insertions(+) create mode 100644 asm.c create mode 100644 assert.c create mode 100644 com.c create mode 100644 dat.h create mode 100644 decl.c create mode 100644 dis.c create mode 100644 exports.c create mode 100644 fib.yo create mode 100644 file.c create mode 100644 fn.h create mode 100644 gen.c create mode 100644 isa.h create mode 100644 lex.c create mode 100644 main.c create mode 100644 makefile create mode 100644 node.c create mode 100644 parse.c create mode 100644 test/fib.yo create mode 100644 type.c create mode 100644 vm/dec.c create mode 100644 vm/makefile create mode 100644 vm/vm.c create mode 100644 vm/vm.h create mode 100644 yo.h 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