1745Speter /* Copyright (c) 1979 Regents of the University of California */ 2745Speter 3*3361Speter static char sccsid[] = "@(#)call.c 1.10 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 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) 723359Smckusic 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" ); 1483359Smckusic 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); 174*3361Speter chk = FALSE; 1753297Smckusic break; 1763297Smckusic } 1773297Smckusic q = lvalue( (int *) argv[1], MOD , LREQ ); 1783297Smckusic if (q == NIL) { 1793297Smckusic chk = FALSE; 1803297Smckusic break; 1813297Smckusic } 1823297Smckusic if (q != p1->type) { 1833297Smckusic error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol); 184*3361Speter chk = FALSE; 1853297Smckusic break; 1863297Smckusic } 1873297Smckusic break; 1883297Smckusic case VAR: 1893297Smckusic /* 1903297Smckusic * Value parameter 1913297Smckusic */ 192745Speter # ifdef OBJ 1933297Smckusic q = rvalue(argv[1], p1->type , RREQ ); 194745Speter # endif OBJ 195745Speter # ifdef PC 1963297Smckusic /* 1973297Smckusic * structure arguments require lvalues, 1983297Smckusic * scalars use rvalue. 1993297Smckusic */ 2003297Smckusic switch( classify( p1 -> type ) ) { 2013297Smckusic case TFILE: 2023297Smckusic case TARY: 2033297Smckusic case TREC: 2043297Smckusic case TSET: 2053297Smckusic case TSTR: 2063297Smckusic q = rvalue( argv[1] , p1 -> type , LREQ ); 207745Speter break; 2083297Smckusic case TINT: 2093297Smckusic case TSCAL: 2103297Smckusic case TBOOL: 2113297Smckusic case TCHAR: 2123297Smckusic precheck( p1 -> type , "_RANG4" , "_RSNG4" ); 2133297Smckusic q = rvalue( argv[1] , p1 -> type , RREQ ); 2143297Smckusic postcheck( p1 -> type ); 215745Speter break; 2163297Smckusic default: 2173297Smckusic q = rvalue( argv[1] , p1 -> type , RREQ ); 2183297Smckusic if ( isa( p1 -> type , "d" ) 2193297Smckusic && isa( q , "i" ) ) { 2203297Smckusic putop( P2SCONV , P2DOUBLE ); 2213297Smckusic } 2223297Smckusic break; 223745Speter } 2243297Smckusic # endif PC 2253297Smckusic if (q == NIL) { 2263297Smckusic chk = FALSE; 2273297Smckusic break; 2283297Smckusic } 2293297Smckusic if (incompat(q, p1->type, argv[1])) { 2303297Smckusic cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol); 231*3361Speter chk = FALSE; 2323297Smckusic break; 2333297Smckusic } 234745Speter # ifdef OBJ 2353297Smckusic if (isa(p1->type, "bcsi")) 2363297Smckusic rangechk(p1->type, q); 2373297Smckusic if (q->class != STR) 2383297Smckusic convert(q, p1->type); 239745Speter # endif OBJ 240745Speter # ifdef PC 2413297Smckusic switch( classify( p1 -> type ) ) { 2423297Smckusic case TFILE: 2433297Smckusic case TARY: 2443297Smckusic case TREC: 2453297Smckusic case TSET: 2463297Smckusic case TSTR: 2473297Smckusic putstrop( P2STARG 2483297Smckusic , p2type( p1 -> type ) 2493297Smckusic , lwidth( p1 -> type ) 2503297Smckusic , align( p1 -> type ) ); 2513297Smckusic } 2521195Speter # endif PC 2533297Smckusic break; 2543297Smckusic case FFUNC: 2551195Speter /* 2563297Smckusic * function parameter 2571195Speter */ 2583297Smckusic q = flvalue( (int *) argv[1] , p1 ); 2593297Smckusic chk = (chk && fcompat(q, p1)); 2603297Smckusic break; 2613297Smckusic case FPROC: 2621195Speter /* 2633297Smckusic * procedure parameter 2641195Speter */ 2653297Smckusic q = flvalue( (int *) argv[1] , p1 ); 2663297Smckusic chk = (chk && fcompat(q, p1)); 2673297Smckusic break; 2683297Smckusic default: 2693297Smckusic panic("call"); 2701195Speter } 2713297Smckusic # ifdef PC 2723297Smckusic /* 2733297Smckusic * if this is the nth (>1) argument, 2743297Smckusic * hang it on the left linear list of arguments 2753297Smckusic */ 2763297Smckusic if ( noarguments ) { 2773297Smckusic noarguments = FALSE; 2783297Smckusic } else { 2793297Smckusic putop( P2LISTOP , P2INT ); 2803297Smckusic } 2813297Smckusic # endif PC 2823297Smckusic argv = argv[2]; 283745Speter } 2843297Smckusic if (argv != NIL) { 2853297Smckusic error("Too many arguments to %s", p->symbol); 2863297Smckusic rvlist(argv); 2873297Smckusic return (NIL); 2883297Smckusic } 2893297Smckusic if (chk == FALSE) 2903297Smckusic return NIL; 291745Speter # ifdef OBJ 2921195Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 2933359Smckusic put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]); 2943297Smckusic put(1, O_FCALL); 2953063Smckusic put(2, O_FRTN, even(width(p->type))); 2961195Speter } else { 2973063Smckusic put(2, O_CALL | psbn << 8, (long)p->entloc); 2981195Speter } 299745Speter # endif OBJ 300745Speter # ifdef PC 3013065Smckusic /* 3023065Smckusic * do the actual call: 3033065Smckusic * either ... p( ... ) ... 3043065Smckusic * or ... ( ...() )( ... ) ... 3053065Smckusic * and maybe an assignment. 3063065Smckusic */ 307745Speter if ( porf == FUNC ) { 3083065Smckusic switch ( p_type_class ) { 309745Speter case TBOOL: 310745Speter case TCHAR: 311745Speter case TINT: 312745Speter case TSCAL: 313745Speter case TDOUBLE: 314745Speter case TPTR: 3153065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , 3163065Smckusic p_type_p2type ); 3173065Smckusic if ( p -> class == FFUNC ) { 3183065Smckusic putop( P2ASSIGN , p_type_p2type ); 319745Speter } 320745Speter break; 321745Speter default: 3223065Smckusic putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ), 3233065Smckusic ADDTYPE( p_type_p2type , P2PTR ) , 3243065Smckusic p_type_width , p_type_align ); 3253065Smckusic putstrop( P2STASG , p_type_p2type , lwidth( p -> type ) 326745Speter , align( p -> type ) ); 327745Speter break; 328745Speter } 329745Speter } else { 3303065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT ); 3313065Smckusic } 3323065Smckusic /* 3333065Smckusic * ... , FRTN( p ) ... 3343065Smckusic */ 3353065Smckusic if ( p -> class == FFUNC || p -> class == FPROC ) { 3363065Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , 3373065Smckusic "_FRTN" ); 3383359Smckusic putRV( 0 , psbn , p -> value[ NL_OFFS ] , P2PTR | P2STRTY ); 3393065Smckusic putop( P2CALL , P2INT ); 3403065Smckusic putop( P2COMOP , P2INT ); 3413065Smckusic } 3423065Smckusic /* 3433065Smckusic * if required: 3443065Smckusic * either ... , temp ) 3453065Smckusic * or ... , &temp ) 3463065Smckusic */ 3473065Smckusic if ( porf == FUNC && temptype != P2UNDEF ) { 3483065Smckusic if ( temptype != P2STRTY ) { 3493065Smckusic putRV( 0 , cbn , tempoffset , p_type_p2type ); 350745Speter } else { 3513065Smckusic putLV( 0 , cbn , tempoffset , p_type_p2type ); 352745Speter } 3533065Smckusic putop( P2COMOP , P2INT ); 3543065Smckusic } 3553065Smckusic if ( porf == PROC ) { 356745Speter putdot( filename , line ); 357745Speter } 358745Speter # endif PC 359745Speter return (p->type); 360745Speter } 361745Speter 362745Speter rvlist(al) 363745Speter register int *al; 364745Speter { 365745Speter 366745Speter for (; al != NIL; al = al[2]) 367745Speter rvalue( (int *) al[1], NLNIL , RREQ ); 368745Speter } 3693297Smckusic 3703297Smckusic /* 3713297Smckusic * check that two function/procedure namelist entries are compatible 3723297Smckusic */ 3733297Smckusic bool 3743297Smckusic fcompat( formal , actual ) 3753297Smckusic struct nl *formal; 3763297Smckusic struct nl *actual; 3773297Smckusic { 3783297Smckusic register struct nl *f_chain; 3793297Smckusic register struct nl *a_chain; 3803297Smckusic bool compat = TRUE; 3813297Smckusic 3823297Smckusic if ( formal == NIL || actual == NIL ) { 3833297Smckusic return FALSE; 3843297Smckusic } 3853297Smckusic for (a_chain = plist(actual), f_chain = plist(formal); 3863297Smckusic f_chain != NIL; 3873297Smckusic f_chain = f_chain->chain, a_chain = a_chain->chain) { 3883297Smckusic if (a_chain == NIL) { 3893297Smckusic error("%s %s declared on line %d has more arguments than", 3903297Smckusic parnam(formal->class), formal->symbol, 3913297Smckusic linenum(formal)); 3923297Smckusic cerror("%s %s declared on line %d", 3933297Smckusic parnam(actual->class), actual->symbol, 3943297Smckusic linenum(actual)); 3953297Smckusic return FALSE; 3963297Smckusic } 3973297Smckusic if ( a_chain -> class != f_chain -> class ) { 3983297Smckusic error("%s parameter %s of %s declared on line %d is not identical", 3993297Smckusic parnam(f_chain->class), f_chain->symbol, 4003297Smckusic formal->symbol, linenum(formal)); 4013297Smckusic cerror("with %s parameter %s of %s declared on line %d", 4023297Smckusic parnam(a_chain->class), a_chain->symbol, 4033297Smckusic actual->symbol, linenum(actual)); 4043297Smckusic compat = FALSE; 4053297Smckusic } else if (a_chain->class == FFUNC || a_chain->class == FPROC) { 4063297Smckusic compat = (compat && fcompat(f_chain, a_chain)); 4073297Smckusic } 4083297Smckusic if ((a_chain->class != FPROC && f_chain->class != FPROC) && 4093297Smckusic (a_chain->type != f_chain->type)) { 4103297Smckusic error("Type of %s parameter %s of %s declared on line %d is not identical", 4113297Smckusic parnam(f_chain->class), f_chain->symbol, 4123297Smckusic formal->symbol, linenum(formal)); 4133297Smckusic cerror("to type of %s parameter %s of %s declared on line %d", 4143297Smckusic parnam(a_chain->class), a_chain->symbol, 4153297Smckusic actual->symbol, linenum(actual)); 4163297Smckusic compat = FALSE; 4173297Smckusic } 4183297Smckusic } 4193297Smckusic if (a_chain != NIL) { 4203297Smckusic error("%s %s declared on line %d has fewer arguments than", 4213297Smckusic parnam(formal->class), formal->symbol, 4223297Smckusic linenum(formal)); 4233297Smckusic cerror("%s %s declared on line %d", 4243297Smckusic parnam(actual->class), actual->symbol, 4253297Smckusic linenum(actual)); 4263297Smckusic return FALSE; 4273297Smckusic } 4283297Smckusic return compat; 4293297Smckusic } 4303297Smckusic 4313297Smckusic char * 4323297Smckusic parnam(nltype) 4333297Smckusic int nltype; 4343297Smckusic { 4353297Smckusic switch(nltype) { 4363297Smckusic case REF: 4373297Smckusic return "var"; 4383297Smckusic case VAR: 4393297Smckusic return "value"; 4403297Smckusic case FUNC: 4413297Smckusic case FFUNC: 4423297Smckusic return "function"; 4433297Smckusic case PROC: 4443297Smckusic case FPROC: 4453297Smckusic return "procedure"; 4463297Smckusic default: 4473297Smckusic return "SNARK"; 4483297Smckusic } 4493297Smckusic } 4503297Smckusic 4513297Smckusic plist(p) 4523297Smckusic struct nl *p; 4533297Smckusic { 4543297Smckusic switch (p->class) { 4553297Smckusic case FFUNC: 4563297Smckusic case FPROC: 4573297Smckusic return p->ptr[ NL_FCHAIN ]; 4583297Smckusic case PROC: 4593297Smckusic case FUNC: 4603297Smckusic return p->chain; 4613297Smckusic default: 4623297Smckusic panic("plist"); 4633297Smckusic } 4643297Smckusic } 4653297Smckusic 4663297Smckusic linenum(p) 4673297Smckusic struct nl *p; 4683297Smckusic { 4693297Smckusic if (p->class == FUNC) 4703297Smckusic return p->ptr[NL_FVAR]->value[NL_LINENO]; 4713297Smckusic return p->value[NL_LINENO]; 4723297Smckusic } 473