2008-06-04 15:37:38 -06:00
|
|
|
// 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"
|
|
|
|
|
2008-06-11 22:06:26 -06:00
|
|
|
int
|
|
|
|
dflag(void)
|
|
|
|
{
|
|
|
|
if(!debug['d'])
|
|
|
|
return 0;
|
|
|
|
if(debug['y'])
|
|
|
|
return 1;
|
|
|
|
if(inimportsys)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
|
|
|
dodclvar(Node *n, Type *t)
|
|
|
|
{
|
|
|
|
if(n == N)
|
|
|
|
return;
|
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
for(; n->op == OLIST; n = n->right)
|
2008-06-04 15:37:38 -06:00
|
|
|
dodclvar(n->left, t);
|
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
dowidth(t);
|
|
|
|
addvar(n, t, dclcontext);
|
2008-08-03 19:47:02 -06:00
|
|
|
if(exportadj)
|
|
|
|
exportsym(n->sym);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-10-06 17:44:17 -06:00
|
|
|
dodclconst(Node *n, Node *e)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2008-10-06 17:44:17 -06:00
|
|
|
if(n == N)
|
2008-06-04 15:37:38 -06:00
|
|
|
return;
|
2008-10-06 17:44:17 -06:00
|
|
|
|
|
|
|
for(; n->op == OLIST; n=n->right)
|
|
|
|
dodclconst(n, e);
|
|
|
|
|
|
|
|
addconst(n, e, dclcontext);
|
2008-10-03 17:15:55 -06:00
|
|
|
if(exportadj)
|
|
|
|
exportsym(n->sym);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
/*
|
|
|
|
* introduce a type named n
|
|
|
|
* but it is an unknown type for now
|
|
|
|
*/
|
|
|
|
Type*
|
|
|
|
dodcltype(Type *n)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
|
|
|
Sym *s;
|
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
// if n has been forward declared,
|
|
|
|
// use the Type* created then
|
|
|
|
s = n->sym;
|
|
|
|
if(s->tblock == block) {
|
|
|
|
switch(s->otype->etype) {
|
|
|
|
case TFORWSTRUCT:
|
|
|
|
case TFORWINTER:
|
2008-10-07 13:42:57 -06:00
|
|
|
n = s->otype;
|
|
|
|
goto found;
|
2008-10-06 17:44:17 -06:00
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
// otherwise declare a new type
|
|
|
|
addtyp(n, dclcontext);
|
2008-10-07 13:42:57 -06:00
|
|
|
|
|
|
|
found:
|
2008-10-06 17:44:17 -06:00
|
|
|
n->sym->local = 1;
|
|
|
|
if(exportadj)
|
|
|
|
exportsym(n->sym);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* now we know what n is: it's t
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
updatetype(Type *n, Type *t)
|
|
|
|
{
|
|
|
|
Sym *s;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
s = n->sym;
|
2008-10-06 17:44:17 -06:00
|
|
|
if(s == S || s->otype != n)
|
|
|
|
fatal("updatetype %T = %T", n, t);
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
switch(n->etype) {
|
|
|
|
case TFORW:
|
|
|
|
break;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
case TFORWSTRUCT:
|
|
|
|
if(t->etype != TSTRUCT) {
|
|
|
|
yyerror("%T forward declared as struct", n);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
2008-10-03 17:15:55 -06:00
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
case TFORWINTER:
|
|
|
|
if(t->etype != TINTER) {
|
|
|
|
yyerror("%T forward declared as interface", n);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
default:
|
|
|
|
fatal("updatetype %T / %T", n, t);
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
*n = *t;
|
|
|
|
n->sym = s;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
// catch declaration of incomplete type
|
|
|
|
switch(n->etype) {
|
|
|
|
case TFORWSTRUCT:
|
|
|
|
case TFORWINTER:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
checkwidth(n);
|
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
Type*
|
|
|
|
functype(Node *this, Node *in, Node *out)
|
|
|
|
{
|
|
|
|
Type *t;
|
|
|
|
|
|
|
|
t = typ(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);
|
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
checkwidth(t);
|
2008-06-04 15:37:38 -06:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
methcmp(Type *t1, Type *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 == T || t2 == T)
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
Node*
|
|
|
|
methodname(Node *n, Type *t)
|
|
|
|
{
|
2008-08-10 16:09:09 -06:00
|
|
|
Sym *s;
|
2008-10-03 17:15:55 -06:00
|
|
|
char buf[NSYMB];
|
2008-08-10 16:09:09 -06:00
|
|
|
|
2008-10-04 03:51:03 -06:00
|
|
|
// caller has already called ismethod to obtain t
|
2008-09-14 17:57:55 -06:00
|
|
|
if(t == T)
|
|
|
|
goto bad;
|
2008-10-04 03:51:03 -06:00
|
|
|
s = t->sym;
|
2008-08-10 16:09:09 -06:00
|
|
|
if(s == S)
|
|
|
|
goto bad;
|
2008-09-14 17:57:55 -06:00
|
|
|
|
2008-10-03 17:15:55 -06:00
|
|
|
snprint(buf, sizeof(buf), "%s_%s", s->name, n->sym->name);
|
2008-10-04 03:51:03 -06:00
|
|
|
return newname(pkglookup(buf, s->opackage));
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
bad:
|
2008-09-28 21:22:31 -06:00
|
|
|
yyerror("illegal <this> type: %T", t);
|
2008-06-04 15:37:38 -06:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* add a method, declared as a function,
|
2008-09-14 17:57:55 -06:00
|
|
|
* n is fieldname, pa is base type, t is function type
|
2008-06-04 15:37:38 -06:00
|
|
|
*/
|
|
|
|
void
|
2008-09-14 17:57:55 -06:00
|
|
|
addmethod(Node *n, Type *t, int local)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2008-09-14 17:57:55 -06:00
|
|
|
Type *f, *d, *pa;
|
|
|
|
Sym *st, *sf;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
pa = nil;
|
|
|
|
sf = nil;
|
|
|
|
|
2008-09-14 17:57:55 -06:00
|
|
|
// get field sym
|
|
|
|
if(n == N)
|
|
|
|
goto bad;
|
2008-06-04 15:37:38 -06:00
|
|
|
if(n->op != ONAME)
|
|
|
|
goto bad;
|
2008-09-14 17:57:55 -06:00
|
|
|
sf = n->sym;
|
|
|
|
if(sf == S)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto bad;
|
2008-09-14 17:57:55 -06:00
|
|
|
|
|
|
|
// get parent type sym
|
|
|
|
pa = *getthis(t); // ptr to this structure
|
2008-06-04 15:37:38 -06:00
|
|
|
if(pa == T)
|
|
|
|
goto bad;
|
2008-09-14 17:57:55 -06:00
|
|
|
pa = pa->type; // ptr to this field
|
|
|
|
if(pa == T)
|
2008-09-13 15:49:36 -06:00
|
|
|
goto bad;
|
2008-09-14 17:57:55 -06:00
|
|
|
pa = pa->type; // ptr to this type
|
|
|
|
if(pa == T)
|
2008-06-04 15:37:38 -06:00
|
|
|
goto bad;
|
|
|
|
|
2008-09-14 17:57:55 -06:00
|
|
|
// and finally the receiver sym
|
2008-10-02 21:51:10 -06:00
|
|
|
f = ismethod(pa);
|
|
|
|
if(f == T)
|
|
|
|
goto bad;
|
|
|
|
pa = f;
|
2008-09-14 17:57:55 -06:00
|
|
|
st = pa->sym;
|
|
|
|
if(st == S)
|
|
|
|
goto bad;
|
|
|
|
if(local && !st->local) {
|
|
|
|
yyerror("method receiver type must be locally defined: %S", st);
|
2008-06-04 15:37:38 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-09-14 17:57:55 -06:00
|
|
|
n = nod(ODCLFIELD, newname(sf), N);
|
|
|
|
n->type = t;
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
d = T; // last found
|
2008-09-14 17:57:55 -06:00
|
|
|
for(f=pa->method; f!=T; f=f->down) {
|
2008-06-04 15:37:38 -06:00
|
|
|
if(f->etype != TFIELD)
|
|
|
|
fatal("addmethod: not TFIELD: %N", f);
|
|
|
|
|
2008-09-14 17:57:55 -06:00
|
|
|
if(strcmp(sf->name, f->sym->name) != 0) {
|
2008-06-04 15:37:38 -06:00
|
|
|
d = f;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(!eqtype(t, f->type, 0))
|
2008-09-14 17:57:55 -06:00
|
|
|
yyerror("method redeclared: %S of type %S", sf, st);
|
2008-09-15 20:07:23 -06:00
|
|
|
return;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if(d == T)
|
2008-09-14 17:57:55 -06:00
|
|
|
stotype(n, &pa->method);
|
2008-06-04 15:37:38 -06:00
|
|
|
else
|
|
|
|
stotype(n, &d->down);
|
2008-09-14 17:57:55 -06:00
|
|
|
|
|
|
|
if(dflag())
|
2008-10-02 21:51:10 -06:00
|
|
|
print("method %S of type %T\n", sf, pa);
|
2008-06-04 15:37:38 -06:00
|
|
|
return;
|
|
|
|
|
|
|
|
bad:
|
2008-09-30 14:52:44 -06:00
|
|
|
yyerror("unknown method pointer: %T %S", pa, sf);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
2008-07-19 19:39:12 -06:00
|
|
|
/*
|
|
|
|
* a function named init is a special case.
|
|
|
|
* it is called by the initialization before
|
|
|
|
* main is run. to make it unique within a
|
|
|
|
* package, the name, normally "pkg.init", is
|
|
|
|
* altered to "pkg.<file>_init".
|
|
|
|
*/
|
|
|
|
Node*
|
|
|
|
renameinit(Node *n)
|
|
|
|
{
|
|
|
|
Sym *s;
|
|
|
|
|
|
|
|
s = n->sym;
|
|
|
|
if(s == S)
|
|
|
|
return n;
|
|
|
|
if(strcmp(s->name, "init") != 0)
|
|
|
|
return n;
|
|
|
|
snprint(namebuf, sizeof(namebuf), "init_%s", filename);
|
|
|
|
s = lookup(namebuf);
|
|
|
|
return newname(s);
|
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
/*
|
|
|
|
* 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 same types
|
|
|
|
if(on != N) {
|
|
|
|
if(eqtype(n->type, on->type, 0)) {
|
|
|
|
if(!eqargs(n->type, on->type))
|
2008-06-27 11:29:02 -06:00
|
|
|
yyerror("forward declarations not the same: %S", s);
|
2008-06-04 15:37:38 -06:00
|
|
|
} else {
|
|
|
|
yyerror("redeclare of function: %S", s);
|
|
|
|
on = N;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-27 11:29:02 -06:00
|
|
|
// check for forward declaration
|
2008-06-04 15:37:38 -06:00
|
|
|
if(on == N) {
|
|
|
|
// initial declaration or redeclaration
|
|
|
|
// declare fun name, argument types and argument names
|
|
|
|
n->nname->type = n->type;
|
|
|
|
if(n->type->thistuple == 0)
|
|
|
|
addvar(n->nname, n->type, PEXTERN);
|
|
|
|
else
|
|
|
|
n->nname->class = PEXTERN;
|
|
|
|
} else {
|
|
|
|
// identical redeclaration
|
|
|
|
// steal previous names
|
|
|
|
n->nname = on;
|
|
|
|
n->type = on->type;
|
|
|
|
n->class = on->class;
|
|
|
|
n->sym = s;
|
2008-06-11 22:06:26 -06:00
|
|
|
if(dflag())
|
2008-06-04 15:37:38 -06:00
|
|
|
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;
|
2008-07-05 13:49:25 -06:00
|
|
|
markdcl();
|
2008-06-04 15:37:38 -06:00
|
|
|
funcargs(n->type);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-07-16 19:31:01 -06:00
|
|
|
funcargs(Type *ft)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
2008-07-16 19:31:01 -06:00
|
|
|
Type *t;
|
2008-06-04 15:37:38 -06:00
|
|
|
Iter save;
|
2008-07-05 13:49:25 -06:00
|
|
|
int all;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-07-05 13:49:25 -06:00
|
|
|
// declare the this/in arguments
|
2008-07-16 19:31:01 -06:00
|
|
|
t = funcfirst(&save, ft);
|
|
|
|
while(t != T) {
|
2008-07-17 16:03:39 -06:00
|
|
|
if(t->nname != N) {
|
|
|
|
t->nname->xoffset = t->width;
|
2008-07-16 19:31:01 -06:00
|
|
|
addvar(t->nname, t->type, PPARAM);
|
2008-07-17 16:03:39 -06:00
|
|
|
}
|
2008-07-16 19:31:01 -06:00
|
|
|
t = funcnext(&save);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// declare the outgoing arguments
|
2008-07-05 13:49:25 -06:00
|
|
|
all = 0;
|
2008-07-16 19:31:01 -06:00
|
|
|
t = structfirst(&save, getoutarg(ft));
|
|
|
|
while(t != T) {
|
2008-07-17 16:03:39 -06:00
|
|
|
if(t->nname != N)
|
|
|
|
t->nname->xoffset = t->width;
|
2008-07-16 19:31:01 -06:00
|
|
|
if(t->nname != N && t->nname->sym->name[0] != '_') {
|
|
|
|
addvar(t->nname, t->type, PPARAM);
|
2008-07-05 13:49:25 -06:00
|
|
|
all |= 1;
|
|
|
|
} else
|
|
|
|
all |= 2;
|
2008-07-16 19:31:01 -06:00
|
|
|
t = structnext(&save);
|
2008-07-05 13:49:25 -06:00
|
|
|
}
|
2008-10-02 21:51:10 -06:00
|
|
|
|
|
|
|
// this test is remarkedly similar to checkarglist
|
2008-07-05 13:49:25 -06:00
|
|
|
if(all == 3)
|
2008-10-02 21:51:10 -06:00
|
|
|
yyerror("cannot mix anonymous and named output arguments");
|
2008-07-05 13:49:25 -06:00
|
|
|
|
2008-07-16 19:31:01 -06:00
|
|
|
ft->outnamed = 0;
|
2008-07-05 13:49:25 -06:00
|
|
|
if(all == 1)
|
2008-07-16 19:31:01 -06:00
|
|
|
ft->outnamed = 1;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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");
|
2008-07-05 13:49:25 -06:00
|
|
|
popdcl();
|
2008-06-04 15:37:38 -06:00
|
|
|
dclcontext = PEXTERN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* turn a parsed struct into a type
|
|
|
|
*/
|
|
|
|
Type**
|
|
|
|
stotype(Node *n, Type **t)
|
|
|
|
{
|
|
|
|
Type *f;
|
|
|
|
Iter save;
|
2008-10-03 17:15:55 -06:00
|
|
|
char buf[100];
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
n = listfirst(&save, &n);
|
|
|
|
|
|
|
|
loop:
|
|
|
|
if(n == N) {
|
|
|
|
*t = T;
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(n->op == OLIST) {
|
|
|
|
// recursive because it can be lists of lists
|
|
|
|
t = stotype(n, t);
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(n->op != ODCLFIELD || n->type == T)
|
|
|
|
fatal("stotype: oops %N\n", n);
|
|
|
|
|
2008-08-28 16:17:37 -06:00
|
|
|
if(n->type->etype == TARRAY && n->type->bound < 0)
|
2008-06-04 15:37:38 -06:00
|
|
|
yyerror("type of a structure field cannot be an open array");
|
|
|
|
|
|
|
|
f = typ(TFIELD);
|
|
|
|
f->type = n->type;
|
|
|
|
|
|
|
|
if(n->left != N && n->left->op == ONAME) {
|
|
|
|
f->nname = n->left;
|
|
|
|
} else {
|
|
|
|
vargen++;
|
2008-10-03 17:15:55 -06:00
|
|
|
snprint(buf, sizeof(buf), "_e%s_%.3ld", filename, vargen);
|
|
|
|
f->nname = newname(lookup(buf));
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
f->sym = f->nname->sym;
|
|
|
|
|
|
|
|
*t = f;
|
|
|
|
t = &f->down;
|
|
|
|
|
|
|
|
next:
|
|
|
|
n = listnext(&save);
|
|
|
|
goto loop;
|
|
|
|
}
|
|
|
|
|
|
|
|
Type*
|
|
|
|
dostruct(Node *n, int et)
|
|
|
|
{
|
|
|
|
Type *t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* convert a parsed id/type list into
|
|
|
|
* a type for struct/interface/arglist
|
|
|
|
*/
|
|
|
|
|
|
|
|
t = typ(et);
|
|
|
|
stotype(n, &t->type);
|
2008-10-06 17:44:17 -06:00
|
|
|
checkwidth(t);
|
2008-06-04 15:37:38 -06:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
Type*
|
|
|
|
sortinter(Type *t)
|
|
|
|
{
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
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->lexical = b->lexical;
|
|
|
|
a->undef = b->undef;
|
|
|
|
a->vargen = b->vargen;
|
2008-06-21 16:11:29 -06:00
|
|
|
a->vblock = b->vblock;
|
|
|
|
a->tblock = b->tblock;
|
2008-10-06 17:44:17 -06:00
|
|
|
a->local = b->local;
|
|
|
|
a->offset = b->offset;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2008-07-05 13:49:25 -06:00
|
|
|
popdcl(void)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
|
|
|
Sym *d, *s;
|
|
|
|
|
2008-06-11 22:06:26 -06:00
|
|
|
// if(dflag())
|
2008-06-04 15:37:38 -06:00
|
|
|
// print("revert\n");
|
2008-06-13 19:16:23 -06:00
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
for(d=dclstack; d!=S; d=d->link) {
|
|
|
|
if(d->name == nil)
|
|
|
|
break;
|
|
|
|
s = pkglookup(d->name, d->package);
|
|
|
|
dcopy(s, d);
|
2008-06-11 22:06:26 -06:00
|
|
|
if(dflag())
|
2008-06-13 19:16:23 -06:00
|
|
|
print("\t%L pop %S\n", lineno, s);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
if(d == S)
|
|
|
|
fatal("popdcl: no mark");
|
|
|
|
dclstack = d->link;
|
2008-06-21 16:11:29 -06:00
|
|
|
block = d->vblock;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
poptodcl(void)
|
|
|
|
{
|
|
|
|
Sym *d, *s;
|
|
|
|
|
|
|
|
for(d=dclstack; d!=S; d=d->link) {
|
|
|
|
if(d->name == nil)
|
|
|
|
break;
|
|
|
|
s = pkglookup(d->name, d->package);
|
|
|
|
dcopy(s, d);
|
2008-06-11 22:06:26 -06:00
|
|
|
if(dflag())
|
2008-06-13 19:16:23 -06:00
|
|
|
print("\t%L pop %S\n", lineno, s);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
if(d == S)
|
|
|
|
fatal("poptodcl: no mark");
|
2008-10-03 17:15:55 -06:00
|
|
|
dclstack = d;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-07-05 13:49:25 -06:00
|
|
|
markdcl(void)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
|
|
|
Sym *d;
|
|
|
|
|
|
|
|
d = push();
|
|
|
|
d->name = nil; // used as a mark in fifo
|
2008-06-21 16:11:29 -06:00
|
|
|
d->vblock = block;
|
|
|
|
|
|
|
|
blockgen++;
|
|
|
|
block = blockgen;
|
2008-07-05 13:49:25 -06:00
|
|
|
|
2008-06-11 22:06:26 -06:00
|
|
|
// if(dflag())
|
2008-06-04 15:37:38 -06:00
|
|
|
// print("markdcl\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
markdclstack(void)
|
|
|
|
{
|
|
|
|
Sym *d, *s;
|
|
|
|
|
2008-07-05 13:49:25 -06:00
|
|
|
markdcl();
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-16 18:22:54 -06:00
|
|
|
void
|
|
|
|
dumpdcl(char *st)
|
|
|
|
{
|
|
|
|
Sym *s, *d;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
print("\ndumpdcl: %s %p\n", st, b0stack);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
for(d=dclstack; d!=S; d=d->link) {
|
|
|
|
i++;
|
|
|
|
print(" %.2d %p", i, d);
|
|
|
|
if(d == b0stack)
|
|
|
|
print(" (b0)");
|
|
|
|
if(d->name == nil) {
|
|
|
|
print("\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
print(" '%s'", d->name);
|
|
|
|
s = pkglookup(d->name, d->package);
|
|
|
|
print(" %lS\n", s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
void
|
|
|
|
testdclstack(void)
|
|
|
|
{
|
|
|
|
Sym *d;
|
|
|
|
|
|
|
|
for(d=dclstack; d!=S; d=d->link) {
|
|
|
|
if(d->name == nil) {
|
|
|
|
yyerror("mark left on the stack");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
addvar(Node *n, Type *t, int ctxt)
|
|
|
|
{
|
|
|
|
Dcl *r, *d;
|
|
|
|
Sym *s;
|
|
|
|
int gen;
|
|
|
|
|
|
|
|
if(n==N || n->sym == S || n->op != ONAME || t == T)
|
|
|
|
fatal("addvar: n=%N t=%T nil", n, t);
|
|
|
|
|
|
|
|
s = n->sym;
|
|
|
|
|
2008-07-05 13:49:25 -06:00
|
|
|
if(s->vblock == block) {
|
|
|
|
if(s->oname != N) {
|
|
|
|
yyerror("var %S redeclared in this block"
|
|
|
|
"\n previous declaration at %L",
|
|
|
|
s, s->oname->lineno);
|
|
|
|
} else
|
|
|
|
yyerror("var %S redeclared in this block", s);
|
|
|
|
}
|
fix up arg list parsing to handle any names:
type t1 int;
type t2 int;
type t3 int;
func f1(t1, t2, t3);
func f2(t1, t2, t3 bool);
func f3(t1, t2, x t3);
func f4(*t2, x t3); // error: cannot mix
func f5(t1, *t3);
func (x *t1) f6(y *[]t2) (t1, *t3);
func f7() (int, *string);
func f8(t1, *t2, x t3); // error: cannot mix
func f9() (x int, *string);
func f10(*t2, t3);
R=ken
OCL=16202
CL=16210
2008-09-30 13:53:11 -06:00
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
if(ctxt == PEXTERN) {
|
|
|
|
r = externdcl;
|
|
|
|
gen = 0;
|
|
|
|
vargen++; // just for diffing output against old compiler
|
|
|
|
} else {
|
|
|
|
r = autodcl;
|
|
|
|
vargen++;
|
|
|
|
gen = vargen;
|
2008-06-04 15:37:38 -06:00
|
|
|
pushdcl(s);
|
2008-10-06 17:44:17 -06:00
|
|
|
}
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
s->vargen = gen;
|
|
|
|
s->oname = n;
|
|
|
|
s->offset = 0;
|
2008-06-21 16:11:29 -06:00
|
|
|
s->vblock = block;
|
2008-09-30 14:49:31 -06:00
|
|
|
s->lexical = LNAME;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
n->type = t;
|
|
|
|
n->vargen = gen;
|
|
|
|
n->class = ctxt;
|
|
|
|
|
|
|
|
d = dcl();
|
|
|
|
d->dsym = s;
|
|
|
|
d->dnode = n;
|
|
|
|
d->op = ONAME;
|
|
|
|
|
|
|
|
r->back->forw = d;
|
|
|
|
r->back = d;
|
|
|
|
|
2008-06-11 22:06:26 -06:00
|
|
|
if(dflag()) {
|
2008-06-04 15:37:38 -06:00
|
|
|
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
|
2008-10-06 17:44:17 -06:00
|
|
|
addtyp(Type *n, int ctxt)
|
2008-06-04 15:37:38 -06:00
|
|
|
{
|
|
|
|
Dcl *r, *d;
|
|
|
|
Sym *s;
|
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
if(n==T || n->sym == S)
|
|
|
|
fatal("addtyp: n=%T t=%T nil", n);
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
s = n->sym;
|
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
if(ctxt == PEXTERN)
|
2008-06-04 15:37:38 -06:00
|
|
|
r = externdcl;
|
2008-10-06 17:44:17 -06:00
|
|
|
else {
|
|
|
|
r = autodcl;
|
|
|
|
pushdcl(s);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
2008-10-06 17:44:17 -06:00
|
|
|
vargen++; // just for diffing output against old compiler
|
2008-06-04 15:37:38 -06:00
|
|
|
|
2008-06-21 16:11:29 -06:00
|
|
|
if(s->tblock == block)
|
|
|
|
yyerror("type %S redeclared in this block %d", s, block);
|
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
s->otype = n;
|
2008-06-04 15:37:38 -06:00
|
|
|
s->lexical = LATYPE;
|
2008-06-21 16:11:29 -06:00
|
|
|
s->tblock = block;
|
2008-06-04 15:37:38 -06:00
|
|
|
|
|
|
|
d = dcl();
|
|
|
|
d->dsym = s;
|
2008-10-06 17:44:17 -06:00
|
|
|
d->dtype = n;
|
2008-06-04 15:37:38 -06:00
|
|
|
d->op = OTYPE;
|
|
|
|
|
|
|
|
r->back->forw = d;
|
|
|
|
r->back = d;
|
|
|
|
|
2008-06-11 22:06:26 -06:00
|
|
|
if(dflag()) {
|
2008-06-04 15:37:38 -06:00
|
|
|
if(ctxt == PEXTERN)
|
2008-10-06 17:44:17 -06:00
|
|
|
print("extern typ-dcl %S G%ld %T\n", s, s->vargen, n);
|
2008-06-04 15:37:38 -06:00
|
|
|
else
|
2008-10-06 17:44:17 -06:00
|
|
|
print("auto typ-dcl %S G%ld %T\n", s, s->vargen, n);
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-06 17:44:17 -06:00
|
|
|
void
|
|
|
|
addconst(Node *n, Node *e, int ctxt)
|
|
|
|
{
|
|
|
|
Sym *s;
|
|
|
|
Dcl *r, *d;
|
|
|
|
|
|
|
|
if(n->op != ONAME)
|
|
|
|
fatal("addconst: not a name");
|
|
|
|
|
|
|
|
if(e->op != OLITERAL) {
|
|
|
|
yyerror("expression must be a constant");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = n->sym;
|
|
|
|
|
|
|
|
if(ctxt == PEXTERN)
|
|
|
|
r = externdcl;
|
|
|
|
else {
|
|
|
|
r = autodcl;
|
|
|
|
pushdcl(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
s->oconst = e;
|
|
|
|
s->lexical = LACONST;
|
|
|
|
|
|
|
|
d = dcl();
|
|
|
|
d->dsym = s;
|
|
|
|
d->dnode = e;
|
|
|
|
d->op = OCONST;
|
|
|
|
|
|
|
|
r->back->forw = d;
|
|
|
|
r->back = d;
|
|
|
|
|
|
|
|
if(dflag())
|
|
|
|
print("const-dcl %S %N\n", n->sym, n->sym->oconst);
|
|
|
|
}
|
|
|
|
|
2008-06-04 15:37:38 -06:00
|
|
|
Node*
|
|
|
|
fakethis(void)
|
|
|
|
{
|
|
|
|
Node *n;
|
|
|
|
Type *t;
|
|
|
|
|
|
|
|
n = nod(ODCLFIELD, N, N);
|
|
|
|
t = dostruct(N, TSTRUCT);
|
|
|
|
t = ptrto(t);
|
|
|
|
n->type = 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 = T;
|
|
|
|
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) {
|
2008-06-21 16:11:29 -06:00
|
|
|
n = nod(ONONAME, N, N);
|
|
|
|
n->sym = s;
|
|
|
|
n->type = T;
|
|
|
|
n->addable = 1;
|
|
|
|
n->ullman = 0;
|
2008-06-04 15:37:38 -06:00
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* same for types
|
|
|
|
*/
|
|
|
|
Type*
|
|
|
|
newtype(Sym *s)
|
|
|
|
{
|
|
|
|
Type *t;
|
|
|
|
|
|
|
|
t = typ(TFORW);
|
|
|
|
t->sym = s;
|
|
|
|
t->type = T;
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
Type*
|
|
|
|
oldtype(Sym *s)
|
|
|
|
{
|
|
|
|
Type *t;
|
|
|
|
|
|
|
|
t = s->otype;
|
|
|
|
if(t == T)
|
|
|
|
fatal("%S not a type", s); // cant happen
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
fix up arg list parsing to handle any names:
type t1 int;
type t2 int;
type t3 int;
func f1(t1, t2, t3);
func f2(t1, t2, t3 bool);
func f3(t1, t2, x t3);
func f4(*t2, x t3); // error: cannot mix
func f5(t1, *t3);
func (x *t1) f6(y *[]t2) (t1, *t3);
func f7() (int, *string);
func f8(t1, *t2, x t3); // error: cannot mix
func f9() (x int, *string);
func f10(*t2, t3);
R=ken
OCL=16202
CL=16210
2008-09-30 13:53:11 -06:00
|
|
|
/*
|
|
|
|
* n is a node with a name (or a reversed list of them).
|
|
|
|
* make it an anonymous declaration of that name's type.
|
|
|
|
*/
|
|
|
|
Node*
|
|
|
|
nametoanondcl(Node *na)
|
|
|
|
{
|
|
|
|
Node **l, *n;
|
|
|
|
Type *t;
|
|
|
|
|
|
|
|
for(l=&na; (n=*l)->op == OLIST; l=&n->left)
|
|
|
|
n->right = nametoanondcl(n->right);
|
|
|
|
|
|
|
|
if(n->sym->lexical != LATYPE && n->sym->lexical != LBASETYPE) {
|
|
|
|
yyerror("%s is not a type", n->sym->name);
|
|
|
|
t = typ(TINT32);
|
|
|
|
} else
|
|
|
|
t = oldtype(n->sym);
|
|
|
|
n = nod(ODCLFIELD, N, N);
|
|
|
|
n->type = t;
|
|
|
|
*l = n;
|
|
|
|
return na;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* n is a node with a name (or a reversed list of them).
|
|
|
|
* make it a declaration of the given type.
|
|
|
|
*/
|
|
|
|
Node*
|
|
|
|
nametodcl(Node *na, Type *t)
|
|
|
|
{
|
|
|
|
Node **l, *n;
|
|
|
|
|
|
|
|
for(l=&na; (n=*l)->op == OLIST; l=&n->left)
|
|
|
|
n->right = nametodcl(n->right, t);
|
|
|
|
|
|
|
|
n = nod(ODCLFIELD, n, N);
|
|
|
|
n->type = t;
|
|
|
|
*l = n;
|
|
|
|
return na;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* make an anonymous declaration for t
|
|
|
|
*/
|
|
|
|
Node*
|
|
|
|
anondcl(Type *t)
|
|
|
|
{
|
|
|
|
Node *n;
|
|
|
|
|
|
|
|
n = nod(ODCLFIELD, N, N);
|
|
|
|
n->type = t;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check that the list of declarations is either all anonymous or all named
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
checkarglist(Node *n)
|
|
|
|
{
|
|
|
|
if(n->op != OLIST)
|
|
|
|
return;
|
|
|
|
if(n->left->op != ODCLFIELD)
|
|
|
|
fatal("checkarglist");
|
|
|
|
if(n->left->left != N) {
|
|
|
|
for(n=n->right; n->op == OLIST; n=n->right)
|
|
|
|
if(n->left->left == N)
|
|
|
|
goto mixed;
|
|
|
|
if(n->left == N)
|
|
|
|
goto mixed;
|
|
|
|
} else {
|
|
|
|
for(n=n->right; n->op == OLIST; n=n->right)
|
|
|
|
if(n->left->left != N)
|
|
|
|
goto mixed;
|
|
|
|
if(n->left != N)
|
|
|
|
goto mixed;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
mixed:
|
|
|
|
yyerror("cannot mix anonymous and named function arguments");
|
|
|
|
}
|
|
|
|
|
2008-07-19 14:38:29 -06:00
|
|
|
// hand-craft the following initialization code
|
2008-07-19 19:39:12 -06:00
|
|
|
// var init_<file>_done bool; (1)
|
|
|
|
// func init_<file>_function() (2)
|
|
|
|
// if init_<file>_done { return } (3)
|
|
|
|
// init_<file>_done = true; (4)
|
|
|
|
// // over all matching imported symbols
|
|
|
|
// <pkg>.init_<file>_function() (5)
|
|
|
|
// { <init stmts> } (6)
|
2008-07-19 14:38:29 -06:00
|
|
|
// init() // if any (7)
|
|
|
|
// return (8)
|
|
|
|
// }
|
2008-07-19 19:39:12 -06:00
|
|
|
// export init_<file>_function (9)
|
2008-07-19 14:38:29 -06:00
|
|
|
|
|
|
|
void
|
|
|
|
fninit(Node *n)
|
|
|
|
{
|
2008-10-03 17:23:02 -06:00
|
|
|
Node *done;
|
2008-07-20 14:33:45 -06:00
|
|
|
Node *a, *fn, *r;
|
2008-08-03 18:25:15 -06:00
|
|
|
uint32 h;
|
2008-07-19 14:38:29 -06:00
|
|
|
Sym *s;
|
|
|
|
|
|
|
|
r = N;
|
|
|
|
|
|
|
|
// (1)
|
2008-07-19 19:39:12 -06:00
|
|
|
snprint(namebuf, sizeof(namebuf), "init_%s_done", filename);
|
2008-07-19 14:38:29 -06:00
|
|
|
done = newname(lookup(namebuf));
|
|
|
|
addvar(done, types[TBOOL], PEXTERN);
|
|
|
|
|
|
|
|
// (2)
|
|
|
|
|
|
|
|
maxarg = 0;
|
2008-10-13 21:14:09 -06:00
|
|
|
stksize = initstksize;
|
2008-07-19 14:38:29 -06:00
|
|
|
|
2008-07-19 15:20:46 -06:00
|
|
|
snprint(namebuf, sizeof(namebuf), "init_%s_function", filename);
|
|
|
|
|
|
|
|
// this is a botch since we need a known name to
|
|
|
|
// call the top level init function out of rt0
|
2008-07-19 14:38:29 -06:00
|
|
|
if(strcmp(package, "main") == 0)
|
2008-07-19 15:20:46 -06:00
|
|
|
snprint(namebuf, sizeof(namebuf), "init_function");
|
|
|
|
|
2008-07-20 14:33:45 -06:00
|
|
|
fn = nod(ODCLFUNC, N, N);
|
|
|
|
fn->nname = newname(lookup(namebuf));
|
|
|
|
fn->type = functype(N, N, N);
|
|
|
|
funchdr(fn);
|
2008-07-19 14:38:29 -06:00
|
|
|
|
|
|
|
// (3)
|
|
|
|
a = nod(OIF, N, N);
|
|
|
|
a->ntest = done;
|
|
|
|
a->nbody = nod(ORETURN, N, N);
|
|
|
|
r = list(r, a);
|
|
|
|
|
|
|
|
// (4)
|
|
|
|
a = nod(OAS, done, booltrue);
|
|
|
|
r = list(r, a);
|
|
|
|
|
|
|
|
// (5)
|
|
|
|
for(h=0; h<NHASH; h++)
|
|
|
|
for(s = hash[h]; s != S; s = s->link) {
|
|
|
|
if(s->name[0] != 'i')
|
|
|
|
continue;
|
2008-07-19 19:39:12 -06:00
|
|
|
if(strstr(s->name, "init_") == nil)
|
2008-07-19 14:38:29 -06:00
|
|
|
continue;
|
2008-07-19 19:39:12 -06:00
|
|
|
if(strstr(s->name, "_function") == nil)
|
2008-07-19 14:38:29 -06:00
|
|
|
continue;
|
|
|
|
if(s->oname == N)
|
|
|
|
continue;
|
|
|
|
|
2008-07-20 14:33:45 -06:00
|
|
|
// could check that it is fn of no args/returns
|
2008-07-19 14:38:29 -06:00
|
|
|
a = nod(OCALL, s->oname, N);
|
|
|
|
r = list(r, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
// (6)
|
|
|
|
r = list(r, n);
|
|
|
|
|
|
|
|
// (7)
|
2008-07-20 14:33:45 -06:00
|
|
|
// could check that it is fn of no args/returns
|
2008-07-19 19:39:12 -06:00
|
|
|
snprint(namebuf, sizeof(namebuf), "init_%s", filename);
|
|
|
|
s = lookup(namebuf);
|
|
|
|
if(s->oname != N) {
|
|
|
|
a = nod(OCALL, s->oname, N);
|
2008-07-19 14:38:29 -06:00
|
|
|
r = list(r, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
// (8)
|
|
|
|
a = nod(ORETURN, N, N);
|
|
|
|
r = list(r, a);
|
|
|
|
|
|
|
|
// (9)
|
2008-08-03 19:47:02 -06:00
|
|
|
exportsym(fn->nname->sym);
|
2008-07-19 14:38:29 -06:00
|
|
|
|
2008-07-20 14:33:45 -06:00
|
|
|
fn->nbody = rev(r);
|
|
|
|
//dump("b", fn);
|
|
|
|
//dump("r", fn->nbody);
|
2008-07-19 14:38:29 -06:00
|
|
|
|
|
|
|
popdcl();
|
2008-07-20 14:33:45 -06:00
|
|
|
compile(fn);
|
2008-07-19 14:38:29 -06:00
|
|
|
}
|
2008-10-06 17:44:17 -06:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* when a type's width should be known, we call checkwidth
|
|
|
|
* to compute it. during a declaration like
|
|
|
|
*
|
|
|
|
* type T *struct { next T }
|
|
|
|
*
|
|
|
|
* it is necessary to defer the calculation of the struct width
|
|
|
|
* until after T has been initialized to be a pointer to that struct.
|
|
|
|
* similarly, during import processing structs may be used
|
|
|
|
* before their definition. in those situations, calling
|
|
|
|
* defercheckwidth() stops width calculations until
|
|
|
|
* resumecheckwidth() is called, at which point all the
|
|
|
|
* checkwidths that were deferred are executed.
|
|
|
|
* sometimes it is okay to
|
|
|
|
*/
|
|
|
|
typedef struct TypeList TypeList;
|
|
|
|
struct TypeList {
|
|
|
|
Type *t;
|
|
|
|
TypeList *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
static TypeList *tlfree;
|
|
|
|
static TypeList *tlq;
|
|
|
|
static int defercalc;
|
|
|
|
|
|
|
|
void
|
|
|
|
checkwidth(Type *t)
|
|
|
|
{
|
|
|
|
TypeList *l;
|
|
|
|
|
|
|
|
if(!defercalc) {
|
|
|
|
dowidth(t);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
l = tlfree;
|
|
|
|
if(l != nil)
|
|
|
|
tlfree = l->next;
|
|
|
|
else
|
|
|
|
l = mal(sizeof *l);
|
|
|
|
|
|
|
|
l->t = t;
|
|
|
|
l->next = tlq;
|
|
|
|
tlq = l;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
defercheckwidth(void)
|
|
|
|
{
|
2008-10-07 14:00:10 -06:00
|
|
|
// we get out of sync on syntax errors, so don't be pedantic.
|
|
|
|
// if(defercalc)
|
|
|
|
// fatal("defercheckwidth");
|
2008-10-06 17:44:17 -06:00
|
|
|
defercalc = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
resumecheckwidth(void)
|
|
|
|
{
|
|
|
|
TypeList *l, *next;
|
|
|
|
|
|
|
|
if(!defercalc)
|
|
|
|
fatal("restartcheckwidth");
|
|
|
|
defercalc = 0;
|
|
|
|
|
|
|
|
for(l = tlq; l != nil; l = tlq) {
|
|
|
|
dowidth(l->t);
|
|
|
|
tlq = l->next;
|
|
|
|
l->next = tlfree;
|
|
|
|
tlfree = l;
|
|
|
|
}
|
|
|
|
}
|