xref: /csrg-svn/usr.bin/pascal/src/fdec.c (revision 2220)
1 /* Copyright (c) 1979 Regents of the University of California */
2 
3 static	char sccsid[] = "@(#)fdec.c 1.13 01/24/81";
4 
5 #include "whoami.h"
6 #include "0.h"
7 #include "tree.h"
8 #include "opcode.h"
9 #include "objfmt.h"
10 #include "align.h"
11 
12 /*
13  * this array keeps the pxp counters associated with
14  * functions and procedures, so that they can be output
15  * when their bodies are encountered
16  */
17 int	bodycnts[ DSPLYSZ ];
18 
19 #ifdef PC
20 #   include "pc.h"
21 #   include "pcops.h"
22 #endif PC
23 
24 #ifdef OBJ
25 int	cntpatch;
26 int	nfppatch;
27 #endif OBJ
28 
29 /*
30  * Funchdr inserts
31  * declaration of a the
32  * prog/proc/func into the
33  * namelist. It also handles
34  * the arguments and puts out
35  * a transfer which defines
36  * the entry point of a procedure.
37  */
38 
39 struct nl *
40 funchdr(r)
41 	int *r;
42 {
43 	register struct nl *p;
44 	register *il, **rl;
45 	int *rll;
46 	struct nl *cp, *dp, *sp;
47 	int s, o, *pp;
48 
49 	if (inpflist(r[2])) {
50 		opush('l');
51 		yyretrieve();	/* kludge */
52 	}
53 	pfcnt++;
54 	parts[ cbn ] |= RPRT;
55 	line = r[1];
56 	if (r[3] == NIL && (p=lookup1(r[2])) != NIL && bn == cbn) {
57 		/*
58 		 * Symbol already defined
59 		 * in this block. it is either
60 		 * a redeclared symbol (error)
61 		 * a forward declaration,
62 		 * or an external declaration.
63 		 */
64 		if ((p->class == FUNC || p->class == PROC) && (p->nl_flags & NFORWD) != 0) {
65 			/*
66 			 * Grammar doesnt forbid
67 			 * types on a resolution
68 			 * of a forward function
69 			 * declaration.
70 			 */
71 			if (p->class == FUNC && r[4])
72 				error("Function type should be given only in forward declaration");
73 			/*
74 			 * get another counter for the actual
75 			 */
76 			if ( monflg ) {
77 			    bodycnts[ cbn ] = getcnt();
78 			}
79 #			ifdef PC
80 			    enclosing[ cbn ] = p -> symbol;
81 #			endif PC
82 #			ifdef PTREE
83 				/*
84 				 *	mark this proc/func as forward
85 				 *	in the pTree.
86 				 */
87 			    pDEF( p -> inTree ).PorFForward = TRUE;
88 #			endif PTREE
89 			return (p);
90 		}
91 	}
92 
93 	/* if a routine segment is being compiled,
94 	 * do level one processing.
95 	 */
96 
97 	 if ((r[0] != T_PROG) && (!progseen))
98 		level1();
99 
100 
101 	/*
102 	 * Declare the prog/proc/func
103 	 */
104 	switch (r[0]) {
105 	    case T_PROG:
106 		    progseen++;
107 		    if (opt('z'))
108 			    monflg++;
109 		    program = p = defnl(r[2], PROG, 0, 0);
110 		    p->value[3] = r[1];
111 		    break;
112 	    case T_PDEC:
113 		    if (r[4] != NIL)
114 			    error("Procedures do not have types, only functions do");
115 		    p = enter(defnl(r[2], PROC, 0, 0));
116 		    p->nl_flags |= NMOD;
117 #		    ifdef PC
118 			enclosing[ cbn ] = r[2];
119 #		    endif PC
120 		    break;
121 	    case T_FDEC:
122 		    il = r[4];
123 		    if (il == NIL)
124 			    error("Function type must be specified");
125 		    else if (il[0] != T_TYID) {
126 			    il = NIL;
127 			    error("Function type can be specified only by using a type identifier");
128 		    } else
129 			    il = gtype(il);
130 		    p = enter(defnl(r[2], FUNC, il, NIL));
131 		    p->nl_flags |= NMOD;
132 		    /*
133 		     * An arbitrary restriction
134 		     */
135 		    switch (o = classify(p->type)) {
136 			    case TFILE:
137 			    case TARY:
138 			    case TREC:
139 			    case TSET:
140 			    case TSTR:
141 				    warning();
142 				    if (opt('s')) {
143 					    standard();
144 				    }
145 				    error("Functions should not return %ss", clnames[o]);
146 		    }
147 #		    ifdef PC
148 			enclosing[ cbn ] = r[2];
149 #		    endif PC
150 		    break;
151 	    default:
152 		    panic("funchdr");
153 	}
154 	if (r[0] != T_PROG) {
155 		/*
156 		 * Mark this proc/func as
157 		 * being forward declared
158 		 */
159 		p->nl_flags |= NFORWD;
160 		/*
161 		 * Enter the parameters
162 		 * in the next block for
163 		 * the time being
164 		 */
165 		if (++cbn >= DSPLYSZ) {
166 			error("Procedure/function nesting too deep");
167 			pexit(ERRS);
168 		}
169 		/*
170 		 * For functions, the function variable
171 		 */
172 		if (p->class == FUNC) {
173 #			ifdef OBJ
174 			    cp = defnl(r[2], FVAR, p->type, 0);
175 #			endif OBJ
176 #			ifdef PC
177 				/*
178 				 * fvars used to be allocated and deallocated
179 				 * by the caller right before the arguments.
180 				 * the offset of the fvar was kept in
181 				 * value[NL_OFFS] of function (very wierd,
182 				 * but see asgnop).
183 				 * now, they are locals to the function
184 				 * with the offset kept in the fvar.
185 				 */
186 
187 			    cp = defnl( r[2] , FVAR , p -> type
188 				      , -( roundup( DPOFF1+width( p -> type )
189 						  , align( p -> type ) ) ) );
190 #			endif PC
191 			cp->chain = p;
192 			p->ptr[NL_FVAR] = cp;
193 		}
194 		/*
195 		 * Enter the parameters
196 		 * and compute total size
197 		 */
198 		cp = sp = p;
199 
200 #		ifdef OBJ
201 		    o = 0;
202 #		endif OBJ
203 #		ifdef PC
204 			/*
205 			 * parameters used to be allocated backwards,
206 			 * then fixed.  for pc, they are allocated correctly.
207 			 * also, they are aligned.
208 			 */
209 		o = DPOFF2;
210 #		endif PC
211 		for (rl = r[3]; rl != NIL; rl = rl[2]) {
212 			p = NIL;
213 			if (rl[1] == NIL)
214 				continue;
215 			/*
216 			 * Parametric procedures
217 			 * don't have types !?!
218 			 */
219 			if (rl[1][0] != T_PPROC) {
220 				rll = rl[1][2];
221 				if (rll[0] != T_TYID) {
222 					error("Types for arguments can be specified only by using type identifiers");
223 					p = NIL;
224 				} else
225 					p = gtype(rll);
226 			}
227 			for (il = rl[1][1]; il != NIL; il = il[2]) {
228 				switch (rl[1][0]) {
229 				    default:
230 					    panic("funchdr2");
231 				    case T_PVAL:
232 					    if (p != NIL) {
233 						    if (p->class == FILET)
234 							    error("Files cannot be passed by value");
235 						    else if (p->nl_flags & NFILES)
236 							    error("Files cannot be a component of %ss passed by value",
237 								    nameof(p));
238 					    }
239 #					    ifdef OBJ
240 						dp = defnl(il[1], VAR, p, o -= even(width(p)));
241 #					    endif OBJ
242 #					    ifdef PC
243 						dp = defnl( il[1] , VAR , p
244 							, o = roundup( o , A_STACK ) );
245 						o += width( p );
246 #					    endif PC
247 					    dp->nl_flags |= NMOD;
248 					    break;
249 				    case T_PVAR:
250 #					    ifdef OBJ
251 						dp = defnl(il[1], REF, p, o -= sizeof ( int * ) );
252 #					    endif OBJ
253 #					    ifdef PC
254 						dp = defnl( il[1] , REF , p
255 							, o = roundup( o , A_STACK ) );
256 						o += sizeof(char *);
257 #					    endif PC
258 					    break;
259 				    case T_PFUNC:
260 #					    ifdef OBJ
261 						dp = defnl(il[1], FFUNC, p, o -= sizeof ( int * ) );
262 #					    endif OBJ
263 #					    ifdef PC
264 						dp = defnl( il[1] , FFUNC , p
265 							, o = roundup( o , A_STACK ) );
266 						o += sizeof(char *);
267 #					    endif PC
268 					    dp -> nl_flags |= NMOD;
269 					    break;
270 				    case T_PPROC:
271 #					    ifdef OBJ
272 						dp = defnl(il[1], FPROC, p, o -= sizeof ( int * ) );
273 #					    endif OBJ
274 #					    ifdef PC
275 						dp = defnl( il[1] , FPROC , p
276 							, o = roundup( o , A_STACK ) );
277 						o += sizeof(char *);
278 #					    endif PC
279 					    dp -> nl_flags |= NMOD;
280 					    break;
281 				    }
282 				if (dp != NIL) {
283 					cp->chain = dp;
284 					cp = dp;
285 				}
286 			}
287 		}
288 		cbn--;
289 		p = sp;
290 #		ifdef OBJ
291 		    p->value[NL_OFFS] = -o+DPOFF2;
292 			/*
293 			 * Correct the naivete (naievity)
294 			 * of our above code to
295 			 * calculate offsets
296 			 */
297 		    for (il = p->chain; il != NIL; il = il->chain)
298 			    il->value[NL_OFFS] += p->value[NL_OFFS];
299 #		endif OBJ
300 #		ifdef PC
301 		    p -> value[ NL_OFFS ] = roundup( o , A_STACK );
302 #		endif PC
303 	} else {
304 		/*
305 		 * The wonderful
306 		 * program statement!
307 		 */
308 #		ifdef OBJ
309 		    if (monflg) {
310 			    put(1, O_PXPBUF);
311 			    cntpatch = put(2, O_CASE4, 0);
312 			    nfppatch = put(2, O_CASE4, 0);
313 		    }
314 #		endif OBJ
315 		cp = p;
316 		for (rl = r[3]; rl; rl = rl[2]) {
317 			if (rl[1] == NIL)
318 				continue;
319 			dp = defnl(rl[1], VAR, 0, 0);
320 			cp->chain = dp;
321 			cp = dp;
322 		}
323 	}
324 	/*
325 	 * Define a branch at
326 	 * the "entry point" of
327 	 * the prog/proc/func.
328 	 */
329 	p->entloc = getlab();
330 	if (monflg) {
331 		bodycnts[ cbn ] = getcnt();
332 		p->value[ NL_CNTR ] = 0;
333 	}
334 #	ifdef OBJ
335 	    put(2, O_TRA4, p->entloc);
336 #	endif OBJ
337 #	ifdef PTREE
338 	    {
339 		pPointer	PF = tCopy( r );
340 
341 		pSeize( PorFHeader[ nesting ] );
342 		if ( r[0] != T_PROG ) {
343 			pPointer	*PFs;
344 
345 			PFs = &( pDEF( PorFHeader[ nesting ] ).PorFPFs );
346 			*PFs = ListAppend( *PFs , PF );
347 		} else {
348 			pDEF( PorFHeader[ nesting ] ).GlobProg = PF;
349 		}
350 		pRelease( PorFHeader[ nesting ] );
351 	    }
352 #	endif PTREE
353 	return (p);
354 }
355 
356 funcfwd(fp)
357 	struct nl *fp;
358 {
359 
360 	    /*
361 	     *	save the counter for this function
362 	     */
363 	if ( monflg ) {
364 	    fp -> value[ NL_CNTR ] = bodycnts[ cbn ];
365 	}
366 	return (fp);
367 }
368 
369 /*
370  * Funcext marks the procedure or
371  * function external in the symbol
372  * table. Funcext should only be
373  * called if PC, and is an error
374  * otherwise.
375  */
376 
377 funcext(fp)
378 	struct nl *fp;
379 {
380 
381 #ifdef PC
382  	if (opt('s')) {
383 		standard();
384 		error("External procedures and functions are not standard");
385 	} else {
386 		if (cbn == 1) {
387 			fp->ext_flags |= NEXTERN;
388 			stabefunc( fp -> symbol , fp -> class , line );
389 		}
390 		else
391 			error("External procedures and functions can only be declared at the outermost level.");
392 	}
393 #endif PC
394 #ifdef OBJ
395 	error("Procedures or functions cannot be declared external.");
396 #endif OBJ
397 
398 	return(fp);
399 }
400 
401 /*
402  * Funcbody is called
403  * when the actual (resolved)
404  * declaration of a procedure is
405  * encountered. It puts the names
406  * of the (function) and parameters
407  * into the symbol table.
408  */
409 funcbody(fp)
410 	struct nl *fp;
411 {
412 	register struct nl *q, *p;
413 
414 	cbn++;
415 	if (cbn >= DSPLYSZ) {
416 		error("Too many levels of function/procedure nesting");
417 		pexit(ERRS);
418 	}
419 	sizes[cbn].om_max = sizes[cbn].om_off = -DPOFF1;
420 	gotos[cbn] = NIL;
421 	errcnt[cbn] = syneflg;
422 	parts[ cbn ] = NIL;
423 	dfiles[ cbn ] = FALSE;
424 	if (fp == NIL)
425 		return (NIL);
426 	/*
427 	 * Save the virtual name
428 	 * list stack pointer so
429 	 * the space can be freed
430 	 * later (funcend).
431 	 */
432 	fp->ptr[2] = nlp;
433 	if (fp->class != PROG) {
434 		for (q = fp->chain; q != NIL; q = q->chain) {
435 			enter(q);
436 		}
437 	}
438 	if (fp->class == FUNC) {
439 		/*
440 		 * For functions, enter the fvar
441 		 */
442 		enter(fp->ptr[NL_FVAR]);
443 #		ifdef PC
444 		    q = fp -> ptr[ NL_FVAR ];
445 		    sizes[cbn].om_off -= lwidth( q -> type );
446 		    sizes[cbn].om_max = sizes[cbn].om_off;
447 #		endif PC
448 	}
449 #	ifdef PTREE
450 		/*
451 		 *	pick up the pointer to porf declaration
452 		 */
453 	    PorFHeader[ ++nesting ] = fp -> inTree;
454 #	endif PTREE
455 	return (fp);
456 }
457 
458 struct	nl *Fp;
459 int	pnumcnt;
460 /*
461  * Funcend is called to
462  * finish a block by generating
463  * the code for the statements.
464  * It then looks for unresolved declarations
465  * of labels, procedures and functions,
466  * and cleans up the name list.
467  * For the program, it checks the
468  * semantics of the program
469  * statement (yuchh).
470  */
471 funcend(fp, bundle, endline)
472 	struct nl *fp;
473 	int *bundle;
474 	int endline;
475 {
476 	register struct nl *p;
477 	register int i, b;
478 	int var, inp, out, chkref, *blk;
479 	struct nl *iop;
480 	char *cp;
481 	extern int cntstat;
482 #	ifdef PC
483 	    int	toplabel = getlab();
484 	    int	botlabel = getlab();
485 #	endif PC
486 
487 	cntstat = 0;
488 /*
489  *	yyoutline();
490  */
491 	if (program != NIL)
492 		line = program->value[3];
493 	blk = bundle[2];
494 	if (fp == NIL) {
495 		cbn--;
496 #		ifdef PTREE
497 		    nesting--;
498 #		endif PTREE
499 		return;
500 	}
501 #ifdef OBJ
502 	/*
503 	 * Patch the branch to the
504 	 * entry point of the function
505 	 */
506 	patch4(fp->entloc);
507 	/*
508 	 * Put out the block entrance code and the block name.
509 	 * HDRSZE is the number of bytes of info in the static
510 	 * BEG data area exclusive of the proc name. It is
511 	 * currently defined as:
512 	/*	struct hdr {
513 	/*		long framesze;	/* number of bytes of local vars */
514 	/*		long nargs;	/* number of bytes of arguments */
515 	/*		short tests;	/* TRUE => perform runtime tests */
516 	/*		short offset;	/* offset of procedure in source file */
517 	/*		char name[1];	/* name of active procedure */
518 	/*	};
519 	 */
520 #	define HDRSZE 12
521 	var = put(2, (lenstr(fp->symbol,0) + HDRSZE << 8)
522 			| (cbn == 1 && opt('p') == 0 ? O_NODUMP: O_BEG), 0);
523 	    /*
524 	     *  output the number of bytes of arguments
525 	     *  this is only checked on formal calls.
526 	     */
527 	put(2, O_CASE4, cbn == 1 ? 0 : fp->value[NL_OFFS]-DPOFF2);
528 	    /*
529 	     *	Output the runtime test mode for the routine
530 	     */
531 	if (opt('t'))
532 		put(2, O_CASE2, TRUE);
533 	else
534 		put(2, O_CASE2, FALSE);
535 	    /*
536 	     *	Output line number and routine name
537 	     */
538 	put(2, O_CASE2, bundle[1]);
539 	putstr(fp->symbol, 0);
540 #endif OBJ
541 #ifdef PC
542 	/*
543 	 * put out the procedure entry code
544 	 */
545 	if ( fp -> class == PROG ) {
546 	    putprintf( "	.text" , 0 );
547 	    putprintf( "	.align	1" , 0 );
548 	    putprintf( "	.globl	_main" , 0 );
549 	    putprintf( "_main:" , 0 );
550 	    putprintf( "	.word	0" , 0 );
551 	    putprintf( "	calls	$0,_PCSTART" , 0 );
552 	    putprintf( "	movl	4(ap),__argc" , 0 );
553 	    putprintf( "	movl	8(ap),__argv" , 0 );
554 	    putprintf( "	calls	$0,_program" , 0 );
555 	    putprintf( "	calls	$0,_PCEXIT" , 0 );
556 	    ftnno = fp -> entloc;
557 	    putprintf( "	.text" , 0 );
558 	    putprintf( "	.align	1" , 0 );
559 	    putprintf( "	.globl	_program" , 0 );
560 	    putprintf( "_program:" , 0 );
561 	    stabfunc( "program" , fp -> class , bundle[1] , 0 );
562 	} else {
563 	    ftnno = fp -> entloc;
564 	    putprintf( "	.text" , 0 );
565 	    putprintf( "	.align	1" , 0 );
566 	    putprintf( "	.globl	" , 1 );
567 	    for ( i = 1 ; i < cbn ; i++ ) {
568 		putprintf( EXTFORMAT , 1 , enclosing[ i ] );
569 	    }
570 	    putprintf( "" , 0 );
571 	    for ( i = 1 ; i < cbn ; i++ ) {
572 		putprintf( EXTFORMAT , 1 , enclosing[ i ] );
573 	    }
574 	    putprintf( ":" , 0 );
575 	    stabfunc( fp -> symbol , fp -> class , bundle[1] , cbn - 1 );
576 	    for ( p = fp -> chain ; p != NIL ; p = p -> chain ) {
577 		stabparam( p -> symbol , p2type( p -> type )
578 			    , p -> value[ NL_OFFS ] , lwidth( p -> type ) );
579 	    }
580 	    if ( fp -> class == FUNC ) {
581 		    /*
582 		     *	stab the function variable
583 		     */
584 		p = fp -> ptr[ NL_FVAR ];
585 		stablvar( p -> symbol , p2type( p -> type ) , cbn
586 			, p -> value[ NL_OFFS ] , lwidth( p -> type ) );
587 	    }
588 		/*
589 		 *	stab local variables
590 		 *	rummage down hash chain links.
591 		 */
592 	    for ( i = 0 ; i <= 077 ; i++ ) {
593 		for ( p = disptab[ i ] ; p != NIL ; p = p->nl_next) {
594 		    if ( ( p -> nl_block & 037 ) != cbn ) {
595 			break;
596 		    }
597 		    /*
598 		     *	stab local variables
599 		     *	that's named variables, but not params
600 		     */
601 		    if (   ( p -> symbol != NIL )
602 			&& ( p -> class == VAR )
603 			&& ( p -> value[ NL_OFFS ] < 0 ) ) {
604 			stablvar( p -> symbol , p2type( p -> type ) , cbn
605 			    , p -> value[ NL_OFFS ] , lwidth( p -> type ) );
606 		    }
607 		}
608 	    }
609 	}
610 	stablbrac( cbn );
611 	    /*
612 	     *	register save mask
613 	     */
614 	if ( opt( 't' ) ) {
615 	    putprintf( "	.word	0x%x" , 0 , RUNCHECK | RSAVEMASK );
616 	} else {
617 	    putprintf( "	.word	0x%x" , 0 , RSAVEMASK );
618 	}
619 	putjbr( botlabel );
620 	putlab( toplabel );
621 	if ( profflag ) {
622 		/*
623 		 *	call mcount for profiling
624 		 */
625 	    putprintf( "	moval	1f,r0" , 0 );
626 	    putprintf( "	jsb	mcount" , 0 );
627 	    putprintf( "	.data" , 0 );
628 	    putprintf( "	.align	2" , 0 );
629 	    putprintf( "1:" , 0 );
630 	    putprintf( "	.long	0" , 0 );
631 	    putprintf( "	.text" , 0 );
632 	}
633 	    /*
634 	     *	set up unwind exception vector.
635 	     */
636 	putprintf( "	moval	%s,%d(%s)" , 0
637 		, UNWINDNAME , UNWINDOFFSET , P2FPNAME );
638 	    /*
639 	     *	save address of display entry, for unwind.
640 	     */
641 	putprintf( "	moval	%s+%d,%d(%s)" , 0
642 		, DISPLAYNAME , cbn * sizeof(struct dispsave)
643 		, DPTROFFSET , P2FPNAME );
644 	    /*
645 	     *	save old display
646 	     */
647 	putprintf( "	movq	%s+%d,%d(%s)" , 0
648 		, DISPLAYNAME , cbn * sizeof(struct dispsave)
649 		, DSAVEOFFSET , P2FPNAME );
650 	    /*
651 	     *	set up new display by saving AP and FP in appropriate
652 	     *	slot in display structure.
653 	     */
654 	putprintf( "	movq	%s,%s+%d" , 0
655 		, P2APNAME , DISPLAYNAME , cbn * sizeof(struct dispsave) );
656 	    /*
657 	     *	ask second pass to allocate known locals
658 	     */
659 	putlbracket( ftnno , -sizes[ cbn ].om_max );
660 	    /*
661 	     *	and zero them if checking is on
662 	     *	by calling blkclr( bytes of locals , starting local address );
663 	     */
664 	if ( opt( 't' ) ) {
665 	    if ( ( -sizes[ cbn ].om_max ) > DPOFF1 ) {
666 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
667 			, "_blkclr" );
668 		putleaf( P2ICON ,  ( -sizes[ cbn ].om_max ) - DPOFF1
669 			, 0 , P2INT , 0 );
670 		putLV( 0 , cbn , sizes[ cbn ].om_max , P2CHAR );
671 		putop( P2LISTOP , P2INT );
672 		putop( P2CALL , P2INT );
673 		putdot( filename , line );
674 	    }
675 		/*
676 		 *  check number of longs of arguments
677 		 *  this can only be wrong for formal calls.
678 		 */
679 	    if ( fp -> class != PROG ) {
680 		    putleaf( P2ICON , 0 , 0 , ADDTYPE( P2PTR , P2FTN | P2INT ) ,
681 			    "_NARGCHK" );
682 		    putleaf( P2ICON ,
683 			(fp->value[NL_OFFS] - DPOFF2) / sizeof(long) ,
684 			0 , P2INT , 0 );
685 		    putop( P2CALL , P2INT );
686 		    putdot( filename , line );
687 	    }
688 	}
689 #endif PC
690 	if ( monflg ) {
691 		if ( fp -> value[ NL_CNTR ] != 0 ) {
692 			inccnt( fp -> value [ NL_CNTR ] );
693 		}
694 		inccnt( bodycnts[ fp -> nl_block & 037 ] );
695 	}
696 	if (fp->class == PROG) {
697 		/*
698 		 * The glorious buffers option.
699 		 *          0 = don't buffer output
700 		 *          1 = line buffer output
701 		 *          2 = 512 byte buffer output
702 		 */
703 #		ifdef OBJ
704 		    if (opt('b') != 1)
705 			    put(1, O_BUFF | opt('b') << 8);
706 #		endif OBJ
707 #		ifdef PC
708 		    if ( opt( 'b' ) != 1 ) {
709 			putleaf( P2ICON , 0 , 0
710 				, ADDTYPE( P2FTN | P2INT , P2PTR ) , "_BUFF" );
711 			putleaf( P2ICON , opt( 'b' ) , 0 , P2INT , 0 );
712 			putop( P2CALL , P2INT );
713 			putdot( filename , line );
714 		    }
715 #		endif PC
716 		out = 0;
717 		for (p = fp->chain; p != NIL; p = p->chain) {
718 			if (strcmp(p->symbol, "input") == 0) {
719 				inp++;
720 				continue;
721 			}
722 			if (strcmp(p->symbol, "output") == 0) {
723 				out++;
724 				continue;
725 			}
726 			iop = lookup1(p->symbol);
727 			if (iop == NIL || bn != cbn) {
728 				error("File %s listed in program statement but not declared", p->symbol);
729 				continue;
730 			}
731 			if (iop->class != VAR) {
732 				error("File %s listed in program statement but declared as a %s", p->symbol, classes[iop->class]);
733 				continue;
734 			}
735 			if (iop->type == NIL)
736 				continue;
737 			if (iop->type->class != FILET) {
738 				error("File %s listed in program statement but defined as %s",
739 					p->symbol, nameof(iop->type));
740 				continue;
741 			}
742 #			ifdef OBJ
743 			    put(2, O_CON24, text(iop->type) ? 0 : width(iop->type->type));
744 			    i = lenstr(p->symbol,0);
745 			    put(2, O_CON24, i);
746 			    put(2, O_LVCON, i);
747 			    putstr(p->symbol, 0);
748 			    put(2, O_LV | bn << 8+INDX, iop->value[NL_OFFS]);
749 			    put(1, O_DEFNAME);
750 #			endif OBJ
751 #			ifdef PC
752 			    putleaf( P2ICON , 0 , 0
753 				    , ADDTYPE( P2FTN | P2INT , P2PTR )
754 				    , "_DEFNAME" );
755 			    putLV( p -> symbol , bn , iop -> value[NL_OFFS]
756 				    , p2type( iop ) );
757 			    putCONG( p -> symbol , strlen( p -> symbol )
758 				    , LREQ );
759 			    putop( P2LISTOP , P2INT );
760 			    putleaf( P2ICON , strlen( p -> symbol )
761 				    , 0 , P2INT , 0 );
762 			    putop( P2LISTOP , P2INT );
763 			    putleaf( P2ICON
764 				, text(iop->type) ? 0 : width(iop->type->type)
765 				, 0 , P2INT , 0 );
766 			    putop( P2LISTOP , P2INT );
767 			    putop( P2CALL , P2INT );
768 			    putdot( filename , line );
769 #			endif PC
770 		}
771 		if (out == 0 && fp->chain != NIL) {
772 			recovered();
773 			error("The file output must appear in the program statement file list");
774 		}
775 	}
776 	/*
777 	 * Process the prog/proc/func body
778 	 */
779 	noreach = 0;
780 	line = bundle[1];
781 	statlist(blk);
782 #	ifdef PTREE
783 	    {
784 		pPointer Body = tCopy( blk );
785 
786 		pDEF( PorFHeader[ nesting -- ] ).PorFBody = Body;
787 	    }
788 #	endif PTREE
789 #	ifdef OBJ
790 	    if (cbn== 1 && monflg != 0) {
791 		    patchfil(cntpatch - 2, cnts, 2);
792 		    patchfil(nfppatch - 2, pfcnt, 2);
793 	    }
794 #	endif OBJ
795 #	ifdef PC
796 	    if ( fp -> class == PROG && monflg ) {
797 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
798 			, "_PMFLUSH" );
799 		putleaf( P2ICON , cnts , 0 , P2INT , 0 );
800 		putleaf( P2ICON , pfcnt , 0 , P2INT , 0 );
801 		putop( P2LISTOP , P2INT );
802 		putLV( PCPCOUNT , 0 , 0 , P2INT );
803 		putop( P2LISTOP , P2INT );
804 		putop( P2CALL , P2INT );
805 		putdot( filename , line );
806 	    }
807 #	endif PC
808 	if (fp->class == PROG && inp == 0 && (input->nl_flags & (NUSED|NMOD)) != 0) {
809 		recovered();
810 		error("Input is used but not defined in the program statement");
811 	}
812 	/*
813 	 * Clean up the symbol table displays and check for unresolves
814 	 */
815 	line = endline;
816 	b = cbn;
817 	Fp = fp;
818 	chkref = syneflg == errcnt[cbn] && opt('w') == 0;
819 	for (i = 0; i <= 077; i++) {
820 		for (p = disptab[i]; p != NIL && (p->nl_block & 037) == b; p = p->nl_next) {
821 			/*
822 			 * Check for variables defined
823 			 * but not referenced
824 			 */
825 			if (chkref && p->symbol != NIL)
826 			switch (p->class) {
827 				case FIELD:
828 					/*
829 					 * If the corresponding record is
830 					 * unused, we shouldn't complain about
831 					 * the fields.
832 					 */
833 				default:
834 					if ((p->nl_flags & (NUSED|NMOD)) == 0) {
835 						warning();
836 						nerror("%s %s is neither used nor set", classes[p->class], p->symbol);
837 						break;
838 					}
839 					/*
840 					 * If a var parameter is either
841 					 * modified or used that is enough.
842 					 */
843 					if (p->class == REF)
844 						continue;
845 #					ifdef OBJ
846 					    if ((p->nl_flags & NUSED) == 0) {
847 						warning();
848 						nerror("%s %s is never used", classes[p->class], p->symbol);
849 						break;
850 					    }
851 #					endif OBJ
852 #					ifdef PC
853 					    if (((p->nl_flags & NUSED) == 0) && ((p->ext_flags & NEXTERN) == 0)) {
854 						warning();
855 						nerror("%s %s is never used", classes[p->class], p->symbol);
856 						break;
857 					    }
858 #					endif PC
859 					if ((p->nl_flags & NMOD) == 0) {
860 						warning();
861 						nerror("%s %s is used but never set", classes[p->class], p->symbol);
862 						break;
863 					}
864 				case LABEL:
865 				case FVAR:
866 				case BADUSE:
867 					break;
868 			}
869 			switch (p->class) {
870 				case BADUSE:
871 					cp = "s";
872 					if (p->chain->ud_next == NIL)
873 						cp++;
874 					eholdnl();
875 					if (p->value[NL_KINDS] & ISUNDEF)
876 						nerror("%s undefined on line%s", p->symbol, cp);
877 					else
878 						nerror("%s improperly used on line%s", p->symbol, cp);
879 					pnumcnt = 10;
880 					pnums(p->chain);
881 					pchr('\n');
882 					break;
883 
884 				case FUNC:
885 				case PROC:
886 #					ifdef OBJ
887 					    if ((p->nl_flags & NFORWD))
888 						nerror("Unresolved forward declaration of %s %s", classes[p->class], p->symbol);
889 #					endif OBJ
890 #					ifdef PC
891 					    if ((p->nl_flags & NFORWD) && ((p->ext_flags & NEXTERN) == 0))
892 						nerror("Unresolved forward declaration of %s %s", classes[p->class], p->symbol);
893 #					endif PC
894 					break;
895 
896 				case LABEL:
897 					if (p->nl_flags & NFORWD)
898 						nerror("label %s was declared but not defined", p->symbol);
899 					break;
900 				case FVAR:
901 					if ((p->nl_flags & NMOD) == 0)
902 						nerror("No assignment to the function variable");
903 					break;
904 			}
905 		}
906 		/*
907 		 * Pop this symbol
908 		 * table slot
909 		 */
910 		disptab[i] = p;
911 	}
912 
913 #	ifdef OBJ
914 	    put(1, O_END);
915 #	endif OBJ
916 #	ifdef PC
917 		/*
918 		 *	if there were file variables declared at this level
919 		 *	call pclose( &__disply[ cbn ] ) to clean them up.
920 		 */
921 	    if ( dfiles[ cbn ] ) {
922 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
923 			, "_PCLOSE" );
924 		putRV( DISPLAYNAME , 0 , cbn * sizeof( struct dispsave )
925 			, P2PTR | P2CHAR );
926 		putop( P2CALL , P2INT );
927 		putdot( filename , line );
928 	    }
929 		/*
930 		 *	if this is a function,
931 		 *	the function variable is the return value.
932 		 *	if it's a scalar valued function, return scalar,
933 		 *	else, return a pointer to the structure value.
934 		 */
935 	    if ( fp -> class == FUNC ) {
936 		struct nl	*fvar = fp -> ptr[ NL_FVAR ];
937 		long		fvartype = p2type( fvar -> type );
938 		long		label;
939 		char		labelname[ BUFSIZ ];
940 
941 		switch ( classify( fvar -> type ) ) {
942 		    case TBOOL:
943 		    case TCHAR:
944 		    case TINT:
945 		    case TSCAL:
946 		    case TDOUBLE:
947 		    case TPTR:
948 			putRV( fvar -> symbol , ( fvar -> nl_block ) & 037
949 				, fvar -> value[ NL_OFFS ] , fvartype );
950 			break;
951 		    default:
952 			label = getlab();
953 			sprintf( labelname , PREFIXFORMAT ,
954 				LABELPREFIX , label );
955 			putprintf( "	.data" , 0 );
956 			putprintf( "	.lcomm	%s,%d" , 0 ,
957 				    labelname , lwidth( fvar -> type ) );
958 			putprintf( "	.text" , 0 );
959 			putleaf( P2NAME , 0 , 0 , fvartype , labelname );
960 			putLV( fvar -> symbol , ( fvar -> nl_block ) & 037
961 				, fvar -> value[ NL_OFFS ] , fvartype );
962 			putstrop( P2STASG , fvartype , lwidth( fvar -> type ) ,
963 				align( fvar -> type ) );
964 			putdot( filename , line );
965 			putleaf( P2ICON , 0 , 0 , fvartype , labelname );
966 			break;
967 		}
968 		putop( P2FORCE , fvartype );
969 		putdot( filename , line );
970 	    }
971 		/*
972 		 *	restore old display entry from save area
973 		 */
974 
975 	    putprintf( "	movq	%d(%s),%s+%d" , 0
976 		, DSAVEOFFSET , P2FPNAME
977 		, DISPLAYNAME , cbn * sizeof(struct dispsave) );
978 	    stabrbrac( cbn );
979 	    putprintf( "	ret" , 0 );
980 		/*
981 		 *	let the second pass allocate locals
982 		 */
983 	    putlab( botlabel );
984 	    putprintf( "	subl2	$LF%d,sp" , 0 , ftnno );
985 	    putrbracket( ftnno );
986 	    putjbr( toplabel );
987 		/*
988 		 *	declare pcp counters, if any
989 		 */
990 	    if ( monflg && fp -> class == PROG ) {
991 		putprintf( "	.data" , 0 );
992 		putprintf( "	.comm	" , 1 );
993 		putprintf( PCPCOUNT , 1 );
994 		putprintf( ",%d" , 0 , ( cnts + 1 ) * sizeof (long) );
995 		putprintf( "	.text" , 0 );
996 	    }
997 #	endif PC
998 #ifdef DEBUG
999 	dumpnl(fp->ptr[2], fp->symbol);
1000 #endif
1001 	/*
1002 	 * Restore the
1003 	 * (virtual) name list
1004 	 * position
1005 	 */
1006 	nlfree(fp->ptr[2]);
1007 	/*
1008 	 * Proc/func has been
1009 	 * resolved
1010 	 */
1011 	fp->nl_flags &= ~NFORWD;
1012 	/*
1013 	 * Patch the beg
1014 	 * of the proc/func to
1015 	 * the proper variable size
1016 	 */
1017 	if (Fp == NIL)
1018 		elineon();
1019 #	ifdef OBJ
1020 	    patchfil(var, -sizes[cbn].om_max, 2);
1021 #	endif OBJ
1022 	cbn--;
1023 	if (inpflist(fp->symbol)) {
1024 		opop('l');
1025 	}
1026 }
1027 
1028 
1029 /*
1030  * Segend is called to check for
1031  * unresolved variables, funcs and
1032  * procs, and deliver unresolved and
1033  * baduse error diagnostics at the
1034  * end of a routine segment (a separately
1035  * compiled segment that is not the
1036  * main program) for PC. This
1037  * routine should only be called
1038  * by PC (not standard).
1039  */
1040  segend()
1041  {
1042 	register struct nl *p;
1043 	register int i,b;
1044 	char *cp;
1045 
1046 #ifdef PC
1047 	if (opt('s')) {
1048 		standard();
1049 		error("Separately compiled routine segments are not standard.");
1050 	} else {
1051 		b = cbn;
1052 		for (i=0; i<077; i++) {
1053 			for (p = disptab[i]; p != NIL && (p->nl_block & 037) == b; p = p->nl_next) {
1054 			switch (p->class) {
1055 				case BADUSE:
1056 					cp = 's';
1057 					if (p->chain->ud_next == NIL)
1058 						cp++;
1059 					eholdnl();
1060 					if (p->value[NL_KINDS] & ISUNDEF)
1061 						nerror("%s undefined on line%s", p->symbol, cp);
1062 					else
1063 						nerror("%s improperly used on line%s", p->symbol, cp);
1064 					pnumcnt = 10;
1065 					pnums(p->chain);
1066 					pchr('\n');
1067 					break;
1068 
1069 				case FUNC:
1070 				case PROC:
1071 					if ((p->nl_flags & NFORWD) && ((p->ext_flags & NEXTERN) == 0))
1072 						nerror("Unresolved forward declaration of %s %s", classes[p->class], p->symbol);
1073 					break;
1074 
1075 				case FVAR:
1076 					if (((p->nl_flags & NMOD) == 0) && ((p->chain->ext_flags & NEXTERN) == 0))
1077 						nerror("No assignment to the function variable");
1078 					break;
1079 			    }
1080 			   }
1081 			   disptab[i] = p;
1082 		    }
1083 	}
1084 #endif PC
1085 #ifdef OBJ
1086 	error("Missing program statement and program body");
1087 #endif OBJ
1088 
1089 }
1090 
1091 
1092 /*
1093  * Level1 does level one processing for
1094  * separately compiled routine segments
1095  */
1096 level1()
1097 {
1098 
1099 #	ifdef OBJ
1100 	    error("Missing program statement");
1101 #	endif OBJ
1102 #	ifdef PC
1103 	    if (opt('s')) {
1104 		    standard();
1105 		    error("Missing program statement");
1106 	    }
1107 #	endif PC
1108 
1109 	cbn++;
1110 	sizes[cbn].om_max = sizes[cbn].om_off = -DPOFF1;
1111 	gotos[cbn] = NIL;
1112 	errcnt[cbn] = syneflg;
1113 	parts[ cbn ] = NIL;
1114 	dfiles[ cbn ] = FALSE;
1115 	progseen++;
1116 }
1117 
1118 
1119 
1120 pnums(p)
1121 	struct udinfo *p;
1122 {
1123 
1124 	if (p->ud_next != NIL)
1125 		pnums(p->ud_next);
1126 	if (pnumcnt == 0) {
1127 		printf("\n\t");
1128 		pnumcnt = 20;
1129 	}
1130 	pnumcnt--;
1131 	printf(" %d", p->ud_line);
1132 }
1133 
1134 nerror(a1, a2, a3)
1135 {
1136 
1137 	if (Fp != NIL) {
1138 		yySsync();
1139 #ifndef PI1
1140 		if (opt('l'))
1141 			yyoutline();
1142 #endif
1143 		yysetfile(filename);
1144 		printf("In %s %s:\n", classes[Fp->class], Fp->symbol);
1145 		Fp = NIL;
1146 		elineoff();
1147 	}
1148 	error(a1, a2, a3);
1149 }
1150