xref: /csrg-svn/usr.bin/pascal/src/call.c (revision 3362)
1745Speter /* Copyright (c) 1979 Regents of the University of California */
2745Speter 
3*3362Speter static	char sccsid[] = "@(#)call.c 1.11 03/24/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 
15745Speter /*
16745Speter  * Call generates code for calls to
17745Speter  * user defined procedures and functions
18745Speter  * and is called by proc and funccod.
19745Speter  * P is the result of the lookup
20745Speter  * of the procedure/function symbol,
21745Speter  * and porf is PROC or FUNC.
22745Speter  * Psbn is the block number of p.
233065Smckusic  *
243065Smckusic  *	the idea here is that regular scalar functions are just called,
253065Smckusic  *	while structure functions and formal functions have their results
263065Smckusic  *	stored in a temporary after the call.
273065Smckusic  *	structure functions do this because they return pointers
283065Smckusic  *	to static results, so we copy the static
293065Smckusic  *	and return a pointer to the copy.
303065Smckusic  *	formal functions do this because we have to save the result
313065Smckusic  *	around a call to the runtime routine which restores the display,
323065Smckusic  *	so we can't just leave the result lying around in registers.
333065Smckusic  *	so PROCs and scalar FUNCs look like
343065Smckusic  *		p(...args...)
353065Smckusic  *	structure FUNCs look like
363065Smckusic  *		(temp = p(...args...),&temp)
373065Smckusic  *	formal FPROCs look like
383065Smckusic  *		((FCALL( p ))(...args...),FRTN( p ))
393065Smckusic  *	formal scalar FFUNCs look like
403065Smckusic  *		(temp = (FCALL( p ))(...args...),FRTN( p ),temp)
413065Smckusic  *	formal structure FFUNCs look like
423065Smckusic  *		(temp = (FCALL( p ))(...args...),FRTN( p ),&temp)
43745Speter  */
44745Speter struct nl *
45745Speter call(p, argv, porf, psbn)
46745Speter 	struct nl *p;
47745Speter 	int *argv, porf, psbn;
48745Speter {
49745Speter 	register struct nl *p1, *q;
50745Speter 	int *r;
513065Smckusic 	struct nl	*p_type_class = classify( p -> type );
523297Smckusic 	bool chk = TRUE;
53745Speter #	ifdef PC
543065Smckusic 	    long	p_p2type = p2type( p );
553065Smckusic 	    long	p_type_p2type = p2type( p -> type );
563065Smckusic 	    bool	noarguments;
573065Smckusic 	    long	calltype;	/* type of the call */
583065Smckusic 		/*
593065Smckusic 		 *	these get used if temporaries and structures are used
603065Smckusic 		 */
613065Smckusic 	    long	tempoffset;
623065Smckusic 	    long	temptype;	/* type of the temporary */
633065Smckusic 	    long	p_type_width;
643065Smckusic 	    long	p_type_align;
65*3362Speter 	    char	extname[ BUFSIZ ];
66*3362Speter 
67745Speter #	endif PC
68745Speter 
69745Speter #	ifdef OBJ
701195Speter 	    if (p->class == FFUNC || p->class == FPROC)
713359Smckusic 		put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]);
72745Speter 	    if (porf == FUNC)
73745Speter 		    /*
74745Speter 		     * Push some space
75745Speter 		     * for the function return type
76745Speter 		     */
773063Smckusic 		    put(2, O_PUSH, leven(-lwidth(p->type)));
78745Speter #	endif OBJ
79745Speter #	ifdef PC
803065Smckusic 		/*
813065Smckusic 		 *	if we have to store a temporary,
823065Smckusic 		 *	temptype will be its type,
833065Smckusic 		 *	otherwise, it's P2UNDEF.
843065Smckusic 		 */
853065Smckusic 	    temptype = P2UNDEF;
863065Smckusic 	    calltype = P2INT;
87745Speter 	    if ( porf == FUNC ) {
883065Smckusic 		p_type_width = width( p -> type );
893065Smckusic 		switch( p_type_class ) {
90745Speter 		    case TSTR:
91745Speter 		    case TSET:
92745Speter 		    case TREC:
93745Speter 		    case TFILE:
94745Speter 		    case TARY:
953065Smckusic 			calltype = temptype = P2STRTY;
963065Smckusic 			p_type_align = align( p -> type );
973065Smckusic 			break;
983065Smckusic 		    default:
993065Smckusic 			if ( p -> class == FFUNC ) {
1003065Smckusic 			    calltype = temptype = p2type( p -> type );
101745Speter 			}
1023065Smckusic 			break;
103745Speter 		}
1043065Smckusic 		if ( temptype != P2UNDEF ) {
1053221Smckusic 		    tempoffset = tmpalloc(p_type_width, p -> type, NOREG);
1063065Smckusic 			/*
1073065Smckusic 			 *	temp
1083065Smckusic 			 *	for (temp = ...
1093065Smckusic 			 */
1103065Smckusic 		    putRV( 0 , cbn , tempoffset , temptype );
1113065Smckusic 		}
112745Speter 	    }
1131195Speter 	    switch ( p -> class ) {
1141195Speter 		case FUNC:
1151195Speter 		case PROC:
1163065Smckusic 			/*
1173065Smckusic 			 *	... p( ...
1183065Smckusic 			 */
119*3362Speter 		    sextname( extname , p -> symbol , p -> nl_block & 037 );
120*3362Speter 		    putleaf( P2ICON , 0 , 0 , p2type( p ) , extname );
1211195Speter 		    break;
1221195Speter 		case FFUNC:
1231195Speter 		case FPROC:
1241195Speter 			    /*
1253065Smckusic 			     *	... (FCALL( p ))( ...
1261195Speter 			     */
1271195Speter 		    	putleaf( P2ICON , 0 , 0
1283065Smckusic 			    , ADDTYPE( ADDTYPE( p_p2type , P2FTN ) , P2PTR )
1291195Speter 			    , "_FCALL" );
1303359Smckusic 			putRV( 0 , psbn , p -> value[NL_OFFS] , P2PTR|P2STRTY );
1313065Smckusic 			putop( P2CALL , p_p2type );
1321195Speter 			break;
1331195Speter 		default:
1341195Speter 			panic("call class");
135745Speter 	    }
1363065Smckusic 	    noarguments = TRUE;
137745Speter #	endif PC
138745Speter 	/*
139745Speter 	 * Loop and process each of
140745Speter 	 * arguments to the proc/func.
1413065Smckusic 	 *	... ( ... args ... ) ...
142745Speter 	 */
1433297Smckusic 	for (p1 = plist(p); p1 != NIL; p1 = p1->chain) {
1443297Smckusic 	    if (argv == NIL) {
1453297Smckusic 		    error("Not enough arguments to %s", p->symbol);
1463297Smckusic 		    return (NIL);
1473297Smckusic 	    }
1483297Smckusic 	    switch (p1->class) {
1493297Smckusic 		case REF:
1503297Smckusic 			/*
1513297Smckusic 			 * Var parameter
1523297Smckusic 			 */
1533297Smckusic 			r = argv[1];
1543297Smckusic 			if (r != NIL && r[0] != T_VAR) {
1553297Smckusic 				error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol);
1563361Speter 				chk = FALSE;
1573297Smckusic 				break;
1583297Smckusic 			}
1593297Smckusic 			q = lvalue( (int *) argv[1], MOD , LREQ );
1603297Smckusic 			if (q == NIL) {
1613297Smckusic 				chk = FALSE;
1623297Smckusic 				break;
1633297Smckusic 			}
1643297Smckusic 			if (q != p1->type) {
1653297Smckusic 				error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol);
1663361Speter 				chk = FALSE;
1673297Smckusic 				break;
1683297Smckusic 			}
1693297Smckusic 			break;
1703297Smckusic 		case VAR:
1713297Smckusic 			/*
1723297Smckusic 			 * Value parameter
1733297Smckusic 			 */
174745Speter #			ifdef OBJ
1753297Smckusic 			    q = rvalue(argv[1], p1->type , RREQ );
176745Speter #			endif OBJ
177745Speter #			ifdef PC
1783297Smckusic 				/*
1793297Smckusic 				 * structure arguments require lvalues,
1803297Smckusic 				 * scalars use rvalue.
1813297Smckusic 				 */
1823297Smckusic 			    switch( classify( p1 -> type ) ) {
1833297Smckusic 				case TFILE:
1843297Smckusic 				case TARY:
1853297Smckusic 				case TREC:
1863297Smckusic 				case TSET:
1873297Smckusic 				case TSTR:
1883297Smckusic 				    q = rvalue( argv[1] , p1 -> type , LREQ );
189745Speter 				    break;
1903297Smckusic 				case TINT:
1913297Smckusic 				case TSCAL:
1923297Smckusic 				case TBOOL:
1933297Smckusic 				case TCHAR:
1943297Smckusic 				    precheck( p1 -> type , "_RANG4" , "_RSNG4" );
1953297Smckusic 				    q = rvalue( argv[1] , p1 -> type , RREQ );
1963297Smckusic 				    postcheck( p1 -> type );
197745Speter 				    break;
1983297Smckusic 				default:
1993297Smckusic 				    q = rvalue( argv[1] , p1 -> type , RREQ );
2003297Smckusic 				    if (  isa( p1 -> type  , "d" )
2013297Smckusic 				       && isa( q , "i" ) ) {
2023297Smckusic 					putop( P2SCONV , P2DOUBLE );
2033297Smckusic 				    }
2043297Smckusic 				    break;
205745Speter 			    }
2063297Smckusic #			endif PC
2073297Smckusic 			if (q == NIL) {
2083297Smckusic 				chk = FALSE;
2093297Smckusic 				break;
2103297Smckusic 			}
2113297Smckusic 			if (incompat(q, p1->type, argv[1])) {
2123297Smckusic 				cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol);
2133361Speter 				chk = FALSE;
2143297Smckusic 				break;
2153297Smckusic 			}
216745Speter #			ifdef OBJ
2173297Smckusic 			    if (isa(p1->type, "bcsi"))
2183297Smckusic 				    rangechk(p1->type, q);
2193297Smckusic 			    if (q->class != STR)
2203297Smckusic 				    convert(q, p1->type);
221745Speter #			endif OBJ
222745Speter #			ifdef PC
2233297Smckusic 			    switch( classify( p1 -> type ) ) {
2243297Smckusic 				case TFILE:
2253297Smckusic 				case TARY:
2263297Smckusic 				case TREC:
2273297Smckusic 				case TSET:
2283297Smckusic 				case TSTR:
2293297Smckusic 					putstrop( P2STARG
2303297Smckusic 					    , p2type( p1 -> type )
2313297Smckusic 					    , lwidth( p1 -> type )
2323297Smckusic 					    , align( p1 -> type ) );
2333297Smckusic 			    }
2341195Speter #			endif PC
2353297Smckusic 			break;
2363297Smckusic 		case FFUNC:
2371195Speter 			/*
2383297Smckusic 			 * function parameter
2391195Speter 			 */
2403297Smckusic 			q = flvalue( (int *) argv[1] , p1 );
2413297Smckusic 			chk = (chk && fcompat(q, p1));
2423297Smckusic 			break;
2433297Smckusic 		case FPROC:
2441195Speter 			/*
2453297Smckusic 			 * procedure parameter
2461195Speter 			 */
2473297Smckusic 			q = flvalue( (int *) argv[1] , p1 );
2483297Smckusic 			chk = (chk && fcompat(q, p1));
2493297Smckusic 			break;
2503297Smckusic 		default:
2513297Smckusic 			panic("call");
2521195Speter 	    }
2533297Smckusic #	    ifdef PC
2543297Smckusic 		    /*
2553297Smckusic 		     *	if this is the nth (>1) argument,
2563297Smckusic 		     *	hang it on the left linear list of arguments
2573297Smckusic 		     */
2583297Smckusic 		if ( noarguments ) {
2593297Smckusic 			noarguments = FALSE;
2603297Smckusic 		} else {
2613297Smckusic 			putop( P2LISTOP , P2INT );
2623297Smckusic 		}
2633297Smckusic #	    endif PC
2643297Smckusic 	    argv = argv[2];
265745Speter 	}
2663297Smckusic 	if (argv != NIL) {
2673297Smckusic 		error("Too many arguments to %s", p->symbol);
2683297Smckusic 		rvlist(argv);
2693297Smckusic 		return (NIL);
2703297Smckusic 	}
2713297Smckusic 	if (chk == FALSE)
2723297Smckusic 		return NIL;
273745Speter #	ifdef OBJ
2741195Speter 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
2753359Smckusic 		put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]);
2763297Smckusic 		put(1, O_FCALL);
2773063Smckusic 		put(2, O_FRTN, even(width(p->type)));
2781195Speter 	    } else {
2793063Smckusic 		put(2, O_CALL | psbn << 8, (long)p->entloc);
2801195Speter 	    }
281745Speter #	endif OBJ
282745Speter #	ifdef PC
2833065Smckusic 		/*
2843065Smckusic 		 *	do the actual call:
2853065Smckusic 		 *	    either	... p( ... ) ...
2863065Smckusic 		 *	    or		... ( ...() )( ... ) ...
2873065Smckusic 		 *	and maybe an assignment.
2883065Smckusic 		 */
289745Speter 	    if ( porf == FUNC ) {
2903065Smckusic 		switch ( p_type_class ) {
291745Speter 		    case TBOOL:
292745Speter 		    case TCHAR:
293745Speter 		    case TINT:
294745Speter 		    case TSCAL:
295745Speter 		    case TDOUBLE:
296745Speter 		    case TPTR:
2973065Smckusic 			putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) ,
2983065Smckusic 				p_type_p2type );
2993065Smckusic 			if ( p -> class == FFUNC ) {
3003065Smckusic 			    putop( P2ASSIGN , p_type_p2type );
301745Speter 			}
302745Speter 			break;
303745Speter 		    default:
3043065Smckusic 			putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ),
3053065Smckusic 				ADDTYPE( p_type_p2type , P2PTR ) ,
3063065Smckusic 				p_type_width , p_type_align );
3073065Smckusic 			putstrop( P2STASG , p_type_p2type , lwidth( p -> type )
308745Speter 				, align( p -> type ) );
309745Speter 			break;
310745Speter 		}
311745Speter 	    } else {
3123065Smckusic 		putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT );
3133065Smckusic 	    }
3143065Smckusic 		/*
3153065Smckusic 		 *	... , FRTN( p ) ...
3163065Smckusic 		 */
3173065Smckusic 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
3183065Smckusic 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) ,
3193065Smckusic 			"_FRTN" );
3203359Smckusic 		putRV( 0 , psbn , p -> value[ NL_OFFS ] , P2PTR | P2STRTY );
3213065Smckusic 		putop( P2CALL , P2INT );
3223065Smckusic 		putop( P2COMOP , P2INT );
3233065Smckusic 	    }
3243065Smckusic 		/*
3253065Smckusic 		 *	if required:
3263065Smckusic 		 *	either	... , temp )
3273065Smckusic 		 *	or	... , &temp )
3283065Smckusic 		 */
3293065Smckusic 	    if ( porf == FUNC && temptype != P2UNDEF ) {
3303065Smckusic 		if ( temptype != P2STRTY ) {
3313065Smckusic 		    putRV( 0 , cbn , tempoffset , p_type_p2type );
332745Speter 		} else {
3333065Smckusic 		    putLV( 0 , cbn , tempoffset , p_type_p2type );
334745Speter 		}
3353065Smckusic 		putop( P2COMOP , P2INT );
3363065Smckusic 	    }
3373065Smckusic 	    if ( porf == PROC ) {
338745Speter 		putdot( filename , line );
339745Speter 	    }
340745Speter #	endif PC
341745Speter 	return (p->type);
342745Speter }
343745Speter 
344745Speter rvlist(al)
345745Speter 	register int *al;
346745Speter {
347745Speter 
348745Speter 	for (; al != NIL; al = al[2])
349745Speter 		rvalue( (int *) al[1], NLNIL , RREQ );
350745Speter }
3513297Smckusic 
3523297Smckusic     /*
3533297Smckusic      *	check that two function/procedure namelist entries are compatible
3543297Smckusic      */
3553297Smckusic bool
3563297Smckusic fcompat( formal , actual )
3573297Smckusic     struct nl	*formal;
3583297Smckusic     struct nl	*actual;
3593297Smckusic {
3603297Smckusic     register struct nl	*f_chain;
3613297Smckusic     register struct nl	*a_chain;
3623297Smckusic     bool compat = TRUE;
3633297Smckusic 
3643297Smckusic     if ( formal == NIL || actual == NIL ) {
3653297Smckusic 	return FALSE;
3663297Smckusic     }
3673297Smckusic     for (a_chain = plist(actual), f_chain = plist(formal);
3683297Smckusic          f_chain != NIL;
3693297Smckusic 	 f_chain = f_chain->chain, a_chain = a_chain->chain) {
3703297Smckusic 	if (a_chain == NIL) {
3713297Smckusic 	    error("%s %s declared on line %d has more arguments than",
3723297Smckusic 		parnam(formal->class), formal->symbol,
3733297Smckusic 		linenum(formal));
3743297Smckusic 	    cerror("%s %s declared on line %d",
3753297Smckusic 		parnam(actual->class), actual->symbol,
3763297Smckusic 		linenum(actual));
3773297Smckusic 	    return FALSE;
3783297Smckusic 	}
3793297Smckusic 	if ( a_chain -> class != f_chain -> class ) {
3803297Smckusic 	    error("%s parameter %s of %s declared on line %d is not identical",
3813297Smckusic 		parnam(f_chain->class), f_chain->symbol,
3823297Smckusic 		formal->symbol, linenum(formal));
3833297Smckusic 	    cerror("with %s parameter %s of %s declared on line %d",
3843297Smckusic 		parnam(a_chain->class), a_chain->symbol,
3853297Smckusic 		actual->symbol, linenum(actual));
3863297Smckusic 	    compat = FALSE;
3873297Smckusic 	} else if (a_chain->class == FFUNC || a_chain->class == FPROC) {
3883297Smckusic 	    compat = (compat && fcompat(f_chain, a_chain));
3893297Smckusic 	}
3903297Smckusic 	if ((a_chain->class != FPROC && f_chain->class != FPROC) &&
3913297Smckusic 	    (a_chain->type != f_chain->type)) {
3923297Smckusic 	    error("Type of %s parameter %s of %s declared on line %d is not identical",
3933297Smckusic 		parnam(f_chain->class), f_chain->symbol,
3943297Smckusic 		formal->symbol, linenum(formal));
3953297Smckusic 	    cerror("to type of %s parameter %s of %s declared on line %d",
3963297Smckusic 		parnam(a_chain->class), a_chain->symbol,
3973297Smckusic 		actual->symbol, linenum(actual));
3983297Smckusic 	    compat = FALSE;
3993297Smckusic 	}
4003297Smckusic     }
4013297Smckusic     if (a_chain != NIL) {
4023297Smckusic 	error("%s %s declared on line %d has fewer arguments than",
4033297Smckusic 	    parnam(formal->class), formal->symbol,
4043297Smckusic 	    linenum(formal));
4053297Smckusic 	cerror("%s %s declared on line %d",
4063297Smckusic 	    parnam(actual->class), actual->symbol,
4073297Smckusic 	    linenum(actual));
4083297Smckusic 	return FALSE;
4093297Smckusic     }
4103297Smckusic     return compat;
4113297Smckusic }
4123297Smckusic 
4133297Smckusic char *
4143297Smckusic parnam(nltype)
4153297Smckusic     int nltype;
4163297Smckusic {
4173297Smckusic     switch(nltype) {
4183297Smckusic 	case REF:
4193297Smckusic 	    return "var";
4203297Smckusic 	case VAR:
4213297Smckusic 	    return "value";
4223297Smckusic 	case FUNC:
4233297Smckusic 	case FFUNC:
4243297Smckusic 	    return "function";
4253297Smckusic 	case PROC:
4263297Smckusic 	case FPROC:
4273297Smckusic 	    return "procedure";
4283297Smckusic 	default:
4293297Smckusic 	    return "SNARK";
4303297Smckusic     }
4313297Smckusic }
4323297Smckusic 
4333297Smckusic plist(p)
4343297Smckusic     struct nl *p;
4353297Smckusic {
4363297Smckusic     switch (p->class) {
4373297Smckusic 	case FFUNC:
4383297Smckusic 	case FPROC:
4393297Smckusic 	    return p->ptr[ NL_FCHAIN ];
4403297Smckusic 	case PROC:
4413297Smckusic 	case FUNC:
4423297Smckusic 	    return p->chain;
4433297Smckusic 	default:
4443297Smckusic 	    panic("plist");
4453297Smckusic     }
4463297Smckusic }
4473297Smckusic 
4483297Smckusic linenum(p)
4493297Smckusic     struct nl *p;
4503297Smckusic {
4513297Smckusic     if (p->class == FUNC)
4523297Smckusic 	return p->ptr[NL_FVAR]->value[NL_LINENO];
4533297Smckusic     return p->value[NL_LINENO];
4543297Smckusic }
455