1745Speter /* Copyright (c) 1979 Regents of the University of California */ 2745Speter 3*3221Smckusic static char sccsid[] = "@(#)call.c 1.7 03/11/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 ); 55745Speter 561195Speter # ifdef OBJ 571195Speter int cnt; 581195Speter # endif OBJ 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 */ 673065Smckusic long tempoffset; 683065Smckusic long temptype; /* type of the temporary */ 693065Smckusic long p_type_width; 703065Smckusic long p_type_align; 71745Speter # endif PC 72745Speter 73745Speter # ifdef OBJ 741195Speter if (p->class == FFUNC || p->class == FPROC) 753063Smckusic put(2, PTR_RV | cbn << 8+INDX, (int)p->value[NL_OFFS]); 76745Speter if (porf == FUNC) 77745Speter /* 78745Speter * Push some space 79745Speter * for the function return type 80745Speter */ 813063Smckusic put(2, O_PUSH, leven(-lwidth(p->type))); 82745Speter # endif OBJ 83745Speter # ifdef PC 843065Smckusic /* 853065Smckusic * if we have to store a temporary, 863065Smckusic * temptype will be its type, 873065Smckusic * otherwise, it's P2UNDEF. 883065Smckusic */ 893065Smckusic temptype = P2UNDEF; 903065Smckusic calltype = P2INT; 91745Speter if ( porf == FUNC ) { 923065Smckusic p_type_width = width( p -> type ); 933065Smckusic switch( p_type_class ) { 94745Speter case TSTR: 95745Speter case TSET: 96745Speter case TREC: 97745Speter case TFILE: 98745Speter case TARY: 993065Smckusic calltype = temptype = P2STRTY; 1003065Smckusic p_type_align = align( p -> type ); 1013065Smckusic break; 1023065Smckusic default: 1033065Smckusic if ( p -> class == FFUNC ) { 1043065Smckusic calltype = temptype = p2type( p -> type ); 105745Speter } 1063065Smckusic break; 107745Speter } 1083065Smckusic if ( temptype != P2UNDEF ) { 109*3221Smckusic tempoffset = tmpalloc(p_type_width, p -> type, NOREG); 1103065Smckusic /* 1113065Smckusic * temp 1123065Smckusic * for (temp = ... 1133065Smckusic */ 1143065Smckusic putRV( 0 , cbn , tempoffset , temptype ); 1153065Smckusic } 116745Speter } 1171195Speter switch ( p -> class ) { 1181195Speter case FUNC: 1191195Speter case PROC: 1203065Smckusic /* 1213065Smckusic * ... p( ... 1223065Smckusic */ 1231195Speter { 1241195Speter char extname[ BUFSIZ ]; 1251195Speter char *starthere; 1261195Speter int funcbn; 1271195Speter int i; 128745Speter 1291195Speter starthere = &extname[0]; 1301195Speter funcbn = p -> nl_block & 037; 1311195Speter for ( i = 1 ; i < funcbn ; i++ ) { 1321195Speter sprintf( starthere , EXTFORMAT , enclosing[ i ] ); 1331195Speter starthere += strlen( enclosing[ i ] ) + 1; 1341195Speter } 1351195Speter sprintf( starthere , EXTFORMAT , p -> symbol ); 1361195Speter starthere += strlen( p -> symbol ) + 1; 1371195Speter if ( starthere >= &extname[ BUFSIZ ] ) { 1381195Speter panic( "call namelength" ); 1391195Speter } 1401195Speter putleaf( P2ICON , 0 , 0 , p2type( p ) , extname ); 1411195Speter } 1421195Speter break; 1431195Speter case FFUNC: 1441195Speter case FPROC: 1451195Speter /* 1463065Smckusic * ... (FCALL( p ))( ... 1471195Speter */ 1481195Speter putleaf( P2ICON , 0 , 0 1493065Smckusic , ADDTYPE( ADDTYPE( p_p2type , P2FTN ) , P2PTR ) 1501195Speter , "_FCALL" ); 1511195Speter putRV( 0 , cbn , p -> value[NL_OFFS] , P2PTR|P2STRTY ); 1523065Smckusic putop( P2CALL , p_p2type ); 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 */ 1641195Speter if ( p -> class == FUNC || p -> class == PROC ) { 1651195Speter for (p1 = p->chain; p1 != NIL; p1 = p1->chain) { 1661195Speter if (argv == NIL) { 1671195Speter error("Not enough arguments to %s", p->symbol); 1681195Speter return (NIL); 1691195Speter } 1701195Speter switch (p1->class) { 1711195Speter case REF: 1721195Speter /* 1731195Speter * Var parameter 1741195Speter */ 1751195Speter r = argv[1]; 1761195Speter if (r != NIL && r[0] != T_VAR) { 1771195Speter error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol); 1781195Speter break; 1791195Speter } 1801195Speter q = lvalue( (int *) argv[1], MOD , LREQ ); 1811195Speter if (q == NIL) 1821195Speter break; 1831195Speter if (q != p1->type) { 1841195Speter error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol); 1851195Speter break; 1861195Speter } 1871195Speter break; 1881195Speter case VAR: 1891195Speter /* 1901195Speter * Value parameter 1911195Speter */ 192745Speter # ifdef OBJ 1931195Speter q = rvalue(argv[1], p1->type , RREQ ); 194745Speter # endif OBJ 195745Speter # ifdef PC 1961195Speter /* 1971195Speter * structure arguments require lvalues, 1981195Speter * scalars use rvalue. 1991195Speter */ 2001195Speter switch( classify( p1 -> type ) ) { 2011195Speter case TFILE: 2021195Speter case TARY: 2031195Speter case TREC: 2041195Speter case TSET: 2051195Speter case TSTR: 2061195Speter q = rvalue( argv[1] , p1 -> type , LREQ ); 2071195Speter break; 2081195Speter case TINT: 2091195Speter case TSCAL: 2101195Speter case TBOOL: 2111195Speter case TCHAR: 2121195Speter precheck( p1 -> type , "_RANG4" , "_RSNG4" ); 2131195Speter q = rvalue( argv[1] , p1 -> type , RREQ ); 2141195Speter postcheck( p1 -> type ); 2151195Speter break; 2161195Speter default: 2171195Speter q = rvalue( argv[1] , p1 -> type , RREQ ); 2181195Speter if ( isa( p1 -> type , "d" ) 2191195Speter && isa( q , "i" ) ) { 2201195Speter putop( P2SCONV , P2DOUBLE ); 2211195Speter } 2221195Speter break; 2231195Speter } 2241195Speter # endif PC 2251195Speter if (q == NIL) 226745Speter break; 2271195Speter if (incompat(q, p1->type, argv[1])) { 2281195Speter cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol); 229745Speter break; 230745Speter } 231745Speter # ifdef OBJ 2321195Speter if (isa(p1->type, "bcsi")) 2331195Speter rangechk(p1->type, q); 2341195Speter if (q->class != STR) 2351195Speter convert(q, p1->type); 236745Speter # endif OBJ 237745Speter # ifdef PC 2381195Speter switch( classify( p1 -> type ) ) { 2391195Speter case TFILE: 2401195Speter case TARY: 2411195Speter case TREC: 2421195Speter case TSET: 2431195Speter case TSTR: 2441195Speter putstrop( P2STARG 2451195Speter , p2type( p1 -> type ) 2461195Speter , lwidth( p1 -> type ) 2471195Speter , align( p1 -> type ) ); 2481195Speter } 2491195Speter # endif PC 2501195Speter break; 2511195Speter case FFUNC: 2521195Speter /* 2531195Speter * function parameter 2541195Speter */ 2551195Speter q = flvalue( (int *) argv[1] , FFUNC ); 2561195Speter if (q == NIL) 2571195Speter break; 2581195Speter if (q != p1->type) { 2591195Speter error("Function type not identical to type of function parameter %s of %s", p1->symbol, p->symbol); 2601195Speter break; 261745Speter } 2621195Speter break; 2631195Speter case FPROC: 2641195Speter /* 2651195Speter * procedure parameter 2661195Speter */ 2671195Speter q = flvalue( (int *) argv[1] , FPROC ); 2681195Speter if (q != NIL) { 2691195Speter error("Procedure parameter %s of %s cannot have a type", p1->symbol, p->symbol); 2701195Speter } 2711195Speter break; 2721195Speter default: 2731195Speter panic("call"); 2741195Speter } 275745Speter # ifdef PC 2761195Speter /* 2771195Speter * if this is the nth (>1) argument, 2781195Speter * hang it on the left linear list of arguments 2791195Speter */ 2803065Smckusic if ( noarguments ) { 2813065Smckusic noarguments = FALSE; 2821195Speter } else { 2831195Speter putop( P2LISTOP , P2INT ); 2841195Speter } 285745Speter # endif PC 2861195Speter argv = argv[2]; 2871195Speter } 2881195Speter if (argv != NIL) { 2891195Speter error("Too many arguments to %s", p->symbol); 2901195Speter rvlist(argv); 2911195Speter return (NIL); 2921195Speter } 2931195Speter } else if ( p -> class == FFUNC || p -> class == FPROC ) { 2941195Speter /* 2951195Speter * formal routines can only have by-value parameters. 2961195Speter * this will lose for integer actuals passed to real 2971195Speter * formals, and strings which people want blank padded. 2981195Speter */ 2991195Speter # ifdef OBJ 3001195Speter cnt = 0; 3011195Speter # endif OBJ 3021195Speter for ( ; argv != NIL ; argv = argv[2] ) { 3031195Speter # ifdef OBJ 3041195Speter q = rvalue(argv[1], NIL, RREQ ); 3053063Smckusic cnt += leven(lwidth(q)); 3061195Speter # endif OBJ 3071195Speter # ifdef PC 3081195Speter /* 3091195Speter * structure arguments require lvalues, 3101195Speter * scalars use rvalue. 3111195Speter */ 3121195Speter codeoff(); 3131195Speter p1 = rvalue( argv[1] , NIL , RREQ ); 3141195Speter codeon(); 3151195Speter switch( classify( p1 ) ) { 3161195Speter case TSTR: 3173065Smckusic if ( p1 -> class == STR && slenline != line ) { 3183065Smckusic slenline = line; 3193065Smckusic ( opt( 's' ) ? (standard()): (warning()) ); 3201195Speter error("Implementation can't construct equal length strings"); 3211195Speter } 3221195Speter /* and fall through */ 3231195Speter case TFILE: 3241195Speter case TARY: 3251195Speter case TREC: 3261195Speter case TSET: 3271195Speter q = rvalue( argv[1] , p1 , LREQ ); 3281195Speter break; 3291195Speter case TINT: 3303065Smckusic if ( floatline != line ) { 3313065Smckusic floatline = line; 3323065Smckusic ( opt( 's' ) ? (standard()) : (warning()) ); 3331195Speter error("Implementation can't coerice integer to real"); 3341195Speter } 3351195Speter /* and fall through */ 3361195Speter case TSCAL: 3371195Speter case TBOOL: 3381195Speter case TCHAR: 3391195Speter default: 3401195Speter q = rvalue( argv[1] , p1 , RREQ ); 3411195Speter break; 3421195Speter } 3431195Speter switch( classify( p1 ) ) { 3441195Speter case TFILE: 3451195Speter case TARY: 3461195Speter case TREC: 3471195Speter case TSET: 3481195Speter case TSTR: 3491195Speter putstrop( P2STARG , p2type( p1 ) , 3501195Speter lwidth( p1 ) , align( p1 ) ); 3511195Speter } 3521195Speter /* 3531195Speter * if this is the nth (>1) argument, 3541195Speter * hang it on the left linear list of arguments 3551195Speter */ 3563065Smckusic if ( noarguments ) { 3573065Smckusic noarguments = FALSE; 3581195Speter } else { 3591195Speter putop( P2LISTOP , P2INT ); 3601195Speter } 3611195Speter # endif PC 3621195Speter } 3631195Speter } else { 3641195Speter panic("call class"); 365745Speter } 366745Speter # ifdef OBJ 3671195Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 3683063Smckusic put(2, PTR_RV | cbn << 8+INDX, (int)p->value[NL_OFFS]); 3693063Smckusic put(2, O_FCALL, (long)cnt); 3703063Smckusic put(2, O_FRTN, even(width(p->type))); 3711195Speter } else { 3723063Smckusic /* put(2, O_CALL | psbn << 8+INDX, (long)p->entloc); */ 3733063Smckusic put(2, O_CALL | psbn << 8, (long)p->entloc); 3741195Speter } 375745Speter # endif OBJ 376745Speter # ifdef PC 3773065Smckusic /* 3783065Smckusic * do the actual call: 3793065Smckusic * either ... p( ... ) ... 3803065Smckusic * or ... ( ...() )( ... ) ... 3813065Smckusic * and maybe an assignment. 3823065Smckusic */ 383745Speter if ( porf == FUNC ) { 3843065Smckusic switch ( p_type_class ) { 385745Speter case TBOOL: 386745Speter case TCHAR: 387745Speter case TINT: 388745Speter case TSCAL: 389745Speter case TDOUBLE: 390745Speter case TPTR: 3913065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , 3923065Smckusic p_type_p2type ); 3933065Smckusic if ( p -> class == FFUNC ) { 3943065Smckusic putop( P2ASSIGN , p_type_p2type ); 395745Speter } 396745Speter break; 397745Speter default: 3983065Smckusic putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ), 3993065Smckusic ADDTYPE( p_type_p2type , P2PTR ) , 4003065Smckusic p_type_width , p_type_align ); 4013065Smckusic putstrop( P2STASG , p_type_p2type , lwidth( p -> type ) 402745Speter , align( p -> type ) ); 403745Speter break; 404745Speter } 405745Speter } else { 4063065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT ); 4073065Smckusic } 4083065Smckusic /* 4093065Smckusic * ... , FRTN( p ) ... 4103065Smckusic */ 4113065Smckusic if ( p -> class == FFUNC || p -> class == FPROC ) { 4123065Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , 4133065Smckusic "_FRTN" ); 4143065Smckusic putRV( 0 , cbn , p -> value[ NL_OFFS ] , P2PTR | P2STRTY ); 4153065Smckusic putop( P2CALL , P2INT ); 4163065Smckusic putop( P2COMOP , P2INT ); 4173065Smckusic } 4183065Smckusic /* 4193065Smckusic * if required: 4203065Smckusic * either ... , temp ) 4213065Smckusic * or ... , &temp ) 4223065Smckusic */ 4233065Smckusic if ( porf == FUNC && temptype != P2UNDEF ) { 4243065Smckusic if ( temptype != P2STRTY ) { 4253065Smckusic putRV( 0 , cbn , tempoffset , p_type_p2type ); 426745Speter } else { 4273065Smckusic putLV( 0 , cbn , tempoffset , p_type_p2type ); 428745Speter } 4293065Smckusic putop( P2COMOP , P2INT ); 4303065Smckusic } 4313065Smckusic if ( porf == PROC ) { 432745Speter putdot( filename , line ); 433745Speter } 434745Speter # endif PC 435745Speter return (p->type); 436745Speter } 437745Speter 438745Speter rvlist(al) 439745Speter register int *al; 440745Speter { 441745Speter 442745Speter for (; al != NIL; al = al[2]) 443745Speter rvalue( (int *) al[1], NLNIL , RREQ ); 444745Speter } 445