xref: /csrg-svn/usr.bin/pascal/src/call.c (revision 14727)
1745Speter /* Copyright (c) 1979 Regents of the University of California */
2745Speter 
3*14727Sthien #ifndef lint
4*14727Sthien static	char sccsid[] = "@(#)call.c 1.25 08/19/83";
5*14727Sthien #endif
6745Speter 
7745Speter #include "whoami.h"
8745Speter #include "0.h"
9745Speter #include "tree.h"
10745Speter #include "opcode.h"
11745Speter #include "objfmt.h"
12745Speter #ifdef PC
13745Speter #   include "pc.h"
14745Speter #   include "pcops.h"
15745Speter #endif PC
1611331Speter #include "tmps.h"
17*14727Sthien #include "tree_ty.h"
18745Speter 
19745Speter /*
20745Speter  * Call generates code for calls to
21745Speter  * user defined procedures and functions
22745Speter  * and is called by proc and funccod.
23745Speter  * P is the result of the lookup
24745Speter  * of the procedure/function symbol,
25745Speter  * and porf is PROC or FUNC.
26745Speter  * Psbn is the block number of p.
273065Smckusic  *
283065Smckusic  *	the idea here is that regular scalar functions are just called,
293065Smckusic  *	while structure functions and formal functions have their results
303065Smckusic  *	stored in a temporary after the call.
313065Smckusic  *	structure functions do this because they return pointers
323065Smckusic  *	to static results, so we copy the static
333065Smckusic  *	and return a pointer to the copy.
343065Smckusic  *	formal functions do this because we have to save the result
353065Smckusic  *	around a call to the runtime routine which restores the display,
363065Smckusic  *	so we can't just leave the result lying around in registers.
373886Speter  *	formal calls save the address of the descriptor in a local
383886Speter  *	temporary, so it can be addressed for the call which restores
393886Speter  *	the display (FRTN).
403426Speter  *	calls to formal parameters pass the formal as a hidden argument
413426Speter  *	to a special entry point for the formal call.
423426Speter  *	[this is somewhat dependent on the way arguments are addressed.]
433065Smckusic  *	so PROCs and scalar FUNCs look like
443065Smckusic  *		p(...args...)
453065Smckusic  *	structure FUNCs look like
463065Smckusic  *		(temp = p(...args...),&temp)
473065Smckusic  *	formal FPROCs look like
484014Smckusic  *		( t=p,( t -> entryaddr )(...args...,t,s),FRTN(t,s))
493065Smckusic  *	formal scalar FFUNCs look like
504014Smckusic  *		( t=p,temp=( t -> entryaddr )(...args...,t,s),FRTN(t,s),temp)
513065Smckusic  *	formal structure FFUNCs look like
524014Smckusic  *		(t=p,temp = ( t -> entryaddr )(...args...,t,s),FRTN(t,s),&temp)
53745Speter  */
54745Speter struct nl *
55*14727Sthien call(p, argv_node, porf, psbn)
56745Speter 	struct nl *p;
57*14727Sthien 	struct tnode	*argv_node;	/* list node */
58*14727Sthien 	int porf, psbn;
59745Speter {
60745Speter 	register struct nl *p1, *q;
61*14727Sthien 	struct tnode *rnode;
623297Smckusic 	bool chk = TRUE;
634014Smckusic  	struct nl	*savedispnp;	/* temporary to hold saved display */
64745Speter #	ifdef PC
65*14727Sthien 	    int		p_type_class = classify( p -> type );
663065Smckusic 	    long	p_type_p2type = p2type( p -> type );
673065Smckusic 	    bool	noarguments;
683065Smckusic 		/*
693065Smckusic 		 *	these get used if temporaries and structures are used
703065Smckusic 		 */
713824Speter 	    struct nl	*tempnlp;
723065Smckusic 	    long	temptype;	/* type of the temporary */
733065Smckusic 	    long	p_type_width;
743065Smckusic 	    long	p_type_align;
753362Speter 	    char	extname[ BUFSIZ ];
763886Speter 	    struct nl	*tempdescrp;
77745Speter #	endif PC
78745Speter 
794014Smckusic          if (p->class == FFUNC || p->class == FPROC) {
804014Smckusic  	    /*
814014Smckusic  	     * allocate space to save the display for formal calls
824014Smckusic  	     */
83*14727Sthien 	    savedispnp = tmpalloc( (long) sizeof display , NLNIL , NOREG );
844014Smckusic  	}
85745Speter #	ifdef OBJ
863426Speter 	    if (p->class == FFUNC || p->class == FPROC) {
87*14727Sthien  		(void) put(2, O_LV | cbn << 8 + INDX ,
884014Smckusic  			(int) savedispnp -> value[ NL_OFFS ] );
89*14727Sthien 		(void) put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]);
903426Speter 	    }
913426Speter 	    if (porf == FUNC) {
92745Speter 		    /*
93745Speter 		     * Push some space
94745Speter 		     * for the function return type
95745Speter 		     */
96*14727Sthien 		    (void) put(2, O_PUSH, leven(-lwidth(p->type)));
973426Speter 	    }
98745Speter #	endif OBJ
99745Speter #	ifdef PC
1003065Smckusic 		/*
1013886Speter 		 *	if this is a formal call,
1023886Speter 		 *	stash the address of the descriptor
1033886Speter 		 *	in a temporary so we can find it
1043886Speter 		 *	after the FCALL for the call to FRTN
1053886Speter 		 */
1063886Speter 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
107*14727Sthien 		tempdescrp = tmpalloc((long) (sizeof( struct formalrtn *)),
108*14727Sthien 					NLNIL, REGOK );
109*14727Sthien 		putRV((char *) 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
1103886Speter 			tempdescrp -> extra_flags , P2PTR|P2STRTY );
111*14727Sthien 		putRV((char *) 0 , psbn , p -> value[ NL_OFFS ] ,
1123886Speter 			p -> extra_flags , P2PTR|P2STRTY );
1133886Speter 		putop( P2ASSIGN , P2PTR | P2STRTY );
1143886Speter 	    }
1153886Speter 		/*
1163065Smckusic 		 *	if we have to store a temporary,
1173065Smckusic 		 *	temptype will be its type,
1183065Smckusic 		 *	otherwise, it's P2UNDEF.
1193065Smckusic 		 */
1203065Smckusic 	    temptype = P2UNDEF;
121745Speter 	    if ( porf == FUNC ) {
1223065Smckusic 		p_type_width = width( p -> type );
1233065Smckusic 		switch( p_type_class ) {
124745Speter 		    case TSTR:
125745Speter 		    case TSET:
126745Speter 		    case TREC:
127745Speter 		    case TFILE:
128745Speter 		    case TARY:
129*14727Sthien 			temptype = P2STRTY;
1303065Smckusic 			p_type_align = align( p -> type );
1313065Smckusic 			break;
1323065Smckusic 		    default:
1333065Smckusic 			if ( p -> class == FFUNC ) {
134*14727Sthien 			    temptype = p2type( p -> type );
135745Speter 			}
1363065Smckusic 			break;
137745Speter 		}
1383065Smckusic 		if ( temptype != P2UNDEF ) {
1393824Speter 		    tempnlp = tmpalloc(p_type_width, p -> type, NOREG);
1403065Smckusic 			/*
1413065Smckusic 			 *	temp
1423065Smckusic 			 *	for (temp = ...
1433065Smckusic 			 */
144*14727Sthien 		    putRV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
145*14727Sthien 			    tempnlp -> extra_flags , (int) temptype );
1463065Smckusic 		}
147745Speter 	    }
1481195Speter 	    switch ( p -> class ) {
1491195Speter 		case FUNC:
1501195Speter 		case PROC:
1513065Smckusic 			/*
1523065Smckusic 			 *	... p( ...
1533065Smckusic 			 */
1543372Speter 		    sextname( extname , p -> symbol , BLOCKNO(p -> nl_block) );
1553362Speter 		    putleaf( P2ICON , 0 , 0 , p2type( p ) , extname );
1561195Speter 		    break;
1571195Speter 		case FFUNC:
1581195Speter 		case FPROC:
1593886Speter 
1601195Speter 			    /*
1613886Speter 			     *	... ( t -> entryaddr )( ...
1621195Speter 			     */
16312902Speter 			    /* 	the descriptor */
164*14727Sthien 			putRV((char *) 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
1653886Speter 				tempdescrp -> extra_flags , P2PTR | P2STRTY );
16612902Speter 			    /*	the entry address within the descriptor */
1673426Speter 			if ( FENTRYOFFSET != 0 ) {
168*14727Sthien 			    putleaf( P2ICON , FENTRYOFFSET , 0 , P2INT ,
169*14727Sthien 						(char *) 0 );
1703426Speter 			    putop( P2PLUS ,
1713426Speter 				ADDTYPE(
1723426Speter 				    ADDTYPE( ADDTYPE( p2type( p ) , P2FTN ) ,
1733426Speter 					    P2PTR ) ,
1743426Speter 					P2PTR ) );
1753426Speter 			}
17612902Speter 			    /*
17712902Speter 			     *	indirect to fetch the formal entry address
17812902Speter 			     *	with the result type of the routine.
17912902Speter 			     */
18012902Speter 			if (p -> class == FFUNC) {
18112902Speter 			    putop( P2UNARY P2MUL ,
18212902Speter 				ADDTYPE(ADDTYPE(p2type(p -> type), P2FTN),
18312902Speter 					P2PTR));
18412902Speter 			} else {
18512902Speter 				/* procedures are int returning functions */
18612902Speter 			    putop( P2UNARY P2MUL ,
18712902Speter 				ADDTYPE(ADDTYPE(P2INT, P2FTN), P2PTR));
18812902Speter 			}
1891195Speter 			break;
1901195Speter 		default:
1911195Speter 			panic("call class");
192745Speter 	    }
1933065Smckusic 	    noarguments = TRUE;
194745Speter #	endif PC
195745Speter 	/*
196745Speter 	 * Loop and process each of
197745Speter 	 * arguments to the proc/func.
1983065Smckusic 	 *	... ( ... args ... ) ...
199745Speter 	 */
200*14727Sthien 	for (p1 = plist(p); p1 != NLNIL; p1 = p1->chain) {
201*14727Sthien 	    if (argv_node == TR_NIL) {
2023297Smckusic 		    error("Not enough arguments to %s", p->symbol);
203*14727Sthien 		    return (NLNIL);
2043297Smckusic 	    }
2053297Smckusic 	    switch (p1->class) {
2063297Smckusic 		case REF:
2073297Smckusic 			/*
2083297Smckusic 			 * Var parameter
2093297Smckusic 			 */
210*14727Sthien 			rnode = argv_node->list_node.list;
211*14727Sthien 			if (rnode != TR_NIL && rnode->tag != T_VAR) {
2123297Smckusic 				error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol);
2133361Speter 				chk = FALSE;
2143297Smckusic 				break;
2153297Smckusic 			}
216*14727Sthien 			q = lvalue( argv_node->list_node.list,
217*14727Sthien 					MOD | ASGN , LREQ );
2183297Smckusic 			if (q == NIL) {
2193297Smckusic 				chk = FALSE;
2203297Smckusic 				break;
2213297Smckusic 			}
2223297Smckusic 			if (q != p1->type) {
2233297Smckusic 				error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol);
2243361Speter 				chk = FALSE;
2253297Smckusic 				break;
2263297Smckusic 			}
2273297Smckusic 			break;
2283297Smckusic 		case VAR:
2293297Smckusic 			/*
2303297Smckusic 			 * Value parameter
2313297Smckusic 			 */
232745Speter #			ifdef OBJ
233*14727Sthien 			    q = rvalue(argv_node->list_node.list,
234*14727Sthien 					p1->type , RREQ );
235745Speter #			endif OBJ
236745Speter #			ifdef PC
2373297Smckusic 				/*
2383297Smckusic 				 * structure arguments require lvalues,
2393297Smckusic 				 * scalars use rvalue.
2403297Smckusic 				 */
2413297Smckusic 			    switch( classify( p1 -> type ) ) {
2423297Smckusic 				case TFILE:
2433297Smckusic 				case TARY:
2443297Smckusic 				case TREC:
2453297Smckusic 				case TSET:
2463297Smckusic 				case TSTR:
247*14727Sthien 				q = stkrval(argv_node->list_node.list,
248*14727Sthien 						p1 -> type , (long) LREQ );
249745Speter 				    break;
2503297Smckusic 				case TINT:
2513297Smckusic 				case TSCAL:
2523297Smckusic 				case TBOOL:
2533297Smckusic 				case TCHAR:
2543297Smckusic 				    precheck( p1 -> type , "_RANG4" , "_RSNG4" );
255*14727Sthien 				q = stkrval(argv_node->list_node.list,
256*14727Sthien 						p1 -> type , (long) RREQ );
25710667Speter 				    postcheck(p1 -> type, nl+T4INT);
258745Speter 				    break;
25910365Smckusick 				case TDOUBLE:
260*14727Sthien 				q = stkrval(argv_node->list_node.list,
261*14727Sthien 						p1 -> type , (long) RREQ );
26210365Smckusick 				    sconv(p2type(q), P2DOUBLE);
26310365Smckusick 				    break;
2643297Smckusic 				default:
265*14727Sthien 				    q = rvalue(argv_node->list_node.list,
266*14727Sthien 						p1 -> type , RREQ );
2673297Smckusic 				    break;
268745Speter 			    }
2693297Smckusic #			endif PC
2703297Smckusic 			if (q == NIL) {
2713297Smckusic 				chk = FALSE;
2723297Smckusic 				break;
2733297Smckusic 			}
274*14727Sthien 			if (incompat(q, p1->type,
275*14727Sthien 				argv_node->list_node.list)) {
2763297Smckusic 				cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol);
2773361Speter 				chk = FALSE;
2783297Smckusic 				break;
2793297Smckusic 			}
280745Speter #			ifdef OBJ
2813297Smckusic 			    if (isa(p1->type, "bcsi"))
2823297Smckusic 				    rangechk(p1->type, q);
2833297Smckusic 			    if (q->class != STR)
2843297Smckusic 				    convert(q, p1->type);
285745Speter #			endif OBJ
286745Speter #			ifdef PC
2873297Smckusic 			    switch( classify( p1 -> type ) ) {
2883297Smckusic 				case TFILE:
2893297Smckusic 				case TARY:
2903297Smckusic 				case TREC:
2913297Smckusic 				case TSET:
2923297Smckusic 				case TSTR:
2933297Smckusic 					putstrop( P2STARG
2943297Smckusic 					    , p2type( p1 -> type )
295*14727Sthien 					    , (int) lwidth( p1 -> type )
2963297Smckusic 					    , align( p1 -> type ) );
2973297Smckusic 			    }
2981195Speter #			endif PC
2993297Smckusic 			break;
3003297Smckusic 		case FFUNC:
3011195Speter 			/*
3023297Smckusic 			 * function parameter
3031195Speter 			 */
304*14727Sthien 			q = flvalue(argv_node->list_node.list, p1 );
305*14727Sthien 			/*chk = (chk && fcompat(q, p1));*/
306*14727Sthien 			if ((chk) && (fcompat(q, p1)))
307*14727Sthien 			    chk = TRUE;
308*14727Sthien 			else
309*14727Sthien 			    chk = FALSE;
3103297Smckusic 			break;
3113297Smckusic 		case FPROC:
3121195Speter 			/*
3133297Smckusic 			 * procedure parameter
3141195Speter 			 */
315*14727Sthien 			q = flvalue(argv_node->list_node.list, p1 );
316*14727Sthien 			/* chk = (chk && fcompat(q, p1)); */
317*14727Sthien 			if ((chk) && (fcompat(q, p1)))
318*14727Sthien 			    chk = TRUE;
319*14727Sthien 			else chk = FALSE;
3203297Smckusic 			break;
3213297Smckusic 		default:
3223297Smckusic 			panic("call");
3231195Speter 	    }
3243297Smckusic #	    ifdef PC
3253297Smckusic 		    /*
3263297Smckusic 		     *	if this is the nth (>1) argument,
3273297Smckusic 		     *	hang it on the left linear list of arguments
3283297Smckusic 		     */
3293297Smckusic 		if ( noarguments ) {
3303297Smckusic 			noarguments = FALSE;
3313297Smckusic 		} else {
3323297Smckusic 			putop( P2LISTOP , P2INT );
3333297Smckusic 		}
3343297Smckusic #	    endif PC
335*14727Sthien 	    argv_node = argv_node->list_node.next;
336745Speter 	}
337*14727Sthien 	if (argv_node != TR_NIL) {
3383297Smckusic 		error("Too many arguments to %s", p->symbol);
339*14727Sthien 		rvlist(argv_node);
340*14727Sthien 		return (NLNIL);
3413297Smckusic 	}
3423297Smckusic 	if (chk == FALSE)
343*14727Sthien 		return NLNIL;
344745Speter #	ifdef OBJ
3451195Speter 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
346*14727Sthien 		(void) put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]);
347*14727Sthien  		(void) put(2, O_LV | cbn << 8 + INDX ,
3484014Smckusic  			(int) savedispnp -> value[ NL_OFFS ] );
349*14727Sthien 		(void) put(1, O_FCALL);
350*14727Sthien 		(void) put(2, O_FRTN, even(width(p->type)));
3511195Speter 	    } else {
352*14727Sthien 		(void) put(2, O_CALL | psbn << 8, (long)p->value[NL_ENTLOC]);
3531195Speter 	    }
354745Speter #	endif OBJ
355745Speter #	ifdef PC
3563065Smckusic 		/*
3573426Speter 		 *	for formal calls: add the hidden argument
3583426Speter 		 *	which is the formal struct describing the
3593426Speter 		 *	environment of the routine.
3603426Speter 		 *	and the argument which is the address of the
3613426Speter 		 *	space into which to save the display.
3623426Speter 		 */
3633426Speter 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
364*14727Sthien 		putRV((char *) 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
3653886Speter 			tempdescrp -> extra_flags , P2PTR|P2STRTY );
3663426Speter 		if ( !noarguments ) {
3673426Speter 		    putop( P2LISTOP , P2INT );
3683426Speter 		}
3693426Speter 		noarguments = FALSE;
370*14727Sthien  		putLV((char *) 0 , cbn , savedispnp -> value[ NL_OFFS ] ,
3714014Smckusic  			savedispnp -> extra_flags , P2PTR | P2STRTY );
3724014Smckusic  		putop( P2LISTOP , P2INT );
3733426Speter 	    }
3743426Speter 		/*
3753065Smckusic 		 *	do the actual call:
3763065Smckusic 		 *	    either	... p( ... ) ...
3773886Speter 		 *	    or		... ( t -> entryaddr )( ... ) ...
3783065Smckusic 		 *	and maybe an assignment.
3793065Smckusic 		 */
380745Speter 	    if ( porf == FUNC ) {
3813065Smckusic 		switch ( p_type_class ) {
382745Speter 		    case TBOOL:
383745Speter 		    case TCHAR:
384745Speter 		    case TINT:
385745Speter 		    case TSCAL:
386745Speter 		    case TDOUBLE:
387745Speter 		    case TPTR:
3883065Smckusic 			putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) ,
389*14727Sthien 				(int) p_type_p2type );
3903065Smckusic 			if ( p -> class == FFUNC ) {
391*14727Sthien 			    putop( P2ASSIGN , (int) p_type_p2type );
392745Speter 			}
393745Speter 			break;
394745Speter 		    default:
3953065Smckusic 			putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ),
396*14727Sthien 				(int) ADDTYPE( p_type_p2type , P2PTR ) ,
397*14727Sthien 				(int) p_type_width ,(int) p_type_align );
398*14727Sthien 			putstrop(P2STASG, (int) ADDTYPE(p_type_p2type, P2PTR),
399*14727Sthien 				(int) lwidth(p -> type), align(p -> type));
400745Speter 			break;
401745Speter 		}
402745Speter 	    } else {
4033065Smckusic 		putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT );
4043065Smckusic 	    }
4053065Smckusic 		/*
4063886Speter 		 *	( t=p , ... , FRTN( t ) ...
4073065Smckusic 		 */
4083065Smckusic 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
4093886Speter 		putop( P2COMOP , P2INT );
4103065Smckusic 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) ,
4113065Smckusic 			"_FRTN" );
412*14727Sthien 		putRV((char *) 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
4133886Speter 			tempdescrp -> extra_flags , P2PTR | P2STRTY );
414*14727Sthien  		putLV((char *) 0 , cbn , savedispnp -> value[ NL_OFFS ] ,
4154014Smckusic  			savedispnp -> extra_flags , P2PTR | P2STRTY );
4164014Smckusic  		putop( P2LISTOP , P2INT );
4173065Smckusic 		putop( P2CALL , P2INT );
4183065Smckusic 		putop( P2COMOP , P2INT );
4193065Smckusic 	    }
4203065Smckusic 		/*
4213065Smckusic 		 *	if required:
4223065Smckusic 		 *	either	... , temp )
4233065Smckusic 		 *	or	... , &temp )
4243065Smckusic 		 */
4253065Smckusic 	    if ( porf == FUNC && temptype != P2UNDEF ) {
4263065Smckusic 		if ( temptype != P2STRTY ) {
427*14727Sthien 		    putRV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
428*14727Sthien 			    tempnlp -> extra_flags , (int) p_type_p2type );
429745Speter 		} else {
430*14727Sthien 		    putLV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
431*14727Sthien 			    tempnlp -> extra_flags , (int) p_type_p2type );
432745Speter 		}
4333065Smckusic 		putop( P2COMOP , P2INT );
4343065Smckusic 	    }
4353065Smckusic 	    if ( porf == PROC ) {
436745Speter 		putdot( filename , line );
437745Speter 	    }
438745Speter #	endif PC
439745Speter 	return (p->type);
440745Speter }
441745Speter 
442745Speter rvlist(al)
443*14727Sthien 	register struct tnode *al;
444745Speter {
445745Speter 
446*14727Sthien 	for (; al != TR_NIL; al = al->list_node.next)
447*14727Sthien 		(void) rvalue( al->list_node.list, NLNIL , RREQ );
448745Speter }
4493297Smckusic 
4503297Smckusic     /*
4513297Smckusic      *	check that two function/procedure namelist entries are compatible
4523297Smckusic      */
4533297Smckusic bool
4543297Smckusic fcompat( formal , actual )
4553297Smckusic     struct nl	*formal;
4563297Smckusic     struct nl	*actual;
4573297Smckusic {
4583297Smckusic     register struct nl	*f_chain;
4593297Smckusic     register struct nl	*a_chain;
460*14727Sthien     extern struct nl	*plist();
4613297Smckusic     bool compat = TRUE;
4623297Smckusic 
463*14727Sthien     if ( formal == NLNIL || actual == NLNIL ) {
4643297Smckusic 	return FALSE;
4653297Smckusic     }
4663297Smckusic     for (a_chain = plist(actual), f_chain = plist(formal);
467*14727Sthien          f_chain != NLNIL;
4683297Smckusic 	 f_chain = f_chain->chain, a_chain = a_chain->chain) {
4693297Smckusic 	if (a_chain == NIL) {
4703297Smckusic 	    error("%s %s declared on line %d has more arguments than",
4713297Smckusic 		parnam(formal->class), formal->symbol,
472*14727Sthien 		(char *) linenum(formal));
4733297Smckusic 	    cerror("%s %s declared on line %d",
4743297Smckusic 		parnam(actual->class), actual->symbol,
475*14727Sthien 		(char *) linenum(actual));
4763297Smckusic 	    return FALSE;
4773297Smckusic 	}
4783297Smckusic 	if ( a_chain -> class != f_chain -> class ) {
4793297Smckusic 	    error("%s parameter %s of %s declared on line %d is not identical",
4803297Smckusic 		parnam(f_chain->class), f_chain->symbol,
481*14727Sthien 		formal->symbol, (char *) linenum(formal));
4823297Smckusic 	    cerror("with %s parameter %s of %s declared on line %d",
4833297Smckusic 		parnam(a_chain->class), a_chain->symbol,
484*14727Sthien 		actual->symbol, (char *) linenum(actual));
4853297Smckusic 	    compat = FALSE;
4863297Smckusic 	} else if (a_chain->class == FFUNC || a_chain->class == FPROC) {
487*14727Sthien 	    /*compat = (compat && fcompat(f_chain, a_chain));*/
488*14727Sthien 	    if ((compat) && (fcompat(f_chain, a_chain)))
489*14727Sthien 		compat = TRUE;
490*14727Sthien 	    else compat = FALSE;
4913297Smckusic 	}
4923297Smckusic 	if ((a_chain->class != FPROC && f_chain->class != FPROC) &&
4933297Smckusic 	    (a_chain->type != f_chain->type)) {
4943297Smckusic 	    error("Type of %s parameter %s of %s declared on line %d is not identical",
4953297Smckusic 		parnam(f_chain->class), f_chain->symbol,
496*14727Sthien 		formal->symbol, (char *) linenum(formal));
4973297Smckusic 	    cerror("to type of %s parameter %s of %s declared on line %d",
4983297Smckusic 		parnam(a_chain->class), a_chain->symbol,
499*14727Sthien 		actual->symbol, (char *) linenum(actual));
5003297Smckusic 	    compat = FALSE;
5013297Smckusic 	}
5023297Smckusic     }
5033297Smckusic     if (a_chain != NIL) {
5043297Smckusic 	error("%s %s declared on line %d has fewer arguments than",
5053297Smckusic 	    parnam(formal->class), formal->symbol,
506*14727Sthien 	    (char *) linenum(formal));
5073297Smckusic 	cerror("%s %s declared on line %d",
5083297Smckusic 	    parnam(actual->class), actual->symbol,
509*14727Sthien 	    (char *) linenum(actual));
5103297Smckusic 	return FALSE;
5113297Smckusic     }
5123297Smckusic     return compat;
5133297Smckusic }
5143297Smckusic 
5153297Smckusic char *
5163297Smckusic parnam(nltype)
5173297Smckusic     int nltype;
5183297Smckusic {
5193297Smckusic     switch(nltype) {
5203297Smckusic 	case REF:
5213297Smckusic 	    return "var";
5223297Smckusic 	case VAR:
5233297Smckusic 	    return "value";
5243297Smckusic 	case FUNC:
5253297Smckusic 	case FFUNC:
5263297Smckusic 	    return "function";
5273297Smckusic 	case PROC:
5283297Smckusic 	case FPROC:
5293297Smckusic 	    return "procedure";
5303297Smckusic 	default:
5313297Smckusic 	    return "SNARK";
5323297Smckusic     }
5333297Smckusic }
5343297Smckusic 
535*14727Sthien struct nl *plist(p)
5363297Smckusic     struct nl *p;
5373297Smckusic {
5383297Smckusic     switch (p->class) {
5393297Smckusic 	case FFUNC:
5403297Smckusic 	case FPROC:
5413297Smckusic 	    return p->ptr[ NL_FCHAIN ];
5423297Smckusic 	case PROC:
5433297Smckusic 	case FUNC:
5443297Smckusic 	    return p->chain;
5453297Smckusic 	default:
546*14727Sthien 	    {
547*14727Sthien 		panic("plist");
548*14727Sthien 		return(NLNIL); /* this is here only so lint won't complain
549*14727Sthien 				  panic actually aborts */
550*14727Sthien 	    }
551*14727Sthien 
5523297Smckusic     }
5533297Smckusic }
5543297Smckusic 
5553297Smckusic linenum(p)
5563297Smckusic     struct nl *p;
5573297Smckusic {
5583297Smckusic     if (p->class == FUNC)
5593297Smckusic 	return p->ptr[NL_FVAR]->value[NL_LINENO];
5603297Smckusic     return p->value[NL_LINENO];
5613297Smckusic }
562