1745Speter /* Copyright (c) 1979 Regents of the University of California */ 2745Speter 3*3824Speter static char sccsid[] = "@(#)call.c 1.14 06/01/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. 333426Speter * calls to formal parameters pass the formal as a hidden argument 343426Speter * to a special entry point for the formal call. 353426Speter * [this is somewhat dependent on the way arguments are addressed.] 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 413426Speter * ( p -> entryaddr )(...args...,p),FRTN( p )) 423065Smckusic * formal scalar FFUNCs look like 433426Speter * (temp = ( p -> entryaddr )(...args...,p),FRTN( p ),temp) 443065Smckusic * formal structure FFUNCs look like 453426Speter * (temp = ( p -> entryaddr )(...args...,p),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; 56*3824Speter struct nl *savedispnp; /* temporary to hold saved display */ 57745Speter # ifdef PC 583065Smckusic long p_p2type = p2type( p ); 593065Smckusic long p_type_p2type = p2type( p -> type ); 603065Smckusic bool noarguments; 613065Smckusic long calltype; /* type of the call */ 623065Smckusic /* 633065Smckusic * these get used if temporaries and structures are used 643065Smckusic */ 65*3824Speter struct nl *tempnlp; 663065Smckusic long temptype; /* type of the temporary */ 673065Smckusic long p_type_width; 683065Smckusic long p_type_align; 693362Speter char extname[ BUFSIZ ]; 70745Speter # endif PC 71745Speter 723426Speter if (p->class == FFUNC || p->class == FPROC) { 733426Speter /* 743426Speter * allocate space to save the display for formal calls 753426Speter */ 76*3824Speter savedispnp = tmpalloc( sizeof display , NIL , NOREG ); 773426Speter } 78745Speter # ifdef OBJ 793426Speter if (p->class == FFUNC || p->class == FPROC) { 80*3824Speter put(2, O_LV | cbn << 8 + INDX , 81*3824Speter (int) savedispnp -> value[ NL_OFFS ] ); 823359Smckusic put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]); 833426Speter } 843426Speter if (porf == FUNC) { 85745Speter /* 86745Speter * Push some space 87745Speter * for the function return type 88745Speter */ 893063Smckusic put(2, O_PUSH, leven(-lwidth(p->type))); 903426Speter } 91745Speter # endif OBJ 92745Speter # ifdef PC 933065Smckusic /* 943065Smckusic * if we have to store a temporary, 953065Smckusic * temptype will be its type, 963065Smckusic * otherwise, it's P2UNDEF. 973065Smckusic */ 983065Smckusic temptype = P2UNDEF; 993065Smckusic calltype = P2INT; 100745Speter if ( porf == FUNC ) { 1013065Smckusic p_type_width = width( p -> type ); 1023065Smckusic switch( p_type_class ) { 103745Speter case TSTR: 104745Speter case TSET: 105745Speter case TREC: 106745Speter case TFILE: 107745Speter case TARY: 1083065Smckusic calltype = temptype = P2STRTY; 1093065Smckusic p_type_align = align( p -> type ); 1103065Smckusic break; 1113065Smckusic default: 1123065Smckusic if ( p -> class == FFUNC ) { 1133065Smckusic calltype = temptype = p2type( p -> type ); 114745Speter } 1153065Smckusic break; 116745Speter } 1173065Smckusic if ( temptype != P2UNDEF ) { 118*3824Speter tempnlp = tmpalloc(p_type_width, p -> type, NOREG); 1193065Smckusic /* 1203065Smckusic * temp 1213065Smckusic * for (temp = ... 1223065Smckusic */ 123*3824Speter putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 124*3824Speter tempnlp -> extra_flags , temptype ); 1253065Smckusic } 126745Speter } 1271195Speter switch ( p -> class ) { 1281195Speter case FUNC: 1291195Speter case PROC: 1303065Smckusic /* 1313065Smckusic * ... p( ... 1323065Smckusic */ 1333372Speter sextname( extname , p -> symbol , BLOCKNO(p -> nl_block) ); 1343362Speter putleaf( P2ICON , 0 , 0 , p2type( p ) , extname ); 1351195Speter break; 1361195Speter case FFUNC: 1371195Speter case FPROC: 1381195Speter /* 1393426Speter * ... ( p -> entryaddr )( ... 1401195Speter */ 141*3824Speter putRV( 0 , psbn , p -> value[ NL_OFFS ] , 142*3824Speter p -> extra_flags , P2PTR | P2STRTY ); 1433426Speter if ( FENTRYOFFSET != 0 ) { 1443426Speter putleaf( P2ICON , FENTRYOFFSET , 0 , P2INT , 0 ); 1453426Speter putop( P2PLUS , 1463426Speter ADDTYPE( 1473426Speter ADDTYPE( ADDTYPE( p2type( p ) , P2FTN ) , 1483426Speter P2PTR ) , 1493426Speter P2PTR ) ); 1503426Speter } 1513426Speter putop( P2UNARY P2MUL , 1523426Speter ADDTYPE( ADDTYPE( p2type( p ) , P2FTN ) , P2PTR ) ); 1531195Speter break; 1541195Speter default: 1551195Speter panic("call class"); 156745Speter } 1573065Smckusic noarguments = TRUE; 158745Speter # endif PC 159745Speter /* 160745Speter * Loop and process each of 161745Speter * arguments to the proc/func. 1623065Smckusic * ... ( ... args ... ) ... 163745Speter */ 1643297Smckusic for (p1 = plist(p); p1 != NIL; p1 = p1->chain) { 1653297Smckusic if (argv == NIL) { 1663297Smckusic error("Not enough arguments to %s", p->symbol); 1673297Smckusic return (NIL); 1683297Smckusic } 1693297Smckusic switch (p1->class) { 1703297Smckusic case REF: 1713297Smckusic /* 1723297Smckusic * Var parameter 1733297Smckusic */ 1743297Smckusic r = argv[1]; 1753297Smckusic if (r != NIL && r[0] != T_VAR) { 1763297Smckusic error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol); 1773361Speter chk = FALSE; 1783297Smckusic break; 1793297Smckusic } 1803372Speter q = lvalue( (int *) argv[1], MOD | ASGN , LREQ ); 1813297Smckusic if (q == NIL) { 1823297Smckusic chk = FALSE; 1833297Smckusic break; 1843297Smckusic } 1853297Smckusic if (q != p1->type) { 1863297Smckusic error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol); 1873361Speter chk = FALSE; 1883297Smckusic break; 1893297Smckusic } 1903297Smckusic break; 1913297Smckusic case VAR: 1923297Smckusic /* 1933297Smckusic * Value parameter 1943297Smckusic */ 195745Speter # ifdef OBJ 1963297Smckusic q = rvalue(argv[1], p1->type , RREQ ); 197745Speter # endif OBJ 198745Speter # ifdef PC 1993297Smckusic /* 2003297Smckusic * structure arguments require lvalues, 2013297Smckusic * scalars use rvalue. 2023297Smckusic */ 2033297Smckusic switch( classify( p1 -> type ) ) { 2043297Smckusic case TFILE: 2053297Smckusic case TARY: 2063297Smckusic case TREC: 2073297Smckusic case TSET: 2083297Smckusic case TSTR: 2093297Smckusic q = rvalue( argv[1] , p1 -> type , LREQ ); 210745Speter break; 2113297Smckusic case TINT: 2123297Smckusic case TSCAL: 2133297Smckusic case TBOOL: 2143297Smckusic case TCHAR: 2153297Smckusic precheck( p1 -> type , "_RANG4" , "_RSNG4" ); 2163297Smckusic q = rvalue( argv[1] , p1 -> type , RREQ ); 2173297Smckusic postcheck( p1 -> type ); 218745Speter break; 2193297Smckusic default: 2203297Smckusic q = rvalue( argv[1] , p1 -> type , RREQ ); 2213297Smckusic if ( isa( p1 -> type , "d" ) 2223297Smckusic && isa( q , "i" ) ) { 2233297Smckusic putop( P2SCONV , P2DOUBLE ); 2243297Smckusic } 2253297Smckusic break; 226745Speter } 2273297Smckusic # endif PC 2283297Smckusic if (q == NIL) { 2293297Smckusic chk = FALSE; 2303297Smckusic break; 2313297Smckusic } 2323297Smckusic if (incompat(q, p1->type, argv[1])) { 2333297Smckusic cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol); 2343361Speter chk = FALSE; 2353297Smckusic break; 2363297Smckusic } 237745Speter # ifdef OBJ 2383297Smckusic if (isa(p1->type, "bcsi")) 2393297Smckusic rangechk(p1->type, q); 2403297Smckusic if (q->class != STR) 2413297Smckusic convert(q, p1->type); 242745Speter # endif OBJ 243745Speter # ifdef PC 2443297Smckusic switch( classify( p1 -> type ) ) { 2453297Smckusic case TFILE: 2463297Smckusic case TARY: 2473297Smckusic case TREC: 2483297Smckusic case TSET: 2493297Smckusic case TSTR: 2503297Smckusic putstrop( P2STARG 2513297Smckusic , p2type( p1 -> type ) 2523297Smckusic , lwidth( p1 -> type ) 2533297Smckusic , align( p1 -> type ) ); 2543297Smckusic } 2551195Speter # endif PC 2563297Smckusic break; 2573297Smckusic case FFUNC: 2581195Speter /* 2593297Smckusic * function parameter 2601195Speter */ 2613297Smckusic q = flvalue( (int *) argv[1] , p1 ); 2623297Smckusic chk = (chk && fcompat(q, p1)); 2633297Smckusic break; 2643297Smckusic case FPROC: 2651195Speter /* 2663297Smckusic * procedure parameter 2671195Speter */ 2683297Smckusic q = flvalue( (int *) argv[1] , p1 ); 2693297Smckusic chk = (chk && fcompat(q, p1)); 2703297Smckusic break; 2713297Smckusic default: 2723297Smckusic panic("call"); 2731195Speter } 2743297Smckusic # ifdef PC 2753297Smckusic /* 2763297Smckusic * if this is the nth (>1) argument, 2773297Smckusic * hang it on the left linear list of arguments 2783297Smckusic */ 2793297Smckusic if ( noarguments ) { 2803297Smckusic noarguments = FALSE; 2813297Smckusic } else { 2823297Smckusic putop( P2LISTOP , P2INT ); 2833297Smckusic } 2843297Smckusic # endif PC 2853297Smckusic argv = argv[2]; 286745Speter } 2873297Smckusic if (argv != NIL) { 2883297Smckusic error("Too many arguments to %s", p->symbol); 2893297Smckusic rvlist(argv); 2903297Smckusic return (NIL); 2913297Smckusic } 2923297Smckusic if (chk == FALSE) 2933297Smckusic return NIL; 294745Speter # ifdef OBJ 2951195Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 2963359Smckusic put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]); 297*3824Speter put(2, O_LV | cbn << 8 + INDX , 298*3824Speter (int) savedispnp -> value[ NL_OFFS ] ); 2993297Smckusic put(1, O_FCALL); 3003063Smckusic put(2, O_FRTN, even(width(p->type))); 3011195Speter } else { 3023063Smckusic put(2, O_CALL | psbn << 8, (long)p->entloc); 3031195Speter } 304745Speter # endif OBJ 305745Speter # ifdef PC 3063065Smckusic /* 3073426Speter * for formal calls: add the hidden argument 3083426Speter * which is the formal struct describing the 3093426Speter * environment of the routine. 3103426Speter * and the argument which is the address of the 3113426Speter * space into which to save the display. 3123426Speter */ 3133426Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 314*3824Speter putRV( 0 , cbn , p -> value[ NL_OFFS ] , 315*3824Speter p -> extra_flags , P2PTR|P2STRTY ); 3163426Speter if ( !noarguments ) { 3173426Speter putop( P2LISTOP , P2INT ); 3183426Speter } 3193426Speter noarguments = FALSE; 320*3824Speter putLV( 0 , cbn , savedispnp -> value[ NL_OFFS ] , 321*3824Speter savedispnp -> extra_flags , P2PTR | P2STRTY ); 3223426Speter putop( P2LISTOP , P2INT ); 3233426Speter } 3243426Speter /* 3253065Smckusic * do the actual call: 3263065Smckusic * either ... p( ... ) ... 3273426Speter * or ... ( p -> entryaddr )( ... ) ... 3283065Smckusic * and maybe an assignment. 3293065Smckusic */ 330745Speter if ( porf == FUNC ) { 3313065Smckusic switch ( p_type_class ) { 332745Speter case TBOOL: 333745Speter case TCHAR: 334745Speter case TINT: 335745Speter case TSCAL: 336745Speter case TDOUBLE: 337745Speter case TPTR: 3383065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , 3393065Smckusic p_type_p2type ); 3403065Smckusic if ( p -> class == FFUNC ) { 3413065Smckusic putop( P2ASSIGN , p_type_p2type ); 342745Speter } 343745Speter break; 344745Speter default: 3453065Smckusic putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ), 3463065Smckusic ADDTYPE( p_type_p2type , P2PTR ) , 3473065Smckusic p_type_width , p_type_align ); 3483065Smckusic putstrop( P2STASG , p_type_p2type , lwidth( p -> type ) 349745Speter , align( p -> type ) ); 350745Speter break; 351745Speter } 352745Speter } else { 3533065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT ); 3543065Smckusic } 3553065Smckusic /* 3563065Smckusic * ... , FRTN( p ) ... 3573065Smckusic */ 3583065Smckusic if ( p -> class == FFUNC || p -> class == FPROC ) { 3593065Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , 3603065Smckusic "_FRTN" ); 361*3824Speter putRV( 0 , psbn , p -> value[ NL_OFFS ] , 362*3824Speter p -> extra_flags , P2PTR | P2STRTY ); 363*3824Speter putLV( 0 , cbn , savedispnp -> value[ NL_OFFS ] , 364*3824Speter savedispnp -> extra_flags , P2PTR | P2STRTY ); 3653426Speter putop( P2LISTOP , P2INT ); 3663065Smckusic putop( P2CALL , P2INT ); 3673065Smckusic putop( P2COMOP , P2INT ); 3683065Smckusic } 3693065Smckusic /* 3703065Smckusic * if required: 3713065Smckusic * either ... , temp ) 3723065Smckusic * or ... , &temp ) 3733065Smckusic */ 3743065Smckusic if ( porf == FUNC && temptype != P2UNDEF ) { 3753065Smckusic if ( temptype != P2STRTY ) { 376*3824Speter putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 377*3824Speter tempnlp -> extra_flags , p_type_p2type ); 378745Speter } else { 379*3824Speter putLV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 380*3824Speter tempnlp -> extra_flags , p_type_p2type ); 381745Speter } 3823065Smckusic putop( P2COMOP , P2INT ); 3833065Smckusic } 3843065Smckusic if ( porf == PROC ) { 385745Speter putdot( filename , line ); 386745Speter } 387745Speter # endif PC 388745Speter return (p->type); 389745Speter } 390745Speter 391745Speter rvlist(al) 392745Speter register int *al; 393745Speter { 394745Speter 395745Speter for (; al != NIL; al = al[2]) 396745Speter rvalue( (int *) al[1], NLNIL , RREQ ); 397745Speter } 3983297Smckusic 3993297Smckusic /* 4003297Smckusic * check that two function/procedure namelist entries are compatible 4013297Smckusic */ 4023297Smckusic bool 4033297Smckusic fcompat( formal , actual ) 4043297Smckusic struct nl *formal; 4053297Smckusic struct nl *actual; 4063297Smckusic { 4073297Smckusic register struct nl *f_chain; 4083297Smckusic register struct nl *a_chain; 4093297Smckusic bool compat = TRUE; 4103297Smckusic 4113297Smckusic if ( formal == NIL || actual == NIL ) { 4123297Smckusic return FALSE; 4133297Smckusic } 4143297Smckusic for (a_chain = plist(actual), f_chain = plist(formal); 4153297Smckusic f_chain != NIL; 4163297Smckusic f_chain = f_chain->chain, a_chain = a_chain->chain) { 4173297Smckusic if (a_chain == NIL) { 4183297Smckusic error("%s %s declared on line %d has more arguments than", 4193297Smckusic parnam(formal->class), formal->symbol, 4203297Smckusic linenum(formal)); 4213297Smckusic cerror("%s %s declared on line %d", 4223297Smckusic parnam(actual->class), actual->symbol, 4233297Smckusic linenum(actual)); 4243297Smckusic return FALSE; 4253297Smckusic } 4263297Smckusic if ( a_chain -> class != f_chain -> class ) { 4273297Smckusic error("%s parameter %s of %s declared on line %d is not identical", 4283297Smckusic parnam(f_chain->class), f_chain->symbol, 4293297Smckusic formal->symbol, linenum(formal)); 4303297Smckusic cerror("with %s parameter %s of %s declared on line %d", 4313297Smckusic parnam(a_chain->class), a_chain->symbol, 4323297Smckusic actual->symbol, linenum(actual)); 4333297Smckusic compat = FALSE; 4343297Smckusic } else if (a_chain->class == FFUNC || a_chain->class == FPROC) { 4353297Smckusic compat = (compat && fcompat(f_chain, a_chain)); 4363297Smckusic } 4373297Smckusic if ((a_chain->class != FPROC && f_chain->class != FPROC) && 4383297Smckusic (a_chain->type != f_chain->type)) { 4393297Smckusic error("Type of %s parameter %s of %s declared on line %d is not identical", 4403297Smckusic parnam(f_chain->class), f_chain->symbol, 4413297Smckusic formal->symbol, linenum(formal)); 4423297Smckusic cerror("to type of %s parameter %s of %s declared on line %d", 4433297Smckusic parnam(a_chain->class), a_chain->symbol, 4443297Smckusic actual->symbol, linenum(actual)); 4453297Smckusic compat = FALSE; 4463297Smckusic } 4473297Smckusic } 4483297Smckusic if (a_chain != NIL) { 4493297Smckusic error("%s %s declared on line %d has fewer arguments than", 4503297Smckusic parnam(formal->class), formal->symbol, 4513297Smckusic linenum(formal)); 4523297Smckusic cerror("%s %s declared on line %d", 4533297Smckusic parnam(actual->class), actual->symbol, 4543297Smckusic linenum(actual)); 4553297Smckusic return FALSE; 4563297Smckusic } 4573297Smckusic return compat; 4583297Smckusic } 4593297Smckusic 4603297Smckusic char * 4613297Smckusic parnam(nltype) 4623297Smckusic int nltype; 4633297Smckusic { 4643297Smckusic switch(nltype) { 4653297Smckusic case REF: 4663297Smckusic return "var"; 4673297Smckusic case VAR: 4683297Smckusic return "value"; 4693297Smckusic case FUNC: 4703297Smckusic case FFUNC: 4713297Smckusic return "function"; 4723297Smckusic case PROC: 4733297Smckusic case FPROC: 4743297Smckusic return "procedure"; 4753297Smckusic default: 4763297Smckusic return "SNARK"; 4773297Smckusic } 4783297Smckusic } 4793297Smckusic 4803297Smckusic plist(p) 4813297Smckusic struct nl *p; 4823297Smckusic { 4833297Smckusic switch (p->class) { 4843297Smckusic case FFUNC: 4853297Smckusic case FPROC: 4863297Smckusic return p->ptr[ NL_FCHAIN ]; 4873297Smckusic case PROC: 4883297Smckusic case FUNC: 4893297Smckusic return p->chain; 4903297Smckusic default: 4913297Smckusic panic("plist"); 4923297Smckusic } 4933297Smckusic } 4943297Smckusic 4953297Smckusic linenum(p) 4963297Smckusic struct nl *p; 4973297Smckusic { 4983297Smckusic if (p->class == FUNC) 4993297Smckusic return p->ptr[NL_FVAR]->value[NL_LINENO]; 5003297Smckusic return p->value[NL_LINENO]; 5013297Smckusic } 502