xref: /csrg-svn/usr.bin/pascal/src/call.c (revision 3297)
1745Speter /* Copyright (c) 1979 Regents of the University of California */
2745Speter 
3*3297Smckusic static	char sccsid[] = "@(#)call.c 1.8 03/18/81";
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
14745Speter 
153065Smckusic short	slenline = 0;
163065Smckusic short	floatline = 0;
171195Speter 
18745Speter /*
19745Speter  * Call generates code for calls to
20745Speter  * user defined procedures and functions
21745Speter  * and is called by proc and funccod.
22745Speter  * P is the result of the lookup
23745Speter  * of the procedure/function symbol,
24745Speter  * and porf is PROC or FUNC.
25745Speter  * Psbn is the block number of p.
263065Smckusic  *
273065Smckusic  *	the idea here is that regular scalar functions are just called,
283065Smckusic  *	while structure functions and formal functions have their results
293065Smckusic  *	stored in a temporary after the call.
303065Smckusic  *	structure functions do this because they return pointers
313065Smckusic  *	to static results, so we copy the static
323065Smckusic  *	and return a pointer to the copy.
333065Smckusic  *	formal functions do this because we have to save the result
343065Smckusic  *	around a call to the runtime routine which restores the display,
353065Smckusic  *	so we can't just leave the result lying around in registers.
363065Smckusic  *	so PROCs and scalar FUNCs look like
373065Smckusic  *		p(...args...)
383065Smckusic  *	structure FUNCs look like
393065Smckusic  *		(temp = p(...args...),&temp)
403065Smckusic  *	formal FPROCs look like
413065Smckusic  *		((FCALL( p ))(...args...),FRTN( p ))
423065Smckusic  *	formal scalar FFUNCs look like
433065Smckusic  *		(temp = (FCALL( p ))(...args...),FRTN( p ),temp)
443065Smckusic  *	formal structure FFUNCs look like
453065Smckusic  *		(temp = (FCALL( p ))(...args...),FRTN( p ),&temp)
46745Speter  */
47745Speter struct nl *
48745Speter call(p, argv, porf, psbn)
49745Speter 	struct nl *p;
50745Speter 	int *argv, porf, psbn;
51745Speter {
52745Speter 	register struct nl *p1, *q;
53745Speter 	int *r;
543065Smckusic 	struct nl	*p_type_class = classify( p -> type );
55*3297Smckusic 	bool chk = TRUE;
56745Speter #	ifdef PC
573065Smckusic 	    long	p_p2type = p2type( p );
583065Smckusic 	    long	p_type_p2type = p2type( p -> type );
593065Smckusic 	    bool	noarguments;
603065Smckusic 	    long	calltype;	/* type of the call */
613065Smckusic 		/*
623065Smckusic 		 *	these get used if temporaries and structures are used
633065Smckusic 		 */
643065Smckusic 	    long	tempoffset;
653065Smckusic 	    long	temptype;	/* type of the temporary */
663065Smckusic 	    long	p_type_width;
673065Smckusic 	    long	p_type_align;
68745Speter #	endif PC
69745Speter 
70745Speter #	ifdef OBJ
711195Speter 	    if (p->class == FFUNC || p->class == FPROC)
723063Smckusic 		put(2, PTR_RV | cbn << 8+INDX, (int)p->value[NL_OFFS]);
73745Speter 	    if (porf == FUNC)
74745Speter 		    /*
75745Speter 		     * Push some space
76745Speter 		     * for the function return type
77745Speter 		     */
783063Smckusic 		    put(2, O_PUSH, leven(-lwidth(p->type)));
79745Speter #	endif OBJ
80745Speter #	ifdef PC
813065Smckusic 		/*
823065Smckusic 		 *	if we have to store a temporary,
833065Smckusic 		 *	temptype will be its type,
843065Smckusic 		 *	otherwise, it's P2UNDEF.
853065Smckusic 		 */
863065Smckusic 	    temptype = P2UNDEF;
873065Smckusic 	    calltype = P2INT;
88745Speter 	    if ( porf == FUNC ) {
893065Smckusic 		p_type_width = width( p -> type );
903065Smckusic 		switch( p_type_class ) {
91745Speter 		    case TSTR:
92745Speter 		    case TSET:
93745Speter 		    case TREC:
94745Speter 		    case TFILE:
95745Speter 		    case TARY:
963065Smckusic 			calltype = temptype = P2STRTY;
973065Smckusic 			p_type_align = align( p -> type );
983065Smckusic 			break;
993065Smckusic 		    default:
1003065Smckusic 			if ( p -> class == FFUNC ) {
1013065Smckusic 			    calltype = temptype = p2type( p -> type );
102745Speter 			}
1033065Smckusic 			break;
104745Speter 		}
1053065Smckusic 		if ( temptype != P2UNDEF ) {
1063221Smckusic 		    tempoffset = tmpalloc(p_type_width, p -> type, NOREG);
1073065Smckusic 			/*
1083065Smckusic 			 *	temp
1093065Smckusic 			 *	for (temp = ...
1103065Smckusic 			 */
1113065Smckusic 		    putRV( 0 , cbn , tempoffset , temptype );
1123065Smckusic 		}
113745Speter 	    }
1141195Speter 	    switch ( p -> class ) {
1151195Speter 		case FUNC:
1161195Speter 		case PROC:
1173065Smckusic 			/*
1183065Smckusic 			 *	... p( ...
1193065Smckusic 			 */
1201195Speter 		    {
1211195Speter 			char	extname[ BUFSIZ ];
1221195Speter 			char	*starthere;
1231195Speter 			int	funcbn;
1241195Speter 			int	i;
125745Speter 
1261195Speter 			starthere = &extname[0];
1271195Speter 			funcbn = p -> nl_block & 037;
1281195Speter 			for ( i = 1 ; i < funcbn ; i++ ) {
1291195Speter 			    sprintf( starthere , EXTFORMAT , enclosing[ i ] );
1301195Speter 			    starthere += strlen( enclosing[ i ] ) + 1;
1311195Speter 			}
1321195Speter 			sprintf( starthere , EXTFORMAT , p -> symbol );
1331195Speter 			starthere += strlen( p -> symbol ) + 1;
1341195Speter 			if ( starthere >= &extname[ BUFSIZ ] ) {
1351195Speter 			    panic( "call namelength" );
1361195Speter 			}
1371195Speter 			putleaf( P2ICON , 0 , 0 , p2type( p ) , extname );
1381195Speter 		    }
1391195Speter 		    break;
1401195Speter 		case FFUNC:
1411195Speter 		case FPROC:
1421195Speter 			    /*
1433065Smckusic 			     *	... (FCALL( p ))( ...
1441195Speter 			     */
1451195Speter 		    	putleaf( P2ICON , 0 , 0
1463065Smckusic 			    , ADDTYPE( ADDTYPE( p_p2type , P2FTN ) , P2PTR )
1471195Speter 			    , "_FCALL" );
1481195Speter 			putRV( 0 , cbn , p -> value[NL_OFFS] , P2PTR|P2STRTY );
1493065Smckusic 			putop( P2CALL , p_p2type );
1501195Speter 			break;
1511195Speter 		default:
1521195Speter 			panic("call class");
153745Speter 	    }
1543065Smckusic 	    noarguments = TRUE;
155745Speter #	endif PC
156745Speter 	/*
157745Speter 	 * Loop and process each of
158745Speter 	 * arguments to the proc/func.
1593065Smckusic 	 *	... ( ... args ... ) ...
160745Speter 	 */
161*3297Smckusic 	for (p1 = plist(p); p1 != NIL; p1 = p1->chain) {
162*3297Smckusic 	    if (argv == NIL) {
163*3297Smckusic 		    error("Not enough arguments to %s", p->symbol);
164*3297Smckusic 		    return (NIL);
165*3297Smckusic 	    }
166*3297Smckusic 	    switch (p1->class) {
167*3297Smckusic 		case REF:
168*3297Smckusic 			/*
169*3297Smckusic 			 * Var parameter
170*3297Smckusic 			 */
171*3297Smckusic 			r = argv[1];
172*3297Smckusic 			if (r != NIL && r[0] != T_VAR) {
173*3297Smckusic 				error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol);
174*3297Smckusic 				break;
175*3297Smckusic 			}
176*3297Smckusic 			q = lvalue( (int *) argv[1], MOD , LREQ );
177*3297Smckusic 			if (q == NIL) {
178*3297Smckusic 				chk = FALSE;
179*3297Smckusic 				break;
180*3297Smckusic 			}
181*3297Smckusic 			if (q != p1->type) {
182*3297Smckusic 				error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol);
183*3297Smckusic 				break;
184*3297Smckusic 			}
185*3297Smckusic 			break;
186*3297Smckusic 		case VAR:
187*3297Smckusic 			/*
188*3297Smckusic 			 * Value parameter
189*3297Smckusic 			 */
190745Speter #			ifdef OBJ
191*3297Smckusic 			    q = rvalue(argv[1], p1->type , RREQ );
192745Speter #			endif OBJ
193745Speter #			ifdef PC
194*3297Smckusic 				/*
195*3297Smckusic 				 * structure arguments require lvalues,
196*3297Smckusic 				 * scalars use rvalue.
197*3297Smckusic 				 */
198*3297Smckusic 			    switch( classify( p1 -> type ) ) {
199*3297Smckusic 				case TFILE:
200*3297Smckusic 				case TARY:
201*3297Smckusic 				case TREC:
202*3297Smckusic 				case TSET:
203*3297Smckusic 				case TSTR:
204*3297Smckusic 				    q = rvalue( argv[1] , p1 -> type , LREQ );
205745Speter 				    break;
206*3297Smckusic 				case TINT:
207*3297Smckusic 				case TSCAL:
208*3297Smckusic 				case TBOOL:
209*3297Smckusic 				case TCHAR:
210*3297Smckusic 				    precheck( p1 -> type , "_RANG4" , "_RSNG4" );
211*3297Smckusic 				    q = rvalue( argv[1] , p1 -> type , RREQ );
212*3297Smckusic 				    postcheck( p1 -> type );
213745Speter 				    break;
214*3297Smckusic 				default:
215*3297Smckusic 				    q = rvalue( argv[1] , p1 -> type , RREQ );
216*3297Smckusic 				    if (  isa( p1 -> type  , "d" )
217*3297Smckusic 				       && isa( q , "i" ) ) {
218*3297Smckusic 					putop( P2SCONV , P2DOUBLE );
219*3297Smckusic 				    }
220*3297Smckusic 				    break;
221745Speter 			    }
222*3297Smckusic #			endif PC
223*3297Smckusic 			if (q == NIL) {
224*3297Smckusic 				chk = FALSE;
225*3297Smckusic 				break;
226*3297Smckusic 			}
227*3297Smckusic 			if (incompat(q, p1->type, argv[1])) {
228*3297Smckusic 				cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol);
229*3297Smckusic 				break;
230*3297Smckusic 			}
231745Speter #			ifdef OBJ
232*3297Smckusic 			    if (isa(p1->type, "bcsi"))
233*3297Smckusic 				    rangechk(p1->type, q);
234*3297Smckusic 			    if (q->class != STR)
235*3297Smckusic 				    convert(q, p1->type);
236745Speter #			endif OBJ
237745Speter #			ifdef PC
238*3297Smckusic 			    switch( classify( p1 -> type ) ) {
239*3297Smckusic 				case TFILE:
240*3297Smckusic 				case TARY:
241*3297Smckusic 				case TREC:
242*3297Smckusic 				case TSET:
243*3297Smckusic 				case TSTR:
244*3297Smckusic 					putstrop( P2STARG
245*3297Smckusic 					    , p2type( p1 -> type )
246*3297Smckusic 					    , lwidth( p1 -> type )
247*3297Smckusic 					    , align( p1 -> type ) );
248*3297Smckusic 			    }
2491195Speter #			endif PC
250*3297Smckusic 			break;
251*3297Smckusic 		case FFUNC:
2521195Speter 			/*
253*3297Smckusic 			 * function parameter
2541195Speter 			 */
255*3297Smckusic 			q = flvalue( (int *) argv[1] , p1 );
256*3297Smckusic 			chk = (chk && fcompat(q, p1));
257*3297Smckusic 			break;
258*3297Smckusic 		case FPROC:
2591195Speter 			/*
260*3297Smckusic 			 * procedure parameter
2611195Speter 			 */
262*3297Smckusic 			q = flvalue( (int *) argv[1] , p1 );
263*3297Smckusic 			chk = (chk && fcompat(q, p1));
264*3297Smckusic 			break;
265*3297Smckusic 		default:
266*3297Smckusic 			panic("call");
2671195Speter 	    }
268*3297Smckusic #	    ifdef PC
269*3297Smckusic 		    /*
270*3297Smckusic 		     *	if this is the nth (>1) argument,
271*3297Smckusic 		     *	hang it on the left linear list of arguments
272*3297Smckusic 		     */
273*3297Smckusic 		if ( noarguments ) {
274*3297Smckusic 			noarguments = FALSE;
275*3297Smckusic 		} else {
276*3297Smckusic 			putop( P2LISTOP , P2INT );
277*3297Smckusic 		}
278*3297Smckusic #	    endif PC
279*3297Smckusic 	    argv = argv[2];
280745Speter 	}
281*3297Smckusic 	if (argv != NIL) {
282*3297Smckusic 		error("Too many arguments to %s", p->symbol);
283*3297Smckusic 		rvlist(argv);
284*3297Smckusic 		return (NIL);
285*3297Smckusic 	}
286*3297Smckusic 	if (chk == FALSE)
287*3297Smckusic 		return NIL;
288745Speter #	ifdef OBJ
2891195Speter 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
2903063Smckusic 		put(2, PTR_RV | cbn << 8+INDX, (int)p->value[NL_OFFS]);
291*3297Smckusic 		put(1, O_FCALL);
2923063Smckusic 		put(2, O_FRTN, even(width(p->type)));
2931195Speter 	    } else {
2943063Smckusic 		put(2, O_CALL | psbn << 8, (long)p->entloc);
2951195Speter 	    }
296745Speter #	endif OBJ
297745Speter #	ifdef PC
2983065Smckusic 		/*
2993065Smckusic 		 *	do the actual call:
3003065Smckusic 		 *	    either	... p( ... ) ...
3013065Smckusic 		 *	    or		... ( ...() )( ... ) ...
3023065Smckusic 		 *	and maybe an assignment.
3033065Smckusic 		 */
304745Speter 	    if ( porf == FUNC ) {
3053065Smckusic 		switch ( p_type_class ) {
306745Speter 		    case TBOOL:
307745Speter 		    case TCHAR:
308745Speter 		    case TINT:
309745Speter 		    case TSCAL:
310745Speter 		    case TDOUBLE:
311745Speter 		    case TPTR:
3123065Smckusic 			putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) ,
3133065Smckusic 				p_type_p2type );
3143065Smckusic 			if ( p -> class == FFUNC ) {
3153065Smckusic 			    putop( P2ASSIGN , p_type_p2type );
316745Speter 			}
317745Speter 			break;
318745Speter 		    default:
3193065Smckusic 			putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ),
3203065Smckusic 				ADDTYPE( p_type_p2type , P2PTR ) ,
3213065Smckusic 				p_type_width , p_type_align );
3223065Smckusic 			putstrop( P2STASG , p_type_p2type , lwidth( p -> type )
323745Speter 				, align( p -> type ) );
324745Speter 			break;
325745Speter 		}
326745Speter 	    } else {
3273065Smckusic 		putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT );
3283065Smckusic 	    }
3293065Smckusic 		/*
3303065Smckusic 		 *	... , FRTN( p ) ...
3313065Smckusic 		 */
3323065Smckusic 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
3333065Smckusic 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) ,
3343065Smckusic 			"_FRTN" );
3353065Smckusic 		putRV( 0 , cbn , p -> value[ NL_OFFS ] , P2PTR | P2STRTY );
3363065Smckusic 		putop( P2CALL , P2INT );
3373065Smckusic 		putop( P2COMOP , P2INT );
3383065Smckusic 	    }
3393065Smckusic 		/*
3403065Smckusic 		 *	if required:
3413065Smckusic 		 *	either	... , temp )
3423065Smckusic 		 *	or	... , &temp )
3433065Smckusic 		 */
3443065Smckusic 	    if ( porf == FUNC && temptype != P2UNDEF ) {
3453065Smckusic 		if ( temptype != P2STRTY ) {
3463065Smckusic 		    putRV( 0 , cbn , tempoffset , p_type_p2type );
347745Speter 		} else {
3483065Smckusic 		    putLV( 0 , cbn , tempoffset , p_type_p2type );
349745Speter 		}
3503065Smckusic 		putop( P2COMOP , P2INT );
3513065Smckusic 	    }
3523065Smckusic 	    if ( porf == PROC ) {
353745Speter 		putdot( filename , line );
354745Speter 	    }
355745Speter #	endif PC
356745Speter 	return (p->type);
357745Speter }
358745Speter 
359745Speter rvlist(al)
360745Speter 	register int *al;
361745Speter {
362745Speter 
363745Speter 	for (; al != NIL; al = al[2])
364745Speter 		rvalue( (int *) al[1], NLNIL , RREQ );
365745Speter }
366*3297Smckusic 
367*3297Smckusic     /*
368*3297Smckusic      *	check that two function/procedure namelist entries are compatible
369*3297Smckusic      */
370*3297Smckusic bool
371*3297Smckusic fcompat( formal , actual )
372*3297Smckusic     struct nl	*formal;
373*3297Smckusic     struct nl	*actual;
374*3297Smckusic {
375*3297Smckusic     register struct nl	*f_chain;
376*3297Smckusic     register struct nl	*a_chain;
377*3297Smckusic     bool compat = TRUE;
378*3297Smckusic 
379*3297Smckusic     if ( formal == NIL || actual == NIL ) {
380*3297Smckusic 	return FALSE;
381*3297Smckusic     }
382*3297Smckusic     for (a_chain = plist(actual), f_chain = plist(formal);
383*3297Smckusic          f_chain != NIL;
384*3297Smckusic 	 f_chain = f_chain->chain, a_chain = a_chain->chain) {
385*3297Smckusic 	if (a_chain == NIL) {
386*3297Smckusic 	    error("%s %s declared on line %d has more arguments than",
387*3297Smckusic 		parnam(formal->class), formal->symbol,
388*3297Smckusic 		linenum(formal));
389*3297Smckusic 	    cerror("%s %s declared on line %d",
390*3297Smckusic 		parnam(actual->class), actual->symbol,
391*3297Smckusic 		linenum(actual));
392*3297Smckusic 	    return FALSE;
393*3297Smckusic 	}
394*3297Smckusic 	if ( a_chain -> class != f_chain -> class ) {
395*3297Smckusic 	    error("%s parameter %s of %s declared on line %d is not identical",
396*3297Smckusic 		parnam(f_chain->class), f_chain->symbol,
397*3297Smckusic 		formal->symbol, linenum(formal));
398*3297Smckusic 	    cerror("with %s parameter %s of %s declared on line %d",
399*3297Smckusic 		parnam(a_chain->class), a_chain->symbol,
400*3297Smckusic 		actual->symbol, linenum(actual));
401*3297Smckusic 	    compat = FALSE;
402*3297Smckusic 	} else if (a_chain->class == FFUNC || a_chain->class == FPROC) {
403*3297Smckusic 	    compat = (compat && fcompat(f_chain, a_chain));
404*3297Smckusic 	}
405*3297Smckusic 	if ((a_chain->class != FPROC && f_chain->class != FPROC) &&
406*3297Smckusic 	    (a_chain->type != f_chain->type)) {
407*3297Smckusic 	    error("Type of %s parameter %s of %s declared on line %d is not identical",
408*3297Smckusic 		parnam(f_chain->class), f_chain->symbol,
409*3297Smckusic 		formal->symbol, linenum(formal));
410*3297Smckusic 	    cerror("to type of %s parameter %s of %s declared on line %d",
411*3297Smckusic 		parnam(a_chain->class), a_chain->symbol,
412*3297Smckusic 		actual->symbol, linenum(actual));
413*3297Smckusic 	    compat = FALSE;
414*3297Smckusic 	}
415*3297Smckusic     }
416*3297Smckusic     if (a_chain != NIL) {
417*3297Smckusic 	error("%s %s declared on line %d has fewer arguments than",
418*3297Smckusic 	    parnam(formal->class), formal->symbol,
419*3297Smckusic 	    linenum(formal));
420*3297Smckusic 	cerror("%s %s declared on line %d",
421*3297Smckusic 	    parnam(actual->class), actual->symbol,
422*3297Smckusic 	    linenum(actual));
423*3297Smckusic 	return FALSE;
424*3297Smckusic     }
425*3297Smckusic     return compat;
426*3297Smckusic }
427*3297Smckusic 
428*3297Smckusic char *
429*3297Smckusic parnam(nltype)
430*3297Smckusic     int nltype;
431*3297Smckusic {
432*3297Smckusic     switch(nltype) {
433*3297Smckusic 	case REF:
434*3297Smckusic 	    return "var";
435*3297Smckusic 	case VAR:
436*3297Smckusic 	    return "value";
437*3297Smckusic 	case FUNC:
438*3297Smckusic 	case FFUNC:
439*3297Smckusic 	    return "function";
440*3297Smckusic 	case PROC:
441*3297Smckusic 	case FPROC:
442*3297Smckusic 	    return "procedure";
443*3297Smckusic 	default:
444*3297Smckusic 	    return "SNARK";
445*3297Smckusic     }
446*3297Smckusic }
447*3297Smckusic 
448*3297Smckusic plist(p)
449*3297Smckusic     struct nl *p;
450*3297Smckusic {
451*3297Smckusic     switch (p->class) {
452*3297Smckusic 	case FFUNC:
453*3297Smckusic 	case FPROC:
454*3297Smckusic 	    return p->ptr[ NL_FCHAIN ];
455*3297Smckusic 	case PROC:
456*3297Smckusic 	case FUNC:
457*3297Smckusic 	    return p->chain;
458*3297Smckusic 	default:
459*3297Smckusic 	    panic("plist");
460*3297Smckusic     }
461*3297Smckusic }
462*3297Smckusic 
463*3297Smckusic linenum(p)
464*3297Smckusic     struct nl *p;
465*3297Smckusic {
466*3297Smckusic     if (p->class == FUNC)
467*3297Smckusic 	return p->ptr[NL_FVAR]->value[NL_LINENO];
468*3297Smckusic     return p->value[NL_LINENO];
469*3297Smckusic }
470