xref: /csrg-svn/usr.bin/pascal/src/call.c (revision 3221)
1745Speter /* Copyright (c) 1979 Regents of the University of California */
2745Speter 
3*3221Smckusic static	char sccsid[] = "@(#)call.c 1.7 03/11/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 );
55745Speter 
561195Speter #	ifdef OBJ
571195Speter 	    int		cnt;
581195Speter #	endif OBJ
59745Speter #	ifdef PC
603065Smckusic 	    long	p_p2type = p2type( p );
613065Smckusic 	    long	p_type_p2type = p2type( p -> type );
623065Smckusic 	    bool	noarguments;
633065Smckusic 	    long	calltype;	/* type of the call */
643065Smckusic 		/*
653065Smckusic 		 *	these get used if temporaries and structures are used
663065Smckusic 		 */
673065Smckusic 	    long	tempoffset;
683065Smckusic 	    long	temptype;	/* type of the temporary */
693065Smckusic 	    long	p_type_width;
703065Smckusic 	    long	p_type_align;
71745Speter #	endif PC
72745Speter 
73745Speter #	ifdef OBJ
741195Speter 	    if (p->class == FFUNC || p->class == FPROC)
753063Smckusic 		put(2, PTR_RV | cbn << 8+INDX, (int)p->value[NL_OFFS]);
76745Speter 	    if (porf == FUNC)
77745Speter 		    /*
78745Speter 		     * Push some space
79745Speter 		     * for the function return type
80745Speter 		     */
813063Smckusic 		    put(2, O_PUSH, leven(-lwidth(p->type)));
82745Speter #	endif OBJ
83745Speter #	ifdef PC
843065Smckusic 		/*
853065Smckusic 		 *	if we have to store a temporary,
863065Smckusic 		 *	temptype will be its type,
873065Smckusic 		 *	otherwise, it's P2UNDEF.
883065Smckusic 		 */
893065Smckusic 	    temptype = P2UNDEF;
903065Smckusic 	    calltype = P2INT;
91745Speter 	    if ( porf == FUNC ) {
923065Smckusic 		p_type_width = width( p -> type );
933065Smckusic 		switch( p_type_class ) {
94745Speter 		    case TSTR:
95745Speter 		    case TSET:
96745Speter 		    case TREC:
97745Speter 		    case TFILE:
98745Speter 		    case TARY:
993065Smckusic 			calltype = temptype = P2STRTY;
1003065Smckusic 			p_type_align = align( p -> type );
1013065Smckusic 			break;
1023065Smckusic 		    default:
1033065Smckusic 			if ( p -> class == FFUNC ) {
1043065Smckusic 			    calltype = temptype = p2type( p -> type );
105745Speter 			}
1063065Smckusic 			break;
107745Speter 		}
1083065Smckusic 		if ( temptype != P2UNDEF ) {
109*3221Smckusic 		    tempoffset = tmpalloc(p_type_width, p -> type, NOREG);
1103065Smckusic 			/*
1113065Smckusic 			 *	temp
1123065Smckusic 			 *	for (temp = ...
1133065Smckusic 			 */
1143065Smckusic 		    putRV( 0 , cbn , tempoffset , temptype );
1153065Smckusic 		}
116745Speter 	    }
1171195Speter 	    switch ( p -> class ) {
1181195Speter 		case FUNC:
1191195Speter 		case PROC:
1203065Smckusic 			/*
1213065Smckusic 			 *	... p( ...
1223065Smckusic 			 */
1231195Speter 		    {
1241195Speter 			char	extname[ BUFSIZ ];
1251195Speter 			char	*starthere;
1261195Speter 			int	funcbn;
1271195Speter 			int	i;
128745Speter 
1291195Speter 			starthere = &extname[0];
1301195Speter 			funcbn = p -> nl_block & 037;
1311195Speter 			for ( i = 1 ; i < funcbn ; i++ ) {
1321195Speter 			    sprintf( starthere , EXTFORMAT , enclosing[ i ] );
1331195Speter 			    starthere += strlen( enclosing[ i ] ) + 1;
1341195Speter 			}
1351195Speter 			sprintf( starthere , EXTFORMAT , p -> symbol );
1361195Speter 			starthere += strlen( p -> symbol ) + 1;
1371195Speter 			if ( starthere >= &extname[ BUFSIZ ] ) {
1381195Speter 			    panic( "call namelength" );
1391195Speter 			}
1401195Speter 			putleaf( P2ICON , 0 , 0 , p2type( p ) , extname );
1411195Speter 		    }
1421195Speter 		    break;
1431195Speter 		case FFUNC:
1441195Speter 		case FPROC:
1451195Speter 			    /*
1463065Smckusic 			     *	... (FCALL( p ))( ...
1471195Speter 			     */
1481195Speter 		    	putleaf( P2ICON , 0 , 0
1493065Smckusic 			    , ADDTYPE( ADDTYPE( p_p2type , P2FTN ) , P2PTR )
1501195Speter 			    , "_FCALL" );
1511195Speter 			putRV( 0 , cbn , p -> value[NL_OFFS] , P2PTR|P2STRTY );
1523065Smckusic 			putop( P2CALL , p_p2type );
1531195Speter 			break;
1541195Speter 		default:
1551195Speter 			panic("call class");
156745Speter 	    }
1573065Smckusic 	    noarguments = TRUE;
158745Speter #	endif PC
159745Speter 	/*
160745Speter 	 * Loop and process each of
161745Speter 	 * arguments to the proc/func.
1623065Smckusic 	 *	... ( ... args ... ) ...
163745Speter 	 */
1641195Speter 	if ( p -> class == FUNC || p -> class == PROC ) {
1651195Speter 	    for (p1 = p->chain; p1 != NIL; p1 = p1->chain) {
1661195Speter 		if (argv == NIL) {
1671195Speter 			error("Not enough arguments to %s", p->symbol);
1681195Speter 			return (NIL);
1691195Speter 		}
1701195Speter 		switch (p1->class) {
1711195Speter 		    case REF:
1721195Speter 			    /*
1731195Speter 			     * Var parameter
1741195Speter 			     */
1751195Speter 			    r = argv[1];
1761195Speter 			    if (r != NIL && r[0] != T_VAR) {
1771195Speter 				    error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol);
1781195Speter 				    break;
1791195Speter 			    }
1801195Speter 			    q = lvalue( (int *) argv[1], MOD , LREQ );
1811195Speter 			    if (q == NIL)
1821195Speter 				    break;
1831195Speter 			    if (q != p1->type) {
1841195Speter 				    error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol);
1851195Speter 				    break;
1861195Speter 			    }
1871195Speter 			    break;
1881195Speter 		    case VAR:
1891195Speter 			    /*
1901195Speter 			     * Value parameter
1911195Speter 			     */
192745Speter #			ifdef OBJ
1931195Speter 				q = rvalue(argv[1], p1->type , RREQ );
194745Speter #			endif OBJ
195745Speter #			ifdef PC
1961195Speter 				    /*
1971195Speter 				     * structure arguments require lvalues,
1981195Speter 				     * scalars use rvalue.
1991195Speter 				     */
2001195Speter 				switch( classify( p1 -> type ) ) {
2011195Speter 				    case TFILE:
2021195Speter 				    case TARY:
2031195Speter 				    case TREC:
2041195Speter 				    case TSET:
2051195Speter 				    case TSTR:
2061195Speter 					q = rvalue( argv[1] , p1 -> type , LREQ );
2071195Speter 					break;
2081195Speter 				    case TINT:
2091195Speter 				    case TSCAL:
2101195Speter 				    case TBOOL:
2111195Speter 				    case TCHAR:
2121195Speter 					precheck( p1 -> type , "_RANG4" , "_RSNG4" );
2131195Speter 					q = rvalue( argv[1] , p1 -> type , RREQ );
2141195Speter 					postcheck( p1 -> type );
2151195Speter 					break;
2161195Speter 				    default:
2171195Speter 					q = rvalue( argv[1] , p1 -> type , RREQ );
2181195Speter 					if (  isa( p1 -> type  , "d" )
2191195Speter 					   && isa( q , "i" ) ) {
2201195Speter 					    putop( P2SCONV , P2DOUBLE );
2211195Speter 					}
2221195Speter 					break;
2231195Speter 				}
2241195Speter #			endif PC
2251195Speter 			    if (q == NIL)
226745Speter 				    break;
2271195Speter 			    if (incompat(q, p1->type, argv[1])) {
2281195Speter 				    cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol);
229745Speter 				    break;
230745Speter 			    }
231745Speter #			ifdef OBJ
2321195Speter 				if (isa(p1->type, "bcsi"))
2331195Speter 					rangechk(p1->type, q);
2341195Speter 				if (q->class != STR)
2351195Speter 					convert(q, p1->type);
236745Speter #			endif OBJ
237745Speter #			ifdef PC
2381195Speter 				switch( classify( p1 -> type ) ) {
2391195Speter 				    case TFILE:
2401195Speter 				    case TARY:
2411195Speter 				    case TREC:
2421195Speter 				    case TSET:
2431195Speter 				    case TSTR:
2441195Speter 					    putstrop( P2STARG
2451195Speter 						, p2type( p1 -> type )
2461195Speter 						, lwidth( p1 -> type )
2471195Speter 						, align( p1 -> type ) );
2481195Speter 				}
2491195Speter #			endif PC
2501195Speter 			    break;
2511195Speter 		    case FFUNC:
2521195Speter 			    /*
2531195Speter 			     * function parameter
2541195Speter 			     */
2551195Speter 			    q = flvalue( (int *) argv[1] , FFUNC );
2561195Speter 			    if (q == NIL)
2571195Speter 				    break;
2581195Speter 			    if (q != p1->type) {
2591195Speter 				    error("Function type not identical to type of function parameter %s of %s", p1->symbol, p->symbol);
2601195Speter 				    break;
261745Speter 			    }
2621195Speter 			    break;
2631195Speter 		    case FPROC:
2641195Speter 			    /*
2651195Speter 			     * procedure parameter
2661195Speter 			     */
2671195Speter 			    q = flvalue( (int *) argv[1] , FPROC );
2681195Speter 			    if (q != NIL) {
2691195Speter 				    error("Procedure parameter %s of %s cannot have a type", p1->symbol, p->symbol);
2701195Speter 			    }
2711195Speter 			    break;
2721195Speter 		    default:
2731195Speter 			    panic("call");
2741195Speter 		}
275745Speter #	    ifdef PC
2761195Speter 			/*
2771195Speter 			 *	if this is the nth (>1) argument,
2781195Speter 			 *	hang it on the left linear list of arguments
2791195Speter 			 */
2803065Smckusic 		    if ( noarguments ) {
2813065Smckusic 			    noarguments = FALSE;
2821195Speter 		    } else {
2831195Speter 			    putop( P2LISTOP , P2INT );
2841195Speter 		    }
285745Speter #	    endif PC
2861195Speter 		argv = argv[2];
2871195Speter 	    }
2881195Speter 	    if (argv != NIL) {
2891195Speter 		    error("Too many arguments to %s", p->symbol);
2901195Speter 		    rvlist(argv);
2911195Speter 		    return (NIL);
2921195Speter 	    }
2931195Speter 	} else if ( p -> class == FFUNC || p -> class == FPROC ) {
2941195Speter 		/*
2951195Speter 		 *	formal routines can only have by-value parameters.
2961195Speter 		 *	this will lose for integer actuals passed to real
2971195Speter 		 *	formals, and strings which people want blank padded.
2981195Speter 		 */
2991195Speter #	    ifdef OBJ
3001195Speter 		cnt = 0;
3011195Speter #	    endif OBJ
3021195Speter 	    for ( ; argv != NIL ; argv = argv[2] ) {
3031195Speter #		ifdef OBJ
3041195Speter 		    q = rvalue(argv[1], NIL, RREQ );
3053063Smckusic 		    cnt += leven(lwidth(q));
3061195Speter #		endif OBJ
3071195Speter #		ifdef PC
3081195Speter 			/*
3091195Speter 			 * structure arguments require lvalues,
3101195Speter 			 * scalars use rvalue.
3111195Speter 			 */
3121195Speter 		    codeoff();
3131195Speter 		    p1 = rvalue( argv[1] , NIL , RREQ );
3141195Speter 		    codeon();
3151195Speter 		    switch( classify( p1 ) ) {
3161195Speter 			case TSTR:
3173065Smckusic 			    if ( p1 -> class == STR && slenline != line ) {
3183065Smckusic 				slenline = line;
3193065Smckusic 				( opt( 's' ) ? (standard()): (warning()) );
3201195Speter 				error("Implementation can't construct equal length strings");
3211195Speter 			    }
3221195Speter 			    /* and fall through */
3231195Speter 			case TFILE:
3241195Speter 			case TARY:
3251195Speter 			case TREC:
3261195Speter 			case TSET:
3271195Speter 			    q = rvalue( argv[1] , p1 , LREQ );
3281195Speter 			    break;
3291195Speter 			case TINT:
3303065Smckusic 			    if ( floatline != line ) {
3313065Smckusic 				floatline = line;
3323065Smckusic 				( opt( 's' ) ? (standard()) : (warning()) );
3331195Speter 				error("Implementation can't coerice integer to real");
3341195Speter 			    }
3351195Speter 			    /* and fall through */
3361195Speter 			case TSCAL:
3371195Speter 			case TBOOL:
3381195Speter 			case TCHAR:
3391195Speter 			default:
3401195Speter 			    q = rvalue( argv[1] , p1 , RREQ );
3411195Speter 			    break;
3421195Speter 		    }
3431195Speter 		    switch( classify( p1 ) ) {
3441195Speter 			case TFILE:
3451195Speter 			case TARY:
3461195Speter 			case TREC:
3471195Speter 			case TSET:
3481195Speter 			case TSTR:
3491195Speter 				putstrop( P2STARG , p2type( p1 ) ,
3501195Speter 				    lwidth( p1 ) , align( p1 ) );
3511195Speter 		    }
3521195Speter 			/*
3531195Speter 			 *	if this is the nth (>1) argument,
3541195Speter 			 *	hang it on the left linear list of arguments
3551195Speter 			 */
3563065Smckusic 		    if ( noarguments ) {
3573065Smckusic 			    noarguments = FALSE;
3581195Speter 		    } else {
3591195Speter 			    putop( P2LISTOP , P2INT );
3601195Speter 		    }
3611195Speter #		endif PC
3621195Speter 	    }
3631195Speter 	} else {
3641195Speter 	    panic("call class");
365745Speter 	}
366745Speter #	ifdef OBJ
3671195Speter 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
3683063Smckusic 		put(2, PTR_RV | cbn << 8+INDX, (int)p->value[NL_OFFS]);
3693063Smckusic 		put(2, O_FCALL, (long)cnt);
3703063Smckusic 		put(2, O_FRTN, even(width(p->type)));
3711195Speter 	    } else {
3723063Smckusic 		/* put(2, O_CALL | psbn << 8+INDX, (long)p->entloc); */
3733063Smckusic 		put(2, O_CALL | psbn << 8, (long)p->entloc);
3741195Speter 	    }
375745Speter #	endif OBJ
376745Speter #	ifdef PC
3773065Smckusic 		/*
3783065Smckusic 		 *	do the actual call:
3793065Smckusic 		 *	    either	... p( ... ) ...
3803065Smckusic 		 *	    or		... ( ...() )( ... ) ...
3813065Smckusic 		 *	and maybe an assignment.
3823065Smckusic 		 */
383745Speter 	    if ( porf == FUNC ) {
3843065Smckusic 		switch ( p_type_class ) {
385745Speter 		    case TBOOL:
386745Speter 		    case TCHAR:
387745Speter 		    case TINT:
388745Speter 		    case TSCAL:
389745Speter 		    case TDOUBLE:
390745Speter 		    case TPTR:
3913065Smckusic 			putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) ,
3923065Smckusic 				p_type_p2type );
3933065Smckusic 			if ( p -> class == FFUNC ) {
3943065Smckusic 			    putop( P2ASSIGN , p_type_p2type );
395745Speter 			}
396745Speter 			break;
397745Speter 		    default:
3983065Smckusic 			putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ),
3993065Smckusic 				ADDTYPE( p_type_p2type , P2PTR ) ,
4003065Smckusic 				p_type_width , p_type_align );
4013065Smckusic 			putstrop( P2STASG , p_type_p2type , lwidth( p -> type )
402745Speter 				, align( p -> type ) );
403745Speter 			break;
404745Speter 		}
405745Speter 	    } else {
4063065Smckusic 		putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT );
4073065Smckusic 	    }
4083065Smckusic 		/*
4093065Smckusic 		 *	... , FRTN( p ) ...
4103065Smckusic 		 */
4113065Smckusic 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
4123065Smckusic 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) ,
4133065Smckusic 			"_FRTN" );
4143065Smckusic 		putRV( 0 , cbn , p -> value[ NL_OFFS ] , P2PTR | P2STRTY );
4153065Smckusic 		putop( P2CALL , P2INT );
4163065Smckusic 		putop( P2COMOP , P2INT );
4173065Smckusic 	    }
4183065Smckusic 		/*
4193065Smckusic 		 *	if required:
4203065Smckusic 		 *	either	... , temp )
4213065Smckusic 		 *	or	... , &temp )
4223065Smckusic 		 */
4233065Smckusic 	    if ( porf == FUNC && temptype != P2UNDEF ) {
4243065Smckusic 		if ( temptype != P2STRTY ) {
4253065Smckusic 		    putRV( 0 , cbn , tempoffset , p_type_p2type );
426745Speter 		} else {
4273065Smckusic 		    putLV( 0 , cbn , tempoffset , p_type_p2type );
428745Speter 		}
4293065Smckusic 		putop( P2COMOP , P2INT );
4303065Smckusic 	    }
4313065Smckusic 	    if ( porf == PROC ) {
432745Speter 		putdot( filename , line );
433745Speter 	    }
434745Speter #	endif PC
435745Speter 	return (p->type);
436745Speter }
437745Speter 
438745Speter rvlist(al)
439745Speter 	register int *al;
440745Speter {
441745Speter 
442745Speter 	for (; al != NIL; al = al[2])
443745Speter 		rvalue( (int *) al[1], NLNIL , RREQ );
444745Speter }
445