1745Speter /* Copyright (c) 1979 Regents of the University of California */ 2745Speter 3*3297Smckusic static char sccsid[] = "@(#)call.c 1.8 03/18/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 ); 55*3297Smckusic 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) 723063Smckusic put(2, PTR_RV | cbn << 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" ); 1481195Speter putRV( 0 , cbn , 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 */ 161*3297Smckusic for (p1 = plist(p); p1 != NIL; p1 = p1->chain) { 162*3297Smckusic if (argv == NIL) { 163*3297Smckusic error("Not enough arguments to %s", p->symbol); 164*3297Smckusic return (NIL); 165*3297Smckusic } 166*3297Smckusic switch (p1->class) { 167*3297Smckusic case REF: 168*3297Smckusic /* 169*3297Smckusic * Var parameter 170*3297Smckusic */ 171*3297Smckusic r = argv[1]; 172*3297Smckusic if (r != NIL && r[0] != T_VAR) { 173*3297Smckusic error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol); 174*3297Smckusic break; 175*3297Smckusic } 176*3297Smckusic q = lvalue( (int *) argv[1], MOD , LREQ ); 177*3297Smckusic if (q == NIL) { 178*3297Smckusic chk = FALSE; 179*3297Smckusic break; 180*3297Smckusic } 181*3297Smckusic if (q != p1->type) { 182*3297Smckusic error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol); 183*3297Smckusic break; 184*3297Smckusic } 185*3297Smckusic break; 186*3297Smckusic case VAR: 187*3297Smckusic /* 188*3297Smckusic * Value parameter 189*3297Smckusic */ 190745Speter # ifdef OBJ 191*3297Smckusic q = rvalue(argv[1], p1->type , RREQ ); 192745Speter # endif OBJ 193745Speter # ifdef PC 194*3297Smckusic /* 195*3297Smckusic * structure arguments require lvalues, 196*3297Smckusic * scalars use rvalue. 197*3297Smckusic */ 198*3297Smckusic switch( classify( p1 -> type ) ) { 199*3297Smckusic case TFILE: 200*3297Smckusic case TARY: 201*3297Smckusic case TREC: 202*3297Smckusic case TSET: 203*3297Smckusic case TSTR: 204*3297Smckusic q = rvalue( argv[1] , p1 -> type , LREQ ); 205745Speter break; 206*3297Smckusic case TINT: 207*3297Smckusic case TSCAL: 208*3297Smckusic case TBOOL: 209*3297Smckusic case TCHAR: 210*3297Smckusic precheck( p1 -> type , "_RANG4" , "_RSNG4" ); 211*3297Smckusic q = rvalue( argv[1] , p1 -> type , RREQ ); 212*3297Smckusic postcheck( p1 -> type ); 213745Speter break; 214*3297Smckusic default: 215*3297Smckusic q = rvalue( argv[1] , p1 -> type , RREQ ); 216*3297Smckusic if ( isa( p1 -> type , "d" ) 217*3297Smckusic && isa( q , "i" ) ) { 218*3297Smckusic putop( P2SCONV , P2DOUBLE ); 219*3297Smckusic } 220*3297Smckusic break; 221745Speter } 222*3297Smckusic # endif PC 223*3297Smckusic if (q == NIL) { 224*3297Smckusic chk = FALSE; 225*3297Smckusic break; 226*3297Smckusic } 227*3297Smckusic if (incompat(q, p1->type, argv[1])) { 228*3297Smckusic cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol); 229*3297Smckusic break; 230*3297Smckusic } 231745Speter # ifdef OBJ 232*3297Smckusic if (isa(p1->type, "bcsi")) 233*3297Smckusic rangechk(p1->type, q); 234*3297Smckusic if (q->class != STR) 235*3297Smckusic convert(q, p1->type); 236745Speter # endif OBJ 237745Speter # ifdef PC 238*3297Smckusic switch( classify( p1 -> type ) ) { 239*3297Smckusic case TFILE: 240*3297Smckusic case TARY: 241*3297Smckusic case TREC: 242*3297Smckusic case TSET: 243*3297Smckusic case TSTR: 244*3297Smckusic putstrop( P2STARG 245*3297Smckusic , p2type( p1 -> type ) 246*3297Smckusic , lwidth( p1 -> type ) 247*3297Smckusic , align( p1 -> type ) ); 248*3297Smckusic } 2491195Speter # endif PC 250*3297Smckusic break; 251*3297Smckusic case FFUNC: 2521195Speter /* 253*3297Smckusic * function parameter 2541195Speter */ 255*3297Smckusic q = flvalue( (int *) argv[1] , p1 ); 256*3297Smckusic chk = (chk && fcompat(q, p1)); 257*3297Smckusic break; 258*3297Smckusic case FPROC: 2591195Speter /* 260*3297Smckusic * procedure parameter 2611195Speter */ 262*3297Smckusic q = flvalue( (int *) argv[1] , p1 ); 263*3297Smckusic chk = (chk && fcompat(q, p1)); 264*3297Smckusic break; 265*3297Smckusic default: 266*3297Smckusic panic("call"); 2671195Speter } 268*3297Smckusic # ifdef PC 269*3297Smckusic /* 270*3297Smckusic * if this is the nth (>1) argument, 271*3297Smckusic * hang it on the left linear list of arguments 272*3297Smckusic */ 273*3297Smckusic if ( noarguments ) { 274*3297Smckusic noarguments = FALSE; 275*3297Smckusic } else { 276*3297Smckusic putop( P2LISTOP , P2INT ); 277*3297Smckusic } 278*3297Smckusic # endif PC 279*3297Smckusic argv = argv[2]; 280745Speter } 281*3297Smckusic if (argv != NIL) { 282*3297Smckusic error("Too many arguments to %s", p->symbol); 283*3297Smckusic rvlist(argv); 284*3297Smckusic return (NIL); 285*3297Smckusic } 286*3297Smckusic if (chk == FALSE) 287*3297Smckusic return NIL; 288745Speter # ifdef OBJ 2891195Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 2903063Smckusic put(2, PTR_RV | cbn << 8+INDX, (int)p->value[NL_OFFS]); 291*3297Smckusic 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" ); 3353065Smckusic putRV( 0 , cbn , 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 } 366*3297Smckusic 367*3297Smckusic /* 368*3297Smckusic * check that two function/procedure namelist entries are compatible 369*3297Smckusic */ 370*3297Smckusic bool 371*3297Smckusic fcompat( formal , actual ) 372*3297Smckusic struct nl *formal; 373*3297Smckusic struct nl *actual; 374*3297Smckusic { 375*3297Smckusic register struct nl *f_chain; 376*3297Smckusic register struct nl *a_chain; 377*3297Smckusic bool compat = TRUE; 378*3297Smckusic 379*3297Smckusic if ( formal == NIL || actual == NIL ) { 380*3297Smckusic return FALSE; 381*3297Smckusic } 382*3297Smckusic for (a_chain = plist(actual), f_chain = plist(formal); 383*3297Smckusic f_chain != NIL; 384*3297Smckusic f_chain = f_chain->chain, a_chain = a_chain->chain) { 385*3297Smckusic if (a_chain == NIL) { 386*3297Smckusic error("%s %s declared on line %d has more arguments than", 387*3297Smckusic parnam(formal->class), formal->symbol, 388*3297Smckusic linenum(formal)); 389*3297Smckusic cerror("%s %s declared on line %d", 390*3297Smckusic parnam(actual->class), actual->symbol, 391*3297Smckusic linenum(actual)); 392*3297Smckusic return FALSE; 393*3297Smckusic } 394*3297Smckusic if ( a_chain -> class != f_chain -> class ) { 395*3297Smckusic error("%s parameter %s of %s declared on line %d is not identical", 396*3297Smckusic parnam(f_chain->class), f_chain->symbol, 397*3297Smckusic formal->symbol, linenum(formal)); 398*3297Smckusic cerror("with %s parameter %s of %s declared on line %d", 399*3297Smckusic parnam(a_chain->class), a_chain->symbol, 400*3297Smckusic actual->symbol, linenum(actual)); 401*3297Smckusic compat = FALSE; 402*3297Smckusic } else if (a_chain->class == FFUNC || a_chain->class == FPROC) { 403*3297Smckusic compat = (compat && fcompat(f_chain, a_chain)); 404*3297Smckusic } 405*3297Smckusic if ((a_chain->class != FPROC && f_chain->class != FPROC) && 406*3297Smckusic (a_chain->type != f_chain->type)) { 407*3297Smckusic error("Type of %s parameter %s of %s declared on line %d is not identical", 408*3297Smckusic parnam(f_chain->class), f_chain->symbol, 409*3297Smckusic formal->symbol, linenum(formal)); 410*3297Smckusic cerror("to type of %s parameter %s of %s declared on line %d", 411*3297Smckusic parnam(a_chain->class), a_chain->symbol, 412*3297Smckusic actual->symbol, linenum(actual)); 413*3297Smckusic compat = FALSE; 414*3297Smckusic } 415*3297Smckusic } 416*3297Smckusic if (a_chain != NIL) { 417*3297Smckusic error("%s %s declared on line %d has fewer arguments than", 418*3297Smckusic parnam(formal->class), formal->symbol, 419*3297Smckusic linenum(formal)); 420*3297Smckusic cerror("%s %s declared on line %d", 421*3297Smckusic parnam(actual->class), actual->symbol, 422*3297Smckusic linenum(actual)); 423*3297Smckusic return FALSE; 424*3297Smckusic } 425*3297Smckusic return compat; 426*3297Smckusic } 427*3297Smckusic 428*3297Smckusic char * 429*3297Smckusic parnam(nltype) 430*3297Smckusic int nltype; 431*3297Smckusic { 432*3297Smckusic switch(nltype) { 433*3297Smckusic case REF: 434*3297Smckusic return "var"; 435*3297Smckusic case VAR: 436*3297Smckusic return "value"; 437*3297Smckusic case FUNC: 438*3297Smckusic case FFUNC: 439*3297Smckusic return "function"; 440*3297Smckusic case PROC: 441*3297Smckusic case FPROC: 442*3297Smckusic return "procedure"; 443*3297Smckusic default: 444*3297Smckusic return "SNARK"; 445*3297Smckusic } 446*3297Smckusic } 447*3297Smckusic 448*3297Smckusic plist(p) 449*3297Smckusic struct nl *p; 450*3297Smckusic { 451*3297Smckusic switch (p->class) { 452*3297Smckusic case FFUNC: 453*3297Smckusic case FPROC: 454*3297Smckusic return p->ptr[ NL_FCHAIN ]; 455*3297Smckusic case PROC: 456*3297Smckusic case FUNC: 457*3297Smckusic return p->chain; 458*3297Smckusic default: 459*3297Smckusic panic("plist"); 460*3297Smckusic } 461*3297Smckusic } 462*3297Smckusic 463*3297Smckusic linenum(p) 464*3297Smckusic struct nl *p; 465*3297Smckusic { 466*3297Smckusic if (p->class == FUNC) 467*3297Smckusic return p->ptr[NL_FVAR]->value[NL_LINENO]; 468*3297Smckusic return p->value[NL_LINENO]; 469*3297Smckusic } 470