1745Speter /* Copyright (c) 1979 Regents of the University of California */ 2745Speter 3*3372Speter static char sccsid[] = "@(#)call.c 1.12 03/26/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; 653362Speter char extname[ BUFSIZ ]; 663362Speter 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*3372Speter sextname( extname , p -> symbol , BLOCKNO(p -> nl_block) ); 1203362Speter 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 } 159*3372Speter q = lvalue( (int *) argv[1], MOD | ASGN , 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