void
dodclvar(Node *n, Type *t)
{
-
-loop:
if(n == N)
return;
- if(n->op == OLIST) {
+ for(; n->op == OLIST; n = n->right)
dodclvar(n->left, t);
- n = n->right;
- goto loop;
- }
+ dowidth(t);
+ addvar(n, t, dclcontext);
if(exportadj)
exportsym(n->sym);
- addvar(n, t, dclcontext);
}
void
-dodcltype(Type *n, Type *t)
+dodclconst(Node *n, Node *e)
{
- Type *nt;
-
- if(n == T)
+ if(n == N)
return;
- if(t->sym != S) {
- // botch -- should be a complete deep copy
- nt = typ(Txxx);
- *nt = *t;
- t = nt;
- t->sym = S;
- }
- n->sym->local = 1;
- addtyp(n, t, dclcontext);
+
+ for(; n->op == OLIST; n=n->right)
+ dodclconst(n, e);
+
+ addconst(n, e, dclcontext);
if(exportadj)
exportsym(n->sym);
}
-void
-dodclconst(Node *n, Node *e)
+/*
+ * introduce a type named n
+ * but it is an unknown type for now
+ */
+Type*
+dodcltype(Type *n)
{
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 has been forward declared,
+ // use the Type* created then
+ s = n->sym;
+ if(s->tblock == block) {
+ switch(s->otype->etype) {
+ case TFORWSTRUCT:
+ case TFORWINTER:
+ return s->otype;
+ }
}
- if(n->op != ONAME)
- fatal("dodclconst: not a name");
+ // otherwise declare a new type
+ addtyp(n, dclcontext);
+ 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;
- if(e->op != OLITERAL) {
- yyerror("expression must be a constant");
- return;
- }
s = n->sym;
+ if(s == S || s->otype != n)
+ fatal("updatetype %T = %T", n, t);
- s->oconst = e;
- s->lexical = LACONST;
+ switch(n->etype) {
+ case TFORW:
+ break;
- if(exportadj)
- exportsym(n->sym);
+ case TFORWSTRUCT:
+ if(t->etype != TSTRUCT) {
+ yyerror("%T forward declared as struct", n);
+ return;
+ }
+ break;
- r = autodcl;
- if(dclcontext == PEXTERN)
- r = externdcl;
+ case TFORWINTER:
+ if(t->etype != TINTER) {
+ yyerror("%T forward declared as interface", n);
+ return;
+ }
+ break;
- d = dcl();
- d->dsym = s;
- d->dnode = e;
- d->op = OCONST;
+ default:
+ fatal("updatetype %T / %T", n, t);
+ }
- r->back->forw = d;
- r->back = d;
+ *n = *t;
+ n->sym = s;
- if(dflag())
- print("const-dcl %S %N\n", n->sym, n->sym->oconst);
+ // catch declaration of incomplete type
+ switch(n->etype) {
+ case TFORWSTRUCT:
+ case TFORWINTER:
+ break;
+ default:
+ checkwidth(n);
+ }
}
+
/*
* return nelem of list
*/
t->outtuple = listcount(out);
t->intuple = listcount(in);
- dowidth(t);
+ checkwidth(t);
return t;
}
Type *f, *d, *pa;
Sym *st, *sf;
+ pa = nil;
+ sf = nil;
+
// get field sym
if(n == N)
goto bad;
t = typ(et);
stotype(n, &t->type);
- dowidth(t);
+ checkwidth(t);
return t;
}
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;
a->vblock = b->vblock;
a->tblock = b->tblock;
+ a->local = b->local;
+ a->offset = b->offset;
}
Sym*
fatal("addvar: n=%N t=%T nil", n, t);
s = n->sym;
- vargen++;
- gen = vargen;
-
- r = autodcl;
- if(ctxt == PEXTERN) {
- r = externdcl;
- gen = 0;
- }
if(s->vblock == block) {
if(s->oname != N) {
yyerror("var %S redeclared in this block", s);
}
- if(ctxt != PEXTERN)
+ if(ctxt == PEXTERN) {
+ r = externdcl;
+ gen = 0;
+vargen++; // just for diffing output against old compiler
+ } else {
+ r = autodcl;
+ vargen++;
+ gen = vargen;
pushdcl(s);
+ }
s->vargen = gen;
s->oname = n;
}
void
-addtyp(Type *n, Type *t, int ctxt)
+addtyp(Type *n, int ctxt)
{
Dcl *r, *d;
Sym *s;
- Type *f, *ot;
- if(n==T || n->sym == S || t == T)
- fatal("addtyp: n=%T t=%T nil", n, t);
+ if(n==T || n->sym == S)
+ fatal("addtyp: n=%T t=%T nil", n);
s = n->sym;
- r = autodcl;
- if(ctxt == PEXTERN) {
- ot = s->otype;
- if(ot != T) {
- // allow nil interface to be
- // redeclared as an interface
- if(ot->etype == TINTER && ot->type == T && t->etype == TINTER) {
- if(dflag())
- print("forew typ-dcl %S G%ld %T\n", s, s->vargen, t);
- s->otype = t;
- return;
- }
- }
+ if(ctxt == PEXTERN)
r = externdcl;
+ else {
+ r = autodcl;
+ pushdcl(s);
}
+vargen++; // just for diffing output against old compiler
if(s->tblock == block)
yyerror("type %S redeclared in this block %d", s, block);
- if(ctxt != PEXTERN)
- pushdcl(s);
-
- if(t->sym != S)
- warn("addtyp: renaming type %S/%lT to %S/%lT",
- t->sym, t->sym->otype, s, n);
-
- vargen++;
- s->vargen = vargen;
- s->otype = t;
+ s->otype = n;
s->lexical = LATYPE;
s->tblock = block;
- t->sym = s;
- t->vargen = vargen;
-
- if(s->forwtype != T) {
- dowidth(t);
- for(f=s->forwtype; f!=T; f=f->nforw) {
- if(!isptr[f->etype])
- fatal("addtyp: forward");
- f->type = t;
- }
- s->forwtype = T;
- }
-
d = dcl();
d->dsym = s;
- d->dtype = t;
+ d->dtype = n;
d->op = OTYPE;
r->back->forw = d;
if(dflag()) {
if(ctxt == PEXTERN)
- print("extern typ-dcl %S G%ld %T\n", s, s->vargen, t);
+ print("extern typ-dcl %S G%ld %T\n", s, s->vargen, n);
else
- print("auto typ-dcl %S G%ld %T\n", s, s->vargen, t);
+ print("auto typ-dcl %S G%ld %T\n", s, s->vargen, n);
}
}
+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);
+}
+
Node*
fakethis(void)
{
t = typ(TFORW);
t = ptrto(t);
-
- t->nforw = s->forwtype;
- s->forwtype = t;
return t;
}
popdcl();
compile(fn);
}
+
+
+/*
+ * 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)
+{
+ if(defercalc)
+ fatal("defercheckwidth");
+ 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;
+ }
+}
// TFIELD
Type* down; // also used in TMAP
- // TPTR
- Type* nforw;
-
// TARRAY
int32 bound; // negative is dynamic array
};
Node* oname; // ONAME node if a var
Type* otype; // TYPE node if a type
Node* oconst; // OLITERAL node if a const
- Type* forwtype; // TPTR iff forward declared
vlong offset; // stack location if automatic
int32 lexical;
int32 vargen; // unique variable number
TFIELD,
TANY,
TSTRING,
+ TFORWSTRUCT,
+ TFORWINTER,
- NTYPE, // 26
+ NTYPE, // 28
};
enum
{
* dcl.c
*/
void dodclvar(Node*, Type*);
-void dodcltype(Type*, Type*);
+Type* dodcltype(Type*);
+void updatetype(Type*, Type*);
void dodclconst(Node*, Node*);
void defaultlit(Node*);
int listcount(Node*);
void testdclstack(void);
Sym* pushdcl(Sym*);
void addvar(Node*, Type*, int);
-void addtyp(Type*, Type*, int);
+void addtyp(Type*, int);
+void addconst(Node*, Node*, int);
Node* fakethis(void);
Node* newname(Sym*);
Node* oldname(Sym*);
Type* newtype(Sym*);
Type* oldtype(Sym*);
-Type* forwdcl(Sym*);
void fninit(Node*);
Node* nametoanondcl(Node*);
Node* nametodcl(Node*, Type*);
Node* anondcl(Type*);
void checkarglist(Node*);
+void checkwidth(Type*);
+void defercheckwidth(void);
+void resumecheckwidth(void);
/*
* export.c
%type <node> fnres Afnres Bfnres fnliteral xfndcl fndcl fnbody
%type <node> keyexpr_list keyval_list_r keyval
%type <node> typedcl Atypedcl Btypedcl
+%type <type> typedclname
%type <type> fntype fnlitdcl Afntype Bfntype fullAtype
%type <type> non_name_Atype non_name_type
}
import_there:
- hidden_import_list_r '$' '$'
+ hidden_import_list '$' '$'
{
checkimports();
unimportfile();
}
-| LIMPORT '$' '$' hidden_import_list_r '$' '$'
+| LIMPORT '$' '$' hidden_import_list '$' '$'
{
checkimports();
}
+hidden_import_list:
+ {
+ defercheckwidth();
+ }
+ hidden_import_list_r
+ {
+ resumecheckwidth();
+ }
+
/*
* declarations
*/
Atypedcl
| Btypedcl
+typedclname:
+ new_type
+ {
+ $$ = dodcltype($1);
+ defercheckwidth();
+ }
+
Atypedcl:
- new_type fullAtype
+ typedclname fullAtype
+ {
+ updatetype($1, $2);
+ resumecheckwidth();
+ }
+| typedclname LSTRUCT
{
- dodcltype($1, $2);
+ updatetype($1, typ(TFORWSTRUCT));
+ resumecheckwidth();
}
+/*
+| typedclname LINTERFACE
+ {
+ updatetype($1, typ(TFORWINTER));
+ resumecheckwidth();
+ }
+*/
Btypedcl:
- new_type fullBtype
+ typedclname fullBtype
{
- dodcltype($1, $2);
+ updatetype($1, $2);
+ resumecheckwidth();
}
else_stmt1:
| interfacetype
| '*' fullAtype
{
- dowidth($2);
$$ = ptrto($2);
}
}
| '*' fullBtype
{
- dowidth($2);
$$ = ptrto($2);
}
| '*' lname
{
- // dont know if this is an error or not
- if(dclcontext != PEXTERN)
- yyerror("forward type in function body %s", $2->name);
- $$ = forwdcl($2);
+ Type *t;
+
+ t = dodcltype(newtype($2));
+ updatetype(t, typ(TFORWSTRUCT));
+ $$ = ptrto(t);
}
Bchantype:
}
| '*' hidden_type
{
- dowidth($2);
+ checkwidth($2);
$$ = ptrto($2);
}
| LCOMM LCHAN hidden_type
* to check whether the rest of the grammar is free of
* reduce/reduce conflicts, comment this section out by
* removing the slash on the next line.
- *
+ */
lpack:
LATYPE
{
yyerror("no type %s.%s", context, $3->name);
YYERROR;
}
-
/**/