1745Speter /* Copyright (c) 1979 Regents of the University of California */ 2745Speter 3*3065Smckusic static char sccsid[] = "@(#)call.c 1.6 03/08/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 15*3065Smckusic short slenline = 0; 16*3065Smckusic 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. 26*3065Smckusic * 27*3065Smckusic * the idea here is that regular scalar functions are just called, 28*3065Smckusic * while structure functions and formal functions have their results 29*3065Smckusic * stored in a temporary after the call. 30*3065Smckusic * structure functions do this because they return pointers 31*3065Smckusic * to static results, so we copy the static 32*3065Smckusic * and return a pointer to the copy. 33*3065Smckusic * formal functions do this because we have to save the result 34*3065Smckusic * around a call to the runtime routine which restores the display, 35*3065Smckusic * so we can't just leave the result lying around in registers. 36*3065Smckusic * so PROCs and scalar FUNCs look like 37*3065Smckusic * p(...args...) 38*3065Smckusic * structure FUNCs look like 39*3065Smckusic * (temp = p(...args...),&temp) 40*3065Smckusic * formal FPROCs look like 41*3065Smckusic * ((FCALL( p ))(...args...),FRTN( p )) 42*3065Smckusic * formal scalar FFUNCs look like 43*3065Smckusic * (temp = (FCALL( p ))(...args...),FRTN( p ),temp) 44*3065Smckusic * formal structure FFUNCs look like 45*3065Smckusic * (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; 54*3065Smckusic struct nl *p_type_class = classify( p -> type ); 55745Speter 561195Speter # ifdef OBJ 571195Speter int cnt; 581195Speter # endif OBJ 59745Speter # ifdef PC 60*3065Smckusic long p_p2type = p2type( p ); 61*3065Smckusic long p_type_p2type = p2type( p -> type ); 62*3065Smckusic bool noarguments; 63*3065Smckusic long calltype; /* type of the call */ 64*3065Smckusic /* 65*3065Smckusic * these get used if temporaries and structures are used 66*3065Smckusic */ 67*3065Smckusic long tempoffset; 68*3065Smckusic long temptype; /* type of the temporary */ 69*3065Smckusic long p_type_width; 70*3065Smckusic 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 84*3065Smckusic /* 85*3065Smckusic * if we have to store a temporary, 86*3065Smckusic * temptype will be its type, 87*3065Smckusic * otherwise, it's P2UNDEF. 88*3065Smckusic */ 89*3065Smckusic temptype = P2UNDEF; 90*3065Smckusic calltype = P2INT; 91745Speter if ( porf == FUNC ) { 92*3065Smckusic p_type_width = width( p -> type ); 93*3065Smckusic switch( p_type_class ) { 94745Speter case TSTR: 95745Speter case TSET: 96745Speter case TREC: 97745Speter case TFILE: 98745Speter case TARY: 99*3065Smckusic calltype = temptype = P2STRTY; 100*3065Smckusic p_type_align = align( p -> type ); 101*3065Smckusic break; 102*3065Smckusic default: 103*3065Smckusic if ( p -> class == FFUNC ) { 104*3065Smckusic calltype = temptype = p2type( p -> type ); 105745Speter } 106*3065Smckusic break; 107745Speter } 108*3065Smckusic if ( temptype != P2UNDEF ) { 109*3065Smckusic tempoffset = sizes[ cbn ].om_off -= p_type_width; 110*3065Smckusic putlbracket( ftnno , -tempoffset ); 111*3065Smckusic if ( tempoffset < sizes[cbn].om_max) { 112*3065Smckusic sizes[cbn].om_max = tempoffset; 113*3065Smckusic } 114*3065Smckusic /* 115*3065Smckusic * temp 116*3065Smckusic * for (temp = ... 117*3065Smckusic */ 118*3065Smckusic putRV( 0 , cbn , tempoffset , temptype ); 119*3065Smckusic } 120745Speter } 1211195Speter switch ( p -> class ) { 1221195Speter case FUNC: 1231195Speter case PROC: 124*3065Smckusic /* 125*3065Smckusic * ... p( ... 126*3065Smckusic */ 1271195Speter { 1281195Speter char extname[ BUFSIZ ]; 1291195Speter char *starthere; 1301195Speter int funcbn; 1311195Speter int i; 132745Speter 1331195Speter starthere = &extname[0]; 1341195Speter funcbn = p -> nl_block & 037; 1351195Speter for ( i = 1 ; i < funcbn ; i++ ) { 1361195Speter sprintf( starthere , EXTFORMAT , enclosing[ i ] ); 1371195Speter starthere += strlen( enclosing[ i ] ) + 1; 1381195Speter } 1391195Speter sprintf( starthere , EXTFORMAT , p -> symbol ); 1401195Speter starthere += strlen( p -> symbol ) + 1; 1411195Speter if ( starthere >= &extname[ BUFSIZ ] ) { 1421195Speter panic( "call namelength" ); 1431195Speter } 1441195Speter putleaf( P2ICON , 0 , 0 , p2type( p ) , extname ); 1451195Speter } 1461195Speter break; 1471195Speter case FFUNC: 1481195Speter case FPROC: 1491195Speter /* 150*3065Smckusic * ... (FCALL( p ))( ... 1511195Speter */ 1521195Speter putleaf( P2ICON , 0 , 0 153*3065Smckusic , ADDTYPE( ADDTYPE( p_p2type , P2FTN ) , P2PTR ) 1541195Speter , "_FCALL" ); 1551195Speter putRV( 0 , cbn , p -> value[NL_OFFS] , P2PTR|P2STRTY ); 156*3065Smckusic putop( P2CALL , p_p2type ); 1571195Speter break; 1581195Speter default: 1591195Speter panic("call class"); 160745Speter } 161*3065Smckusic noarguments = TRUE; 162745Speter # endif PC 163745Speter /* 164745Speter * Loop and process each of 165745Speter * arguments to the proc/func. 166*3065Smckusic * ... ( ... args ... ) ... 167745Speter */ 1681195Speter if ( p -> class == FUNC || p -> class == PROC ) { 1691195Speter for (p1 = p->chain; p1 != NIL; p1 = p1->chain) { 1701195Speter if (argv == NIL) { 1711195Speter error("Not enough arguments to %s", p->symbol); 1721195Speter return (NIL); 1731195Speter } 1741195Speter switch (p1->class) { 1751195Speter case REF: 1761195Speter /* 1771195Speter * Var parameter 1781195Speter */ 1791195Speter r = argv[1]; 1801195Speter if (r != NIL && r[0] != T_VAR) { 1811195Speter error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol); 1821195Speter break; 1831195Speter } 1841195Speter q = lvalue( (int *) argv[1], MOD , LREQ ); 1851195Speter if (q == NIL) 1861195Speter break; 1871195Speter if (q != p1->type) { 1881195Speter error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol); 1891195Speter break; 1901195Speter } 1911195Speter break; 1921195Speter case VAR: 1931195Speter /* 1941195Speter * Value parameter 1951195Speter */ 196745Speter # ifdef OBJ 1971195Speter q = rvalue(argv[1], p1->type , RREQ ); 198745Speter # endif OBJ 199745Speter # ifdef PC 2001195Speter /* 2011195Speter * structure arguments require lvalues, 2021195Speter * scalars use rvalue. 2031195Speter */ 2041195Speter switch( classify( p1 -> type ) ) { 2051195Speter case TFILE: 2061195Speter case TARY: 2071195Speter case TREC: 2081195Speter case TSET: 2091195Speter case TSTR: 2101195Speter q = rvalue( argv[1] , p1 -> type , LREQ ); 2111195Speter break; 2121195Speter case TINT: 2131195Speter case TSCAL: 2141195Speter case TBOOL: 2151195Speter case TCHAR: 2161195Speter precheck( p1 -> type , "_RANG4" , "_RSNG4" ); 2171195Speter q = rvalue( argv[1] , p1 -> type , RREQ ); 2181195Speter postcheck( p1 -> type ); 2191195Speter break; 2201195Speter default: 2211195Speter q = rvalue( argv[1] , p1 -> type , RREQ ); 2221195Speter if ( isa( p1 -> type , "d" ) 2231195Speter && isa( q , "i" ) ) { 2241195Speter putop( P2SCONV , P2DOUBLE ); 2251195Speter } 2261195Speter break; 2271195Speter } 2281195Speter # endif PC 2291195Speter if (q == NIL) 230745Speter break; 2311195Speter if (incompat(q, p1->type, argv[1])) { 2321195Speter cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol); 233745Speter break; 234745Speter } 235745Speter # ifdef OBJ 2361195Speter if (isa(p1->type, "bcsi")) 2371195Speter rangechk(p1->type, q); 2381195Speter if (q->class != STR) 2391195Speter convert(q, p1->type); 240745Speter # endif OBJ 241745Speter # ifdef PC 2421195Speter switch( classify( p1 -> type ) ) { 2431195Speter case TFILE: 2441195Speter case TARY: 2451195Speter case TREC: 2461195Speter case TSET: 2471195Speter case TSTR: 2481195Speter putstrop( P2STARG 2491195Speter , p2type( p1 -> type ) 2501195Speter , lwidth( p1 -> type ) 2511195Speter , align( p1 -> type ) ); 2521195Speter } 2531195Speter # endif PC 2541195Speter break; 2551195Speter case FFUNC: 2561195Speter /* 2571195Speter * function parameter 2581195Speter */ 2591195Speter q = flvalue( (int *) argv[1] , FFUNC ); 2601195Speter if (q == NIL) 2611195Speter break; 2621195Speter if (q != p1->type) { 2631195Speter error("Function type not identical to type of function parameter %s of %s", p1->symbol, p->symbol); 2641195Speter break; 265745Speter } 2661195Speter break; 2671195Speter case FPROC: 2681195Speter /* 2691195Speter * procedure parameter 2701195Speter */ 2711195Speter q = flvalue( (int *) argv[1] , FPROC ); 2721195Speter if (q != NIL) { 2731195Speter error("Procedure parameter %s of %s cannot have a type", p1->symbol, p->symbol); 2741195Speter } 2751195Speter break; 2761195Speter default: 2771195Speter panic("call"); 2781195Speter } 279745Speter # ifdef PC 2801195Speter /* 2811195Speter * if this is the nth (>1) argument, 2821195Speter * hang it on the left linear list of arguments 2831195Speter */ 284*3065Smckusic if ( noarguments ) { 285*3065Smckusic noarguments = FALSE; 2861195Speter } else { 2871195Speter putop( P2LISTOP , P2INT ); 2881195Speter } 289745Speter # endif PC 2901195Speter argv = argv[2]; 2911195Speter } 2921195Speter if (argv != NIL) { 2931195Speter error("Too many arguments to %s", p->symbol); 2941195Speter rvlist(argv); 2951195Speter return (NIL); 2961195Speter } 2971195Speter } else if ( p -> class == FFUNC || p -> class == FPROC ) { 2981195Speter /* 2991195Speter * formal routines can only have by-value parameters. 3001195Speter * this will lose for integer actuals passed to real 3011195Speter * formals, and strings which people want blank padded. 3021195Speter */ 3031195Speter # ifdef OBJ 3041195Speter cnt = 0; 3051195Speter # endif OBJ 3061195Speter for ( ; argv != NIL ; argv = argv[2] ) { 3071195Speter # ifdef OBJ 3081195Speter q = rvalue(argv[1], NIL, RREQ ); 3093063Smckusic cnt += leven(lwidth(q)); 3101195Speter # endif OBJ 3111195Speter # ifdef PC 3121195Speter /* 3131195Speter * structure arguments require lvalues, 3141195Speter * scalars use rvalue. 3151195Speter */ 3161195Speter codeoff(); 3171195Speter p1 = rvalue( argv[1] , NIL , RREQ ); 3181195Speter codeon(); 3191195Speter switch( classify( p1 ) ) { 3201195Speter case TSTR: 321*3065Smckusic if ( p1 -> class == STR && slenline != line ) { 322*3065Smckusic slenline = line; 323*3065Smckusic ( opt( 's' ) ? (standard()): (warning()) ); 3241195Speter error("Implementation can't construct equal length strings"); 3251195Speter } 3261195Speter /* and fall through */ 3271195Speter case TFILE: 3281195Speter case TARY: 3291195Speter case TREC: 3301195Speter case TSET: 3311195Speter q = rvalue( argv[1] , p1 , LREQ ); 3321195Speter break; 3331195Speter case TINT: 334*3065Smckusic if ( floatline != line ) { 335*3065Smckusic floatline = line; 336*3065Smckusic ( opt( 's' ) ? (standard()) : (warning()) ); 3371195Speter error("Implementation can't coerice integer to real"); 3381195Speter } 3391195Speter /* and fall through */ 3401195Speter case TSCAL: 3411195Speter case TBOOL: 3421195Speter case TCHAR: 3431195Speter default: 3441195Speter q = rvalue( argv[1] , p1 , RREQ ); 3451195Speter break; 3461195Speter } 3471195Speter switch( classify( p1 ) ) { 3481195Speter case TFILE: 3491195Speter case TARY: 3501195Speter case TREC: 3511195Speter case TSET: 3521195Speter case TSTR: 3531195Speter putstrop( P2STARG , p2type( p1 ) , 3541195Speter lwidth( p1 ) , align( p1 ) ); 3551195Speter } 3561195Speter /* 3571195Speter * if this is the nth (>1) argument, 3581195Speter * hang it on the left linear list of arguments 3591195Speter */ 360*3065Smckusic if ( noarguments ) { 361*3065Smckusic noarguments = FALSE; 3621195Speter } else { 3631195Speter putop( P2LISTOP , P2INT ); 3641195Speter } 3651195Speter # endif PC 3661195Speter } 3671195Speter } else { 3681195Speter panic("call class"); 369745Speter } 370745Speter # ifdef OBJ 3711195Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 3723063Smckusic put(2, PTR_RV | cbn << 8+INDX, (int)p->value[NL_OFFS]); 3733063Smckusic put(2, O_FCALL, (long)cnt); 3743063Smckusic put(2, O_FRTN, even(width(p->type))); 3751195Speter } else { 3763063Smckusic /* put(2, O_CALL | psbn << 8+INDX, (long)p->entloc); */ 3773063Smckusic put(2, O_CALL | psbn << 8, (long)p->entloc); 3781195Speter } 379745Speter # endif OBJ 380745Speter # ifdef PC 381*3065Smckusic /* 382*3065Smckusic * do the actual call: 383*3065Smckusic * either ... p( ... ) ... 384*3065Smckusic * or ... ( ...() )( ... ) ... 385*3065Smckusic * and maybe an assignment. 386*3065Smckusic */ 387745Speter if ( porf == FUNC ) { 388*3065Smckusic switch ( p_type_class ) { 389745Speter case TBOOL: 390745Speter case TCHAR: 391745Speter case TINT: 392745Speter case TSCAL: 393745Speter case TDOUBLE: 394745Speter case TPTR: 395*3065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , 396*3065Smckusic p_type_p2type ); 397*3065Smckusic if ( p -> class == FFUNC ) { 398*3065Smckusic putop( P2ASSIGN , p_type_p2type ); 399745Speter } 400745Speter break; 401745Speter default: 402*3065Smckusic putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ), 403*3065Smckusic ADDTYPE( p_type_p2type , P2PTR ) , 404*3065Smckusic p_type_width , p_type_align ); 405*3065Smckusic putstrop( P2STASG , p_type_p2type , lwidth( p -> type ) 406745Speter , align( p -> type ) ); 407745Speter break; 408745Speter } 409745Speter } else { 410*3065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT ); 411*3065Smckusic } 412*3065Smckusic /* 413*3065Smckusic * ... , FRTN( p ) ... 414*3065Smckusic */ 415*3065Smckusic if ( p -> class == FFUNC || p -> class == FPROC ) { 416*3065Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , 417*3065Smckusic "_FRTN" ); 418*3065Smckusic putRV( 0 , cbn , p -> value[ NL_OFFS ] , P2PTR | P2STRTY ); 419*3065Smckusic putop( P2CALL , P2INT ); 420*3065Smckusic putop( P2COMOP , P2INT ); 421*3065Smckusic } 422*3065Smckusic /* 423*3065Smckusic * if required: 424*3065Smckusic * either ... , temp ) 425*3065Smckusic * or ... , &temp ) 426*3065Smckusic */ 427*3065Smckusic if ( porf == FUNC && temptype != P2UNDEF ) { 428*3065Smckusic if ( temptype != P2STRTY ) { 429*3065Smckusic putRV( 0 , cbn , tempoffset , p_type_p2type ); 430745Speter } else { 431*3065Smckusic putLV( 0 , cbn , tempoffset , p_type_p2type ); 432745Speter } 433*3065Smckusic putop( P2COMOP , P2INT ); 434*3065Smckusic } 435*3065Smckusic if ( porf == PROC ) { 436745Speter putdot( filename , line ); 437745Speter } 438745Speter # endif PC 439745Speter return (p->type); 440745Speter } 441745Speter 442745Speter rvlist(al) 443745Speter register int *al; 444745Speter { 445745Speter 446745Speter for (; al != NIL; al = al[2]) 447745Speter rvalue( (int *) al[1], NLNIL , RREQ ); 448745Speter } 449