1745Speter /* Copyright (c) 1979 Regents of the University of California */ 2745Speter 3*3886Speter static char sccsid[] = "@(#)call.c 1.17 06/12/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. 33*3886Speter * formal calls save the address of the descriptor in a local 34*3886Speter * temporary, so it can be addressed for the call which restores 35*3886Speter * the display (FRTN). 363426Speter * calls to formal parameters pass the formal as a hidden argument 373426Speter * to a special entry point for the formal call. 383426Speter * [this is somewhat dependent on the way arguments are addressed.] 393065Smckusic * so PROCs and scalar FUNCs look like 403065Smckusic * p(...args...) 413065Smckusic * structure FUNCs look like 423065Smckusic * (temp = p(...args...),&temp) 433065Smckusic * formal FPROCs look like 44*3886Speter * ( t=p,( t -> entryaddr )(...args...,t),FRTN( t )) 453065Smckusic * formal scalar FFUNCs look like 46*3886Speter * ( t=p,temp=( t -> entryaddr )(...args...,t),FRTN( t ),temp) 473065Smckusic * formal structure FFUNCs look like 48*3886Speter * (t=p,temp = ( t -> entryaddr )(...args...,t),FRTN( t ),&temp) 49745Speter */ 50745Speter struct nl * 51745Speter call(p, argv, porf, psbn) 52745Speter struct nl *p; 53745Speter int *argv, porf, psbn; 54745Speter { 55745Speter register struct nl *p1, *q; 56745Speter int *r; 573065Smckusic struct nl *p_type_class = classify( p -> type ); 583297Smckusic bool chk = TRUE; 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 */ 673824Speter struct nl *tempnlp; 683065Smckusic long temptype; /* type of the temporary */ 693065Smckusic long p_type_width; 703065Smckusic long p_type_align; 713362Speter char extname[ BUFSIZ ]; 72*3886Speter struct nl *tempdescrp; 73745Speter # endif PC 74745Speter 75745Speter # ifdef OBJ 763426Speter if (p->class == FFUNC || p->class == FPROC) { 773359Smckusic put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]); 783426Speter } 793426Speter if (porf == FUNC) { 80745Speter /* 81745Speter * Push some space 82745Speter * for the function return type 83745Speter */ 843063Smckusic put(2, O_PUSH, leven(-lwidth(p->type))); 853426Speter } 86745Speter # endif OBJ 87745Speter # ifdef PC 883065Smckusic /* 89*3886Speter * if this is a formal call, 90*3886Speter * stash the address of the descriptor 91*3886Speter * in a temporary so we can find it 92*3886Speter * after the FCALL for the call to FRTN 93*3886Speter */ 94*3886Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 95*3886Speter tempdescrp = tmpalloc(sizeof( struct formalrtn *) , NIL , 96*3886Speter REGOK ); 97*3886Speter putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 98*3886Speter tempdescrp -> extra_flags , P2PTR|P2STRTY ); 99*3886Speter putRV( 0 , psbn , p -> value[ NL_OFFS ] , 100*3886Speter p -> extra_flags , P2PTR|P2STRTY ); 101*3886Speter putop( P2ASSIGN , P2PTR | P2STRTY ); 102*3886Speter } 103*3886Speter /* 1043065Smckusic * if we have to store a temporary, 1053065Smckusic * temptype will be its type, 1063065Smckusic * otherwise, it's P2UNDEF. 1073065Smckusic */ 1083065Smckusic temptype = P2UNDEF; 1093065Smckusic calltype = P2INT; 110745Speter if ( porf == FUNC ) { 1113065Smckusic p_type_width = width( p -> type ); 1123065Smckusic switch( p_type_class ) { 113745Speter case TSTR: 114745Speter case TSET: 115745Speter case TREC: 116745Speter case TFILE: 117745Speter case TARY: 1183065Smckusic calltype = temptype = P2STRTY; 1193065Smckusic p_type_align = align( p -> type ); 1203065Smckusic break; 1213065Smckusic default: 1223065Smckusic if ( p -> class == FFUNC ) { 1233065Smckusic calltype = temptype = p2type( p -> type ); 124745Speter } 1253065Smckusic break; 126745Speter } 1273065Smckusic if ( temptype != P2UNDEF ) { 1283824Speter tempnlp = tmpalloc(p_type_width, p -> type, NOREG); 1293065Smckusic /* 1303065Smckusic * temp 1313065Smckusic * for (temp = ... 1323065Smckusic */ 1333824Speter putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 1343824Speter tempnlp -> extra_flags , temptype ); 1353065Smckusic } 136745Speter } 1371195Speter switch ( p -> class ) { 1381195Speter case FUNC: 1391195Speter case PROC: 1403065Smckusic /* 1413065Smckusic * ... p( ... 1423065Smckusic */ 1433372Speter sextname( extname , p -> symbol , BLOCKNO(p -> nl_block) ); 1443362Speter putleaf( P2ICON , 0 , 0 , p2type( p ) , extname ); 1451195Speter break; 1461195Speter case FFUNC: 1471195Speter case FPROC: 148*3886Speter 1491195Speter /* 150*3886Speter * ... ( t -> entryaddr )( ... 1511195Speter */ 152*3886Speter putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 153*3886Speter tempdescrp -> extra_flags , P2PTR | P2STRTY ); 1543426Speter if ( FENTRYOFFSET != 0 ) { 1553426Speter putleaf( P2ICON , FENTRYOFFSET , 0 , P2INT , 0 ); 1563426Speter putop( P2PLUS , 1573426Speter ADDTYPE( 1583426Speter ADDTYPE( ADDTYPE( p2type( p ) , P2FTN ) , 1593426Speter P2PTR ) , 1603426Speter P2PTR ) ); 1613426Speter } 1623426Speter putop( P2UNARY P2MUL , 1633426Speter ADDTYPE( ADDTYPE( p2type( p ) , P2FTN ) , P2PTR ) ); 1641195Speter break; 1651195Speter default: 1661195Speter panic("call class"); 167745Speter } 1683065Smckusic noarguments = TRUE; 169745Speter # endif PC 170745Speter /* 171745Speter * Loop and process each of 172745Speter * arguments to the proc/func. 1733065Smckusic * ... ( ... args ... ) ... 174745Speter */ 1753297Smckusic for (p1 = plist(p); p1 != NIL; p1 = p1->chain) { 1763297Smckusic if (argv == NIL) { 1773297Smckusic error("Not enough arguments to %s", p->symbol); 1783297Smckusic return (NIL); 1793297Smckusic } 1803297Smckusic switch (p1->class) { 1813297Smckusic case REF: 1823297Smckusic /* 1833297Smckusic * Var parameter 1843297Smckusic */ 1853297Smckusic r = argv[1]; 1863297Smckusic if (r != NIL && r[0] != T_VAR) { 1873297Smckusic error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol); 1883361Speter chk = FALSE; 1893297Smckusic break; 1903297Smckusic } 1913372Speter q = lvalue( (int *) argv[1], MOD | ASGN , LREQ ); 1923297Smckusic if (q == NIL) { 1933297Smckusic chk = FALSE; 1943297Smckusic break; 1953297Smckusic } 1963297Smckusic if (q != p1->type) { 1973297Smckusic error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol); 1983361Speter chk = FALSE; 1993297Smckusic break; 2003297Smckusic } 2013297Smckusic break; 2023297Smckusic case VAR: 2033297Smckusic /* 2043297Smckusic * Value parameter 2053297Smckusic */ 206745Speter # ifdef OBJ 2073297Smckusic q = rvalue(argv[1], p1->type , RREQ ); 208745Speter # endif OBJ 209745Speter # ifdef PC 2103297Smckusic /* 2113297Smckusic * structure arguments require lvalues, 2123297Smckusic * scalars use rvalue. 2133297Smckusic */ 2143297Smckusic switch( classify( p1 -> type ) ) { 2153297Smckusic case TFILE: 2163297Smckusic case TARY: 2173297Smckusic case TREC: 2183297Smckusic case TSET: 2193297Smckusic case TSTR: 2203297Smckusic q = rvalue( argv[1] , p1 -> type , LREQ ); 221745Speter break; 2223297Smckusic case TINT: 2233297Smckusic case TSCAL: 2243297Smckusic case TBOOL: 2253297Smckusic case TCHAR: 2263297Smckusic precheck( p1 -> type , "_RANG4" , "_RSNG4" ); 2273297Smckusic q = rvalue( argv[1] , p1 -> type , RREQ ); 2283297Smckusic postcheck( p1 -> type ); 229745Speter break; 2303297Smckusic default: 2313297Smckusic q = rvalue( argv[1] , p1 -> type , RREQ ); 2323297Smckusic if ( isa( p1 -> type , "d" ) 2333297Smckusic && isa( q , "i" ) ) { 2343297Smckusic putop( P2SCONV , P2DOUBLE ); 2353297Smckusic } 2363297Smckusic break; 237745Speter } 2383297Smckusic # endif PC 2393297Smckusic if (q == NIL) { 2403297Smckusic chk = FALSE; 2413297Smckusic break; 2423297Smckusic } 2433297Smckusic if (incompat(q, p1->type, argv[1])) { 2443297Smckusic cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol); 2453361Speter chk = FALSE; 2463297Smckusic break; 2473297Smckusic } 248745Speter # ifdef OBJ 2493297Smckusic if (isa(p1->type, "bcsi")) 2503297Smckusic rangechk(p1->type, q); 2513297Smckusic if (q->class != STR) 2523297Smckusic convert(q, p1->type); 253745Speter # endif OBJ 254745Speter # ifdef PC 2553297Smckusic switch( classify( p1 -> type ) ) { 2563297Smckusic case TFILE: 2573297Smckusic case TARY: 2583297Smckusic case TREC: 2593297Smckusic case TSET: 2603297Smckusic case TSTR: 2613297Smckusic putstrop( P2STARG 2623297Smckusic , p2type( p1 -> type ) 2633297Smckusic , lwidth( p1 -> type ) 2643297Smckusic , align( p1 -> type ) ); 2653297Smckusic } 2661195Speter # endif PC 2673297Smckusic break; 2683297Smckusic case FFUNC: 2691195Speter /* 2703297Smckusic * function parameter 2711195Speter */ 2723297Smckusic q = flvalue( (int *) argv[1] , p1 ); 2733297Smckusic chk = (chk && fcompat(q, p1)); 2743297Smckusic break; 2753297Smckusic case FPROC: 2761195Speter /* 2773297Smckusic * procedure parameter 2781195Speter */ 2793297Smckusic q = flvalue( (int *) argv[1] , p1 ); 2803297Smckusic chk = (chk && fcompat(q, p1)); 2813297Smckusic break; 2823297Smckusic default: 2833297Smckusic panic("call"); 2841195Speter } 2853297Smckusic # ifdef PC 2863297Smckusic /* 2873297Smckusic * if this is the nth (>1) argument, 2883297Smckusic * hang it on the left linear list of arguments 2893297Smckusic */ 2903297Smckusic if ( noarguments ) { 2913297Smckusic noarguments = FALSE; 2923297Smckusic } else { 2933297Smckusic putop( P2LISTOP , P2INT ); 2943297Smckusic } 2953297Smckusic # endif PC 2963297Smckusic argv = argv[2]; 297745Speter } 2983297Smckusic if (argv != NIL) { 2993297Smckusic error("Too many arguments to %s", p->symbol); 3003297Smckusic rvlist(argv); 3013297Smckusic return (NIL); 3023297Smckusic } 3033297Smckusic if (chk == FALSE) 3043297Smckusic return NIL; 305745Speter # ifdef OBJ 3061195Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 3073359Smckusic put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]); 3083297Smckusic put(1, O_FCALL); 3093063Smckusic put(2, O_FRTN, even(width(p->type))); 3101195Speter } else { 3113063Smckusic put(2, O_CALL | psbn << 8, (long)p->entloc); 3121195Speter } 313745Speter # endif OBJ 314745Speter # ifdef PC 3153065Smckusic /* 3163426Speter * for formal calls: add the hidden argument 3173426Speter * which is the formal struct describing the 3183426Speter * environment of the routine. 3193426Speter * and the argument which is the address of the 3203426Speter * space into which to save the display. 3213426Speter */ 3223426Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 323*3886Speter putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 324*3886Speter tempdescrp -> extra_flags , P2PTR|P2STRTY ); 3253426Speter if ( !noarguments ) { 3263426Speter putop( P2LISTOP , P2INT ); 3273426Speter } 3283426Speter noarguments = FALSE; 3293426Speter } 3303426Speter /* 3313065Smckusic * do the actual call: 3323065Smckusic * either ... p( ... ) ... 333*3886Speter * or ... ( t -> entryaddr )( ... ) ... 3343065Smckusic * and maybe an assignment. 3353065Smckusic */ 336745Speter if ( porf == FUNC ) { 3373065Smckusic switch ( p_type_class ) { 338745Speter case TBOOL: 339745Speter case TCHAR: 340745Speter case TINT: 341745Speter case TSCAL: 342745Speter case TDOUBLE: 343745Speter case TPTR: 3443065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , 3453065Smckusic p_type_p2type ); 3463065Smckusic if ( p -> class == FFUNC ) { 3473065Smckusic putop( P2ASSIGN , p_type_p2type ); 348745Speter } 349745Speter break; 350745Speter default: 3513065Smckusic putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ), 3523065Smckusic ADDTYPE( p_type_p2type , P2PTR ) , 3533065Smckusic p_type_width , p_type_align ); 3543065Smckusic putstrop( P2STASG , p_type_p2type , lwidth( p -> type ) 355745Speter , align( p -> type ) ); 356745Speter break; 357745Speter } 358745Speter } else { 3593065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT ); 3603065Smckusic } 3613065Smckusic /* 362*3886Speter * ( t=p , ... , FRTN( t ) ... 3633065Smckusic */ 3643065Smckusic if ( p -> class == FFUNC || p -> class == FPROC ) { 365*3886Speter putop( P2COMOP , P2INT ); 3663065Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , 3673065Smckusic "_FRTN" ); 368*3886Speter putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 369*3886Speter tempdescrp -> extra_flags , P2PTR | P2STRTY ); 3703065Smckusic putop( P2CALL , P2INT ); 3713065Smckusic putop( P2COMOP , P2INT ); 3723065Smckusic } 3733065Smckusic /* 3743065Smckusic * if required: 3753065Smckusic * either ... , temp ) 3763065Smckusic * or ... , &temp ) 3773065Smckusic */ 3783065Smckusic if ( porf == FUNC && temptype != P2UNDEF ) { 3793065Smckusic if ( temptype != P2STRTY ) { 3803824Speter putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 3813824Speter tempnlp -> extra_flags , p_type_p2type ); 382745Speter } else { 3833824Speter putLV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 3843824Speter tempnlp -> extra_flags , p_type_p2type ); 385745Speter } 3863065Smckusic putop( P2COMOP , P2INT ); 3873065Smckusic } 3883065Smckusic if ( porf == PROC ) { 389745Speter putdot( filename , line ); 390745Speter } 391745Speter # endif PC 392745Speter return (p->type); 393745Speter } 394745Speter 395745Speter rvlist(al) 396745Speter register int *al; 397745Speter { 398745Speter 399745Speter for (; al != NIL; al = al[2]) 400745Speter rvalue( (int *) al[1], NLNIL , RREQ ); 401745Speter } 4023297Smckusic 4033297Smckusic /* 4043297Smckusic * check that two function/procedure namelist entries are compatible 4053297Smckusic */ 4063297Smckusic bool 4073297Smckusic fcompat( formal , actual ) 4083297Smckusic struct nl *formal; 4093297Smckusic struct nl *actual; 4103297Smckusic { 4113297Smckusic register struct nl *f_chain; 4123297Smckusic register struct nl *a_chain; 4133297Smckusic bool compat = TRUE; 4143297Smckusic 4153297Smckusic if ( formal == NIL || actual == NIL ) { 4163297Smckusic return FALSE; 4173297Smckusic } 4183297Smckusic for (a_chain = plist(actual), f_chain = plist(formal); 4193297Smckusic f_chain != NIL; 4203297Smckusic f_chain = f_chain->chain, a_chain = a_chain->chain) { 4213297Smckusic if (a_chain == NIL) { 4223297Smckusic error("%s %s declared on line %d has more arguments than", 4233297Smckusic parnam(formal->class), formal->symbol, 4243297Smckusic linenum(formal)); 4253297Smckusic cerror("%s %s declared on line %d", 4263297Smckusic parnam(actual->class), actual->symbol, 4273297Smckusic linenum(actual)); 4283297Smckusic return FALSE; 4293297Smckusic } 4303297Smckusic if ( a_chain -> class != f_chain -> class ) { 4313297Smckusic error("%s parameter %s of %s declared on line %d is not identical", 4323297Smckusic parnam(f_chain->class), f_chain->symbol, 4333297Smckusic formal->symbol, linenum(formal)); 4343297Smckusic cerror("with %s parameter %s of %s declared on line %d", 4353297Smckusic parnam(a_chain->class), a_chain->symbol, 4363297Smckusic actual->symbol, linenum(actual)); 4373297Smckusic compat = FALSE; 4383297Smckusic } else if (a_chain->class == FFUNC || a_chain->class == FPROC) { 4393297Smckusic compat = (compat && fcompat(f_chain, a_chain)); 4403297Smckusic } 4413297Smckusic if ((a_chain->class != FPROC && f_chain->class != FPROC) && 4423297Smckusic (a_chain->type != f_chain->type)) { 4433297Smckusic error("Type of %s parameter %s of %s declared on line %d is not identical", 4443297Smckusic parnam(f_chain->class), f_chain->symbol, 4453297Smckusic formal->symbol, linenum(formal)); 4463297Smckusic cerror("to type of %s parameter %s of %s declared on line %d", 4473297Smckusic parnam(a_chain->class), a_chain->symbol, 4483297Smckusic actual->symbol, linenum(actual)); 4493297Smckusic compat = FALSE; 4503297Smckusic } 4513297Smckusic } 4523297Smckusic if (a_chain != NIL) { 4533297Smckusic error("%s %s declared on line %d has fewer arguments than", 4543297Smckusic parnam(formal->class), formal->symbol, 4553297Smckusic linenum(formal)); 4563297Smckusic cerror("%s %s declared on line %d", 4573297Smckusic parnam(actual->class), actual->symbol, 4583297Smckusic linenum(actual)); 4593297Smckusic return FALSE; 4603297Smckusic } 4613297Smckusic return compat; 4623297Smckusic } 4633297Smckusic 4643297Smckusic char * 4653297Smckusic parnam(nltype) 4663297Smckusic int nltype; 4673297Smckusic { 4683297Smckusic switch(nltype) { 4693297Smckusic case REF: 4703297Smckusic return "var"; 4713297Smckusic case VAR: 4723297Smckusic return "value"; 4733297Smckusic case FUNC: 4743297Smckusic case FFUNC: 4753297Smckusic return "function"; 4763297Smckusic case PROC: 4773297Smckusic case FPROC: 4783297Smckusic return "procedure"; 4793297Smckusic default: 4803297Smckusic return "SNARK"; 4813297Smckusic } 4823297Smckusic } 4833297Smckusic 4843297Smckusic plist(p) 4853297Smckusic struct nl *p; 4863297Smckusic { 4873297Smckusic switch (p->class) { 4883297Smckusic case FFUNC: 4893297Smckusic case FPROC: 4903297Smckusic return p->ptr[ NL_FCHAIN ]; 4913297Smckusic case PROC: 4923297Smckusic case FUNC: 4933297Smckusic return p->chain; 4943297Smckusic default: 4953297Smckusic panic("plist"); 4963297Smckusic } 4973297Smckusic } 4983297Smckusic 4993297Smckusic linenum(p) 5003297Smckusic struct nl *p; 5013297Smckusic { 5023297Smckusic if (p->class == FUNC) 5033297Smckusic return p->ptr[NL_FVAR]->value[NL_LINENO]; 5043297Smckusic return p->value[NL_LINENO]; 5053297Smckusic } 506