SVN=114202

This commit is contained in:
Ken Thompson 2008-03-28 13:41:41 -07:00
parent e311457488
commit cb87526ce3
14 changed files with 10958 additions and 0 deletions

377
src/c/const.c Normal file
View file

@ -0,0 +1,377 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go.h"
#define TUP(x,y) (((x)<<16)|(y))
void
convlit(Node *n, Node *t)
{
int et;
if(n->op != OLITERAL)
return;
if(t == N)
return;
n->type = t;
et = t->etype;
switch(whatis(n)) {
case Wlitint:
if(isptrto(t, TSTRING)) {
Rune rune;
int l;
String *s;
rune = n->val.vval;
l = runelen(rune);
s = mal(sizeof(*s)+l);
s->len = l;
runetochar((char*)(s->s), &rune);
n->val.sval = s;
n->val.ctype = CTSTR;
break;
}
if(isint[et]) {
if(n->val.vval < minintval[et])
goto bad2;
if(n->val.vval > maxintval[et])
goto bad2;
break;
}
if(isfloat[et]) {
if(n->val.vval < minfloatval[et])
goto bad2;
if(n->val.vval > maxfloatval[et])
goto bad2;
n->val.dval = n->val.vval;
n->val.ctype = CTFLT;
break;
}
goto bad1;
case Wlitfloat:
if(isint[et]) {
if(n->val.dval < minintval[et])
goto bad2;
if(n->val.dval > maxintval[et])
goto bad2;
n->val.vval = n->val.dval;
n->val.ctype = CTINT;
break;
}
if(isfloat[et]) {
if(n->val.dval < minfloatval[et])
goto bad2;
if(n->val.dval > maxfloatval[et])
goto bad2;
break;
}
goto bad1;
}
return;
bad1:
yyerror("illegal conversion of constant to %T", t);
return;
bad2:
yyerror("overflow converting constant to %T", t);
return;
}
void
evconst(Node *n)
{
Node *t, *nl, *nr;
long len;
String *str;
int wl, wr;
nl = n->left;
if(nl == N)
return;
switch(n->op) {
case OCONV:
t = n->type;
*n = *nl;
n->type = t;
return;
}
wl = whatis(nl);
switch(wl) {
default:
return;
case Wlitint:
case Wlitfloat:
case Wlitbool:
case Wlitstr:
break;
}
nr = n->right;
if(nr == N)
goto unary;
wr = whatis(nr);
switch(wr) {
default:
return;
case Wlitint:
case Wlitfloat:
case Wlitbool:
case Wlitstr:
break;
}
if(wl != wr) {
yyerror("illegal combination of literals %d %d", nl->etype, nr->etype);
return;
}
switch(TUP(n->op, wl)) {
default:
yyerror("illegal combination of literals %O %d", n->op, wl);
return;
case TUP(OADD, Wlitint):
nl->val.vval += nr->val.vval;
break;
case TUP(OSUB, Wlitint):
nl->val.vval -= nr->val.vval;
break;
case TUP(OMUL, Wlitint):
nl->val.vval *= nr->val.vval;
break;
case TUP(ODIV, Wlitint):
nl->val.vval /= nr->val.vval;
break;
case TUP(OMOD, Wlitint):
nl->val.vval %= nr->val.vval;
break;
case TUP(OLSH, Wlitint):
nl->val.vval <<= nr->val.vval;
break;
case TUP(ORSH, Wlitint):
nl->val.vval >>= nr->val.vval;
break;
case TUP(OOR, Wlitint):
nl->val.vval |= nr->val.vval;
break;
case TUP(OAND, Wlitint):
nl->val.vval &= nr->val.vval;
break;
case TUP(OADD, Wlitfloat):
nl->val.dval += nr->val.dval;
break;
case TUP(OSUB, Wlitfloat):
nl->val.dval -= nr->val.dval;
break;
case TUP(OMUL, Wlitfloat):
nl->val.dval *= nr->val.dval;
break;
case TUP(ODIV, Wlitfloat):
nl->val.dval /= nr->val.dval;
break;
case TUP(OEQ, Wlitint):
if(nl->val.vval == nr->val.vval)
goto settrue;
goto setfalse;
case TUP(ONE, Wlitint):
if(nl->val.vval != nr->val.vval)
goto settrue;
goto setfalse;
case TUP(OLT, Wlitint):
if(nl->val.vval < nr->val.vval)
goto settrue;
goto setfalse;
case TUP(OLE, Wlitint):
if(nl->val.vval <= nr->val.vval)
goto settrue;
goto setfalse;
case TUP(OGE, Wlitint):
if(nl->val.vval >= nr->val.vval)
goto settrue;
goto setfalse;
case TUP(OGT, Wlitint):
if(nl->val.vval > nr->val.vval)
goto settrue;
goto setfalse;
case TUP(OEQ, Wlitfloat):
if(nl->val.dval == nr->val.dval)
goto settrue;
goto setfalse;
case TUP(ONE, Wlitfloat):
if(nl->val.dval != nr->val.dval)
goto settrue;
goto setfalse;
case TUP(OLT, Wlitfloat):
if(nl->val.dval < nr->val.dval)
goto settrue;
goto setfalse;
case TUP(OLE, Wlitfloat):
if(nl->val.dval <= nr->val.dval)
goto settrue;
goto setfalse;
case TUP(OGE, Wlitfloat):
if(nl->val.dval >= nr->val.dval)
goto settrue;
goto setfalse;
case TUP(OGT, Wlitfloat):
if(nl->val.dval > nr->val.dval)
goto settrue;
goto setfalse;
case TUP(OEQ, Wlitstr):
if(cmpslit(nl, nr) == 0)
goto settrue;
goto setfalse;
case TUP(ONE, Wlitstr):
if(cmpslit(nl, nr) != 0)
goto settrue;
goto setfalse;
case TUP(OLT, Wlitstr):
if(cmpslit(nl, nr) < 0)
goto settrue;
goto setfalse;
case TUP(OLE, Wlitstr):
if(cmpslit(nl, nr) <= 0)
goto settrue;
goto setfalse;
case TUP(OGE, Wlitstr):
if(cmpslit(nl, nr) >= 0l)
goto settrue;
goto setfalse;
case TUP(OGT, Wlitstr):
if(cmpslit(nl, nr) > 0)
goto settrue;
goto setfalse;
case TUP(OADD, Wlitstr):
len = nl->val.sval->len + nr->val.sval->len;
str = mal(sizeof(*str) + len);
str->len = len;
memcpy(str->s, nl->val.sval->s, nl->val.sval->len);
memcpy(str->s+nl->val.sval->len, nr->val.sval->s, nr->val.sval->len);
str->len = len;
nl->val.sval = str;
break;
case TUP(OOROR, Wlitbool):
if(nl->val.vval || nr->val.vval)
goto settrue;
goto setfalse;
case TUP(OANDAND, Wlitbool):
if(nl->val.vval && nr->val.vval)
goto settrue;
goto setfalse;
}
*n = *nl;
return;
settrue:
*n = *booltrue;
return;
setfalse:
*n = *boolfalse;
return;
unary:
switch(TUP(n->op, wl)) {
default:
yyerror("illegal combination of literals %O %d", n->op, wl);
return;
case TUP(OPLUS, Wlitint):
nl->val.vval = +nl->val.vval;
break;
case TUP(OMINUS, Wlitint):
nl->val.vval = -nl->val.vval;
break;
case TUP(OCOM, Wlitint):
nl->val.vval = ~nl->val.vval;
break;
case TUP(OPLUS, Wlitfloat):
nl->val.dval = +nl->val.dval;
break;
case TUP(OMINUS, Wlitfloat):
nl->val.dval = -nl->val.dval;
break;
case TUP(ONOT, Wlitbool):
if(nl->val.vval)
goto settrue;
goto setfalse;
}
*n = *nl;
}
void
defaultlit(Node *n)
{
if(n == N)
return;
if(n->type != N)
return;
if(n->op != OLITERAL)
return;
switch(n->val.ctype) {
default:
yyerror("defaultlit: unknown literal: %N", n);
break;
case CTINT:
case CTSINT:
case CTUINT:
n->type = types[TINT32];
break;
case CTFLT:
n->type = types[TFLOAT64];
break;
case CTBOOL:
n->type = types[TBOOL];
break;
case CTSTR:
n->type = types[TSTRING];
break;
}
}
int
cmpslit(Node *l, Node *r)
{
long l1, l2, i, m;
uchar *s1, *s2;
l1 = l->val.sval->len;
l2 = r->val.sval->len;
s1 = l->val.sval->s;
s2 = r->val.sval->s;
m = l1;
if(l2 < m)
m = l2;
for(i=0; i<m; i++) {
if(s1[i] == s2[i])
continue;
if(s1[i] > s2[i])
return +1;
return -1;
}
if(l1 == l2)
return 0;
if(l1 > l2)
return +1;
return -1;
}

764
src/c/dcl.c Normal file
View file

@ -0,0 +1,764 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go.h"
#include "y.tab.h"
void
dodclvar(Node *n, Node *t)
{
loop:
if(n == N)
return;
if(n->op == OLIST) {
dodclvar(n->left, t);
n = n->right;
goto loop;
}
addvar(n, t, dclcontext);
}
void
dodcltype(Node *n, Node *t)
{
loop:
if(n == N)
return;
if(n->op == OLIST) {
dodcltype(n->left, t);
n = n->right;
goto loop;
}
addtyp(n, t, dclcontext);
}
void
dodclconst(Node *n, Node *e)
{
Sym *s;
Dcl *r, *d;
loop:
if(n == N)
return;
if(n->op == OLIST) {
dodclconst(n->left, e);
n = n->right;
goto loop;
}
if(n->op != ONAME)
fatal("dodclconst: not a name");
if(e->op != OLITERAL) {
yyerror("expression must be a constant");
goto loop;
}
s = n->sym;
s->oconst = e;
s->lexical = LACONST;
r = autodcl;
if(dclcontext == PEXTERN)
r = externdcl;
d = dcl();
d->dsym = s;
d->dnode = e;
d->op = OCONST;
r->back->forw = d;
r->back = d;
if(debug['d'])
print("const-dcl %S %N\n", n->sym, n->sym->oconst);
}
/*
* return nelem of list
*/
int
listcount(Node *n)
{
int v;
v = 0;
while(n != N) {
v++;
if(n->op != OLIST)
break;
n = n->right;
}
return v;
}
/*
* turn a parsed function declaration
* into a type
*/
Node*
functype(Node *this, Node *in, Node *out)
{
Node *t;
t = nod(OTYPE, N, N);
t->etype = TFUNC;
t->type = dostruct(this, TSTRUCT);
t->type->down = dostruct(out, TSTRUCT);
t->type->down->down = dostruct(in, TSTRUCT);
t->thistuple = listcount(this);
t->outtuple = listcount(out);
t->intuple = listcount(in);
return t;
}
void
funcnam(Node *t, char *nam)
{
Node *n;
Sym *s;
char buf[100];
if(nam == nil) {
vargen++;
snprint(buf, sizeof(buf), "_f%.3ld", vargen);
nam = buf;
}
if(t->etype != TFUNC)
fatal("funcnam: not func %T\n", t);
if(t->thistuple > 0) {
vargen++;
snprint(namebuf, sizeof(namebuf), "_t%.3ld", vargen);
s = lookup(namebuf);
addtyp(newtype(s), t->type, PEXTERN);
n = newname(s);
n->vargen = vargen;
t->type->nname = n;
}
if(t->outtuple > 0) {
vargen++;
snprint(namebuf, sizeof(namebuf), "_o%.3ld", vargen);
s = lookup(namebuf);
addtyp(newtype(s), t->type->down, PEXTERN);
n = newname(s);
n->vargen = vargen;
t->type->down->nname = n;
}
if(t->intuple > 0) {
vargen++;
snprint(namebuf, sizeof(namebuf), "_i%.3ld", vargen);
s = lookup(namebuf);
addtyp(newtype(s), t->type->down->down, PEXTERN);
n = newname(s);
n->vargen = vargen;
t->type->down->down->nname = n;
}
}
int
methcmp(Node *t1, Node *t2)
{
if(t1->etype != TFUNC)
return 0;
if(t2->etype != TFUNC)
return 0;
t1 = t1->type->down; // skip this arg
t2 = t2->type->down; // skip this arg
for(;;) {
if(t1 == t2)
break;
if(t1 == N || t2 == N)
return 0;
if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
return 0;
if(!eqtype(t1->type, t2->type, 0))
return 0;
t1 = t1->down;
t2 = t2->down;
}
return 1;
}
/*
* add a method, declared as a function,
* into the structure
*/
void
addmethod(Node *n, Node *pa, Node *t)
{
Node *p, *f, *d;
Sym *s;
if(n->op != ONAME)
goto bad;
s = n->sym;
if(s == S)
goto bad;
if(pa == N)
goto bad;
if(pa->etype != TPTR)
goto bad;
p = pa->type;
if(p == N)
goto bad;
if(p->etype != TSTRUCT)
goto bad;
if(p->sym == S)
goto bad;
if(p->type == N) {
n = nod(ODCLFIELD, newname(s), N);
n->type = t;
stotype(n, &p->type, p);
return;
}
d = N; // last found
for(f=p->type; f!=N; f=f->down) {
if(f->etype != TFIELD)
fatal("addmethod: not TFIELD: %N", f);
if(strcmp(s->name, f->sym->name) != 0) {
d = f;
continue;
}
// if a field matches a non-this function
// then delete it and let it be redeclared
if(methcmp(t, f->type)) {
if(d == N) {
p->type = f->down;
continue;
}
d->down = f->down;
continue;
}
if(!eqtype(t, f->type, 0))
yyerror("field redeclared as method: %S", s);
return;
}
n = nod(ODCLFIELD, newname(s), N);
n->type = t;
if(d == N)
stotype(n, &p->type, p);
else
stotype(n, &d->down, p);
return;
bad:
yyerror("unknown method pointer: %T", pa);
}
/*
* declare the function proper.
* and declare the arguments
* called in extern-declaration context
* returns in auto-declaration context.
*/
void
funchdr(Node *n)
{
Node *on;
Sym *s;
s = n->nname->sym;
on = s->oname;
// check for foreward declaration
if(on == N || !eqtype(n->type, on->type, 0)) {
// initial declaration or redeclaration
// declare fun name, argument types and argument names
funcnam(n->type, s->name);
n->nname->type = n->type;
if(n->type->thistuple == 0)
addvar(n->nname, n->type, PEXTERN);
} else {
// identical redeclaration
// steal previous names
n->nname = on;
n->type = on->type;
n->sym = s;
s->oname = n;
if(debug['d'])
print("forew var-dcl %S %T\n", n->sym, n->type);
}
// change the declaration context from extern to auto
autodcl = dcl();
autodcl->back = autodcl;
if(dclcontext != PEXTERN)
fatal("funchdr: dclcontext");
dclcontext = PAUTO;
funcargs(n->type);
if(n->type->thistuple > 0) {
Node *n1;
n1 = *getthis(n->type);
addmethod(n->nname, n1->type->type, n->type);
}
}
void
funcargs(Node *t)
{
Node *n1;
Iter save;
// declare the this argument
n1 = structfirst(&save, getthis(t));
if(n1 != N) {
if(n1->nname != N)
addvar(n1->nname, n1->type, PAUTO);
}
// declare the incoming arguments
n1 = structfirst(&save, getinarg(t));
while(n1 != N) {
if(n1->nname != N)
addvar(n1->nname, n1->type, PAUTO);
n1 = structnext(&save);
}
// declare the outgoing arguments
// n1 = structfirst(&save, getoutarg(t));
// while(n1 != N) {
// n1->left = newname(n1->sym);
// if(n1->nname != N)
// addvar(n1->nname, n1->type, PAUTO);
// n1 = structnext(&save);
// }
}
/*
* compile the function.
* called in auto-declaration context.
* returns in extern-declaration context.
*/
void
funcbody(Node *n)
{
compile(n);
// change the declaration context from auto to extern
if(dclcontext != PAUTO)
fatal("funcbody: dclcontext");
dclcontext = PEXTERN;
}
/*
* turn a parsed struct into a type
*/
Node**
stotype(Node *n, Node **t, Node *uber)
{
Node *f;
Iter save;
n = listfirst(&save, &n);
loop:
if(n == N) {
*t = N;
return t;
}
if(n->op == OLIST) {
// recursive because it can be lists of lists
t = stotype(n, t, uber);
goto next;
}
if(n->op != ODCLFIELD || n->type == N)
fatal("stotype: oops %N\n", n);
if(n->type->etype == TDARRAY)
yyerror("type of a structure field cannot be an open array");
f = nod(OTYPE, N, N);
f->etype = TFIELD;
f->type = n->type;
f->uberstruct = uber;
if(n->left != N && n->left->op == ONAME) {
f->nname = n->left;
} else {
vargen++;
snprint(namebuf, sizeof(namebuf), "_e%.3ld", vargen);
f->nname = newname(lookup(namebuf));
}
f->sym = f->nname->sym;
f->nname->uberstruct = uber; // can reach parent from element
*t = f;
t = &f->down;
next:
n = listnext(&save);
goto loop;
}
Node*
dostruct(Node *n, int et)
{
Node *t;
/*
* convert a parsed id/type list into
* a type for struct/interface/arglist
*/
t = nod(OTYPE, N, N);
stotype(n, &t->type, t);
t->etype = et;
return t;
}
Node*
sortinter(Node *n)
{
return n;
}
void
dcopy(Sym *a, Sym *b)
{
a->name = b->name;
a->oname = b->oname;
a->otype = b->otype;
a->oconst = b->oconst;
a->package = b->package;
a->opackage = b->opackage;
a->forwtype = b->forwtype;
a->lexical = b->lexical;
a->undef = b->undef;
a->vargen = b->vargen;
}
Sym*
push(void)
{
Sym *d;
d = mal(sizeof(*d));
d->link = dclstack;
dclstack = d;
return d;
}
Sym*
pushdcl(Sym *s)
{
Sym *d;
d = push();
dcopy(d, s);
return d;
}
void
popdcl(void)
{
Sym *d, *s;
// if(debug['d'])
// print("revert\n");
for(d=dclstack; d!=S; d=d->link) {
if(d->name == nil)
break;
s = pkglookup(d->name, d->package);
dcopy(s, d);
if(debug['d'])
print("\t%ld pop %S\n", curio.lineno, s);
}
if(d != S)
d = d->link;
dclstack = d;
}
void
markdcl(void)
{
Sym *d;
d = push();
d->name = nil; // used as a mark in fifo
// if(debug['d'])
// print("markdcl\n");
}
void
markdclstack(void)
{
Sym *d, *s;
markdcl();
// copy the entire pop of the stack
// all the way back to block0.
// after this the symbol table is at
// block0 and popdcl will restore it.
for(d=dclstack; d!=S; d=d->link) {
if(d == b0stack)
break;
if(d->name != nil) {
s = pkglookup(d->name, d->package);
pushdcl(s);
dcopy(s, d);
}
}
}
void
addvar(Node *n, Node *t, int ctxt)
{
Dcl *r, *d;
Sym *s;
Node *on;
int gen;
if(n==N || n->sym == S || n->op != ONAME || t == N)
fatal("addvar: n=%N t=%N nil", n, t);
on = t;
if(on->etype == TPTR)
on = on->type;
if(on->etype == TSTRUCT && on->vargen == 0) {
vargen++;
snprint(namebuf, sizeof(namebuf), "_s%.3ld", vargen);
addtyp(newtype(lookup(namebuf)), on, PEXTERN);
}
s = n->sym;
vargen++;
gen = vargen;
r = autodcl;
if(ctxt == PEXTERN) {
on = s->oname;
if(on != N) {
if(eqtype(t, on->type, 0)) {
warn("%S redeclared", s);
return;
}
yyerror("%S redeclared (%T %T)", s,
on->type, t);
}
r = externdcl;
gen = 0;
}
pushdcl(s);
s->vargen = gen;
s->oname = n;
n->type = t;
n->vargen = gen;
d = dcl();
d->dsym = s;
d->dnode = n;
d->op = ONAME;
r->back->forw = d;
r->back = d;
if(debug['d']) {
if(ctxt == PEXTERN)
print("extern var-dcl %S G%ld %T\n", s, s->vargen, t);
else
print("auto var-dcl %S G%ld %T\n", s, s->vargen, t);
}
}
void
addtyp(Node *n, Node *t, int ctxt)
{
Dcl *r, *d;
Sym *s;
Node *f, *ot;
if(n==N || n->sym == S || n->op != OTYPE || t == N)
fatal("addtyp: n=%N t=%N nil", n, t);
s = n->sym;
r = autodcl;
if(ctxt == PEXTERN) {
ot = s->otype;
if(ot != N) {
// allow nil interface to be
// redeclared as an interface
if(ot->etype == TINTER && ot->type == N && t->etype == TINTER) {
if(debug['d'])
print("forew typ-dcl %S G%ld %T\n", s, s->vargen, t);
s->otype = t;
return;
}
if(eqtype(t, ot, 0)) {
warn("%S redeclared", s);
return;
}
yyerror("%S redeclared (%T %T)", s,
ot, t);
}
r = externdcl;
}
pushdcl(s);
vargen++;
s->vargen = vargen;
s->otype = t;
s->lexical = LATYPE;
if(t->sym != S)
warn("addtyp: renaming %S to %S", t->sym, s);
t->sym = s;
t->vargen = vargen;
for(f=s->forwtype; f!=N; f=f->nforw) {
if(f->op != OTYPE && f->etype != TPTR)
fatal("addtyp: foreward");
f->type = t;
}
s->forwtype = N;
d = dcl();
d->dsym = s;
d->dnode = t;
d->op = OTYPE;
r->back->forw = d;
r->back = d;
if(debug['d']) {
if(ctxt == PEXTERN)
print("extern typ-dcl %S G%ld %T\n", s, s->vargen, t);
else
print("auto typ-dcl %S G%ld %T\n", s, s->vargen, t);
}
}
/*
* make a new variable
*/
Node*
tempname(Node *t)
{
Sym *s;
Node *n;
if(t == N) {
yyerror("tempname called with nil type");
t = types[TINT32];
}
s = lookup("!tmpname!");
n = newname(s);
dodclvar(n, t);
return n;
}
/*
* this generates a new name that is
* pushed down on the declaration list.
* no diagnostics are produced as this
* name will soon be declared.
*/
Node*
newname(Sym *s)
{
Node *n;
n = nod(ONAME, N, N);
n->sym = s;
n->type = N;
n->addable = 1;
n->ullman = 0;
return n;
}
/*
* this will return an old name
* that has already been pushed on the
* declaration list. a diagnostic is
* generated if no name has been defined.
*/
Node*
oldname(Sym *s)
{
Node *n;
n = s->oname;
if(n == N) {
yyerror("%S undefined", s);
n = newname(s);
dodclvar(n, types[TINT32]);
}
return n;
}
/*
* same for types
*/
Node*
newtype(Sym *s)
{
Node *n;
n = nod(OTYPE, N, N);
n->etype = TFORW;
n->sym = s;
n->type = N;
return n;
}
Node*
oldtype(Sym *s)
{
Node *n;
n = s->otype;
if(n == N)
fatal("%S not a type", s); // cant happen
return n;
}
Node*
forwdcl(Sym *s)
{
Node *n;
// this type has no meaning and
// will cause an error if referenced.
// it will be patched when/if the
// type is ever assigned.
n = nod(OTYPE, N, N);
n->etype = TFORW;
n = ptrto(n);
n->nforw = s->forwtype;
s->forwtype = n;
return n;
}

585
src/c/export.c Normal file
View file

@ -0,0 +1,585 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go.h"
#include "y.tab.h"
void
markexport(Node *n)
{
Sym *s;
Dcl *d, *r;
loop:
if(n == N)
return;
if(n->op == OLIST) {
markexport(n->left);
n = n->right;
goto loop;
}
if(n->op != OEXPORT)
fatal("markexport: op no OEXPORT: %O", n->op);
s = n->sym;
if(n->psym != S)
s = pkglookup(n->sym->name, n->psym->name);
if(s->export != 0)
return;
s->export = 1;
d = mal(sizeof(*d));
d->dsym = s;
d->dnode = N;
d->lineno = curio.lineno;
r = exportlist;
d->back = r->back;
r->back->forw = d;
r->back = d;
}
void
reexport(Node *t)
{
Sym *s;
if(t == N)
fatal("reexport: type nil\n");
s = t->sym;
if(s == S/* || s->name[0] == '_'*/) {
exportgen++;
snprint(namebuf, sizeof(namebuf), "_e%.3ld", exportgen);
s = lookup(namebuf);
s->lexical = LATYPE;
s->otype = t;
t->sym = s;
}
dumpexporttype(s);
}
void
dumpexportconst(Sym *s)
{
Node *n, *t;
if(s->exported != 0)
return;
s->exported = 1;
n = s->oconst;
if(n == N || n->op != OLITERAL)
fatal("dumpexportconst: oconst nil: %S\n", s);
t = n->type; // may or may not be specified
if(t != N)
reexport(t);
Bprint(bout, "\tconst ");
if(s->export != 0)
Bprint(bout, "!");
Bprint(bout, "%lS ", s);
if(t != N)
Bprint(bout, "%lS ", t->sym);
switch(n->val.ctype) {
default:
fatal("dumpexportconst: unknown ctype: %S\n", s);
case CTINT:
case CTSINT:
case CTUINT:
case CTBOOL:
Bprint(bout, "0x%llux\n", n->val.vval);
break;
case CTFLT:
Bprint(bout, "%.17e\n", n->val.dval);
break;
case CTSTR:
Bprint(bout, "\"%Z\"\n", n->val.sval);
break;
}
}
void
dumpexportvar(Sym *s)
{
Node *n, *t;
if(s->exported != 0)
return;
s->exported = 1;
n = s->oname;
if(n == N || n->type == N)
fatal("dumpexportvar: oname nil: %S\n", s);
t = n->type;
reexport(t);
Bprint(bout, "\tvar ");
if(s->export != 0)
Bprint(bout, "!");
Bprint(bout, "%lS %lS\n", s, t->sym);
}
void
dumpexporttype(Sym *s)
{
Node *t, *f;
Sym *ts;
int et;
if(s->exported != 0)
return;
s->exported = 1;
t = s->otype;
if(t == N || t->op != OTYPE)
fatal("dumpexporttype: otype nil: %S\n", s);
if(t->sym != s)
fatal("dumpexporttype: cross reference: %S\n", s);
et = t->etype;
switch(et) {
default:
if(et < 0 || et >= nelem(types) || types[et] == N)
fatal("dumpexporttype: basic type: %E\n", et);
/* type 5 */
Bprint(bout, "\ttype %lS %d\n", s, et);
break;
case TARRAY:
reexport(t->type);
/* type 2 */
Bprint(bout, "\ttype ");
if(s->export != 0)
Bprint(bout, "!");
Bprint(bout, "%lS [%lud] %lS\n", s, t->bound, t->type->sym);
break;
case TPTR:
reexport(t->type);
/* type 6 */
Bprint(bout, "\ttype ");
if(s->export != 0)
Bprint(bout, "!");
Bprint(bout, "%lS *%lS\n", s, t->type->sym);
break;
case TFUNC:
for(f=t->type; f!=N; f=f->down) {
if(f->op != OTYPE || f->etype != TSTRUCT)
fatal("dumpexporttype: funct not field: %O/%E\n",
f->op, f->etype);
reexport(f);
}
/* type 3 */
Bprint(bout, "\ttype ");
if(s->export != 0)
Bprint(bout, "!");
Bprint(bout, "%lS (", s);
for(f=t->type; f!=N; f=f->down) {
if(f != t->type)
Bprint(bout, " ");
Bprint(bout, "%lS", f->sym);
}
Bprint(bout, ")\n");
break;
case TSTRUCT:
case TINTER:
for(f=t->type; f!=N; f=f->down) {
if(f->op != OTYPE || f->etype != TFIELD)
fatal("dumpexporttype: funct not field: %O/%E\n",
f->op, f->etype);
reexport(f->type);
}
/* type 4 */
Bprint(bout, "\ttype ");
if(s->export)
Bprint(bout, "!");
Bprint(bout, "%lS %c", s, (et==TSTRUCT)? '{': '<');
for(f=t->type; f!=N; f=f->down) {
ts = f->type->sym;
if(f != t->type)
Bprint(bout, " ");
Bprint(bout, "%s %lS", f->sym->name, ts);
}
Bprint(bout, "%c\n", (et==TSTRUCT)? '}': '>');
break;
}
}
void
dumpe(Sym *s)
{
switch(s->lexical) {
default:
yyerror("unknown export symbol: %S\n", s, s->lexical);
break;
case LPACK:
yyerror("package export symbol: %S\n", s);
break;
case LATYPE:
case LBASETYPE:
dumpexporttype(s);
break;
case LNAME:
dumpexportvar(s);
break;
case LACONST:
dumpexportconst(s);
break;
}
}
void
dumpexport(void)
{
Dcl *d;
long lno;
lno = dynlineno;
Bprint(bout, " import\n");
Bprint(bout, " ((\n");
// print it depth first
for(d=exportlist->forw; d!=D; d=d->forw) {
dynlineno = d->lineno;
dumpe(d->dsym);
}
Bprint(bout, " ))\n");
dynlineno = lno;
}
/*
* ******* import *******
*/
Node*
importlooktype(Node *n)
{
Sym *s;
if(n->op != OIMPORT)
fatal("importlooktype: oops1 %N\n", n);
s = pkglookup(n->sym->name, n->psym->name);
if(s->otype == N)
fatal("importlooktype: oops2 %S\n", s);
return s->otype;
}
Node**
importstotype(Node *n, Node **t, Node *uber)
{
Node *f;
Iter save;
n = listfirst(&save, &n);
loop:
if(n == N) {
*t = N;
return t;
}
f = nod(OTYPE, N, N);
f->etype = TFIELD;
f->type = importlooktype(n);
f->uberstruct = uber;
if(n->fsym != S) {
f->nname = newname(n->fsym);
} else {
vargen++;
snprint(namebuf, sizeof(namebuf), "_m%.3ld", vargen);
f->nname = newname(lookup(namebuf));
}
f->sym = f->nname->sym;
f->nname->uberstruct = uber;
*t = f;
t = &f->down;
n = listnext(&save);
goto loop;
}
int
importcount(Node *t)
{
int i;
Node *f;
if(t == N || t->op != OTYPE || t->etype != TSTRUCT)
fatal("importcount: not a struct: %N", t);
i = 0;
for(f=t->type; f!=N; f=f->down)
i = i+1;
return i;
}
void
importfuncnam(Node *t)
{
Node *n, *n1;
if(t->etype != TFUNC)
fatal("importfuncnam: not func %T\n", t);
if(t->thistuple > 0) {
n1 = t->type;
if(n1->sym == S)
fatal("importfuncnam: no this");
n = newname(n1->sym);
vargen++;
n->vargen = vargen;
n1->nname = n;
}
if(t->outtuple > 0) {
n1 = t->type->down;
if(n1->sym == S)
fatal("importfuncnam: no output");
n = newname(n1->sym);
vargen++;
n->vargen = vargen;
n1->nname = n;
}
if(t->intuple > 0) {
n1 = t->type->down->down;
if(n1->sym == S)
fatal("importfuncnam: no input");
n = newname(n1->sym);
vargen++;
n->vargen = vargen;
n1->nname = n;
}
}
Sym*
getimportsym(Node *ss)
{
char *pkg;
Sym *s;
pkg = ss->psym->name;
if(ss->kaka) {
pkg = package;
if(pkgmyname != S)
pkg = pkgmyname->name;
}
s = pkglookup(ss->sym->name, pkg);
/* botch - need some diagnostic checking for the following assignment */
s->opackage = ss->osym->name;
return s;
}
void
importaddtyp(Node *ss, Node *t)
{
Sym *s;
s = getimportsym(ss);
if(s->otype == N || !eqtype(t, s->otype, 0)) {
addtyp(newtype(s), t, PEXTERN);
}
}
/*
* LCONST importsym LITERAL
* untyped constant
*/
void
doimportc1(Node *ss, Val *v)
{
Node *n;
Sym *s;
n = nod(OLITERAL, N, N);
n->val = *v;
s = getimportsym(ss);
if(s->oconst == N) {
// botch sould ask if already declared the same
dodclconst(newname(s), n);
}
}
/*
* LCONST importsym importsym LITERAL
* typed constant
*/
void
doimportc2(Node *ss, Node *st, Val *v)
{
Node *n, *t;
Sym *s;
n = nod(OLITERAL, N, N);
n->val = *v;
t = importlooktype(st);
n->type = t;
s = getimportsym(ss);
if(s->oconst == N) {
// botch sould ask if already declared the same
dodclconst(newname(s), n);
}
}
/*
* LVAR importsym importsym
* variable
*/
void
doimportv1(Node *ss, Node *st)
{
Node *t;
Sym *s;
t = importlooktype(st);
s = getimportsym(ss);
if(s->oname == N || !eqtype(t, s->oname->type, 0)) {
addvar(newname(s), t, dclcontext);
}
}
/*
* LTYPE importsym [ importsym ] importsym
* array type
*/
void
doimport1(Node *ss, Node *ss1, Node *s)
{
fatal("doimport1");
}
/*
* LTYPE importsym [ LLITERAL ] importsym
* array type
*/
void
doimport2(Node *ss, Val *b, Node *st)
{
Node *t;
Sym *s;
t = nod(OTYPE, N, N);
t->etype = TARRAY;
t->bound = b->vval;
s = pkglookup(st->sym->name, st->psym->name);
t->type = s->otype;
importaddtyp(ss, t);
}
/*
* LTYPE importsym '(' importsym_list ')'
* function/method type
*/
void
doimport3(Node *ss, Node *n)
{
Node *t;
t = nod(OTYPE, N, N);
t->etype = TFUNC;
t->type = importlooktype(n->left);
t->type->down = importlooktype(n->right->left);
t->type->down->down = importlooktype(n->right->right);
t->thistuple = importcount(t->type);
t->outtuple = importcount(t->type->down);
t->intuple = importcount(t->type->down->down);
importfuncnam(t);
importaddtyp(ss, t);
}
/*
* LTYPE importsym '{' importsym_list '}'
* structure type
*/
void
doimport4(Node *ss, Node *n)
{
Node *t;
t = nod(OTYPE, N, N);
t->etype = TSTRUCT;
importstotype(n, &t->type, t);
importaddtyp(ss, t);
}
/*
* LTYPE importsym LLITERAL
* basic type
*/
void
doimport5(Node *ss, Val *v)
{
int et;
Node *t;
et = v->vval;
if(et <= 0 || et >= nelem(types) || types[et] == N)
fatal("doimport5: bad type index: %E\n", et);
t = nod(OTYPE, 0, 0);
t->etype = et;
t->sym = S;
importaddtyp(ss, t);
}
/*
* LTYPE importsym * importsym
* pointer type
*/
void
doimport6(Node *ss, Node *st)
{
Node *t;
Sym *s;
s = pkglookup(st->sym->name, st->psym->name);
t = s->otype;
if(t == N)
t = forwdcl(s);
else
t = ptrto(t);
importaddtyp(ss, t);
}
/*
* LTYPE importsym '<' importsym '>'
* interface type
*/
void
doimport7(Node *ss, Node *n)
{
Node *t;
t = nod(OTYPE, N, N);
t->etype = TINTER;
importstotype(n, &t->type, t);
importaddtyp(ss, t);
}

1176
src/c/gen.c Normal file

File diff suppressed because it is too large Load diff

206
src/c/gen.h Normal file
View file

@ -0,0 +1,206 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#ifndef EXTERN
#define EXTERN extern
#endif
typedef struct Prog Prog;
typedef struct Addr Addr;
struct Addr
{
int type;
Node* node;
Prog* branch;
};
enum
{
AXXX = 0,
ANONE,
ANODE,
ABRANCH,
};
struct Prog
{
int op; // opcode
int pt;
int pt1;
int param;
long lineno; // source line
long loc; // program counter for print
int mark;
Addr addr; // operand
Prog* link;
};
#define P ((Prog*)0)
typedef struct Plist Plist;
struct Plist
{
Node* name;
Dcl* locals;
Prog* firstpc;
int recur;
Plist* link;
};
typedef struct Sig Sig;
struct Sig
{
char* fun;
ulong hash;
int offset;
Sig* link;
};
enum
{
PTxxx,
PTINT8 = TINT8,
PTUINT8 = TUINT8,
PTINT16 = TINT16,
PTUINT16 = TUINT16,
PTINT32 = TINT32,
PTUINT32 = TUINT32,
PTINT64 = TINT64,
PTUINT64 = TUINT64,
PTFLOAT32 = TFLOAT32,
PTFLOAT64 = TFLOAT64,
PTFLOAT80 = TFLOAT80,
PTBOOL = TBOOL,
PTPTR = TPTR,
PTSTRUCT = TSTRUCT,
PTINTER = TINTER,
PTARRAY = TARRAY,
PTSTRING = TSTRING,
PTCHAN = TCHAN,
PTMAP = TMAP,
PTNIL = NTYPE,
PTADDR,
PTERROR,
NPTYPE,
};
enum
{
PXXX = 0,
PERROR, PPANIC, PPRINT, PGOTO, PGOTOX,
PCMP, PTEST, PNEW, PLEN,
PCALL1, PCALL2, PCALLI2, PCALLM2, PCALLF2, PCALL3, PRETURN,
PBEQ, PBNE,
PBLT, PBLE, PBGE, PBGT,
PBTRUE, PBFALSE,
PLOAD, PLOADI,
PSTORE, PSTOREI,
PSTOREZ, PSTOREZIP,
PCONV, PADDR, PADDO, PINDEX, PINDEXZ,
PSLICE,
PADD, PSUB, PMUL, PDIV, PLSH, PRSH, PMOD,
PAND, POR, PXOR, PCAT,
PMINUS, PCOM,
PEND,
};
typedef struct Case Case;
struct Case
{
Prog* sprog;
Node* scase;
Case* slink;
};
#define C ((Case*)0)
EXTERN Prog* continpc;
EXTERN Prog* breakpc;
EXTERN Prog* pc;
EXTERN Prog* firstpc;
EXTERN Plist* plist;
EXTERN Plist* plast;
EXTERN Biobuf* bout;
EXTERN long dynloc;
/*
* gen.c
*/
void compile(Node*);
void proglist(void);
void gen(Node*);
void cgen(Node*);
void agen(Node*);
void bgen(Node*, int, Prog*);
void swgen(Node*);
Node* lookdot(Node*, Node*, int);
int usesptr(Node*);
void inarggen(void);
void cgen_as(Node*, Node*, int, int);
void cgen_asop(Node*, Node*, int);
void cgen_ret(Node*);
void cgen_call(Node*, int);
void cgen_callret(Node*, Node*);
void genprint(Node*);
int needconvert(Node*, Node*);
void genconv(Node*, Node*);
void genindex(Node*);
/*
* gsubr.c
*/
int Aconv(Fmt*);
int Pconv(Fmt*);
void proglist(void);
Prog* gbranch(int, Node*);
void patch(Prog*, Prog*);
Prog* prog(int);
Node* tempname(Node*);
Prog* gopcode(int, int, Node*);
Prog* gopcodet(int, Node*, Node*);
void gaddoffset(Node*);
void gconv(int, int);
int conv2pt(Node*);
void belexinit(int);
vlong convvtox(vlong, int);
int brcom(int);
int brrev(int);
void fnparam(Node*, int, int);
Sig* lsort(Sig*, int(*)(Sig*, Sig*));
/*
* obj.c
*/
void dumpobj(void);
void litrl(Prog*);
void obj(Prog*);
void follow(Prog*);
Prog* gotochain(Prog*);
int Xconv(Fmt*);
int Rconv(Fmt*);
int Qconv(Fmt*);
int Dconv(Fmt*);
int Cconv(Fmt*);
void dumpexterns(void);
void dumpfunct(Plist*);
void dumpsignatures(void);
void doframe(Dcl*, char*);
void docall1(Prog*);
void docall2(Prog*);
void docalli2(Prog*);
void docallm2(Prog*);
void docallf2(Prog*);
void docall3(Prog*);
void doconv(Prog*);
char* getfmt(int);
void dumpmethods(void);

513
src/c/go.h Normal file
View file

@ -0,0 +1,513 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
todo:
1. dyn arrays
2. multi
3. block 0
tothinkabout:
1. alias name name.name.name
2. argument in import
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#ifndef EXTERN
#define EXTERN extern
#endif
enum
{
NHUNK = 50000,
BUFSIZ = 8192,
NSYMB = 500,
NHASH = 1024,
STRINGSZ = 200,
YYMAXDEPTH = 500,
MAXALIGN = 7,
UINF = 100,
PRIME1 = 3,
PRIME2 = 10007,
PRIME3 = 10009,
PRIME4 = 10037,
PRIME5 = 10039,
PRIME6 = 10061,
PRIME7 = 10067,
PRIME8 = 10079,
PRIME9 = 10091,
};
/* note this is the representation
* of the compilers string literals,
* it happens to also be the runtime
* representation, but that may change */
typedef struct String String;
struct String
{
long len;
uchar s[3]; // variable
};
typedef struct Val Val;
struct Val
{
int ctype;
double dval;
vlong vval;
String* sval;
};
typedef struct Sym Sym;
typedef struct Node Node;
struct Node
{
int op;
// most nodes
Node* left;
Node* right;
Node* type;
// for-body
Node* ninit;
Node* ntest;
Node* nincr;
Node* nbody;
// if-body
Node* nelse;
// OTYPE-TFIELD
Node* down; // also used in TMAP
Node* uberstruct;
// cases
Node* ncase;
// OTYPE-TPTR
Node* nforw;
// OTYPE-TFUNCT
Node* this;
Node* argout;
Node* argin;
Node* nname;
int thistuple;
int outtuple;
int intuple;
// OTYPE-TARRAY
long bound;
// OLITERAL
Val val;
Sym* osym; // import
Sym* fsym; // import
Sym* psym; // import
Sym* sym; // various
uchar ullman; // sethi/ullman number
uchar addable; // type of addressability - 0 is not addressable
uchar recur; // to detect loops
uchar trecur; // to detect loops
uchar etype; // is an op for OASOP, is etype for OTYPE
uchar chan;
uchar kaka;
uchar multi; // type of assignment or call
long vargen; // unique name for OTYPE/ONAME
long lineno;
};
#define N ((Node*)0)
struct Sym
{
char* opackage; // original package name
char* package; // package name
char* name; // variable name
Node* oname; // ONAME node if a var
Node* otype; // OTYPE node if a type
Node* oconst; // OLITERAL node if a const
Node* forwtype; // OTYPE/TPTR iff foreward declared
void* label; // pointer to Prog* of label
long lexical;
long vargen; // unique variable number
uchar undef; // a diagnostic has been generated
uchar export; // marked as export
uchar exported; // has been exported
Sym* link;
};
#define S ((Sym*)0)
typedef struct Dcl Dcl;
struct Dcl
{
int op; // ONAME for var, OTYPE for type, Oxxx for const
Sym* dsym; // for printing only
Node* dnode; // otype or oname
long lineno;
Dcl* forw;
Dcl* back; // sentinel has pointer to last
};
#define D ((Dcl*)0)
typedef struct Iter Iter;
struct Iter
{
int done;
Node** an;
Node* n;
};
enum
{
OXXX,
OTYPE, OCONST, OVAR, OEXPORT, OIMPORT,
ONAME,
ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
ODCLFUNC, ODCLCONST, ODCLVAR,
ODCLTYPE, ODCLFIELD, ODCLARG,
OLIST,
OPTR, OARRAY,
ORETURN, OFOR, OIF, OSWITCH,
OAS, OASOP, OCOLAS, OCASE, OXCASE, OFALL, OXFALL,
OGOTO, OPROC, ONEW, OPANIC, OPRINT, OEMPTY,
OOROR,
OANDAND,
OEQ, ONE, OLT, OLE, OGE, OGT,
OADD, OSUB, OOR, OXOR, OCAT,
OMUL, ODIV, OMOD, OLSH, ORSH, OAND,
ODEC, OINC,
OLEN,
OFUNC,
OLABEL,
OBREAK,
OCONTINUE,
OADDR,
OIND,
OCALL, OCALLPTR, OCALLMETH, OCALLINTER,
OINDEX, OINDEXPTR, OINDEXSTR, OINDEXMAP, OINDEXPTRMAP,
OSLICE,
ONOT, OCOM, OPLUS, OMINUS, OSEND, ORECV,
OLITERAL,
OCONV,
OBAD,
OEND,
};
enum
{
Txxx,
TINT8, TUINT8,
TINT16, TUINT16,
TINT32, TUINT32,
TINT64, TUINT64,
TFLOAT32,
TFLOAT64,
TFLOAT80,
TBOOL,
TPTR,
TFUNC,
TARRAY,
TDARRAY,
TSTRUCT,
TCHAN,
TMAP,
TINTER,
TFORW,
TFIELD,
TPOLY,
TSTRING,
NTYPE,
};
enum
{
CTxxx,
CTINT,
CTSINT,
CTUINT,
CTFLT,
CTSTR,
CTBOOL,
CTNIL,
};
enum
{
/* indications for whatis() */
Wnil = 0,
Wtnil,
Wtfloat,
Wtint,
Wtbool,
Wtstr,
Wlitfloat,
Wlitint,
Wlitbool,
Wlitstr,
Wtunkn,
};
enum
{
/* types of channel */
Cxxx,
Cboth,
Crecv,
Csend,
};
enum
{
Pxxx,
PEXTERN, // declaration context
PAUTO,
PCALL_NIL, // no return value
PCALL_SINGLE, // single return value
PCALL_MULTI, // multiple return values
PAS_SINGLE, // top level walk->gen hints for OAS
PAS_MULTI, // multiple values
PAS_CALLM, // multiple values from a call
PAS_STRUCT, // structure assignment
};
typedef struct Io Io;
struct Io
{
char* infile;
Biobuf* bin;
long lineno;
int peekc;
};
EXTERN Io curio;
EXTERN Io pushedio;
EXTERN char* outfile;
EXTERN char* package;
EXTERN Biobuf* bout;
EXTERN int nerrors;
EXTERN char namebuf[NSYMB];
EXTERN char debug[256];
EXTERN long dynlineno;
EXTERN Sym* hash[NHASH];
EXTERN Sym* dclstack;
EXTERN Sym* b0stack;
EXTERN Sym* pkgmyname; // my name for package
EXTERN Node* types[NTYPE];
EXTERN uchar isint[NTYPE];
EXTERN uchar isfloat[NTYPE];
EXTERN uchar okforeq[NTYPE];
EXTERN uchar okforadd[NTYPE];
EXTERN uchar okforand[NTYPE];
EXTERN double minfloatval[NTYPE];
EXTERN double maxfloatval[NTYPE];
EXTERN vlong minintval[NTYPE];
EXTERN vlong maxintval[NTYPE];
EXTERN Dcl* autodcl;
EXTERN Dcl* externdcl;
EXTERN Dcl* exportlist;
EXTERN int dclcontext; // PEXTERN/PAUTO
EXTERN int importflag;
EXTERN Node* booltrue;
EXTERN Node* boolfalse;
EXTERN ulong iota;
EXTERN long vargen;
EXTERN long exportgen;
EXTERN Node* retnil;
EXTERN Node* fskel;
EXTERN char* context;
EXTERN int thechar;
EXTERN char* thestring;
EXTERN char* hunk;
EXTERN long nhunk;
EXTERN long thunk;
/*
* y.tab.c
*/
int yyparse(void);
/*
* lex.c
*/
int main(int, char*[]);
void importfile(Val*);
void unimportfile();
long yylex(void);
void lexinit(void);
char* lexname(int);
long getr(void);
int getnsc(void);
long escchar(long, int*);
int getc(void);
void ungetc(int);
void mkpackage(char*);
/*
* mpatof.c
*/
int mpatof(char*, double*);
int mpatov(char*, vlong*);
/*
* subr.c
*/
void myexit(int);
void* mal(long);
void* remal(void*, long, long);
void errorexit(void);
ulong stringhash(char*);
Sym* lookup(char*);
Sym* pkglookup(char*, char*);
void yyerror(char*, ...);
void warn(char*, ...);
void fatal(char*, ...);
Node* nod(int, Node*, Node*);
Dcl* dcl(void);
Node* rev(Node*);
Node* unrev(Node*);
void dodump(Node*, int);
void dump(char*, Node*);
Node* aindex(Node*, Node*);
int isptrto(Node*, int);
int isinter(Node*);
int isbytearray(Node*);
int eqtype(Node*, Node*, int);
ulong typehash(Node*, int);
void frame(int);
Node* literal(long);
Node* dobad(void);
void ullmancalc(Node*);
void badtype(int, Node*, Node*);
Node* ptrto(Node*);
Node* cleanidlist(Node*);
Node** getthis(Node*);
Node** getoutarg(Node*);
Node** getinarg(Node*);
Node* getthisx(Node*);
Node* getoutargx(Node*);
Node* getinargx(Node*);
Node* listfirst(Iter*, Node**);
Node* listnext(Iter*);
Node* structfirst(Iter*, Node**);
Node* structnext(Iter*);
int Econv(Fmt*);
int Jconv(Fmt*);
int Oconv(Fmt*);
int Sconv(Fmt*);
int Tconv(Fmt*);
int Nconv(Fmt*);
int Zconv(Fmt*);
/*
* dcl.c
*/
void dodclvar(Node*, Node*);
void dodcltype(Node*, Node*);
void dodclconst(Node*, Node*);
void defaultlit(Node*);
int listcount(Node*);
Node* functype(Node*, Node*, Node*);
char* thistypenam(Node*);
void funcnam(Node*, char*);
void funchdr(Node*);
void funcargs(Node*);
void funcbody(Node*);
Node* dostruct(Node*, int);
Node** stotype(Node*, Node**, Node*);
Node* sortinter(Node*);
void markdcl(void);
void popdcl(void);
void markdclstack(void);
Sym* pushdcl(Sym*);
void addvar(Node*, Node*, int);
void addtyp(Node*, Node*, int);
Node* newname(Sym*);
Node* oldname(Sym*);
Node* newtype(Sym*);
Node* oldtype(Sym*);
Node* forwdcl(Sym*);
/*
* export.c
*/
void markexport(Node*);
void dumpe(Sym*);
void dumpexport(void);
void dumpexporttype(Sym*);
void dumpexportvar(Sym*);
void dumpexportconst(Sym*);
void doimportv1(Node*, Node*);
void doimportc1(Node*, Val*);
void doimportc2(Node*, Node*, Val*);
void doimport1(Node*, Node*, Node*);
void doimport2(Node*, Val*, Node*);
void doimport3(Node*, Node*);
void doimport4(Node*, Node*);
void doimport5(Node*, Val*);
void doimport6(Node*, Node*);
void doimport7(Node*, Node*);
/*
* walk.c
*/
void walk(Node*);
void walktype(Node*, int);
Node* walkswitch(Node*, Node*, Node*(*)(Node*, Node*));
int casebody(Node*);
int whatis(Node*);
void walkdot(Node*);
void walkslice(Node*);
void ascompatee(int, Node**, Node**);
void ascompatet(int, Node**, Node**);
void ascompatte(int, Node**, Node**);
void ascompattt(int, Node**, Node**);
int ascompat(Node*, Node*);
void prcompat(Node**);
/*
* const.c
*/
void convlit(Node*, Node*);
void evconst(Node*);
int cmpslit(Node *l, Node *r);
/*
* gen.c/gsubr.c/obj.c
*/
void belexinit(int);
vlong convvtox(vlong, int);
void compile(Node*);
void proglist(void);
void dumpobj(void);
int optopop(int);

1302
src/c/go.y Normal file

File diff suppressed because it is too large Load diff

523
src/c/gsubr.c Normal file
View file

@ -0,0 +1,523 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go.h"
#include "gen.h"
Prog*
gbranch(int op, Node *t)
{
Prog *p;
p = prog(op);
p->addr.type = ABRANCH;
p->pt = conv2pt(t);
return p;
}
Prog*
gopcode(int op, int pt, Node *n)
{
Prog *p;
p = prog(op);
p->pt = pt;
p->addr.node = n;
if(n == N) {
p->addr.type = ANONE;
return p;
}
if(n->op == OTYPE) {
p->pt1 = conv2pt(n);
p->addr.type = ANONE;
return p;
}
p->addr.type = ANODE;
// p->param = n->param;
return p;
}
Prog*
gopcodet(int op, Node *t, Node *n)
{
return gopcode(op, conv2pt(t), n);
}
void
gaddoffset(Node *n)
{
Prog *p;
if(n == N || n->op != ONAME || n->sym == S)
goto bad;
p = gopcode(PADDO, PTADDR, n);
return;
bad:
fatal("gaddoffset: %N", n);
}
void
gconv(int t1, int t2)
{
Prog *p;
p = gopcode(PCONV, t1, N);
p->pt1 = t2;
}
int
conv2pt(Node *t)
{
if(t == N)
return PTxxx;
switch(t->etype) {
case TPTR:
t = t->type;
if(t == N)
return PTERROR;
switch(t->etype) {
case PTSTRING:
case PTCHAN:
case PTMAP:
return t->etype;
}
return TPTR;
}
return t->etype;
}
void
patch(Prog *p, Prog *to)
{
if(p->addr.type != ABRANCH)
yyerror("patch: not a branch");
p->addr.branch = to;
}
Prog*
prog(int as)
{
Prog *p;
p = pc;
pc = mal(sizeof(*pc));
pc->op = PEND;
pc->addr.type = ANONE;
pc->loc = p->loc+1;
p->op = as;
p->lineno = dynlineno;
p->link = pc;
return p;
}
void
proglist(void)
{
Prog *p;
print("--- prog list ---\n");
for(p=firstpc; p!=P; p=p->link)
print("%P\n", p);
}
char* ptnames[] =
{
[PTxxx] = "",
[PTINT8] = "I8",
[PTUINT8] = "U8",
[PTINT16] = "I16",
[PTUINT16] = "U16",
[PTINT32] = "I32",
[PTUINT32] = "U32",
[PTINT64] = "I64",
[PTUINT64] = "U64",
[PTFLOAT32] = "F32",
[PTFLOAT64] = "F64",
[PTFLOAT80] = "F80",
[PTBOOL] = "B",
[PTPTR] = "P",
[PTADDR] = "A",
[PTINTER] = "I",
[PTNIL] = "N",
[PTSTRUCT] = "S",
[PTSTRING] = "Z",
[PTCHAN] = "C",
[PTMAP] = "M",
[PTERROR] = "?",
};
int
Xconv(Fmt *fp)
{
char buf[100];
int pt;
pt = va_arg(fp->args, int);
if(pt < 0 || pt >= nelem(ptnames) || ptnames[pt] == nil) {
snprint(buf, sizeof(buf), "PT(%d)", pt);
return fmtstrcpy(fp, buf);
}
return fmtstrcpy(fp, ptnames[pt]);
}
int
Qconv(Fmt *fp)
{
char buf[100];
int pt;
pt = va_arg(fp->args, int);
if(pt == PTADDR)
pt = PTPTR;
snprint(buf, sizeof(buf), "_T_%X", pt);
return fmtstrcpy(fp, buf);
}
int
Rconv(Fmt *fp)
{
char buf[100];
int pt;
pt = va_arg(fp->args, int);
if(pt == PTADDR)
snprint(buf, sizeof(buf), "_R_%X", pt);
else
snprint(buf, sizeof(buf), "_U._R_%X", pt);
return fmtstrcpy(fp, buf);
}
/*
s%[ ]*%%g
s%(\/\*.*)*%%g
s%,%\n%g
s%\n+%\n%g
s%(=0)*%%g
s%^P(.+)% [P\1] = "\1",%g
s%^ ........*\] =%&~%g
s% =~%=%g
*/
static char*
pnames[] =
{
[PXXX] = "XXX",
[PERROR] = "ERROR",
[PPANIC] = "PANIC",
[PPRINT] = "PRINT",
[PGOTO] = "GOTO",
[PGOTOX] = "GOTOX",
[PCMP] = "CMP",
[PNEW] = "NEW",
[PLEN] = "LEN",
[PTEST] = "TEST",
[PCALL1] = "CALL1",
[PCALL2] = "CALL2",
[PCALLI2] = "CALLI2",
[PCALLM2] = "CALLM2",
[PCALLF2] = "CALLF2",
[PCALL3] = "CALL3",
[PRETURN] = "RETURN",
[PBEQ] = "BEQ",
[PBNE] = "BNE",
[PBLT] = "BLT",
[PBLE] = "BLE",
[PBGE] = "BGE",
[PBGT] = "BGT",
[PBTRUE] = "BTRUE",
[PBFALSE] = "BFALSE",
[PLOAD] = "LOAD",
[PLOADI] = "LOADI",
[PSTORE] = "STORE",
[PSTOREI] = "STOREI",
[PSTOREZ] = "STOREZ",
[PCONV] = "CONV",
[PADDR] = "ADDR",
[PADDO] = "ADDO",
[PINDEX] = "INDEX",
[PINDEXZ] = "INDEXZ",
[PCAT] = "CAT",
[PADD] = "ADD",
[PSUB] = "SUB",
[PSLICE] = "SLICE",
[PMUL] = "MUL",
[PDIV] = "DIV",
[PLSH] = "LSH",
[PRSH] = "RSH",
[PMOD] = "MOD",
[PMINUS] = "MINUS",
[PCOM] = "COM",
[PAND] = "AND",
[POR] = "OR",
[PXOR] = "XOR",
[PEND] = "END",
};
int
Aconv(Fmt *fp)
{
char buf[100], buf1[100];
Prog *p;
int o;
p = va_arg(fp->args, Prog*);
if(p == P) {
snprint(buf, sizeof(buf), "<P>");
goto ret;
}
o = p->op;
if(o < 0 || o >= nelem(pnames) || pnames[o] == nil)
snprint(buf, sizeof(buf), "(A%d)", o);
else
snprint(buf, sizeof(buf), "%s", pnames[o]);
o = p->pt;
if(o != PTxxx) {
snprint(buf1, sizeof(buf1), "-%X", o);
strncat(buf, buf1, sizeof(buf));
}
o = p->pt1;
if(o != PTxxx) {
snprint(buf1, sizeof(buf1), "-%X", o);
strncat(buf, buf1, sizeof(buf));
}
ret:
return fmtstrcpy(fp, buf);
}
int
Pconv(Fmt *fp)
{
char buf[500], buf1[500];
Prog *p;
p = va_arg(fp->args, Prog*);
snprint(buf1, sizeof(buf1), "%4ld %4ld %-9A", p->loc, p->lineno, p);
switch(p->addr.type) {
default:
snprint(buf, sizeof(buf), "?%d", p->addr.type);
break;
case ANONE:
goto out;
case ANODE:
snprint(buf, sizeof(buf), "%N", p->addr.node);
break;
case ABRANCH:
if(p->addr.branch == P) {
snprint(buf, sizeof(buf), "<nil>");
break;
}
snprint(buf, sizeof(buf), "%ld", p->addr.branch->loc);
break;
}
strncat(buf1, " ", sizeof(buf1));
strncat(buf1, buf, sizeof(buf1));
out:
return fmtstrcpy(fp, buf1);
}
static char*
typedefs[] =
{
"int", "int32",
"uint", "uint32",
"rune", "uint32",
"short", "int16",
"ushort", "uint16",
"long", "int32",
"ulong", "uint32",
"vlong", "int64",
"uvlong", "uint64",
"float", "float32",
"double", "float64",
};
void
belexinit(int lextype)
{
int i;
Sym *s0, *s1;
for(i=0; i<nelem(typedefs); i+=2) {
s1 = lookup(typedefs[i+1]);
if(s1->lexical != lextype)
yyerror("need %s to define %s",
typedefs[i+1], typedefs[i+0]);
s0 = lookup(typedefs[i+0]);
s0->lexical = s1->lexical;
s0->otype = s1->otype;
}
fmtinstall('A', Aconv); // asm opcodes
fmtinstall('P', Pconv); // asm instruction
fmtinstall('R', Rconv); // interpreted register
fmtinstall('Q', Qconv); // interpreted etype
fmtinstall('X', Xconv); // interpreted etype
fmtinstall('D', Dconv); // addressed operand
fmtinstall('C', Cconv); // C type
}
vlong
convvtox(vlong v, int et)
{
/* botch - do truncation conversion when energetic */
return v;
}
/*
* return !(op)
* eg == <=> !=
*/
int
brcom(int a)
{
switch(a) {
case PBEQ: return PBNE;
case PBNE: return PBEQ;
case PBLT: return PBGE;
case PBGT: return PBLE;
case PBLE: return PBGT;
case PBGE: return PBLT;
case PBTRUE: return PBFALSE;
case PBFALSE: return PBTRUE;
}
fatal("brcom: no com for %A\n", a);
return PERROR;
}
/*
* return reverse(op)
* eg a op b <=> b r(op) a
*/
int
brrev(int a)
{
switch(a) {
case PBEQ: return PBEQ;
case PBNE: return PBNE;
case PBLT: return PBGT;
case PBGT: return PBLT;
case PBLE: return PBGE;
case PBGE: return PBLE;
}
fatal("brcom: no rev for %A\n", a);
return PERROR;
}
/*
* codegen the address of the ith
* element in the jth argument.
*/
void
fnparam(Node *t, int j, int i)
{
Node *a, *f;
switch(j) {
default:
fatal("fnparam: bad j");
case 0:
a = getthisx(t);
break;
case 1:
a = getoutargx(t);
break;
case 2:
a = getinargx(t);
break;
}
f = a->type;
while(i > 0) {
f = f->down;
i--;
}
if(f->etype != TFIELD)
fatal("fnparam: not field");
gopcode(PLOAD, PTADDR, a->nname);
gopcode(PADDO, PTADDR, f->nname);
}
Sig*
lsort(Sig *l, int(*f)(Sig*, Sig*))
{
Sig *l1, *l2, *le;
if(l == 0 || l->link == 0)
return l;
l1 = l;
l2 = l;
for(;;) {
l2 = l2->link;
if(l2 == 0)
break;
l2 = l2->link;
if(l2 == 0)
break;
l1 = l1->link;
}
l2 = l1->link;
l1->link = 0;
l1 = lsort(l, f);
l2 = lsort(l2, f);
/* set up lead element */
if((*f)(l1, l2) < 0) {
l = l1;
l1 = l1->link;
} else {
l = l2;
l2 = l2->link;
}
le = l;
for(;;) {
if(l1 == 0) {
while(l2) {
le->link = l2;
le = l2;
l2 = l2->link;
}
le->link = 0;
break;
}
if(l2 == 0) {
while(l1) {
le->link = l1;
le = l1;
l1 = l1->link;
}
break;
}
if((*f)(l1, l2) < 0) {
le->link = l1;
le = l1;
l1 = l1->link;
} else {
le->link = l2;
le = l2;
l2 = l2->link;
}
}
le->link = 0;
return l;
}

1058
src/c/lex.c Normal file

File diff suppressed because it is too large Load diff

342
src/c/mpatof.c Executable file
View file

@ -0,0 +1,342 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include <u.h>
#include <libc.h>
int mpatof(char*, double*);
int mpatov(char *s, vlong *v);
enum
{
Mpscale = 29, /* safely smaller than bits in a long */
Mpprec = 36, /* Mpscale*Mpprec sb > largest fp exp */
Mpbase = 1L<<Mpscale,
};
typedef
struct
{
long a[Mpprec];
char ovf;
} Mp;
static void mpint(Mp*, int);
static void mppow(Mp*, int, int);
static void mpmul(Mp*, int);
static void mpadd(Mp*, Mp*);
static int mptof(Mp*, double*);
/*
* convert a string, s, to floating in *d
* return conversion overflow.
* required syntax is [+-]d*[.]d*[e[+-]d*]
*/
int
mpatof(char *s, double *d)
{
Mp a, b;
int dp, c, f, ef, ex, zer;
double d1, d2;
dp = 0; /* digits after decimal point */
f = 0; /* sign */
ex = 0; /* exponent */
zer = 1; /* zero */
memset(&a, 0, sizeof(a));
for(;;) {
switch(c = *s++) {
default:
goto bad;
case '-':
f = 1;
case ' ':
case '\t':
case '+':
continue;
case '.':
dp = 1;
continue;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
zer = 0;
case '0':
mpint(&b, c-'0');
mpmul(&a, 10);
mpadd(&a, &b);
if(dp)
dp++;
continue;
case 'E':
case 'e':
ex = 0;
ef = 0;
for(;;) {
c = *s++;
if(c == '+' || c == ' ' || c == '\t')
continue;
if(c == '-') {
ef = 1;
continue;
}
if(c >= '0' && c <= '9') {
ex = ex*10 + (c-'0');
continue;
}
break;
}
if(ef)
ex = -ex;
case 0:
break;
}
break;
}
if(a.ovf)
goto bad;
if(zer) {
*d = 0;
return 0;
}
if(dp)
dp--;
dp -= ex;
if(dp > 0) {
/*
* must divide by 10**dp
*/
if(mptof(&a, &d1))
goto bad;
/*
* trial exponent of 8**dp
* 8 (being between 5 and 10)
* should pick up all underflows
* in the division of 5**dp.
*/
d2 = frexp(d1, &ex);
d2 = ldexp(d2, ex-3*dp);
if(d2 == 0)
goto bad;
/*
* decompose each 10 into 5*2.
* create 5**dp in fixed point
* and then play with the exponent
* for the remaining 2**dp.
* note that 5**dp will overflow
* with as few as 134 input digits.
*/
mpint(&a, 1);
mppow(&a, 5, dp);
if(mptof(&a, &d2))
goto bad;
d1 = frexp(d1/d2, &ex);
d1 = ldexp(d1, ex-dp);
if(d1 == 0)
goto bad;
} else {
/*
* must multiply by 10**|dp| --
* just do it in fixed point.
*/
mppow(&a, 10, -dp);
if(mptof(&a, &d1))
goto bad;
}
if(f)
d1 = -d1;
*d = d1;
return 0;
bad:
return 1;
}
/*
* convert a to floating in *d
* return conversion overflow
*/
static int
mptof(Mp *a, double *d)
{
double f, g;
long x, *a1;
int i;
if(a->ovf)
return 1;
a1 = a->a;
f = ldexp(*a1++, 0);
for(i=Mpscale; i<Mpprec*Mpscale; i+=Mpscale)
if(x = *a1++) {
g = ldexp(x, i);
/*
* NOTE: the test (g==0) is plan9
* specific. ansi compliant overflow
* is signaled by HUGE and errno==ERANGE.
* change this for your particular ldexp.
*/
if(g == 0)
return 1;
f += g; /* this could bomb! */
}
*d = f;
return 0;
}
/*
* return a += b
*/
static void
mpadd(Mp *a, Mp *b)
{
int i, c;
long x, *a1, *b1;
if(b->ovf)
a->ovf = 1;
if(a->ovf)
return;
c = 0;
a1 = a->a;
b1 = b->a;
for(i=0; i<Mpprec; i++) {
x = *a1 + *b1++ + c;
c = 0;
if(x >= Mpbase) {
x -= Mpbase;
c = 1;
}
*a1++ = x;
}
a->ovf = c;
}
/*
* return a = c
*/
static void
mpint(Mp *a, int c)
{
memset(a, 0, sizeof(*a));
a->a[0] = c;
}
/*
* return a *= c
*/
static void
mpmul(Mp *a, int c)
{
Mp p;
int b;
memmove(&p, a, sizeof(p));
if(!(c & 1))
memset(a, 0, sizeof(*a));
c &= ~1;
for(b=2; c; b<<=1) {
mpadd(&p, &p);
if(c & b) {
mpadd(a, &p);
c &= ~b;
}
}
}
/*
* return a *= b**e
*/
static void
mppow(Mp *a, int b, int e)
{
int b1;
b1 = b*b;
b1 = b1*b1;
while(e >= 4) {
mpmul(a, b1);
e -= 4;
if(a->ovf)
return;
}
while(e > 0) {
mpmul(a, b);
e--;
}
}
/*
* convert a string, s, to vlong in *v
* return conversion overflow.
* required syntax is [0[x]]d*
*/
int
mpatov(char *s, vlong *v)
{
vlong n, nn;
int c;
n = 0;
c = *s;
if(c == '0')
goto oct;
while(c = *s++) {
if(c >= '0' && c <= '9')
nn = n*10 + c-'0';
else
goto bad;
if(n < 0 && nn >= 0)
goto bad;
n = nn;
}
goto out;
oct:
s++;
c = *s;
if(c == 'x' || c == 'X')
goto hex;
while(c = *s++) {
if(c >= '0' || c <= '7')
nn = n*8 + c-'0';
else
goto bad;
if(n < 0 && nn >= 0)
goto bad;
n = nn;
}
goto out;
hex:
s++;
while(c = *s++) {
if(c >= '0' && c <= '9')
c += 0-'0';
else
if(c >= 'a' && c <= 'f')
c += 10-'a';
else
if(c >= 'A' && c <= 'F')
c += 10-'A';
else
goto bad;
nn = n*16 + c;
if(n < 0 && nn >= 0)
goto bad;
n = nn;
}
out:
*v = n;
return 0;
bad:
*v = ~0;
return 1;
}

1535
src/c/obj.c Normal file

File diff suppressed because it is too large Load diff

1472
src/c/subr.c Normal file

File diff suppressed because it is too large Load diff

138
src/c/test.c Normal file
View file

@ -0,0 +1,138 @@
/*
* automatic code generated from
* test.go in package "test"
*/
// basic types
typedef unsigned char _T_U8;
typedef signed char _T_I8;
typedef unsigned short _T_U16;
typedef signed short _T_I16;
typedef unsigned long _T_U32;
typedef signed long _T_I32;
typedef unsigned long long _T_U64;
typedef signed long long _T_I64;
typedef float _T_F32;
typedef double _T_F64;
typedef double _T_F80;
typedef int _T_B;
typedef unsigned char* _T_P;
#define offsetof(s, m) (_T_U32)(&(((s*)0)->m))
typedef struct{_T_U32 I1; _T_U32 I2; _T_U32 I3;} _T_I;
typedef struct{_T_U32 O1; _T_U32 O2;} _T_O;
void test_main(void);
_T_O test_simple(_T_I);
int printf(char*, ...);
// external variables
void
test_main(void)
{
// registers
register union
{
_T_U8 _R_U8;
_T_I8 _R_I8;
_T_U16 _R_U16;
_T_I16 _R_I16;
_T_U32 _R_U32;
_T_I32 _R_I32;
_T_U64 _R_U64;
_T_I64 _R_I64;
_T_F32 _R_F32;
_T_F64 _R_F64;
_T_F80 _R_F80;
_T_B _R_B;
_T_P _R_P;
} _U;
// local variables
_T_I32 _V_3; // x
_T_I32 _V_4; // y
{
_T_I I;
_T_O O;
I.I1 = 10;
I.I2 = 20;
I.I3 = 30;
O = test_simple(I);
_V_3 = O.O1;
_V_4 = O.O2;
}
// 1 7 LOAD_I32 NAME a(1) p(3) l(7) x G0 INT32
_U._R_I32 = _V_3;
// 2 10 CMP_I32 I15 LITERAL a(1) l(10) INT32
if(_U._R_I32 == 15)
// 3 10 BEQ_I32 4
goto _L4;
printf("no 1 %d\n", _V_3);
// 4 7 LOAD_I32 NAME a(1) p(4) l(7) y G0 INT32
_L4:
_U._R_I32 = _V_4;
// 5 11 CMP_I32 I50 LITERAL a(1) l(11) INT32
if(_U._R_I32 == 50)
// 6 11 BEQ_I32 7
goto _L7;
printf("no 2 %d\n", _V_4);
// 7 0 END
_L7:
;
}
_T_O
test_simple(_T_I I)
{
// registers
register union
{
_T_U8 _R_U8;
_T_I8 _R_I8;
_T_U16 _R_U16;
_T_I16 _R_I16;
_T_U32 _R_U32;
_T_I32 _R_I32;
_T_U64 _R_U64;
_T_I64 _R_I64;
_T_F32 _R_F32;
_T_F64 _R_F64;
_T_F80 _R_F80;
_T_B _R_B;
_T_P _R_P;
} _U;
_T_O O;
int ia, ib, ic;
ia = I.I1;
ib = I.I2;
ic = I.I3;
O.O1 = ia+5;
O.O2 = ib+ic;
return O;
}
int
main(void)
{
test_main();
return 0;
}

967
src/c/walk.c Normal file
View file

@ -0,0 +1,967 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go.h"
static Node* sw1(Node*, Node*);
static Node* sw2(Node*, Node*);
static Node* sw3(Node*, Node*);
static Node* curfn;
void
walk(Node *fn)
{
curfn = fn;
walktype(fn->nbody, 1);
}
void
walktype(Node *n, int top)
{
Node *t, *r;
Sym *s;
long lno;
int et;
/*
* walk the whole tree of the body of a function.
* the types expressions are calculated.
* compile-time constants are evaluated.
*/
lno = dynlineno;
loop:
if(n == N)
goto ret;
if(n->op != ONAME)
dynlineno = n->lineno; // for diagnostics
t = N;
et = Txxx;
switch(n->op) {
default:
fatal("walktype: switch 1 unknown op %N", n);
goto ret;
case ODCLTYPE:
goto ret;
case OPANIC:
case OPRINT:
walktype(n->left, 0);
prcompat(&n->left);
goto ret;
case OLITERAL:
n->addable = 1;
ullmancalc(n);
goto ret;
case ONAME:
n->addable = 1;
ullmancalc(n);
if(n->type == N) {
s = n->sym;
if(s->undef == 0) {
yyerror("walktype: %N undeclared", n);
s->undef = 1;
}
}
goto ret;
case OLIST:
walktype(n->left, top);
n = n->right;
goto loop;
case OFOR:
if(!top)
goto nottop;
walktype(n->ninit, 1);
walktype(n->ntest, 1);
walktype(n->nincr, 1);
n = n->nbody;
goto loop;
case OSWITCH:
if(!top)
goto nottop;
if(n->ntest == N)
n->ntest = booltrue;
walktype(n->ninit, 1);
walktype(n->ntest, 1);
walktype(n->nbody, 1);
// find common type
if(n->ntest->type == N)
n->ntest->type = walkswitch(n->ntest, n->nbody, sw1);
// if that fails pick a type
if(n->ntest->type == N)
n->ntest->type = walkswitch(n->ntest, n->nbody, sw2);
// set the type on all literals
if(n->ntest->type != N)
walkswitch(n->ntest, n->nbody, sw3);
n = n->nincr;
goto loop;
case OEMPTY:
if(!top)
goto nottop;
goto ret;
case OIF:
if(!top)
goto nottop;
walktype(n->ninit, 1);
walktype(n->ntest, 1);
walktype(n->nelse, 1);
n = n->nbody;
goto loop;
case OCALL:
case OCALLPTR:
case OCALLMETH:
case OCALLINTER:
walktype(n->left, 0);
if(n->left == N)
goto ret;
t = n->left->type;
if(t == N)
goto ret;
if(n->left->op == ODOTMETH)
n->op = OCALLMETH;
if(n->left->op == ODOTINTER)
n->op = OCALLINTER;
if(t->etype == TPTR) {
t = t->type;
n->op = OCALLPTR;
}
if(t->etype != TFUNC) {
yyerror("call of a non-function %T", t);
goto ret;
}
n->type = *getoutarg(t);
switch(t->outtuple) {
default:
n->kaka = PCALL_MULTI;
if(!top)
yyerror("function call must be single valued (%d)", et);
break;
case 0:
n->kaka = PCALL_NIL;
break;
case 1:
n->kaka = PCALL_SINGLE;
n->type = n->type->type->type;
break;
}
r = n->right;
walktype(r, 0);
ascompatte(n->op, getinarg(t), &n->right);
goto ret;
case OCOLAS:
case ODCLVAR:
case OAS:
if(!top)
goto nottop;
n->kaka = PAS_SINGLE;
r = n->left;
if(r != N && r->op == OLIST)
n->kaka = PAS_MULTI;
walktype(r, 0);
r = n->right;
if(r == N)
goto ret;
if(r->op == OCALL && n->kaka == PAS_MULTI) {
walktype(r, 1);
if(r->kaka == PCALL_MULTI) {
ascompatet(n->op, &n->left, &r->type);
n->kaka = PAS_CALLM;
goto ret;
}
}
walktype(n->right, 0);
ascompatee(n->op, &n->left, &n->right);
if(n->kaka == PAS_SINGLE) {
t = n->right->type;
if(t != N && t->etype == TSTRUCT)
n->kaka = PAS_STRUCT;
}
goto ret;
case OBREAK:
case OCONTINUE:
case OGOTO:
case OLABEL:
goto ret;
case OXCASE:
yyerror("case statement out of place");
n->op = OCASE;
case OCASE:
n = n->left;
goto loop;
case OXFALL:
yyerror("fallthrough statement out of place");
n->op = OFALL;
case OFALL:
goto ret;
case OCONV:
walktype(n->left, 0);
if(n->left == N)
goto ret;
convlit(n->left, n->type);
if(eqtype(n->type, n->left->type, 0))
*n = *n->left;
goto ret;
case ORETURN:
walktype(n->left, 0);
ascompatte(n->op, getoutarg(curfn->type), &n->left);
goto ret;
case ONOT:
walktype(n->left, 0);
if(n->left == N || n->left->type == N)
goto ret;
et = n->left->type->etype;
break;
case OASOP:
if(!top)
goto nottop;
case OLSH:
case ORSH:
case OMOD:
case OAND:
case OOR:
case OXOR:
case OANDAND:
case OOROR:
case OEQ:
case ONE:
case OLT:
case OLE:
case OGE:
case OGT:
case OADD:
case OSUB:
case OMUL:
case ODIV:
case OCAT:
walktype(n->left, 0);
walktype(n->right, 0);
if(n->left == N || n->right == N)
goto ret;
convlit(n->left, n->right->type);
convlit(n->right, n->left->type);
evconst(n);
if(n->op == OLITERAL)
goto ret;
if(n->left->type == N || n->right->type == N)
goto ret;
if(!ascompat(n->left->type, n->right->type))
goto badt;
break;
case OPLUS:
case OMINUS:
case OCOM:
walktype(n->left, 0);
if(n->left == N)
goto ret;
evconst(n);
ullmancalc(n);
if(n->op == OLITERAL)
goto ret;
break;
case OLEN:
walktype(n->left, 0);
evconst(n);
ullmancalc(n);
t = n->left->type;
if(t != N && t->etype == TPTR)
t = t->type;
if(t == N)
goto ret;
switch(t->etype) {
default:
goto badt;
case TSTRING:
break;
}
n->type = types[TINT32];
goto ret;
case OINDEX:
case OINDEXPTR:
case OINDEXSTR:
case OINDEXMAP:
case OINDEXPTRMAP:
walktype(n->left, 0);
walktype(n->right, 0);
ullmancalc(n);
if(n->left == N || n->right == N)
goto ret;
t = n->left->type;
if(t == N)
goto ret;
// map - left and right sides must match
if(t->etype == TMAP || isptrto(t, TMAP)) {
n->ullman = UINF;
n->op = OINDEXMAP;
if(isptrto(t, TMAP)) {
n->op = OINDEXPTRMAP;
t = t->type;
if(t == N)
goto ret;
}
convlit(n->right, t->down);
if(!ascompat(t->down, n->right->type))
goto badt;
n->type = t->type;
goto ret;
}
// right side must be an int
if(n->right->type == N)
convlit(n->right, types[TINT32]);
if(n->left->type == N || n->right->type == N)
goto ret;
if(!isint[n->right->type->etype])
goto badt;
// left side is string
if(isptrto(t, TSTRING)) {
n->op = OINDEXSTR;
n->type = types[TUINT8];
goto ret;
}
// left side is array
if(t->etype == TPTR) {
t = t->type;
n->op = OINDEXPTR;
}
if(t->etype != TARRAY && t->etype != TDARRAY)
goto badt;
n->type = t->type;
goto ret;
case OSLICE:
walkslice(n);
goto ret;
case ODOT:
case ODOTPTR:
case ODOTMETH:
case ODOTINTER:
walkdot(n);
goto ret;
case OADDR:
walktype(n->left, 0);
if(n->left == N)
goto ret;
t = n->left->type;
if(t == N)
goto ret;
n->type = ptrto(t);
goto ret;
case OIND:
walktype(n->left, 0);
if(n->left == N)
goto ret;
t = n->left->type;
if(t == N)
goto ret;
if(t->etype != TPTR)
goto badt;
n->type = t->type;
goto ret;
case ONEW:
if(n->left != N)
yyerror("dont know what new(,e) means");
goto ret;
}
/*
* ======== second switch ========
*/
switch(n->op) {
default:
fatal("walktype: switch 2 unknown op %N", n);
goto ret;
case OASOP:
break;
case ONOT:
case OANDAND:
case OOROR:
et = n->left->type->etype;
if(et != TBOOL)
goto badt;
t = types[TBOOL];
break;
case OEQ:
case ONE:
et = n->left->type->etype;
if(!okforeq[et])
goto badt;
t = types[TBOOL];
break;
case OLT:
case OLE:
case OGE:
case OGT:
et = n->left->type->etype;
if(!okforadd[et])
if(!isptrto(n->left->type, TSTRING))
goto badt;
t = types[TBOOL];
break;
case OCAT:
case OADD:
if(isptrto(n->left->type, TSTRING)) {
n->op = OCAT;
break;
}
case OSUB:
case OMUL:
case ODIV:
case OPLUS:
case OMINUS:
et = n->left->type->etype;
if(!okforadd[et])
goto badt;
break;
case OLSH:
case ORSH:
case OAND:
case OOR:
case OXOR:
case OMOD:
case OCOM:
et = n->left->type->etype;
if(!okforand[et])
goto badt;
break;
}
if(t == N)
t = n->left->type;
n->type = t;
ullmancalc(n);
goto ret;
nottop:
fatal("walktype: not top %O", n->op);
badt:
if(n->right == N) {
if(n->left == N) {
badtype(n->op, N, N);
goto ret;
}
badtype(n->op, n->left->type, N);
goto ret;
}
badtype(n->op, n->left->type, n->right->type);
goto ret;
ret:
dynlineno = lno;
}
/*
* return the first type
*/
Node*
sw1(Node *c, Node *place)
{
if(place == N)
return c->type;
return place;
}
/*
* return a suitable type
*/
Node*
sw2(Node *c, Node *place)
{
return types[TINT32]; // botch
}
/*
* check that selected type
* is compat with all the cases
*/
Node*
sw3(Node *c, Node *place)
{
if(place == N)
return c->type;
if(c->type == N)
c->type = place;
convlit(c, place);
if(!ascompat(place, c->type))
badtype(OSWITCH, place, c->type);
return place;
}
Node*
walkswitch(Node *test, Node *body, Node*(*call)(Node*, Node*))
{
Node *n, *c;
Node *place;
place = call(test, N);
n = body;
if(n->op == OLIST)
n = n->left;
for(; n!=N; n=n->right) {
if(n->op != OCASE)
fatal("walkswitch: not case %O\n", n->op);
for(c=n->left; c!=N; c=c->right) {
if(c->op != OLIST) {
place = call(c, place);
break;
}
place = call(c->left, place);
}
}
return place;
}
int
casebody(Node *n)
{
Node *oc, *ot, *t;
Iter save;
/*
* look to see if statements at top level have
* case labels attached to them. convert the illegal
* ops XFALL and XCASE into legal ops FALL and CASE.
* all unconverted ops will thus be caught as illegal
*/
oc = N; // last case statement
ot = N; // last statement (look for XFALL)
t = listfirst(&save, &n);
if(t->op != OXCASE)
return 0;
loop:
if(t == N) {
if(oc == N)
return 0;
return 1;
}
if(t->op == OXCASE) {
/* rewrite and link top level cases */
t->op = OCASE;
if(oc != N)
oc->right = t;
oc = t;
/* rewrite top fall that preceed case */
if(ot != N && ot->op == OXFALL)
ot->op = OFALL;
}
/* if first statement is not case then return 0 */
if(oc == N)
return 0;
ot = t;
t = listnext(&save);
goto loop;
}
/*
* allowable type combinations for
* normal binary operations.
*/
Node*
lookdot(Node *n, Node *t, int d)
{
Node *r, *f, *c;
Sym *s;
int o;
r = N;
s = n->sym;
if(d > 0)
goto deep;
o = 0;
for(f=t->type; f!=N; f=f->down) {
f->kaka = o;
o++;
if(f->sym == S)
continue;
if(f->sym != s)
continue;
if(r != N) {
yyerror("ambiguous DOT reference %s", s->name);
break;
}
r = f;
}
return r;
deep:
/* deeper look after shallow failed */
for(f=t->type; f!=N; f=f->down) {
// only look at unnamed sub-structures
// BOTCH no such thing -- all are assigned temp names
if(f->sym != S)
continue;
c = f->type;
if(c->etype != TSTRUCT)
continue;
c = lookdot(n, c, d-1);
if(c == N)
continue;
if(r != N) {
yyerror("ambiguous unnamed DOT reference %s", s->name);
break;
}
r = c;
}
return r;
}
void
walkdot(Node *n)
{
Node *t, *f;
int i;
if(n->left == N || n->right == N)
return;
walktype(n->left, 0);
if(n->right->op != ONAME) {
yyerror("rhs of . must be a name");
return;
}
t = n->left->type;
if(t == N)
return;
if(t->etype == TPTR) {
t = t->type;
if(t == N)
return;
n->op = ODOTPTR;
}
if(n->right->op != ONAME)
fatal("walkdot: not name %O", n->right->op);
switch(t->etype) {
default:
badtype(ODOT, t, N);
return;
case TSTRUCT:
case TINTER:
for(i=0; i<5; i++) {
f = lookdot(n->right, t, i);
if(f != N)
break;
}
if(f == N) {
yyerror("undefined DOT reference %N", n->right);
break;
}
n->right = f->nname; // substitute real name
n->type = f->type;
if(n->type->etype == TFUNC) {
n->op = ODOTMETH;
if(t->etype == TINTER) {
n->op = ODOTINTER;
n->kaka = f->kaka;
}
}
break;
}
}
void
walkslice(Node *n)
{
Node *l, *r;
if(n->left == N || n->right == N)
return;
walktype(n->left, 0);
if(!isptrto(n->left->type, TSTRING)) {
badtype(OSLICE, n->left->type, N);
return;
}
if(n->right->op != OLIST)
fatal("slice not a list");
// check for type errors
walktype(n->right, 0);
l = n->right->left;
r = n->right->right;
convlit(l, types[TINT32]);
convlit(r, types[TINT32]);
if(l == N || r == N ||
l->type == N || r->type == N)
return;
if(!isint[l->type->etype] || !isint[l->type->etype]) {
badtype(OSLICE, l->type, r->type);
return;
}
// now convert to int32
n->right->left = nod(OCONV, n->right->left, N);
n->right->left->type = types[TINT32];
n->right->right = nod(OCONV, n->right->right, N);
n->right->right->type = types[TINT32];
walktype(n->right, 0);
n->type = n->left->type;
}
/*
* test tuple type list against each other
* called in four contexts
* 1. a,b = c,d ...ee
* 2. a,b = fn() ...et
* 3. call(fn()) ...tt
* 4. call(a,b) ...te
*/
void
ascompatee(int op, Node **nl, Node **nr)
{
Node *l, *r;
Iter savel, saver;
int sa, na;
l = listfirst(&savel, nl);
r = listfirst(&saver, nr);
na = 0; // number of assignments - looking for multi
sa = 0; // one of the assignments is a structure assignment
loop:
if(l == N || r == N) {
if(l != r)
yyerror("error in shape across assignment");
if(sa != 0 && na > 1)
yyerror("cant do multi-struct assignments");
return;
}
convlit(r, l->type);
if(!ascompat(l->type, r->type)) {
badtype(op, l->type, r->type);
return;
}
if(l->type != N && l->type->etype == TSTRUCT)
sa = 1;
l = listnext(&savel);
r = listnext(&saver);
na++;
goto loop;
}
void
ascompatet(int op, Node **nl, Node **nr)
{
Node *l, *r;
Iter savel, saver;
l = listfirst(&savel, nl);
r = structfirst(&saver, nr);
loop:
if(l == N || r == N) {
if(l != r)
yyerror("error in shape across assignment");
return;
}
if(!ascompat(l->type, r->type)) {
badtype(op, l->type, r->type);
return;
}
l = listnext(&savel);
r = structnext(&saver);
goto loop;
}
void
ascompatte(int op, Node **nl, Node **nr)
{
Node *l, *r;
Iter savel, saver;
l = structfirst(&savel, nl);
r = listfirst(&saver, nr);
loop:
if(l == N || r == N) {
if(l != r)
yyerror("error in shape across assignment");
return;
}
convlit(r, l->type);
if(!ascompat(l->type, r->type)) {
badtype(op, l->type, r->type);
return;
}
l = structnext(&savel);
r = listnext(&saver);
goto loop;
}
void
ascompattt(int op, Node **nl, Node **nr)
{
Node *l, *r;
Iter savel, saver;
l = structfirst(&savel, nl);
r = structfirst(&saver, nr);
loop:
if(l == N || r == N) {
if(l != r)
yyerror("error in shape across assignment");
return;
}
if(!ascompat(l->type, r->type)) {
badtype(op, l->type, r->type);
return;
}
l = structnext(&savel);
r = structnext(&saver);
goto loop;
}
/*
* can we assign var of type t2 to var of type t1
*/
int
ascompat(Node *t1, Node *t2)
{
if(eqtype(t1, t2, 0))
return 1;
// if(eqtype(t1, nilptr, 0))
// return 1;
// if(eqtype(t2, nilptr, 0))
// return 1;
if(isinter(t1))
if(isptrto(t2, TSTRUCT) || isinter(t2))
return 1;
if(isinter(t2))
if(isptrto(t1, TSTRUCT))
return 1;
return 0;
}
void
prcompat(Node **n)
{
Node *l, *t;
Iter save;
int w;
l = listfirst(&save, n);
loop:
if(l == N)
return;
t = N;
w = whatis(l);
switch(w) {
default:
badtype((*n)->op, l->type, N);
break;
case Wtint:
case Wtfloat:
case Wtbool:
case Wtstr:
break;
case Wlitint:
t = types[TINT32];
break;
case Wlitfloat:
t = types[TFLOAT64];
break;
case Wlitbool:
t = types[TBOOL];
break;
case Wlitstr:
t = types[TSTRING];
break;
}
if(t != N)
convlit(l, t);
l = listnext(&save);
goto loop;
}