mirror of
https://github.com/golang/go
synced 2024-11-21 19:04:44 -07:00
SVN=114202
This commit is contained in:
parent
e311457488
commit
cb87526ce3
377
src/c/const.c
Normal file
377
src/c/const.c
Normal 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
764
src/c/dcl.c
Normal 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
585
src/c/export.c
Normal 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
1176
src/c/gen.c
Normal file
File diff suppressed because it is too large
Load Diff
206
src/c/gen.h
Normal file
206
src/c/gen.h
Normal 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
513
src/c/go.h
Normal 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
1302
src/c/go.y
Normal file
File diff suppressed because it is too large
Load Diff
523
src/c/gsubr.c
Normal file
523
src/c/gsubr.c
Normal 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
1058
src/c/lex.c
Normal file
File diff suppressed because it is too large
Load Diff
342
src/c/mpatof.c
Executable file
342
src/c/mpatof.c
Executable 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
1535
src/c/obj.c
Normal file
File diff suppressed because it is too large
Load Diff
1472
src/c/subr.c
Normal file
1472
src/c/subr.c
Normal file
File diff suppressed because it is too large
Load Diff
138
src/c/test.c
Normal file
138
src/c/test.c
Normal 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
967
src/c/walk.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user