xref: /csrg-svn/usr.bin/pascal/src/call.c (revision 3065)
1745Speter /* Copyright (c) 1979 Regents of the University of California */
2745Speter 
3*3065Smckusic static	char sccsid[] = "@(#)call.c 1.6 03/08/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 
15*3065Smckusic short	slenline = 0;
16*3065Smckusic 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.
26*3065Smckusic  *
27*3065Smckusic  *	the idea here is that regular scalar functions are just called,
28*3065Smckusic  *	while structure functions and formal functions have their results
29*3065Smckusic  *	stored in a temporary after the call.
30*3065Smckusic  *	structure functions do this because they return pointers
31*3065Smckusic  *	to static results, so we copy the static
32*3065Smckusic  *	and return a pointer to the copy.
33*3065Smckusic  *	formal functions do this because we have to save the result
34*3065Smckusic  *	around a call to the runtime routine which restores the display,
35*3065Smckusic  *	so we can't just leave the result lying around in registers.
36*3065Smckusic  *	so PROCs and scalar FUNCs look like
37*3065Smckusic  *		p(...args...)
38*3065Smckusic  *	structure FUNCs look like
39*3065Smckusic  *		(temp = p(...args...),&temp)
40*3065Smckusic  *	formal FPROCs look like
41*3065Smckusic  *		((FCALL( p ))(...args...),FRTN( p ))
42*3065Smckusic  *	formal scalar FFUNCs look like
43*3065Smckusic  *		(temp = (FCALL( p ))(...args...),FRTN( p ),temp)
44*3065Smckusic  *	formal structure FFUNCs look like
45*3065Smckusic  *		(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;
54*3065Smckusic 	struct nl	*p_type_class = classify( p -> type );
55745Speter 
561195Speter #	ifdef OBJ
571195Speter 	    int		cnt;
581195Speter #	endif OBJ
59745Speter #	ifdef PC
60*3065Smckusic 	    long	p_p2type = p2type( p );
61*3065Smckusic 	    long	p_type_p2type = p2type( p -> type );
62*3065Smckusic 	    bool	noarguments;
63*3065Smckusic 	    long	calltype;	/* type of the call */
64*3065Smckusic 		/*
65*3065Smckusic 		 *	these get used if temporaries and structures are used
66*3065Smckusic 		 */
67*3065Smckusic 	    long	tempoffset;
68*3065Smckusic 	    long	temptype;	/* type of the temporary */
69*3065Smckusic 	    long	p_type_width;
70*3065Smckusic 	    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
84*3065Smckusic 		/*
85*3065Smckusic 		 *	if we have to store a temporary,
86*3065Smckusic 		 *	temptype will be its type,
87*3065Smckusic 		 *	otherwise, it's P2UNDEF.
88*3065Smckusic 		 */
89*3065Smckusic 	    temptype = P2UNDEF;
90*3065Smckusic 	    calltype = P2INT;
91745Speter 	    if ( porf == FUNC ) {
92*3065Smckusic 		p_type_width = width( p -> type );
93*3065Smckusic 		switch( p_type_class ) {
94745Speter 		    case TSTR:
95745Speter 		    case TSET:
96745Speter 		    case TREC:
97745Speter 		    case TFILE:
98745Speter 		    case TARY:
99*3065Smckusic 			calltype = temptype = P2STRTY;
100*3065Smckusic 			p_type_align = align( p -> type );
101*3065Smckusic 			break;
102*3065Smckusic 		    default:
103*3065Smckusic 			if ( p -> class == FFUNC ) {
104*3065Smckusic 			    calltype = temptype = p2type( p -> type );
105745Speter 			}
106*3065Smckusic 			break;
107745Speter 		}
108*3065Smckusic 		if ( temptype != P2UNDEF ) {
109*3065Smckusic 		    tempoffset = sizes[ cbn ].om_off -= p_type_width;
110*3065Smckusic 		    putlbracket( ftnno , -tempoffset );
111*3065Smckusic 		    if ( tempoffset < sizes[cbn].om_max) {
112*3065Smckusic 			    sizes[cbn].om_max = tempoffset;
113*3065Smckusic 		    }
114*3065Smckusic 			/*
115*3065Smckusic 			 *	temp
116*3065Smckusic 			 *	for (temp = ...
117*3065Smckusic 			 */
118*3065Smckusic 		    putRV( 0 , cbn , tempoffset , temptype );
119*3065Smckusic 		}
120745Speter 	    }
1211195Speter 	    switch ( p -> class ) {
1221195Speter 		case FUNC:
1231195Speter 		case PROC:
124*3065Smckusic 			/*
125*3065Smckusic 			 *	... p( ...
126*3065Smckusic 			 */
1271195Speter 		    {
1281195Speter 			char	extname[ BUFSIZ ];
1291195Speter 			char	*starthere;
1301195Speter 			int	funcbn;
1311195Speter 			int	i;
132745Speter 
1331195Speter 			starthere = &extname[0];
1341195Speter 			funcbn = p -> nl_block & 037;
1351195Speter 			for ( i = 1 ; i < funcbn ; i++ ) {
1361195Speter 			    sprintf( starthere , EXTFORMAT , enclosing[ i ] );
1371195Speter 			    starthere += strlen( enclosing[ i ] ) + 1;
1381195Speter 			}
1391195Speter 			sprintf( starthere , EXTFORMAT , p -> symbol );
1401195Speter 			starthere += strlen( p -> symbol ) + 1;
1411195Speter 			if ( starthere >= &extname[ BUFSIZ ] ) {
1421195Speter 			    panic( "call namelength" );
1431195Speter 			}
1441195Speter 			putleaf( P2ICON , 0 , 0 , p2type( p ) , extname );
1451195Speter 		    }
1461195Speter 		    break;
1471195Speter 		case FFUNC:
1481195Speter 		case FPROC:
1491195Speter 			    /*
150*3065Smckusic 			     *	... (FCALL( p ))( ...
1511195Speter 			     */
1521195Speter 		    	putleaf( P2ICON , 0 , 0
153*3065Smckusic 			    , ADDTYPE( ADDTYPE( p_p2type , P2FTN ) , P2PTR )
1541195Speter 			    , "_FCALL" );
1551195Speter 			putRV( 0 , cbn , p -> value[NL_OFFS] , P2PTR|P2STRTY );
156*3065Smckusic 			putop( P2CALL , p_p2type );
1571195Speter 			break;
1581195Speter 		default:
1591195Speter 			panic("call class");
160745Speter 	    }
161*3065Smckusic 	    noarguments = TRUE;
162745Speter #	endif PC
163745Speter 	/*
164745Speter 	 * Loop and process each of
165745Speter 	 * arguments to the proc/func.
166*3065Smckusic 	 *	... ( ... args ... ) ...
167745Speter 	 */
1681195Speter 	if ( p -> class == FUNC || p -> class == PROC ) {
1691195Speter 	    for (p1 = p->chain; p1 != NIL; p1 = p1->chain) {
1701195Speter 		if (argv == NIL) {
1711195Speter 			error("Not enough arguments to %s", p->symbol);
1721195Speter 			return (NIL);
1731195Speter 		}
1741195Speter 		switch (p1->class) {
1751195Speter 		    case REF:
1761195Speter 			    /*
1771195Speter 			     * Var parameter
1781195Speter 			     */
1791195Speter 			    r = argv[1];
1801195Speter 			    if (r != NIL && r[0] != T_VAR) {
1811195Speter 				    error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol);
1821195Speter 				    break;
1831195Speter 			    }
1841195Speter 			    q = lvalue( (int *) argv[1], MOD , LREQ );
1851195Speter 			    if (q == NIL)
1861195Speter 				    break;
1871195Speter 			    if (q != p1->type) {
1881195Speter 				    error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol);
1891195Speter 				    break;
1901195Speter 			    }
1911195Speter 			    break;
1921195Speter 		    case VAR:
1931195Speter 			    /*
1941195Speter 			     * Value parameter
1951195Speter 			     */
196745Speter #			ifdef OBJ
1971195Speter 				q = rvalue(argv[1], p1->type , RREQ );
198745Speter #			endif OBJ
199745Speter #			ifdef PC
2001195Speter 				    /*
2011195Speter 				     * structure arguments require lvalues,
2021195Speter 				     * scalars use rvalue.
2031195Speter 				     */
2041195Speter 				switch( classify( p1 -> type ) ) {
2051195Speter 				    case TFILE:
2061195Speter 				    case TARY:
2071195Speter 				    case TREC:
2081195Speter 				    case TSET:
2091195Speter 				    case TSTR:
2101195Speter 					q = rvalue( argv[1] , p1 -> type , LREQ );
2111195Speter 					break;
2121195Speter 				    case TINT:
2131195Speter 				    case TSCAL:
2141195Speter 				    case TBOOL:
2151195Speter 				    case TCHAR:
2161195Speter 					precheck( p1 -> type , "_RANG4" , "_RSNG4" );
2171195Speter 					q = rvalue( argv[1] , p1 -> type , RREQ );
2181195Speter 					postcheck( p1 -> type );
2191195Speter 					break;
2201195Speter 				    default:
2211195Speter 					q = rvalue( argv[1] , p1 -> type , RREQ );
2221195Speter 					if (  isa( p1 -> type  , "d" )
2231195Speter 					   && isa( q , "i" ) ) {
2241195Speter 					    putop( P2SCONV , P2DOUBLE );
2251195Speter 					}
2261195Speter 					break;
2271195Speter 				}
2281195Speter #			endif PC
2291195Speter 			    if (q == NIL)
230745Speter 				    break;
2311195Speter 			    if (incompat(q, p1->type, argv[1])) {
2321195Speter 				    cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol);
233745Speter 				    break;
234745Speter 			    }
235745Speter #			ifdef OBJ
2361195Speter 				if (isa(p1->type, "bcsi"))
2371195Speter 					rangechk(p1->type, q);
2381195Speter 				if (q->class != STR)
2391195Speter 					convert(q, p1->type);
240745Speter #			endif OBJ
241745Speter #			ifdef PC
2421195Speter 				switch( classify( p1 -> type ) ) {
2431195Speter 				    case TFILE:
2441195Speter 				    case TARY:
2451195Speter 				    case TREC:
2461195Speter 				    case TSET:
2471195Speter 				    case TSTR:
2481195Speter 					    putstrop( P2STARG
2491195Speter 						, p2type( p1 -> type )
2501195Speter 						, lwidth( p1 -> type )
2511195Speter 						, align( p1 -> type ) );
2521195Speter 				}
2531195Speter #			endif PC
2541195Speter 			    break;
2551195Speter 		    case FFUNC:
2561195Speter 			    /*
2571195Speter 			     * function parameter
2581195Speter 			     */
2591195Speter 			    q = flvalue( (int *) argv[1] , FFUNC );
2601195Speter 			    if (q == NIL)
2611195Speter 				    break;
2621195Speter 			    if (q != p1->type) {
2631195Speter 				    error("Function type not identical to type of function parameter %s of %s", p1->symbol, p->symbol);
2641195Speter 				    break;
265745Speter 			    }
2661195Speter 			    break;
2671195Speter 		    case FPROC:
2681195Speter 			    /*
2691195Speter 			     * procedure parameter
2701195Speter 			     */
2711195Speter 			    q = flvalue( (int *) argv[1] , FPROC );
2721195Speter 			    if (q != NIL) {
2731195Speter 				    error("Procedure parameter %s of %s cannot have a type", p1->symbol, p->symbol);
2741195Speter 			    }
2751195Speter 			    break;
2761195Speter 		    default:
2771195Speter 			    panic("call");
2781195Speter 		}
279745Speter #	    ifdef PC
2801195Speter 			/*
2811195Speter 			 *	if this is the nth (>1) argument,
2821195Speter 			 *	hang it on the left linear list of arguments
2831195Speter 			 */
284*3065Smckusic 		    if ( noarguments ) {
285*3065Smckusic 			    noarguments = FALSE;
2861195Speter 		    } else {
2871195Speter 			    putop( P2LISTOP , P2INT );
2881195Speter 		    }
289745Speter #	    endif PC
2901195Speter 		argv = argv[2];
2911195Speter 	    }
2921195Speter 	    if (argv != NIL) {
2931195Speter 		    error("Too many arguments to %s", p->symbol);
2941195Speter 		    rvlist(argv);
2951195Speter 		    return (NIL);
2961195Speter 	    }
2971195Speter 	} else if ( p -> class == FFUNC || p -> class == FPROC ) {
2981195Speter 		/*
2991195Speter 		 *	formal routines can only have by-value parameters.
3001195Speter 		 *	this will lose for integer actuals passed to real
3011195Speter 		 *	formals, and strings which people want blank padded.
3021195Speter 		 */
3031195Speter #	    ifdef OBJ
3041195Speter 		cnt = 0;
3051195Speter #	    endif OBJ
3061195Speter 	    for ( ; argv != NIL ; argv = argv[2] ) {
3071195Speter #		ifdef OBJ
3081195Speter 		    q = rvalue(argv[1], NIL, RREQ );
3093063Smckusic 		    cnt += leven(lwidth(q));
3101195Speter #		endif OBJ
3111195Speter #		ifdef PC
3121195Speter 			/*
3131195Speter 			 * structure arguments require lvalues,
3141195Speter 			 * scalars use rvalue.
3151195Speter 			 */
3161195Speter 		    codeoff();
3171195Speter 		    p1 = rvalue( argv[1] , NIL , RREQ );
3181195Speter 		    codeon();
3191195Speter 		    switch( classify( p1 ) ) {
3201195Speter 			case TSTR:
321*3065Smckusic 			    if ( p1 -> class == STR && slenline != line ) {
322*3065Smckusic 				slenline = line;
323*3065Smckusic 				( opt( 's' ) ? (standard()): (warning()) );
3241195Speter 				error("Implementation can't construct equal length strings");
3251195Speter 			    }
3261195Speter 			    /* and fall through */
3271195Speter 			case TFILE:
3281195Speter 			case TARY:
3291195Speter 			case TREC:
3301195Speter 			case TSET:
3311195Speter 			    q = rvalue( argv[1] , p1 , LREQ );
3321195Speter 			    break;
3331195Speter 			case TINT:
334*3065Smckusic 			    if ( floatline != line ) {
335*3065Smckusic 				floatline = line;
336*3065Smckusic 				( opt( 's' ) ? (standard()) : (warning()) );
3371195Speter 				error("Implementation can't coerice integer to real");
3381195Speter 			    }
3391195Speter 			    /* and fall through */
3401195Speter 			case TSCAL:
3411195Speter 			case TBOOL:
3421195Speter 			case TCHAR:
3431195Speter 			default:
3441195Speter 			    q = rvalue( argv[1] , p1 , RREQ );
3451195Speter 			    break;
3461195Speter 		    }
3471195Speter 		    switch( classify( p1 ) ) {
3481195Speter 			case TFILE:
3491195Speter 			case TARY:
3501195Speter 			case TREC:
3511195Speter 			case TSET:
3521195Speter 			case TSTR:
3531195Speter 				putstrop( P2STARG , p2type( p1 ) ,
3541195Speter 				    lwidth( p1 ) , align( p1 ) );
3551195Speter 		    }
3561195Speter 			/*
3571195Speter 			 *	if this is the nth (>1) argument,
3581195Speter 			 *	hang it on the left linear list of arguments
3591195Speter 			 */
360*3065Smckusic 		    if ( noarguments ) {
361*3065Smckusic 			    noarguments = FALSE;
3621195Speter 		    } else {
3631195Speter 			    putop( P2LISTOP , P2INT );
3641195Speter 		    }
3651195Speter #		endif PC
3661195Speter 	    }
3671195Speter 	} else {
3681195Speter 	    panic("call class");
369745Speter 	}
370745Speter #	ifdef OBJ
3711195Speter 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
3723063Smckusic 		put(2, PTR_RV | cbn << 8+INDX, (int)p->value[NL_OFFS]);
3733063Smckusic 		put(2, O_FCALL, (long)cnt);
3743063Smckusic 		put(2, O_FRTN, even(width(p->type)));
3751195Speter 	    } else {
3763063Smckusic 		/* put(2, O_CALL | psbn << 8+INDX, (long)p->entloc); */
3773063Smckusic 		put(2, O_CALL | psbn << 8, (long)p->entloc);
3781195Speter 	    }
379745Speter #	endif OBJ
380745Speter #	ifdef PC
381*3065Smckusic 		/*
382*3065Smckusic 		 *	do the actual call:
383*3065Smckusic 		 *	    either	... p( ... ) ...
384*3065Smckusic 		 *	    or		... ( ...() )( ... ) ...
385*3065Smckusic 		 *	and maybe an assignment.
386*3065Smckusic 		 */
387745Speter 	    if ( porf == FUNC ) {
388*3065Smckusic 		switch ( p_type_class ) {
389745Speter 		    case TBOOL:
390745Speter 		    case TCHAR:
391745Speter 		    case TINT:
392745Speter 		    case TSCAL:
393745Speter 		    case TDOUBLE:
394745Speter 		    case TPTR:
395*3065Smckusic 			putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) ,
396*3065Smckusic 				p_type_p2type );
397*3065Smckusic 			if ( p -> class == FFUNC ) {
398*3065Smckusic 			    putop( P2ASSIGN , p_type_p2type );
399745Speter 			}
400745Speter 			break;
401745Speter 		    default:
402*3065Smckusic 			putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ),
403*3065Smckusic 				ADDTYPE( p_type_p2type , P2PTR ) ,
404*3065Smckusic 				p_type_width , p_type_align );
405*3065Smckusic 			putstrop( P2STASG , p_type_p2type , lwidth( p -> type )
406745Speter 				, align( p -> type ) );
407745Speter 			break;
408745Speter 		}
409745Speter 	    } else {
410*3065Smckusic 		putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT );
411*3065Smckusic 	    }
412*3065Smckusic 		/*
413*3065Smckusic 		 *	... , FRTN( p ) ...
414*3065Smckusic 		 */
415*3065Smckusic 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
416*3065Smckusic 		putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) ,
417*3065Smckusic 			"_FRTN" );
418*3065Smckusic 		putRV( 0 , cbn , p -> value[ NL_OFFS ] , P2PTR | P2STRTY );
419*3065Smckusic 		putop( P2CALL , P2INT );
420*3065Smckusic 		putop( P2COMOP , P2INT );
421*3065Smckusic 	    }
422*3065Smckusic 		/*
423*3065Smckusic 		 *	if required:
424*3065Smckusic 		 *	either	... , temp )
425*3065Smckusic 		 *	or	... , &temp )
426*3065Smckusic 		 */
427*3065Smckusic 	    if ( porf == FUNC && temptype != P2UNDEF ) {
428*3065Smckusic 		if ( temptype != P2STRTY ) {
429*3065Smckusic 		    putRV( 0 , cbn , tempoffset , p_type_p2type );
430745Speter 		} else {
431*3065Smckusic 		    putLV( 0 , cbn , tempoffset , p_type_p2type );
432745Speter 		}
433*3065Smckusic 		putop( P2COMOP , P2INT );
434*3065Smckusic 	    }
435*3065Smckusic 	    if ( porf == PROC ) {
436745Speter 		putdot( filename , line );
437745Speter 	    }
438745Speter #	endif PC
439745Speter 	return (p->type);
440745Speter }
441745Speter 
442745Speter rvlist(al)
443745Speter 	register int *al;
444745Speter {
445745Speter 
446745Speter 	for (; al != NIL; al = al[2])
447745Speter 		rvalue( (int *) al[1], NLNIL , RREQ );
448745Speter }
449