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