dcl.c 18.2 KB
Newer Older
1 2 3 4 5 6 7
// 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"

Ken Thompson's avatar
Ken Thompson committed
8 9 10 11 12 13 14 15 16 17 18 19
int
dflag(void)
{
	if(!debug['d'])
		return 0;
	if(debug['y'])
		return 1;
	if(inimportsys)
		return 0;
	return 1;
}

20 21 22 23 24 25 26 27 28 29 30 31 32 33
void
dodclvar(Node *n, Type *t)
{

loop:
	if(n == N)
		return;

	if(n->op == OLIST) {
		dodclvar(n->left, t);
		n = n->right;
		goto loop;
	}

34 35
	if(exportadj)
		exportsym(n->sym);
36 37 38 39 40 41
	addvar(n, t, dclcontext);
}

void
dodcltype(Type *n, Type *t)
{
42
	Type *nt;
43 44 45

	if(n == T)
		return;
46 47 48 49 50 51 52
	if(t->sym != S) {
		// botch -- should be a complete deep copy
		nt = typ(Txxx);
		*nt = *t;
		t = nt;
		t->sym = S;
	}
53 54
	if(exportadj)
		exportsym(n->sym);
55
	n->sym->local = 1;
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
	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;
	}
73 74
	if(exportadj)
		exportsym(n->sym);
75 76 77 78 79 80

	if(n->op != ONAME)
		fatal("dodclconst: not a name");

	if(e->op != OLITERAL) {
		yyerror("expression must be a constant");
Ken Thompson's avatar
Ken Thompson committed
81
		return;
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
	}
	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;

Ken Thompson's avatar
Ken Thompson committed
100
	if(dflag())
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
		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
 */
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);

	dowidth(t);
	return t;
}

void
funcnam(Type *t, char *nam)
{
	Node *n;
	Sym *s;
	char buf[100];

	if(nam == nil) {
		vargen++;
Ken Thompson's avatar
Ken Thompson committed
154
		snprint(buf, sizeof(buf), "_f%s_%.3ld", filename, vargen);
155 156 157 158 159 160 161 162
		nam = buf;
	}

	if(t->etype != TFUNC)
		fatal("funcnam: not func %T\n", t);

	if(t->thistuple > 0) {
		vargen++;
Ken Thompson's avatar
Ken Thompson committed
163
		snprint(namebuf, sizeof(namebuf), "_t%s_%.3ld", filename, vargen);
164 165 166 167 168 169 170 171
		s = lookup(namebuf);
		addtyp(newtype(s), t->type, PEXTERN);
		n = newname(s);
		n->vargen = vargen;
		t->type->nname = n;
	}
	if(t->outtuple > 0) {
		vargen++;
Ken Thompson's avatar
Ken Thompson committed
172
		snprint(namebuf, sizeof(namebuf), "_o%s_%.3ld", filename, vargen);
173 174 175 176 177 178 179 180
		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++;
Ken Thompson's avatar
Ken Thompson committed
181
		snprint(namebuf, sizeof(namebuf), "_i%s_%.3ld", filename, vargen);
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
		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(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)
{
220 221
	Sym *s;

Ken Thompson's avatar
Ken Thompson committed
222 223 224 225
	if(t == T)
		goto bad;

	// method receiver must be typename or *typename
226 227 228
	s = S;
	if(t->sym != S)
		s = t->sym;
229 230
	if(isptr[t->etype])
		t = t->type;
231 232 233 234
	if(t->sym != S)
		s = t->sym;
	if(s == S)
		goto bad;
Ken Thompson's avatar
Ken Thompson committed
235

236
	snprint(namebuf, sizeof(namebuf), "%s_%s", s->name, n->sym->name);
237 238 239
	return newname(lookup(namebuf));

bad:
Ken Thompson's avatar
Ken Thompson committed
240
	yyerror("illegal <this> type: %T", t);
241 242 243 244 245
	return n;
}

/*
 * add a method, declared as a function,
Ken Thompson's avatar
Ken Thompson committed
246
 * n is fieldname, pa is base type, t is function type
247 248
 */
void
Ken Thompson's avatar
Ken Thompson committed
249
addmethod(Node *n, Type *t, int local)
250
{
Ken Thompson's avatar
Ken Thompson committed
251 252 253
	Type *f, *d, *pa;
	Sym *st, *sf;
	int ptr;
254

Ken Thompson's avatar
Ken Thompson committed
255 256 257
	// get field sym
	if(n == N)
		goto bad;
258 259
	if(n->op != ONAME)
		goto bad;
Ken Thompson's avatar
Ken Thompson committed
260 261
	sf = n->sym;
	if(sf == S)
262
		goto bad;
Ken Thompson's avatar
Ken Thompson committed
263 264 265

	// get parent type sym
	pa = *getthis(t);	// ptr to this structure
266 267
	if(pa == T)
		goto bad;
Ken Thompson's avatar
Ken Thompson committed
268 269
	pa = pa->type;		// ptr to this field
	if(pa == T)
270
		goto bad;
Ken Thompson's avatar
Ken Thompson committed
271 272
	pa = pa->type;		// ptr to this type
	if(pa == T)
273 274
		goto bad;

Ken Thompson's avatar
Ken Thompson committed
275 276 277 278 279 280 281 282 283
	switch(algtype(pa)) {
	default:
		goto bad;
	case ASIMP:
	case APTR:
	case ASTRING:
		break;
	}

Ken Thompson's avatar
Ken Thompson committed
284 285 286 287 288 289 290 291 292 293 294 295
	// optionally rip off ptr to type
	ptr = 0;
	if(isptr[pa->etype]) {
		if(pa->sym == S || pa->sym->name[0] == '_') {
			ptr = 1;
			pa = pa->type;
			if(pa == T)
				goto bad;
		}
	}
	if(pa->etype == TINTER)
		yyerror("no methods on interfaces");
296

Ken Thompson's avatar
Ken Thompson committed
297 298 299 300 301 302
	// and finally the receiver sym
	st = pa->sym;
	if(st == S)
		goto bad;
	if(local && !st->local) {
		yyerror("method receiver type must be locally defined: %S", st);
303 304 305
		return;
	}

Ken Thompson's avatar
Ken Thompson committed
306 307 308 309 310 311 312 313
	n = nod(ODCLFIELD, newname(sf), N);
	n->type = t;

	if(pa->method == T)
		pa->methptr = ptr;
	if(pa->methptr != ptr)
		yyerror("combination of direct and ptr receivers of: %S", st);

314
	d = T;	// last found
Ken Thompson's avatar
Ken Thompson committed
315
	for(f=pa->method; f!=T; f=f->down) {
316 317 318
		if(f->etype != TFIELD)
			fatal("addmethod: not TFIELD: %N", f);

Ken Thompson's avatar
Ken Thompson committed
319
		if(strcmp(sf->name, f->sym->name) != 0) {
320 321 322 323
			d = f;
			continue;
		}
		if(!eqtype(t, f->type, 0))
Ken Thompson's avatar
Ken Thompson committed
324
			yyerror("method redeclared: %S of type %S", sf, st);
Ken Thompson's avatar
Ken Thompson committed
325
		return;
326 327 328
	}

	if(d == T)
Ken Thompson's avatar
Ken Thompson committed
329
		stotype(n, &pa->method);
330 331
	else
		stotype(n, &d->down);
Ken Thompson's avatar
Ken Thompson committed
332 333 334

	if(dflag())
		print("method         %S of type %s%S\n", sf, (ptr? "*":""), st);
335 336 337
	return;

bad:
Russ Cox's avatar
Russ Cox committed
338
	yyerror("unknown method pointer: %T %S %S", pa, sf, st);
339 340
}

Ken Thompson's avatar
init  
Ken Thompson committed
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
/*
 * 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);
}

363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
/*
 * 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))
382
				yyerror("forward declarations not the same: %S", s);
383 384 385 386 387 388
		} else {
			yyerror("redeclare of function: %S", s);
			on = N;
		}
	}

389
	// check for forward declaration
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
	if(on == N) {
		// 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
			n->nname->class = PEXTERN;
	} else {
		// identical redeclaration
		// steal previous names
		n->nname = on;
		n->type = on->type;
		n->class = on->class;
		n->sym = s;
Ken Thompson's avatar
Ken Thompson committed
406
		if(dflag())
407 408 409 410 411 412 413 414 415 416 417
			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;
Ken Thompson's avatar
Ken Thompson committed
418
	markdcl();
419 420 421 422 423
	funcargs(n->type);

}

void
Ken Thompson's avatar
Ken Thompson committed
424
funcargs(Type *ft)
425
{
Ken Thompson's avatar
Ken Thompson committed
426
	Type *t;
427
	Iter save;
Ken Thompson's avatar
Ken Thompson committed
428
	int all;
429

Ken Thompson's avatar
Ken Thompson committed
430
	// declare the this/in arguments
Ken Thompson's avatar
Ken Thompson committed
431 432
	t = funcfirst(&save, ft);
	while(t != T) {
Ken Thompson's avatar
div bug  
Ken Thompson committed
433 434
		if(t->nname != N) {
			t->nname->xoffset = t->width;
Ken Thompson's avatar
Ken Thompson committed
435
			addvar(t->nname, t->type, PPARAM);
Ken Thompson's avatar
div bug  
Ken Thompson committed
436
		}
Ken Thompson's avatar
Ken Thompson committed
437
		t = funcnext(&save);
438 439 440
	}

	// declare the outgoing arguments
Ken Thompson's avatar
Ken Thompson committed
441
	all = 0;
Ken Thompson's avatar
Ken Thompson committed
442 443
	t = structfirst(&save, getoutarg(ft));
	while(t != T) {
Ken Thompson's avatar
div bug  
Ken Thompson committed
444 445
		if(t->nname != N)
			t->nname->xoffset = t->width;
Ken Thompson's avatar
Ken Thompson committed
446 447
		if(t->nname != N && t->nname->sym->name[0] != '_') {
			addvar(t->nname, t->type, PPARAM);
Ken Thompson's avatar
Ken Thompson committed
448 449 450
			all |= 1;
		} else
			all |= 2;
Ken Thompson's avatar
Ken Thompson committed
451
		t = structnext(&save);
Ken Thompson's avatar
Ken Thompson committed
452 453 454 455
	}
	if(all == 3)
		yyerror("output parameters are all named or not named");

Ken Thompson's avatar
Ken Thompson committed
456
	ft->outnamed = 0;
Ken Thompson's avatar
Ken Thompson committed
457
	if(all == 1)
Ken Thompson's avatar
Ken Thompson committed
458
		ft->outnamed = 1;
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
}

/*
 * 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");
Ken Thompson's avatar
Ken Thompson committed
475
	popdcl();
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
	dclcontext = PEXTERN;
}

/*
 * turn a parsed struct into a type
 */
Type**
stotype(Node *n, Type **t)
{
	Type *f;
	Iter save;

	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);

505
	if(n->type->etype == TARRAY && n->type->bound < 0)
506 507 508 509 510 511 512 513 514
		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++;
Ken Thompson's avatar
Ken Thompson committed
515
		snprint(namebuf, sizeof(namebuf), "_e%s_%.3ld", filename, vargen);
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
		f->nname = newname(lookup(namebuf));
	}
	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);
	dowidth(t);
	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->forwtype = b->forwtype;
	a->lexical = b->lexical;
	a->undef = b->undef;
	a->vargen = b->vargen;
563 564
	a->vblock = b->vblock;
	a->tblock = b->tblock;
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
}

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
Ken Thompson's avatar
Ken Thompson committed
589
popdcl(void)
590 591 592
{
	Sym *d, *s;

Ken Thompson's avatar
Ken Thompson committed
593
//	if(dflag())
594
//		print("revert\n");
595

596 597 598 599 600
	for(d=dclstack; d!=S; d=d->link) {
		if(d->name == nil)
			break;
		s = pkglookup(d->name, d->package);
		dcopy(s, d);
Ken Thompson's avatar
Ken Thompson committed
601
		if(dflag())
602
			print("\t%L pop %S\n", lineno, s);
603 604 605 606
	}
	if(d == S)
		fatal("popdcl: no mark");
	dclstack = d->link;
607
	block = d->vblock;
608 609 610 611 612 613 614 615 616 617 618 619
}

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);
Ken Thompson's avatar
Ken Thompson committed
620
		if(dflag())
621
			print("\t%L pop %S\n", lineno, s);
622 623 624 625 626 627
	}
	if(d == S)
		fatal("poptodcl: no mark");
}

void
Ken Thompson's avatar
Ken Thompson committed
628
markdcl(void)
629 630 631 632 633
{
	Sym *d;

	d = push();
	d->name = nil;		// used as a mark in fifo
634 635 636 637
	d->vblock = block;

	blockgen++;
	block = blockgen;
Ken Thompson's avatar
Ken Thompson committed
638

Ken Thompson's avatar
Ken Thompson committed
639
//	if(dflag())
640 641 642 643 644 645 646 647
//		print("markdcl\n");
}

void
markdclstack(void)
{
	Sym *d, *s;

Ken Thompson's avatar
Ken Thompson committed
648
	markdcl();
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664

	// 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);
		}
	}
}

665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
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);
	}
}

689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
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;
	Type *ot;
	Node *on;
	int gen;

	if(n==N || n->sym == S || n->op != ONAME || t == T)
		fatal("addvar: n=%N t=%T nil", n, t);

	ot = t;
	if(isptr[ot->etype])
		ot = ot->type;

	if(ot->etype == TSTRUCT && ot->vargen == 0) {
		vargen++;
Ken Thompson's avatar
Ken Thompson committed
720
		snprint(namebuf, sizeof(namebuf), "_s%s_%.3ld", filename, vargen);
721 722 723 724 725 726 727 728 729 730 731 732 733 734
		s = lookup(namebuf);
		addtyp(newtype(s), ot, PEXTERN);
	}

	s = n->sym;
	vargen++;
	gen = vargen;

	r = autodcl;
	if(ctxt == PEXTERN) {
		r = externdcl;
		gen = 0;
	}

Ken Thompson's avatar
Ken Thompson committed
735 736 737 738 739 740 741 742
	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);
	}
743

744 745 746 747 748 749
	if(ctxt != PEXTERN)
		pushdcl(s);

	s->vargen = gen;
	s->oname = n;
	s->offset = 0;
750
	s->vblock = block;
Russ Cox's avatar
Russ Cox committed
751
	s->lexical = LNAME;
752 753 754 755 756 757 758 759 760 761 762 763 764

	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;

Ken Thompson's avatar
Ken Thompson committed
765
	if(dflag()) {
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
		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(Type *n, Type *t, 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);

	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) {
Ken Thompson's avatar
Ken Thompson committed
792
				if(dflag())
793 794 795 796 797 798 799 800
					print("forew  typ-dcl %S G%ld %T\n", s, s->vargen, t);
				s->otype = t;
				return;
			}
		}
		r = externdcl;
	}

801 802 803
	if(s->tblock == block)
		yyerror("type %S redeclared in this block %d", s, block);

804 805 806 807 808 809 810 811 812 813
	if(ctxt != PEXTERN)
		pushdcl(s);

	if(t->sym != S)
		warn("addtyp: renaming %S/%lT to %S/%lT", t->sym, t->sym->otype, s, n);

	vargen++;
	s->vargen = vargen;
	s->otype = t;
	s->lexical = LATYPE;
814
	s->tblock = block;
815 816 817 818

	t->sym = s;
	t->vargen = vargen;

Ken Thompson's avatar
Ken Thompson committed
819 820 821 822 823 824 825 826
	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;
827 828 829 830 831 832 833 834 835 836
	}

	d = dcl();
	d->dsym = s;
	d->dtype = t;
	d->op = OTYPE;

	r->back->forw = d;
	r->back = d;

Ken Thompson's avatar
Ken Thompson committed
837
	if(dflag()) {
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889
		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);
	}
}

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) {
890 891 892 893 894
		n = nod(ONONAME, N, N);
		n->sym = s;
		n->type = T;
		n->addable = 1;
		n->ullman = 0;
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
	}
	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;
}

Type*
forwdcl(Sym *s)
{
	Type *t;

	// this type has no meaning and
	// will cause an error if referenced.
	// it will be patched when/if the
	// type is ever assigned.

	t = typ(TFORW);
	t = ptrto(t);

	t->nforw = s->forwtype;
	s->forwtype = t;
	return t;
}
Ken Thompson's avatar
Ken Thompson committed
941

942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
/*
 * 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");
}

Ken Thompson's avatar
Ken Thompson committed
1026
// hand-craft the following initialization code
Ken Thompson's avatar
init  
Ken Thompson committed
1027 1028 1029 1030 1031 1032 1033
//	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)
Ken Thompson's avatar
Ken Thompson committed
1034 1035 1036
//		init()	// if any			(7)
//		return					(8)
//	}
Ken Thompson's avatar
init  
Ken Thompson committed
1037
//	export	init_<file>_function			(9)
Ken Thompson's avatar
Ken Thompson committed
1038 1039 1040 1041

void
fninit(Node *n)
{
Ken Thompson's avatar
init  
Ken Thompson committed
1042
	Node *done, *any;
Ken Thompson's avatar
Ken Thompson committed
1043
	Node *a, *fn, *r;
Ken Thompson's avatar
Ken Thompson committed
1044
	Iter iter;
1045
	uint32 h;
Ken Thompson's avatar
Ken Thompson committed
1046 1047 1048 1049 1050
	Sym *s;

	r = N;

	// (1)
Ken Thompson's avatar
init  
Ken Thompson committed
1051
	snprint(namebuf, sizeof(namebuf), "init_%s_done", filename);
Ken Thompson's avatar
Ken Thompson committed
1052 1053 1054 1055 1056 1057 1058 1059
	done = newname(lookup(namebuf));
	addvar(done, types[TBOOL], PEXTERN);

	// (2)

	maxarg = 0;
	stksize = 0;

Ken Thompson's avatar
Ken Thompson committed
1060 1061 1062 1063
	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
Ken Thompson's avatar
Ken Thompson committed
1064
	if(strcmp(package, "main") == 0)
Ken Thompson's avatar
Ken Thompson committed
1065 1066
		snprint(namebuf, sizeof(namebuf), "init_function");

Ken Thompson's avatar
Ken Thompson committed
1067 1068 1069 1070
	fn = nod(ODCLFUNC, N, N);
	fn->nname = newname(lookup(namebuf));
	fn->type = functype(N, N, N);
	funchdr(fn);
Ken Thompson's avatar
Ken Thompson committed
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086

	// (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;
Ken Thompson's avatar
init  
Ken Thompson committed
1087
		if(strstr(s->name, "init_") == nil)
Ken Thompson's avatar
Ken Thompson committed
1088
			continue;
Ken Thompson's avatar
init  
Ken Thompson committed
1089
		if(strstr(s->name, "_function") == nil)
Ken Thompson's avatar
Ken Thompson committed
1090 1091 1092 1093
			continue;
		if(s->oname == N)
			continue;

Ken Thompson's avatar
Ken Thompson committed
1094
		// could check that it is fn of no args/returns
Ken Thompson's avatar
Ken Thompson committed
1095 1096 1097 1098 1099 1100 1101 1102
		a = nod(OCALL, s->oname, N);
		r = list(r, a);
	}

	// (6)
	r = list(r, n);

	// (7)
Ken Thompson's avatar
Ken Thompson committed
1103
	// could check that it is fn of no args/returns
Ken Thompson's avatar
init  
Ken Thompson committed
1104 1105 1106 1107
	snprint(namebuf, sizeof(namebuf), "init_%s", filename);
	s = lookup(namebuf);
	if(s->oname != N) {
		a = nod(OCALL, s->oname, N);
Ken Thompson's avatar
Ken Thompson committed
1108 1109 1110 1111 1112 1113 1114 1115
		r = list(r, a);
	}

	// (8)
	a = nod(ORETURN, N, N);
	r = list(r, a);

	// (9)
1116
	exportsym(fn->nname->sym);
Ken Thompson's avatar
Ken Thompson committed
1117

Ken Thompson's avatar
Ken Thompson committed
1118 1119 1120
	fn->nbody = rev(r);
//dump("b", fn);
//dump("r", fn->nbody);
Ken Thompson's avatar
Ken Thompson committed
1121 1122

	popdcl();
Ken Thompson's avatar
Ken Thompson committed
1123
	compile(fn);
Ken Thompson's avatar
Ken Thompson committed
1124
}