first commit

This commit is contained in:
yoyo 2024-11-03 06:24:26 +09:00
parent b8ffc0632a
commit f4b991f953
24 changed files with 5316 additions and 0 deletions

50
asm.c Normal file
View File

@ -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;
}
}
}

465
assert.c Normal file
View File

@ -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;
}

767
com.c Normal file
View File

@ -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);
}

273
dat.h Normal file
View File

@ -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;
};

315
decl.c Normal file
View File

@ -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;
}

91
dis.c Normal file
View File

@ -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;
}

105
exports.c Normal file
View File

@ -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);
}

13
fib.yo Normal file
View File

@ -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);
};

48
file.c Normal file
View File

@ -0,0 +1,48 @@
#include "yo.h"
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
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;
}

119
fn.h Normal file
View File

@ -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);

478
gen.c Normal file
View File

@ -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;
}
}

70
isa.h Normal file
View File

@ -0,0 +1,70 @@
/* instructions */
#include <stdint.h>
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))

323
lex.c Normal file
View File

@ -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;
}

102
main.c Normal file
View File

@ -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);
}

19
makefile Normal file
View File

@ -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

106
node.c Normal file
View File

@ -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;
}

917
parse.c Normal file
View File

@ -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;
}
}

13
test/fib.yo Normal file
View File

@ -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);
};

404
type.c Normal file
View File

@ -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;
}

222
vm/dec.c Normal file
View File

@ -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,
};

12
vm/makefile Normal file
View File

@ -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)

278
vm/vm.c Normal file
View File

@ -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();
}

76
vm/vm.h Normal file
View File

@ -0,0 +1,76 @@
#include "isa.h"
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
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);

50
yo.h Normal file
View File

@ -0,0 +1,50 @@
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#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;