1745Speter /* Copyright (c) 1979 Regents of the University of California */ 2745Speter 3*3359Smckusic static char sccsid[] = "@(#)call.c 1.9 03/23/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 ); 553297Smckusic 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) 72*3359Smckusic put(2, PTR_RV | psbn << 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" ); 148*3359Smckusic putRV( 0 , psbn , 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 */ 1613297Smckusic for (p1 = plist(p); p1 != NIL; p1 = p1->chain) { 1623297Smckusic if (argv == NIL) { 1633297Smckusic error("Not enough arguments to %s", p->symbol); 1643297Smckusic return (NIL); 1653297Smckusic } 1663297Smckusic switch (p1->class) { 1673297Smckusic case REF: 1683297Smckusic /* 1693297Smckusic * Var parameter 1703297Smckusic */ 1713297Smckusic r = argv[1]; 1723297Smckusic if (r != NIL && r[0] != T_VAR) { 1733297Smckusic error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol); 1743297Smckusic break; 1753297Smckusic } 1763297Smckusic q = lvalue( (int *) argv[1], MOD , LREQ ); 1773297Smckusic if (q == NIL) { 1783297Smckusic chk = FALSE; 1793297Smckusic break; 1803297Smckusic } 1813297Smckusic if (q != p1->type) { 1823297Smckusic error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol); 1833297Smckusic break; 1843297Smckusic } 1853297Smckusic break; 1863297Smckusic case VAR: 1873297Smckusic /* 1883297Smckusic * Value parameter 1893297Smckusic */ 190745Speter # ifdef OBJ 1913297Smckusic q = rvalue(argv[1], p1->type , RREQ ); 192745Speter # endif OBJ 193745Speter # ifdef PC 1943297Smckusic /* 1953297Smckusic * structure arguments require lvalues, 1963297Smckusic * scalars use rvalue. 1973297Smckusic */ 1983297Smckusic switch( classify( p1 -> type ) ) { 1993297Smckusic case TFILE: 2003297Smckusic case TARY: 2013297Smckusic case TREC: 2023297Smckusic case TSET: 2033297Smckusic case TSTR: 2043297Smckusic q = rvalue( argv[1] , p1 -> type , LREQ ); 205745Speter break; 2063297Smckusic case TINT: 2073297Smckusic case TSCAL: 2083297Smckusic case TBOOL: 2093297Smckusic case TCHAR: 2103297Smckusic precheck( p1 -> type , "_RANG4" , "_RSNG4" ); 2113297Smckusic q = rvalue( argv[1] , p1 -> type , RREQ ); 2123297Smckusic postcheck( p1 -> type ); 213745Speter break; 2143297Smckusic default: 2153297Smckusic q = rvalue( argv[1] , p1 -> type , RREQ ); 2163297Smckusic if ( isa( p1 -> type , "d" ) 2173297Smckusic && isa( q , "i" ) ) { 2183297Smckusic putop( P2SCONV , P2DOUBLE ); 2193297Smckusic } 2203297Smckusic break; 221745Speter } 2223297Smckusic # endif PC 2233297Smckusic if (q == NIL) { 2243297Smckusic chk = FALSE; 2253297Smckusic break; 2263297Smckusic } 2273297Smckusic if (incompat(q, p1->type, argv[1])) { 2283297Smckusic cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol); 2293297Smckusic break; 2303297Smckusic } 231745Speter # ifdef OBJ 2323297Smckusic if (isa(p1->type, "bcsi")) 2333297Smckusic rangechk(p1->type, q); 2343297Smckusic if (q->class != STR) 2353297Smckusic convert(q, p1->type); 236745Speter # endif OBJ 237745Speter # ifdef PC 2383297Smckusic switch( classify( p1 -> type ) ) { 2393297Smckusic case TFILE: 2403297Smckusic case TARY: 2413297Smckusic case TREC: 2423297Smckusic case TSET: 2433297Smckusic case TSTR: 2443297Smckusic putstrop( P2STARG 2453297Smckusic , p2type( p1 -> type ) 2463297Smckusic , lwidth( p1 -> type ) 2473297Smckusic , align( p1 -> type ) ); 2483297Smckusic } 2491195Speter # endif PC 2503297Smckusic break; 2513297Smckusic case FFUNC: 2521195Speter /* 2533297Smckusic * function parameter 2541195Speter */ 2553297Smckusic q = flvalue( (int *) argv[1] , p1 ); 2563297Smckusic chk = (chk && fcompat(q, p1)); 2573297Smckusic break; 2583297Smckusic case FPROC: 2591195Speter /* 2603297Smckusic * procedure parameter 2611195Speter */ 2623297Smckusic q = flvalue( (int *) argv[1] , p1 ); 2633297Smckusic chk = (chk && fcompat(q, p1)); 2643297Smckusic break; 2653297Smckusic default: 2663297Smckusic panic("call"); 2671195Speter } 2683297Smckusic # ifdef PC 2693297Smckusic /* 2703297Smckusic * if this is the nth (>1) argument, 2713297Smckusic * hang it on the left linear list of arguments 2723297Smckusic */ 2733297Smckusic if ( noarguments ) { 2743297Smckusic noarguments = FALSE; 2753297Smckusic } else { 2763297Smckusic putop( P2LISTOP , P2INT ); 2773297Smckusic } 2783297Smckusic # endif PC 2793297Smckusic argv = argv[2]; 280745Speter } 2813297Smckusic if (argv != NIL) { 2823297Smckusic error("Too many arguments to %s", p->symbol); 2833297Smckusic rvlist(argv); 2843297Smckusic return (NIL); 2853297Smckusic } 2863297Smckusic if (chk == FALSE) 2873297Smckusic return NIL; 288745Speter # ifdef OBJ 2891195Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 290*3359Smckusic put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]); 2913297Smckusic 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" ); 335*3359Smckusic putRV( 0 , psbn , 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 } 3663297Smckusic 3673297Smckusic /* 3683297Smckusic * check that two function/procedure namelist entries are compatible 3693297Smckusic */ 3703297Smckusic bool 3713297Smckusic fcompat( formal , actual ) 3723297Smckusic struct nl *formal; 3733297Smckusic struct nl *actual; 3743297Smckusic { 3753297Smckusic register struct nl *f_chain; 3763297Smckusic register struct nl *a_chain; 3773297Smckusic bool compat = TRUE; 3783297Smckusic 3793297Smckusic if ( formal == NIL || actual == NIL ) { 3803297Smckusic return FALSE; 3813297Smckusic } 3823297Smckusic for (a_chain = plist(actual), f_chain = plist(formal); 3833297Smckusic f_chain != NIL; 3843297Smckusic f_chain = f_chain->chain, a_chain = a_chain->chain) { 3853297Smckusic if (a_chain == NIL) { 3863297Smckusic error("%s %s declared on line %d has more arguments than", 3873297Smckusic parnam(formal->class), formal->symbol, 3883297Smckusic linenum(formal)); 3893297Smckusic cerror("%s %s declared on line %d", 3903297Smckusic parnam(actual->class), actual->symbol, 3913297Smckusic linenum(actual)); 3923297Smckusic return FALSE; 3933297Smckusic } 3943297Smckusic if ( a_chain -> class != f_chain -> class ) { 3953297Smckusic error("%s parameter %s of %s declared on line %d is not identical", 3963297Smckusic parnam(f_chain->class), f_chain->symbol, 3973297Smckusic formal->symbol, linenum(formal)); 3983297Smckusic cerror("with %s parameter %s of %s declared on line %d", 3993297Smckusic parnam(a_chain->class), a_chain->symbol, 4003297Smckusic actual->symbol, linenum(actual)); 4013297Smckusic compat = FALSE; 4023297Smckusic } else if (a_chain->class == FFUNC || a_chain->class == FPROC) { 4033297Smckusic compat = (compat && fcompat(f_chain, a_chain)); 4043297Smckusic } 4053297Smckusic if ((a_chain->class != FPROC && f_chain->class != FPROC) && 4063297Smckusic (a_chain->type != f_chain->type)) { 4073297Smckusic error("Type of %s parameter %s of %s declared on line %d is not identical", 4083297Smckusic parnam(f_chain->class), f_chain->symbol, 4093297Smckusic formal->symbol, linenum(formal)); 4103297Smckusic cerror("to type of %s parameter %s of %s declared on line %d", 4113297Smckusic parnam(a_chain->class), a_chain->symbol, 4123297Smckusic actual->symbol, linenum(actual)); 4133297Smckusic compat = FALSE; 4143297Smckusic } 4153297Smckusic } 4163297Smckusic if (a_chain != NIL) { 4173297Smckusic error("%s %s declared on line %d has fewer arguments than", 4183297Smckusic parnam(formal->class), formal->symbol, 4193297Smckusic linenum(formal)); 4203297Smckusic cerror("%s %s declared on line %d", 4213297Smckusic parnam(actual->class), actual->symbol, 4223297Smckusic linenum(actual)); 4233297Smckusic return FALSE; 4243297Smckusic } 4253297Smckusic return compat; 4263297Smckusic } 4273297Smckusic 4283297Smckusic char * 4293297Smckusic parnam(nltype) 4303297Smckusic int nltype; 4313297Smckusic { 4323297Smckusic switch(nltype) { 4333297Smckusic case REF: 4343297Smckusic return "var"; 4353297Smckusic case VAR: 4363297Smckusic return "value"; 4373297Smckusic case FUNC: 4383297Smckusic case FFUNC: 4393297Smckusic return "function"; 4403297Smckusic case PROC: 4413297Smckusic case FPROC: 4423297Smckusic return "procedure"; 4433297Smckusic default: 4443297Smckusic return "SNARK"; 4453297Smckusic } 4463297Smckusic } 4473297Smckusic 4483297Smckusic plist(p) 4493297Smckusic struct nl *p; 4503297Smckusic { 4513297Smckusic switch (p->class) { 4523297Smckusic case FFUNC: 4533297Smckusic case FPROC: 4543297Smckusic return p->ptr[ NL_FCHAIN ]; 4553297Smckusic case PROC: 4563297Smckusic case FUNC: 4573297Smckusic return p->chain; 4583297Smckusic default: 4593297Smckusic panic("plist"); 4603297Smckusic } 4613297Smckusic } 4623297Smckusic 4633297Smckusic linenum(p) 4643297Smckusic struct nl *p; 4653297Smckusic { 4663297Smckusic if (p->class == FUNC) 4673297Smckusic return p->ptr[NL_FVAR]->value[NL_LINENO]; 4683297Smckusic return p->value[NL_LINENO]; 4693297Smckusic } 470