first commit
This commit is contained in:
parent
b8ffc0632a
commit
f4b991f953
50
asm.c
Normal file
50
asm.c
Normal 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
465
assert.c
Normal 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
767
com.c
Normal 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
273
dat.h
Normal 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
315
decl.c
Normal 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
91
dis.c
Normal 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
105
exports.c
Normal 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
13
fib.yo
Normal 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
48
file.c
Normal 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
119
fn.h
Normal 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
478
gen.c
Normal 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
70
isa.h
Normal 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
323
lex.c
Normal 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
102
main.c
Normal 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
19
makefile
Normal 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
106
node.c
Normal 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
917
parse.c
Normal 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
13
test/fib.yo
Normal 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
404
type.c
Normal 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
222
vm/dec.c
Normal 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
12
vm/makefile
Normal 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
278
vm/vm.c
Normal 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
76
vm/vm.h
Normal 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
50
yo.h
Normal 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;
|
||||
Loading…
Reference in New Issue
Block a user