xref: /csrg-svn/usr.bin/pascal/src/call.c (revision 12902)
1745Speter /* Copyright (c) 1979 Regents of the University of California */
2745Speter 
3*12902Speter static	char sccsid[] = "@(#)call.c 1.24 06/03/83";
4745Speter 
5745Speter #include "whoami.h"
6745Speter #include "0.h"
7745Speter #include "tree.h"
8745Speter #include "opcode.h"
9745Speter #include "objfmt.h"
10745Speter #ifdef PC
11745Speter #   include "pc.h"
12745Speter #   include "pcops.h"
13745Speter #endif PC
1411331Speter #include "tmps.h"
15745Speter 
16745Speter /*
17745Speter  * Call generates code for calls to
18745Speter  * user defined procedures and functions
19745Speter  * and is called by proc and funccod.
20745Speter  * P is the result of the lookup
21745Speter  * of the procedure/function symbol,
22745Speter  * and porf is PROC or FUNC.
23745Speter  * Psbn is the block number of p.
243065Smckusic  *
253065Smckusic  *	the idea here is that regular scalar functions are just called,
263065Smckusic  *	while structure functions and formal functions have their results
273065Smckusic  *	stored in a temporary after the call.
283065Smckusic  *	structure functions do this because they return pointers
293065Smckusic  *	to static results, so we copy the static
303065Smckusic  *	and return a pointer to the copy.
313065Smckusic  *	formal functions do this because we have to save the result
323065Smckusic  *	around a call to the runtime routine which restores the display,
333065Smckusic  *	so we can't just leave the result lying around in registers.
343886Speter  *	formal calls save the address of the descriptor in a local
353886Speter  *	temporary, so it can be addressed for the call which restores
363886Speter  *	the display (FRTN).
373426Speter  *	calls to formal parameters pass the formal as a hidden argument
383426Speter  *	to a special entry point for the formal call.
393426Speter  *	[this is somewhat dependent on the way arguments are addressed.]
403065Smckusic  *	so PROCs and scalar FUNCs look like
413065Smckusic  *		p(...args...)
423065Smckusic  *	structure FUNCs look like
433065Smckusic  *		(temp = p(...args...),&temp)
443065Smckusic  *	formal FPROCs look like
454014Smckusic  *		( t=p,( t -> entryaddr )(...args...,t,s),FRTN(t,s))
463065Smckusic  *	formal scalar FFUNCs look like
474014Smckusic  *		( t=p,temp=( t -> entryaddr )(...args...,t,s),FRTN(t,s),temp)
483065Smckusic  *	formal structure FFUNCs look like
494014Smckusic  *		(t=p,temp = ( t -> entryaddr )(...args...,t,s),FRTN(t,s),&temp)
50745Speter  */
51745Speter struct nl *
52745Speter call(p, argv, porf, psbn)
53745Speter 	struct nl *p;
54745Speter 	int *argv, porf, psbn;
55745Speter {
56745Speter 	register struct nl *p1, *q;
57745Speter 	int *r;
583065Smckusic 	struct nl	*p_type_class = classify( p -> type );
593297Smckusic 	bool chk = TRUE;
604014Smckusic  	struct nl	*savedispnp;	/* temporary to hold saved display */
61745Speter #	ifdef PC
623065Smckusic 	    long	p_p2type = p2type( p );
633065Smckusic 	    long	p_type_p2type = p2type( p -> type );
643065Smckusic 	    bool	noarguments;
653065Smckusic 	    long	calltype;	/* type of the call */
663065Smckusic 		/*
673065Smckusic 		 *	these get used if temporaries and structures are used
683065Smckusic 		 */
693824Speter 	    struct nl	*tempnlp;
703065Smckusic 	    long	temptype;	/* type of the temporary */
713065Smckusic 	    long	p_type_width;
723065Smckusic 	    long	p_type_align;
733362Speter 	    char	extname[ BUFSIZ ];
743886Speter 	    struct nl	*tempdescrp;
75745Speter #	endif PC
76745Speter 
774014Smckusic          if (p->class == FFUNC || p->class == FPROC) {
784014Smckusic  	    /*
794014Smckusic  	     * allocate space to save the display for formal calls
804014Smckusic  	     */
814014Smckusic 	    savedispnp = tmpalloc( sizeof display , NIL , NOREG );
824014Smckusic  	}
83745Speter #	ifdef OBJ
843426Speter 	    if (p->class == FFUNC || p->class == FPROC) {
854014Smckusic  		put(2, O_LV | cbn << 8 + INDX ,
864014Smckusic  			(int) savedispnp -> value[ NL_OFFS ] );
873359Smckusic 		put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]);
883426Speter 	    }
893426Speter 	    if (porf == FUNC) {
90745Speter 		    /*
91745Speter 		     * Push some space
92745Speter 		     * for the function return type
93745Speter 		     */
943063Smckusic 		    put(2, O_PUSH, leven(-lwidth(p->type)));
953426Speter 	    }
96745Speter #	endif OBJ
97745Speter #	ifdef PC
983065Smckusic 		/*
993886Speter 		 *	if this is a formal call,
1003886Speter 		 *	stash the address of the descriptor
1013886Speter 		 *	in a temporary so we can find it
1023886Speter 		 *	after the FCALL for the call to FRTN
1033886Speter 		 */
1043886Speter 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
1053886Speter 		tempdescrp = tmpalloc(sizeof( struct formalrtn *) , NIL ,
1063886Speter 					REGOK );
1073886Speter 		putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
1083886Speter 			tempdescrp -> extra_flags , P2PTR|P2STRTY );
1093886Speter 		putRV( 0 , psbn , p -> value[ NL_OFFS ] ,
1103886Speter 			p -> extra_flags , P2PTR|P2STRTY );
1113886Speter 		putop( P2ASSIGN , P2PTR | P2STRTY );
1123886Speter 	    }
1133886Speter 		/*
1143065Smckusic 		 *	if we have to store a temporary,
1153065Smckusic 		 *	temptype will be its type,
1163065Smckusic 		 *	otherwise, it's P2UNDEF.
1173065Smckusic 		 */
1183065Smckusic 	    temptype = P2UNDEF;
1193065Smckusic 	    calltype = P2INT;
120745Speter 	    if ( porf == FUNC ) {
1213065Smckusic 		p_type_width = width( p -> type );
1223065Smckusic 		switch( p_type_class ) {
123745Speter 		    case TSTR:
124745Speter 		    case TSET:
125745Speter 		    case TREC:
126745Speter 		    case TFILE:
127745Speter 		    case TARY:
1283065Smckusic 			calltype = temptype = P2STRTY;
1293065Smckusic 			p_type_align = align( p -> type );
1303065Smckusic 			break;
1313065Smckusic 		    default:
1323065Smckusic 			if ( p -> class == FFUNC ) {
1333065Smckusic 			    calltype = temptype = p2type( p -> type );
134745Speter 			}
1353065Smckusic 			break;
136745Speter 		}
1373065Smckusic 		if ( temptype != P2UNDEF ) {
1383824Speter 		    tempnlp = tmpalloc(p_type_width, p -> type, NOREG);
1393065Smckusic 			/*
1403065Smckusic 			 *	temp
1413065Smckusic 			 *	for (temp = ...
1423065Smckusic 			 */
1433824Speter 		    putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
1443824Speter 			    tempnlp -> extra_flags , temptype );
1453065Smckusic 		}
146745Speter 	    }
1471195Speter 	    switch ( p -> class ) {
1481195Speter 		case FUNC:
1491195Speter 		case PROC:
1503065Smckusic 			/*
1513065Smckusic 			 *	... p( ...
1523065Smckusic 			 */
1533372Speter 		    sextname( extname , p -> symbol , BLOCKNO(p -> nl_block) );
1543362Speter 		    putleaf( P2ICON , 0 , 0 , p2type( p ) , extname );
1551195Speter 		    break;
1561195Speter 		case FFUNC:
1571195Speter 		case FPROC:
1583886Speter 
1591195Speter 			    /*
1603886Speter 			     *	... ( t -> entryaddr )( ...
1611195Speter 			     */
162*12902Speter 			    /* 	the descriptor */
1633886Speter 			putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
1643886Speter 				tempdescrp -> extra_flags , P2PTR | P2STRTY );
165*12902Speter 			    /*	the entry address within the descriptor */
1663426Speter 			if ( FENTRYOFFSET != 0 ) {
1673426Speter 			    putleaf( P2ICON , FENTRYOFFSET , 0 , P2INT , 0 );
1683426Speter 			    putop( P2PLUS ,
1693426Speter 				ADDTYPE(
1703426Speter 				    ADDTYPE( ADDTYPE( p2type( p ) , P2FTN ) ,
1713426Speter 					    P2PTR ) ,
1723426Speter 					P2PTR ) );
1733426Speter 			}
174*12902Speter 			    /*
175*12902Speter 			     *	indirect to fetch the formal entry address
176*12902Speter 			     *	with the result type of the routine.
177*12902Speter 			     */
178*12902Speter 			if (p -> class == FFUNC) {
179*12902Speter 			    putop( P2UNARY P2MUL ,
180*12902Speter 				ADDTYPE(ADDTYPE(p2type(p -> type), P2FTN),
181*12902Speter 					P2PTR));
182*12902Speter 			} else {
183*12902Speter 				/* procedures are int returning functions */
184*12902Speter 			    putop( P2UNARY P2MUL ,
185*12902Speter 				ADDTYPE(ADDTYPE(P2INT, P2FTN), P2PTR));
186*12902Speter 			}
1871195Speter 			break;
1881195Speter 		default:
1891195Speter 			panic("call class");
190745Speter 	    }
1913065Smckusic 	    noarguments = TRUE;
192745Speter #	endif PC
193745Speter 	/*
194745Speter 	 * Loop and process each of
195745Speter 	 * arguments to the proc/func.
1963065Smckusic 	 *	... ( ... args ... ) ...
197745Speter 	 */
1983297Smckusic 	for (p1 = plist(p); p1 != NIL; p1 = p1->chain) {
1993297Smckusic 	    if (argv == NIL) {
2003297Smckusic 		    error("Not enough arguments to %s", p->symbol);
2013297Smckusic 		    return (NIL);
2023297Smckusic 	    }
2033297Smckusic 	    switch (p1->class) {
2043297Smckusic 		case REF:
2053297Smckusic 			/*
2063297Smckusic 			 * Var parameter
2073297Smckusic 			 */
2083297Smckusic 			r = argv[1];
2093297Smckusic 			if (r != NIL && r[0] != T_VAR) {
2103297Smckusic 				error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol);
2113361Speter 				chk = FALSE;
2123297Smckusic 				break;
2133297Smckusic 			}
2143372Speter 			q = lvalue( (int *) argv[1], MOD | ASGN , LREQ );
2153297Smckusic 			if (q == NIL) {
2163297Smckusic 				chk = FALSE;
2173297Smckusic 				break;
2183297Smckusic 			}
2193297Smckusic 			if (q != p1->type) {
2203297Smckusic 				error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol);
2213361Speter 				chk = FALSE;
2223297Smckusic 				break;
2233297Smckusic 			}
2243297Smckusic 			break;
2253297Smckusic 		case VAR:
2263297Smckusic 			/*
2273297Smckusic 			 * Value parameter
2283297Smckusic 			 */
229745Speter #			ifdef OBJ
2303297Smckusic 			    q = rvalue(argv[1], p1->type , RREQ );
231745Speter #			endif OBJ
232745Speter #			ifdef PC
2333297Smckusic 				/*
2343297Smckusic 				 * structure arguments require lvalues,
2353297Smckusic 				 * scalars use rvalue.
2363297Smckusic 				 */
2373297Smckusic 			    switch( classify( p1 -> type ) ) {
2383297Smckusic 				case TFILE:
2393297Smckusic 				case TARY:
2403297Smckusic 				case TREC:
2413297Smckusic 				case TSET:
2423297Smckusic 				case TSTR:
24310365Smckusick 				    q = stkrval( argv[1] , p1 -> type , LREQ );
244745Speter 				    break;
2453297Smckusic 				case TINT:
2463297Smckusic 				case TSCAL:
2473297Smckusic 				case TBOOL:
2483297Smckusic 				case TCHAR:
2493297Smckusic 				    precheck( p1 -> type , "_RANG4" , "_RSNG4" );
25010365Smckusick 				    q = stkrval( argv[1] , p1 -> type , RREQ );
25110667Speter 				    postcheck(p1 -> type, nl+T4INT);
252745Speter 				    break;
25310365Smckusick 				case TDOUBLE:
25410365Smckusick 				    q = stkrval( argv[1] , p1 -> type , RREQ );
25510365Smckusick 				    sconv(p2type(q), P2DOUBLE);
25610365Smckusick 				    break;
2573297Smckusic 				default:
2583297Smckusic 				    q = rvalue( argv[1] , p1 -> type , RREQ );
2593297Smckusic 				    break;
260745Speter 			    }
2613297Smckusic #			endif PC
2623297Smckusic 			if (q == NIL) {
2633297Smckusic 				chk = FALSE;
2643297Smckusic 				break;
2653297Smckusic 			}
2663297Smckusic 			if (incompat(q, p1->type, argv[1])) {
2673297Smckusic 				cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol);
2683361Speter 				chk = FALSE;
2693297Smckusic 				break;
2703297Smckusic 			}
271745Speter #			ifdef OBJ
2723297Smckusic 			    if (isa(p1->type, "bcsi"))
2733297Smckusic 				    rangechk(p1->type, q);
2743297Smckusic 			    if (q->class != STR)
2753297Smckusic 				    convert(q, p1->type);
276745Speter #			endif OBJ
277745Speter #			ifdef PC
2783297Smckusic 			    switch( classify( p1 -> type ) ) {
2793297Smckusic 				case TFILE:
2803297Smckusic 				case TARY:
2813297Smckusic 				case TREC:
2823297Smckusic 				case TSET:
2833297Smckusic 				case TSTR:
2843297Smckusic 					putstrop( P2STARG
2853297Smckusic 					    , p2type( p1 -> type )
2863297Smckusic 					    , lwidth( p1 -> type )
2873297Smckusic 					    , align( p1 -> type ) );
2883297Smckusic 			    }
2891195Speter #			endif PC
2903297Smckusic 			break;
2913297Smckusic 		case FFUNC:
2921195Speter 			/*
2933297Smckusic 			 * function parameter
2941195Speter 			 */
2953297Smckusic 			q = flvalue( (int *) argv[1] , p1 );
2963297Smckusic 			chk = (chk && fcompat(q, p1));
2973297Smckusic 			break;
2983297Smckusic 		case FPROC:
2991195Speter 			/*
3003297Smckusic 			 * procedure parameter
3011195Speter 			 */
3023297Smckusic 			q = flvalue( (int *) argv[1] , p1 );
3033297Smckusic 			chk = (chk && fcompat(q, p1));
3043297Smckusic 			break;
3053297Smckusic 		default:
3063297Smckusic 			panic("call");
3071195Speter 	    }
3083297Smckusic #	    ifdef PC
3093297Smckusic 		    /*
3103297Smckusic 		     *	if this is the nth (>1) argument,
3113297Smckusic 		     *	hang it on the left linear list of arguments
3123297Smckusic 		     */
3133297Smckusic 		if ( noarguments ) {
3143297Smckusic 			noarguments = FALSE;
3153297Smckusic 		} else {
3163297Smckusic 			putop( P2LISTOP , P2INT );
3173297Smckusic 		}
3183297Smckusic #	    endif PC
3193297Smckusic 	    argv = argv[2];
320745Speter 	}
3213297Smckusic 	if (argv != NIL) {
3223297Smckusic 		error("Too many arguments to %s", p->symbol);
3233297Smckusic 		rvlist(argv);
3243297Smckusic 		return (NIL);
3253297Smckusic 	}
3263297Smckusic 	if (chk == FALSE)
3273297Smckusic 		return NIL;
328745Speter #	ifdef OBJ
3291195Speter 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
3303359Smckusic 		put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]);
3314014Smckusic  		put(2, O_LV | cbn << 8 + INDX ,
3324014Smckusic  			(int) savedispnp -> value[ NL_OFFS ] );
3333297Smckusic 		put(1, O_FCALL);
3343063Smckusic 		put(2, O_FRTN, even(width(p->type)));
3351195Speter 	    } else {
3367916Smckusick 		put(2, O_CALL | psbn << 8, (long)p->value[NL_ENTLOC]);
3371195Speter 	    }
338745Speter #	endif OBJ
339745Speter #	ifdef PC
3403065Smckusic 		/*
3413426Speter 		 *	for formal calls: add the hidden argument
3423426Speter 		 *	which is the formal struct describing the
3433426Speter 		 *	environment of the routine.
3443426Speter 		 *	and the argument which is the address of the
3453426Speter 		 *	space into which to save the display.
3463426Speter 		 */
3473426Speter 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
3483886Speter 		putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
3493886Speter 			tempdescrp -> extra_flags , P2PTR|P2STRTY );
3503426Speter 		if ( !noarguments ) {
3513426Speter 		    putop( P2LISTOP , P2INT );
3523426Speter 		}
3533426Speter 		noarguments = FALSE;
3544014Smckusic  		putLV( 0 , cbn , savedispnp -> value[ NL_OFFS ] ,
3554014Smckusic  			savedispnp -> extra_flags , P2PTR | P2STRTY );
3564014Smckusic  		putop( P2LISTOP , P2INT );
3573426Speter 	    }
3583426Speter 		/*
3593065Smckusic 		 *	do the actual call:
3603065Smckusic 		 *	    either	... p( ... ) ...
3613886Speter 		 *	    or		... ( t -> entryaddr )( ... ) ...
3623065Smckusic 		 *	and maybe an assignment.
3633065Smckusic 		 */
364745Speter 	    if ( porf == FUNC ) {
3653065Smckusic 		switch ( p_type_class ) {
366745Speter 		    case TBOOL:
367745Speter 		    case TCHAR:
368745Speter 		    case TINT:
369745Speter 		    case TSCAL:
370745Speter 		    case TDOUBLE:
371745Speter 		    case TPTR:
3723065Smckusic 			putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) ,
3733065Smckusic 				p_type_p2type );
3743065Smckusic 			if ( p -> class == FFUNC ) {
3753065Smckusic 			    putop( P2ASSIGN , p_type_p2type );
376745Speter 			}
377745Speter 			break;
378745Speter 		    default:
3793065Smckusic 			putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ),
3803065Smckusic 				ADDTYPE( p_type_p2type , P2PTR ) ,
3813065Smckusic 				p_type_width , p_type_align );
38211855Speter 			putstrop(P2STASG, ADDTYPE(p_type_p2type, P2PTR),
38311855Speter 				lwidth(p -> type), align(p -> type));
384745Speter 			break;
385745Speter 		}
386745Speter 	    } else {
3873065Smckusic 		putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT );
3883065Smckusic 	    }
3893065Smckusic 		/*
3903886Speter 		 *	( t=p , ... , FRTN( t ) ...
3913065Smckusic 		 */
3923065Smckusic 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
3933886Speter 		putop( P2COMOP , P2INT );
3943065Smckusic 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) ,
3953065Smckusic 			"_FRTN" );
3963886Speter 		putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
3973886Speter 			tempdescrp -> extra_flags , P2PTR | P2STRTY );
3984014Smckusic  		putLV( 0 , cbn , savedispnp -> value[ NL_OFFS ] ,
3994014Smckusic  			savedispnp -> extra_flags , P2PTR | P2STRTY );
4004014Smckusic  		putop( P2LISTOP , P2INT );
4013065Smckusic 		putop( P2CALL , P2INT );
4023065Smckusic 		putop( P2COMOP , P2INT );
4033065Smckusic 	    }
4043065Smckusic 		/*
4053065Smckusic 		 *	if required:
4063065Smckusic 		 *	either	... , temp )
4073065Smckusic 		 *	or	... , &temp )
4083065Smckusic 		 */
4093065Smckusic 	    if ( porf == FUNC && temptype != P2UNDEF ) {
4103065Smckusic 		if ( temptype != P2STRTY ) {
4113824Speter 		    putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
4123824Speter 			    tempnlp -> extra_flags , p_type_p2type );
413745Speter 		} else {
4143824Speter 		    putLV( 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
4153824Speter 			    tempnlp -> extra_flags , p_type_p2type );
416745Speter 		}
4173065Smckusic 		putop( P2COMOP , P2INT );
4183065Smckusic 	    }
4193065Smckusic 	    if ( porf == PROC ) {
420745Speter 		putdot( filename , line );
421745Speter 	    }
422745Speter #	endif PC
423745Speter 	return (p->type);
424745Speter }
425745Speter 
426745Speter rvlist(al)
427745Speter 	register int *al;
428745Speter {
429745Speter 
430745Speter 	for (; al != NIL; al = al[2])
431745Speter 		rvalue( (int *) al[1], NLNIL , RREQ );
432745Speter }
4333297Smckusic 
4343297Smckusic     /*
4353297Smckusic      *	check that two function/procedure namelist entries are compatible
4363297Smckusic      */
4373297Smckusic bool
4383297Smckusic fcompat( formal , actual )
4393297Smckusic     struct nl	*formal;
4403297Smckusic     struct nl	*actual;
4413297Smckusic {
4423297Smckusic     register struct nl	*f_chain;
4433297Smckusic     register struct nl	*a_chain;
4443297Smckusic     bool compat = TRUE;
4453297Smckusic 
4463297Smckusic     if ( formal == NIL || actual == NIL ) {
4473297Smckusic 	return FALSE;
4483297Smckusic     }
4493297Smckusic     for (a_chain = plist(actual), f_chain = plist(formal);
4503297Smckusic          f_chain != NIL;
4513297Smckusic 	 f_chain = f_chain->chain, a_chain = a_chain->chain) {
4523297Smckusic 	if (a_chain == NIL) {
4533297Smckusic 	    error("%s %s declared on line %d has more arguments than",
4543297Smckusic 		parnam(formal->class), formal->symbol,
4553297Smckusic 		linenum(formal));
4563297Smckusic 	    cerror("%s %s declared on line %d",
4573297Smckusic 		parnam(actual->class), actual->symbol,
4583297Smckusic 		linenum(actual));
4593297Smckusic 	    return FALSE;
4603297Smckusic 	}
4613297Smckusic 	if ( a_chain -> class != f_chain -> class ) {
4623297Smckusic 	    error("%s parameter %s of %s declared on line %d is not identical",
4633297Smckusic 		parnam(f_chain->class), f_chain->symbol,
4643297Smckusic 		formal->symbol, linenum(formal));
4653297Smckusic 	    cerror("with %s parameter %s of %s declared on line %d",
4663297Smckusic 		parnam(a_chain->class), a_chain->symbol,
4673297Smckusic 		actual->symbol, linenum(actual));
4683297Smckusic 	    compat = FALSE;
4693297Smckusic 	} else if (a_chain->class == FFUNC || a_chain->class == FPROC) {
4703297Smckusic 	    compat = (compat && fcompat(f_chain, a_chain));
4713297Smckusic 	}
4723297Smckusic 	if ((a_chain->class != FPROC && f_chain->class != FPROC) &&
4733297Smckusic 	    (a_chain->type != f_chain->type)) {
4743297Smckusic 	    error("Type of %s parameter %s of %s declared on line %d is not identical",
4753297Smckusic 		parnam(f_chain->class), f_chain->symbol,
4763297Smckusic 		formal->symbol, linenum(formal));
4773297Smckusic 	    cerror("to type of %s parameter %s of %s declared on line %d",
4783297Smckusic 		parnam(a_chain->class), a_chain->symbol,
4793297Smckusic 		actual->symbol, linenum(actual));
4803297Smckusic 	    compat = FALSE;
4813297Smckusic 	}
4823297Smckusic     }
4833297Smckusic     if (a_chain != NIL) {
4843297Smckusic 	error("%s %s declared on line %d has fewer arguments than",
4853297Smckusic 	    parnam(formal->class), formal->symbol,
4863297Smckusic 	    linenum(formal));
4873297Smckusic 	cerror("%s %s declared on line %d",
4883297Smckusic 	    parnam(actual->class), actual->symbol,
4893297Smckusic 	    linenum(actual));
4903297Smckusic 	return FALSE;
4913297Smckusic     }
4923297Smckusic     return compat;
4933297Smckusic }
4943297Smckusic 
4953297Smckusic char *
4963297Smckusic parnam(nltype)
4973297Smckusic     int nltype;
4983297Smckusic {
4993297Smckusic     switch(nltype) {
5003297Smckusic 	case REF:
5013297Smckusic 	    return "var";
5023297Smckusic 	case VAR:
5033297Smckusic 	    return "value";
5043297Smckusic 	case FUNC:
5053297Smckusic 	case FFUNC:
5063297Smckusic 	    return "function";
5073297Smckusic 	case PROC:
5083297Smckusic 	case FPROC:
5093297Smckusic 	    return "procedure";
5103297Smckusic 	default:
5113297Smckusic 	    return "SNARK";
5123297Smckusic     }
5133297Smckusic }
5143297Smckusic 
5153297Smckusic plist(p)
5163297Smckusic     struct nl *p;
5173297Smckusic {
5183297Smckusic     switch (p->class) {
5193297Smckusic 	case FFUNC:
5203297Smckusic 	case FPROC:
5213297Smckusic 	    return p->ptr[ NL_FCHAIN ];
5223297Smckusic 	case PROC:
5233297Smckusic 	case FUNC:
5243297Smckusic 	    return p->chain;
5253297Smckusic 	default:
5263297Smckusic 	    panic("plist");
5273297Smckusic     }
5283297Smckusic }
5293297Smckusic 
5303297Smckusic linenum(p)
5313297Smckusic     struct nl *p;
5323297Smckusic {
5333297Smckusic     if (p->class == FUNC)
5343297Smckusic 	return p->ptr[NL_FVAR]->value[NL_LINENO];
5353297Smckusic     return p->value[NL_LINENO];
5363297Smckusic }
537