1745Speter /* Copyright (c) 1979 Regents of the University of California */ 2745Speter 3*14727Sthien #ifndef lint 4*14727Sthien static char sccsid[] = "@(#)call.c 1.25 08/19/83"; 5*14727Sthien #endif 6745Speter 7745Speter #include "whoami.h" 8745Speter #include "0.h" 9745Speter #include "tree.h" 10745Speter #include "opcode.h" 11745Speter #include "objfmt.h" 12745Speter #ifdef PC 13745Speter # include "pc.h" 14745Speter # include "pcops.h" 15745Speter #endif PC 1611331Speter #include "tmps.h" 17*14727Sthien #include "tree_ty.h" 18745Speter 19745Speter /* 20745Speter * Call generates code for calls to 21745Speter * user defined procedures and functions 22745Speter * and is called by proc and funccod. 23745Speter * P is the result of the lookup 24745Speter * of the procedure/function symbol, 25745Speter * and porf is PROC or FUNC. 26745Speter * Psbn is the block number of p. 273065Smckusic * 283065Smckusic * the idea here is that regular scalar functions are just called, 293065Smckusic * while structure functions and formal functions have their results 303065Smckusic * stored in a temporary after the call. 313065Smckusic * structure functions do this because they return pointers 323065Smckusic * to static results, so we copy the static 333065Smckusic * and return a pointer to the copy. 343065Smckusic * formal functions do this because we have to save the result 353065Smckusic * around a call to the runtime routine which restores the display, 363065Smckusic * so we can't just leave the result lying around in registers. 373886Speter * formal calls save the address of the descriptor in a local 383886Speter * temporary, so it can be addressed for the call which restores 393886Speter * the display (FRTN). 403426Speter * calls to formal parameters pass the formal as a hidden argument 413426Speter * to a special entry point for the formal call. 423426Speter * [this is somewhat dependent on the way arguments are addressed.] 433065Smckusic * so PROCs and scalar FUNCs look like 443065Smckusic * p(...args...) 453065Smckusic * structure FUNCs look like 463065Smckusic * (temp = p(...args...),&temp) 473065Smckusic * formal FPROCs look like 484014Smckusic * ( t=p,( t -> entryaddr )(...args...,t,s),FRTN(t,s)) 493065Smckusic * formal scalar FFUNCs look like 504014Smckusic * ( t=p,temp=( t -> entryaddr )(...args...,t,s),FRTN(t,s),temp) 513065Smckusic * formal structure FFUNCs look like 524014Smckusic * (t=p,temp = ( t -> entryaddr )(...args...,t,s),FRTN(t,s),&temp) 53745Speter */ 54745Speter struct nl * 55*14727Sthien call(p, argv_node, porf, psbn) 56745Speter struct nl *p; 57*14727Sthien struct tnode *argv_node; /* list node */ 58*14727Sthien int porf, psbn; 59745Speter { 60745Speter register struct nl *p1, *q; 61*14727Sthien struct tnode *rnode; 623297Smckusic bool chk = TRUE; 634014Smckusic struct nl *savedispnp; /* temporary to hold saved display */ 64745Speter # ifdef PC 65*14727Sthien int p_type_class = classify( p -> type ); 663065Smckusic long p_type_p2type = p2type( p -> type ); 673065Smckusic bool noarguments; 683065Smckusic /* 693065Smckusic * these get used if temporaries and structures are used 703065Smckusic */ 713824Speter struct nl *tempnlp; 723065Smckusic long temptype; /* type of the temporary */ 733065Smckusic long p_type_width; 743065Smckusic long p_type_align; 753362Speter char extname[ BUFSIZ ]; 763886Speter struct nl *tempdescrp; 77745Speter # endif PC 78745Speter 794014Smckusic if (p->class == FFUNC || p->class == FPROC) { 804014Smckusic /* 814014Smckusic * allocate space to save the display for formal calls 824014Smckusic */ 83*14727Sthien savedispnp = tmpalloc( (long) sizeof display , NLNIL , NOREG ); 844014Smckusic } 85745Speter # ifdef OBJ 863426Speter if (p->class == FFUNC || p->class == FPROC) { 87*14727Sthien (void) put(2, O_LV | cbn << 8 + INDX , 884014Smckusic (int) savedispnp -> value[ NL_OFFS ] ); 89*14727Sthien (void) put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]); 903426Speter } 913426Speter if (porf == FUNC) { 92745Speter /* 93745Speter * Push some space 94745Speter * for the function return type 95745Speter */ 96*14727Sthien (void) put(2, O_PUSH, leven(-lwidth(p->type))); 973426Speter } 98745Speter # endif OBJ 99745Speter # ifdef PC 1003065Smckusic /* 1013886Speter * if this is a formal call, 1023886Speter * stash the address of the descriptor 1033886Speter * in a temporary so we can find it 1043886Speter * after the FCALL for the call to FRTN 1053886Speter */ 1063886Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 107*14727Sthien tempdescrp = tmpalloc((long) (sizeof( struct formalrtn *)), 108*14727Sthien NLNIL, REGOK ); 109*14727Sthien putRV((char *) 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 1103886Speter tempdescrp -> extra_flags , P2PTR|P2STRTY ); 111*14727Sthien putRV((char *) 0 , psbn , p -> value[ NL_OFFS ] , 1123886Speter p -> extra_flags , P2PTR|P2STRTY ); 1133886Speter putop( P2ASSIGN , P2PTR | P2STRTY ); 1143886Speter } 1153886Speter /* 1163065Smckusic * if we have to store a temporary, 1173065Smckusic * temptype will be its type, 1183065Smckusic * otherwise, it's P2UNDEF. 1193065Smckusic */ 1203065Smckusic temptype = P2UNDEF; 121745Speter if ( porf == FUNC ) { 1223065Smckusic p_type_width = width( p -> type ); 1233065Smckusic switch( p_type_class ) { 124745Speter case TSTR: 125745Speter case TSET: 126745Speter case TREC: 127745Speter case TFILE: 128745Speter case TARY: 129*14727Sthien temptype = P2STRTY; 1303065Smckusic p_type_align = align( p -> type ); 1313065Smckusic break; 1323065Smckusic default: 1333065Smckusic if ( p -> class == FFUNC ) { 134*14727Sthien temptype = p2type( p -> type ); 135745Speter } 1363065Smckusic break; 137745Speter } 1383065Smckusic if ( temptype != P2UNDEF ) { 1393824Speter tempnlp = tmpalloc(p_type_width, p -> type, NOREG); 1403065Smckusic /* 1413065Smckusic * temp 1423065Smckusic * for (temp = ... 1433065Smckusic */ 144*14727Sthien putRV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] , 145*14727Sthien tempnlp -> extra_flags , (int) temptype ); 1463065Smckusic } 147745Speter } 1481195Speter switch ( p -> class ) { 1491195Speter case FUNC: 1501195Speter case PROC: 1513065Smckusic /* 1523065Smckusic * ... p( ... 1533065Smckusic */ 1543372Speter sextname( extname , p -> symbol , BLOCKNO(p -> nl_block) ); 1553362Speter putleaf( P2ICON , 0 , 0 , p2type( p ) , extname ); 1561195Speter break; 1571195Speter case FFUNC: 1581195Speter case FPROC: 1593886Speter 1601195Speter /* 1613886Speter * ... ( t -> entryaddr )( ... 1621195Speter */ 16312902Speter /* the descriptor */ 164*14727Sthien putRV((char *) 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 1653886Speter tempdescrp -> extra_flags , P2PTR | P2STRTY ); 16612902Speter /* the entry address within the descriptor */ 1673426Speter if ( FENTRYOFFSET != 0 ) { 168*14727Sthien putleaf( P2ICON , FENTRYOFFSET , 0 , P2INT , 169*14727Sthien (char *) 0 ); 1703426Speter putop( P2PLUS , 1713426Speter ADDTYPE( 1723426Speter ADDTYPE( ADDTYPE( p2type( p ) , P2FTN ) , 1733426Speter P2PTR ) , 1743426Speter P2PTR ) ); 1753426Speter } 17612902Speter /* 17712902Speter * indirect to fetch the formal entry address 17812902Speter * with the result type of the routine. 17912902Speter */ 18012902Speter if (p -> class == FFUNC) { 18112902Speter putop( P2UNARY P2MUL , 18212902Speter ADDTYPE(ADDTYPE(p2type(p -> type), P2FTN), 18312902Speter P2PTR)); 18412902Speter } else { 18512902Speter /* procedures are int returning functions */ 18612902Speter putop( P2UNARY P2MUL , 18712902Speter ADDTYPE(ADDTYPE(P2INT, P2FTN), P2PTR)); 18812902Speter } 1891195Speter break; 1901195Speter default: 1911195Speter panic("call class"); 192745Speter } 1933065Smckusic noarguments = TRUE; 194745Speter # endif PC 195745Speter /* 196745Speter * Loop and process each of 197745Speter * arguments to the proc/func. 1983065Smckusic * ... ( ... args ... ) ... 199745Speter */ 200*14727Sthien for (p1 = plist(p); p1 != NLNIL; p1 = p1->chain) { 201*14727Sthien if (argv_node == TR_NIL) { 2023297Smckusic error("Not enough arguments to %s", p->symbol); 203*14727Sthien return (NLNIL); 2043297Smckusic } 2053297Smckusic switch (p1->class) { 2063297Smckusic case REF: 2073297Smckusic /* 2083297Smckusic * Var parameter 2093297Smckusic */ 210*14727Sthien rnode = argv_node->list_node.list; 211*14727Sthien if (rnode != TR_NIL && rnode->tag != T_VAR) { 2123297Smckusic error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol); 2133361Speter chk = FALSE; 2143297Smckusic break; 2153297Smckusic } 216*14727Sthien q = lvalue( argv_node->list_node.list, 217*14727Sthien MOD | ASGN , LREQ ); 2183297Smckusic if (q == NIL) { 2193297Smckusic chk = FALSE; 2203297Smckusic break; 2213297Smckusic } 2223297Smckusic if (q != p1->type) { 2233297Smckusic error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol); 2243361Speter chk = FALSE; 2253297Smckusic break; 2263297Smckusic } 2273297Smckusic break; 2283297Smckusic case VAR: 2293297Smckusic /* 2303297Smckusic * Value parameter 2313297Smckusic */ 232745Speter # ifdef OBJ 233*14727Sthien q = rvalue(argv_node->list_node.list, 234*14727Sthien p1->type , RREQ ); 235745Speter # endif OBJ 236745Speter # ifdef PC 2373297Smckusic /* 2383297Smckusic * structure arguments require lvalues, 2393297Smckusic * scalars use rvalue. 2403297Smckusic */ 2413297Smckusic switch( classify( p1 -> type ) ) { 2423297Smckusic case TFILE: 2433297Smckusic case TARY: 2443297Smckusic case TREC: 2453297Smckusic case TSET: 2463297Smckusic case TSTR: 247*14727Sthien q = stkrval(argv_node->list_node.list, 248*14727Sthien p1 -> type , (long) LREQ ); 249745Speter break; 2503297Smckusic case TINT: 2513297Smckusic case TSCAL: 2523297Smckusic case TBOOL: 2533297Smckusic case TCHAR: 2543297Smckusic precheck( p1 -> type , "_RANG4" , "_RSNG4" ); 255*14727Sthien q = stkrval(argv_node->list_node.list, 256*14727Sthien p1 -> type , (long) RREQ ); 25710667Speter postcheck(p1 -> type, nl+T4INT); 258745Speter break; 25910365Smckusick case TDOUBLE: 260*14727Sthien q = stkrval(argv_node->list_node.list, 261*14727Sthien p1 -> type , (long) RREQ ); 26210365Smckusick sconv(p2type(q), P2DOUBLE); 26310365Smckusick break; 2643297Smckusic default: 265*14727Sthien q = rvalue(argv_node->list_node.list, 266*14727Sthien p1 -> type , RREQ ); 2673297Smckusic break; 268745Speter } 2693297Smckusic # endif PC 2703297Smckusic if (q == NIL) { 2713297Smckusic chk = FALSE; 2723297Smckusic break; 2733297Smckusic } 274*14727Sthien if (incompat(q, p1->type, 275*14727Sthien argv_node->list_node.list)) { 2763297Smckusic cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol); 2773361Speter chk = FALSE; 2783297Smckusic break; 2793297Smckusic } 280745Speter # ifdef OBJ 2813297Smckusic if (isa(p1->type, "bcsi")) 2823297Smckusic rangechk(p1->type, q); 2833297Smckusic if (q->class != STR) 2843297Smckusic convert(q, p1->type); 285745Speter # endif OBJ 286745Speter # ifdef PC 2873297Smckusic switch( classify( p1 -> type ) ) { 2883297Smckusic case TFILE: 2893297Smckusic case TARY: 2903297Smckusic case TREC: 2913297Smckusic case TSET: 2923297Smckusic case TSTR: 2933297Smckusic putstrop( P2STARG 2943297Smckusic , p2type( p1 -> type ) 295*14727Sthien , (int) lwidth( p1 -> type ) 2963297Smckusic , align( p1 -> type ) ); 2973297Smckusic } 2981195Speter # endif PC 2993297Smckusic break; 3003297Smckusic case FFUNC: 3011195Speter /* 3023297Smckusic * function parameter 3031195Speter */ 304*14727Sthien q = flvalue(argv_node->list_node.list, p1 ); 305*14727Sthien /*chk = (chk && fcompat(q, p1));*/ 306*14727Sthien if ((chk) && (fcompat(q, p1))) 307*14727Sthien chk = TRUE; 308*14727Sthien else 309*14727Sthien chk = FALSE; 3103297Smckusic break; 3113297Smckusic case FPROC: 3121195Speter /* 3133297Smckusic * procedure parameter 3141195Speter */ 315*14727Sthien q = flvalue(argv_node->list_node.list, p1 ); 316*14727Sthien /* chk = (chk && fcompat(q, p1)); */ 317*14727Sthien if ((chk) && (fcompat(q, p1))) 318*14727Sthien chk = TRUE; 319*14727Sthien else chk = FALSE; 3203297Smckusic break; 3213297Smckusic default: 3223297Smckusic panic("call"); 3231195Speter } 3243297Smckusic # ifdef PC 3253297Smckusic /* 3263297Smckusic * if this is the nth (>1) argument, 3273297Smckusic * hang it on the left linear list of arguments 3283297Smckusic */ 3293297Smckusic if ( noarguments ) { 3303297Smckusic noarguments = FALSE; 3313297Smckusic } else { 3323297Smckusic putop( P2LISTOP , P2INT ); 3333297Smckusic } 3343297Smckusic # endif PC 335*14727Sthien argv_node = argv_node->list_node.next; 336745Speter } 337*14727Sthien if (argv_node != TR_NIL) { 3383297Smckusic error("Too many arguments to %s", p->symbol); 339*14727Sthien rvlist(argv_node); 340*14727Sthien return (NLNIL); 3413297Smckusic } 3423297Smckusic if (chk == FALSE) 343*14727Sthien return NLNIL; 344745Speter # ifdef OBJ 3451195Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 346*14727Sthien (void) put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]); 347*14727Sthien (void) put(2, O_LV | cbn << 8 + INDX , 3484014Smckusic (int) savedispnp -> value[ NL_OFFS ] ); 349*14727Sthien (void) put(1, O_FCALL); 350*14727Sthien (void) put(2, O_FRTN, even(width(p->type))); 3511195Speter } else { 352*14727Sthien (void) put(2, O_CALL | psbn << 8, (long)p->value[NL_ENTLOC]); 3531195Speter } 354745Speter # endif OBJ 355745Speter # ifdef PC 3563065Smckusic /* 3573426Speter * for formal calls: add the hidden argument 3583426Speter * which is the formal struct describing the 3593426Speter * environment of the routine. 3603426Speter * and the argument which is the address of the 3613426Speter * space into which to save the display. 3623426Speter */ 3633426Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 364*14727Sthien putRV((char *) 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 3653886Speter tempdescrp -> extra_flags , P2PTR|P2STRTY ); 3663426Speter if ( !noarguments ) { 3673426Speter putop( P2LISTOP , P2INT ); 3683426Speter } 3693426Speter noarguments = FALSE; 370*14727Sthien putLV((char *) 0 , cbn , savedispnp -> value[ NL_OFFS ] , 3714014Smckusic savedispnp -> extra_flags , P2PTR | P2STRTY ); 3724014Smckusic putop( P2LISTOP , P2INT ); 3733426Speter } 3743426Speter /* 3753065Smckusic * do the actual call: 3763065Smckusic * either ... p( ... ) ... 3773886Speter * or ... ( t -> entryaddr )( ... ) ... 3783065Smckusic * and maybe an assignment. 3793065Smckusic */ 380745Speter if ( porf == FUNC ) { 3813065Smckusic switch ( p_type_class ) { 382745Speter case TBOOL: 383745Speter case TCHAR: 384745Speter case TINT: 385745Speter case TSCAL: 386745Speter case TDOUBLE: 387745Speter case TPTR: 3883065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , 389*14727Sthien (int) p_type_p2type ); 3903065Smckusic if ( p -> class == FFUNC ) { 391*14727Sthien putop( P2ASSIGN , (int) p_type_p2type ); 392745Speter } 393745Speter break; 394745Speter default: 3953065Smckusic putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ), 396*14727Sthien (int) ADDTYPE( p_type_p2type , P2PTR ) , 397*14727Sthien (int) p_type_width ,(int) p_type_align ); 398*14727Sthien putstrop(P2STASG, (int) ADDTYPE(p_type_p2type, P2PTR), 399*14727Sthien (int) lwidth(p -> type), align(p -> type)); 400745Speter break; 401745Speter } 402745Speter } else { 4033065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT ); 4043065Smckusic } 4053065Smckusic /* 4063886Speter * ( t=p , ... , FRTN( t ) ... 4073065Smckusic */ 4083065Smckusic if ( p -> class == FFUNC || p -> class == FPROC ) { 4093886Speter putop( P2COMOP , P2INT ); 4103065Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , 4113065Smckusic "_FRTN" ); 412*14727Sthien putRV((char *) 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 4133886Speter tempdescrp -> extra_flags , P2PTR | P2STRTY ); 414*14727Sthien putLV((char *) 0 , cbn , savedispnp -> value[ NL_OFFS ] , 4154014Smckusic savedispnp -> extra_flags , P2PTR | P2STRTY ); 4164014Smckusic putop( P2LISTOP , P2INT ); 4173065Smckusic putop( P2CALL , P2INT ); 4183065Smckusic putop( P2COMOP , P2INT ); 4193065Smckusic } 4203065Smckusic /* 4213065Smckusic * if required: 4223065Smckusic * either ... , temp ) 4233065Smckusic * or ... , &temp ) 4243065Smckusic */ 4253065Smckusic if ( porf == FUNC && temptype != P2UNDEF ) { 4263065Smckusic if ( temptype != P2STRTY ) { 427*14727Sthien putRV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] , 428*14727Sthien tempnlp -> extra_flags , (int) p_type_p2type ); 429745Speter } else { 430*14727Sthien putLV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] , 431*14727Sthien tempnlp -> extra_flags , (int) p_type_p2type ); 432745Speter } 4333065Smckusic putop( P2COMOP , P2INT ); 4343065Smckusic } 4353065Smckusic if ( porf == PROC ) { 436745Speter putdot( filename , line ); 437745Speter } 438745Speter # endif PC 439745Speter return (p->type); 440745Speter } 441745Speter 442745Speter rvlist(al) 443*14727Sthien register struct tnode *al; 444745Speter { 445745Speter 446*14727Sthien for (; al != TR_NIL; al = al->list_node.next) 447*14727Sthien (void) rvalue( al->list_node.list, NLNIL , RREQ ); 448745Speter } 4493297Smckusic 4503297Smckusic /* 4513297Smckusic * check that two function/procedure namelist entries are compatible 4523297Smckusic */ 4533297Smckusic bool 4543297Smckusic fcompat( formal , actual ) 4553297Smckusic struct nl *formal; 4563297Smckusic struct nl *actual; 4573297Smckusic { 4583297Smckusic register struct nl *f_chain; 4593297Smckusic register struct nl *a_chain; 460*14727Sthien extern struct nl *plist(); 4613297Smckusic bool compat = TRUE; 4623297Smckusic 463*14727Sthien if ( formal == NLNIL || actual == NLNIL ) { 4643297Smckusic return FALSE; 4653297Smckusic } 4663297Smckusic for (a_chain = plist(actual), f_chain = plist(formal); 467*14727Sthien f_chain != NLNIL; 4683297Smckusic f_chain = f_chain->chain, a_chain = a_chain->chain) { 4693297Smckusic if (a_chain == NIL) { 4703297Smckusic error("%s %s declared on line %d has more arguments than", 4713297Smckusic parnam(formal->class), formal->symbol, 472*14727Sthien (char *) linenum(formal)); 4733297Smckusic cerror("%s %s declared on line %d", 4743297Smckusic parnam(actual->class), actual->symbol, 475*14727Sthien (char *) linenum(actual)); 4763297Smckusic return FALSE; 4773297Smckusic } 4783297Smckusic if ( a_chain -> class != f_chain -> class ) { 4793297Smckusic error("%s parameter %s of %s declared on line %d is not identical", 4803297Smckusic parnam(f_chain->class), f_chain->symbol, 481*14727Sthien formal->symbol, (char *) linenum(formal)); 4823297Smckusic cerror("with %s parameter %s of %s declared on line %d", 4833297Smckusic parnam(a_chain->class), a_chain->symbol, 484*14727Sthien actual->symbol, (char *) linenum(actual)); 4853297Smckusic compat = FALSE; 4863297Smckusic } else if (a_chain->class == FFUNC || a_chain->class == FPROC) { 487*14727Sthien /*compat = (compat && fcompat(f_chain, a_chain));*/ 488*14727Sthien if ((compat) && (fcompat(f_chain, a_chain))) 489*14727Sthien compat = TRUE; 490*14727Sthien else compat = FALSE; 4913297Smckusic } 4923297Smckusic if ((a_chain->class != FPROC && f_chain->class != FPROC) && 4933297Smckusic (a_chain->type != f_chain->type)) { 4943297Smckusic error("Type of %s parameter %s of %s declared on line %d is not identical", 4953297Smckusic parnam(f_chain->class), f_chain->symbol, 496*14727Sthien formal->symbol, (char *) linenum(formal)); 4973297Smckusic cerror("to type of %s parameter %s of %s declared on line %d", 4983297Smckusic parnam(a_chain->class), a_chain->symbol, 499*14727Sthien actual->symbol, (char *) linenum(actual)); 5003297Smckusic compat = FALSE; 5013297Smckusic } 5023297Smckusic } 5033297Smckusic if (a_chain != NIL) { 5043297Smckusic error("%s %s declared on line %d has fewer arguments than", 5053297Smckusic parnam(formal->class), formal->symbol, 506*14727Sthien (char *) linenum(formal)); 5073297Smckusic cerror("%s %s declared on line %d", 5083297Smckusic parnam(actual->class), actual->symbol, 509*14727Sthien (char *) linenum(actual)); 5103297Smckusic return FALSE; 5113297Smckusic } 5123297Smckusic return compat; 5133297Smckusic } 5143297Smckusic 5153297Smckusic char * 5163297Smckusic parnam(nltype) 5173297Smckusic int nltype; 5183297Smckusic { 5193297Smckusic switch(nltype) { 5203297Smckusic case REF: 5213297Smckusic return "var"; 5223297Smckusic case VAR: 5233297Smckusic return "value"; 5243297Smckusic case FUNC: 5253297Smckusic case FFUNC: 5263297Smckusic return "function"; 5273297Smckusic case PROC: 5283297Smckusic case FPROC: 5293297Smckusic return "procedure"; 5303297Smckusic default: 5313297Smckusic return "SNARK"; 5323297Smckusic } 5333297Smckusic } 5343297Smckusic 535*14727Sthien struct nl *plist(p) 5363297Smckusic struct nl *p; 5373297Smckusic { 5383297Smckusic switch (p->class) { 5393297Smckusic case FFUNC: 5403297Smckusic case FPROC: 5413297Smckusic return p->ptr[ NL_FCHAIN ]; 5423297Smckusic case PROC: 5433297Smckusic case FUNC: 5443297Smckusic return p->chain; 5453297Smckusic default: 546*14727Sthien { 547*14727Sthien panic("plist"); 548*14727Sthien return(NLNIL); /* this is here only so lint won't complain 549*14727Sthien panic actually aborts */ 550*14727Sthien } 551*14727Sthien 5523297Smckusic } 5533297Smckusic } 5543297Smckusic 5553297Smckusic linenum(p) 5563297Smckusic struct nl *p; 5573297Smckusic { 5583297Smckusic if (p->class == FUNC) 5593297Smckusic return p->ptr[NL_FVAR]->value[NL_LINENO]; 5603297Smckusic return p->value[NL_LINENO]; 5613297Smckusic } 562