xref: /original-bsd/usr.bin/pascal/src/call.c (revision f052b07a)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)call.c	5.3 (Berkeley) 11/12/86";
9 #endif not lint
10 
11 #include "whoami.h"
12 #include "0.h"
13 #include "tree.h"
14 #include "opcode.h"
15 #include "objfmt.h"
16 #include "align.h"
17 #ifdef PC
18 #   include "pc.h"
19 #   include <pcc.h>
20 #endif PC
21 #include "tmps.h"
22 #include "tree_ty.h"
23 
24 /*
25  * Call generates code for calls to
26  * user defined procedures and functions
27  * and is called by proc and funccod.
28  * P is the result of the lookup
29  * of the procedure/function symbol,
30  * and porf is PROC or FUNC.
31  * Psbn is the block number of p.
32  *
33  *	the idea here is that regular scalar functions are just called,
34  *	while structure functions and formal functions have their results
35  *	stored in a temporary after the call.
36  *	structure functions do this because they return pointers
37  *	to static results, so we copy the static
38  *	and return a pointer to the copy.
39  *	formal functions do this because we have to save the result
40  *	around a call to the runtime routine which restores the display,
41  *	so we can't just leave the result lying around in registers.
42  *	formal calls save the address of the descriptor in a local
43  *	temporary, so it can be addressed for the call which restores
44  *	the display (FRTN).
45  *	calls to formal parameters pass the formal as a hidden argument
46  *	to a special entry point for the formal call.
47  *	[this is somewhat dependent on the way arguments are addressed.]
48  *	so PROCs and scalar FUNCs look like
49  *		p(...args...)
50  *	structure FUNCs look like
51  *		(temp = p(...args...),&temp)
52  *	formal FPROCs look like
53  *		( t=p,( t -> entryaddr )(...args...,t,s),FRTN(t,s))
54  *	formal scalar FFUNCs look like
55  *		( t=p,temp=( t -> entryaddr )(...args...,t,s),FRTN(t,s),temp)
56  *	formal structure FFUNCs look like
57  *		(t=p,temp = ( t -> entryaddr )(...args...,t,s),FRTN(t,s),&temp)
58  */
59 struct nl *
60 call(p, argv_node, porf, psbn)
61 	struct nl *p;
62 	struct tnode	*argv_node;	/* list node */
63 	int porf, psbn;
64 {
65 	register struct nl *p1, *q, *p2;
66 	register struct nl *ptype, *ctype;
67 	struct tnode *rnode;
68 	int i, j, d;
69 	bool chk = TRUE;
70  	struct nl	*savedispnp;	/* temporary to hold saved display */
71 #	ifdef PC
72 	    int		p_type_class = classify( p -> type );
73 	    long	p_type_p2type = p2type( p -> type );
74 	    bool	noarguments;
75 		/*
76 		 *	these get used if temporaries and structures are used
77 		 */
78 	    struct nl	*tempnlp;
79 	    long	temptype;	/* type of the temporary */
80 	    long	p_type_width;
81 	    long	p_type_align;
82 	    char	extname[ BUFSIZ ];
83 	    struct nl	*tempdescrp;
84 #	endif PC
85 
86          if (p->class == FFUNC || p->class == FPROC) {
87  	    /*
88  	     * allocate space to save the display for formal calls
89  	     */
90 	    savedispnp = tmpalloc( (long) sizeof display , NLNIL , NOREG );
91  	}
92 #	ifdef OBJ
93 	    if (p->class == FFUNC || p->class == FPROC) {
94  		(void) put(2, O_LV | cbn << 8 + INDX ,
95  			(int) savedispnp -> value[ NL_OFFS ] );
96 		(void) put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]);
97 	    }
98 	    if (porf == FUNC) {
99 		    /*
100 		     * Push some space
101 		     * for the function return type
102 		     */
103 		    (void) put(2, O_PUSH,
104 			-roundup(lwidth(p->type), (long) A_STACK));
105 	    }
106 #	endif OBJ
107 #	ifdef PC
108 		/*
109 		 *	if this is a formal call,
110 		 *	stash the address of the descriptor
111 		 *	in a temporary so we can find it
112 		 *	after the FCALL for the call to FRTN
113 		 */
114 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
115 		tempdescrp = tmpalloc((long) (sizeof( struct formalrtn *)),
116 					NLNIL, REGOK );
117 		putRV((char *) 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
118 			tempdescrp -> extra_flags , PCCTM_PTR|PCCT_STRTY );
119 		putRV((char *) 0 , psbn , p -> value[ NL_OFFS ] ,
120 			p -> extra_flags , PCCTM_PTR|PCCT_STRTY );
121 		putop( PCC_ASSIGN , PCCTM_PTR | PCCT_STRTY );
122 	    }
123 		/*
124 		 *	if we have to store a temporary,
125 		 *	temptype will be its type,
126 		 *	otherwise, it's PCCT_UNDEF.
127 		 */
128 	    temptype = PCCT_UNDEF;
129 	    if ( porf == FUNC ) {
130 		p_type_width = width( p -> type );
131 		switch( p_type_class ) {
132 		    case TSTR:
133 		    case TSET:
134 		    case TREC:
135 		    case TFILE:
136 		    case TARY:
137 			temptype = PCCT_STRTY;
138 			p_type_align = align( p -> type );
139 			break;
140 		    default:
141 			if ( p -> class == FFUNC ) {
142 			    temptype = p2type( p -> type );
143 			}
144 			break;
145 		}
146 		if ( temptype != PCCT_UNDEF ) {
147 		    tempnlp = tmpalloc(p_type_width, p -> type, NOREG);
148 			/*
149 			 *	temp
150 			 *	for (temp = ...
151 			 */
152 		    putRV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
153 			    tempnlp -> extra_flags , (int) temptype );
154 		}
155 	    }
156 	    switch ( p -> class ) {
157 		case FUNC:
158 		case PROC:
159 			/*
160 			 *	... p( ...
161 			 */
162 		    sextname( extname , p -> symbol , BLOCKNO(p -> nl_block) );
163 		    putleaf( PCC_ICON , 0 , 0 , p2type( p ) , extname );
164 		    break;
165 		case FFUNC:
166 		case FPROC:
167 
168 			    /*
169 			     *	... ( t -> entryaddr )( ...
170 			     */
171 			    /* 	the descriptor */
172 			putRV((char *) 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
173 				tempdescrp -> extra_flags , PCCTM_PTR | PCCT_STRTY );
174 			    /*	the entry address within the descriptor */
175 			if ( FENTRYOFFSET != 0 ) {
176 			    putleaf( PCC_ICON , FENTRYOFFSET , 0 , PCCT_INT ,
177 						(char *) 0 );
178 			    putop( PCC_PLUS ,
179 				PCCM_ADDTYPE(
180 				    PCCM_ADDTYPE( PCCM_ADDTYPE( p2type( p ) , PCCTM_FTN ) ,
181 					    PCCTM_PTR ) ,
182 					PCCTM_PTR ) );
183 			}
184 			    /*
185 			     *	indirect to fetch the formal entry address
186 			     *	with the result type of the routine.
187 			     */
188 			if (p -> class == FFUNC) {
189 			    putop( PCCOM_UNARY PCC_MUL ,
190 				PCCM_ADDTYPE(PCCM_ADDTYPE(p2type(p -> type), PCCTM_FTN),
191 					PCCTM_PTR));
192 			} else {
193 				/* procedures are int returning functions */
194 			    putop( PCCOM_UNARY PCC_MUL ,
195 				PCCM_ADDTYPE(PCCM_ADDTYPE(PCCT_INT, PCCTM_FTN), PCCTM_PTR));
196 			}
197 			break;
198 		default:
199 			panic("call class");
200 	    }
201 	    noarguments = TRUE;
202 #	endif PC
203 	/*
204 	 * Loop and process each of
205 	 * arguments to the proc/func.
206 	 *	... ( ... args ... ) ...
207 	 */
208 	ptype = NIL;
209 	for (p1 = plist(p); p1 != NLNIL; p1 = p1->chain) {
210 	    if (argv_node == TR_NIL) {
211 		    error("Not enough arguments to %s", p->symbol);
212 		    return (NLNIL);
213 	    }
214 	    switch (p1->class) {
215 		case REF:
216 			/*
217 			 * Var parameter
218 			 */
219 			rnode = argv_node->list_node.list;
220 			if (rnode != TR_NIL && rnode->tag != T_VAR) {
221 				error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol);
222 				chk = FALSE;
223 				break;
224 			}
225 			q = lvalue( argv_node->list_node.list,
226 					MOD | ASGN , LREQ );
227 			if (q == NIL) {
228 				chk = FALSE;
229 				break;
230 			}
231 			p2 = p1->type;
232 			if (p2 == NLNIL || p2->chain == NLNIL || p2->chain->class != CRANGE) {
233 			    if (q != p2) {
234 				error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol);
235 				chk = FALSE;
236 			    }
237 			    break;
238 			} else {
239 			    /* conformant array */
240 			    if (p1 == ptype) {
241 				if (q != ctype) {
242 				    error("Conformant array parameters in the same specification must be the same type.");
243 				    goto conf_err;
244 				}
245 			    } else {
246 				if (classify(q) != TARY && classify(q) != TSTR) {
247 				    error("Array type required for var parameter %s of %s",p1->symbol,p->symbol);
248 				    goto conf_err;
249 				}
250 				/* check base type of array */
251 				if (p2->type != q->type) {
252 				    error("Base type of array not identical to that of conformant array parameter %s of %s", p1->symbol, p->symbol);
253 				    goto conf_err;
254 				}
255 				if (p2->value[0] != q->value[0]) {
256 				    error("Subscript number mismatch on conformant array parameter %s of %s", p1->symbol, p->symbol);
257 				    /* Don't process array bounds & width */
258 conf_err:			    if (p1->chain->type->class == CRANGE) {
259 					d = p1->value[0];
260 					for (i = 1; i <= d; i++) {
261 					    /* for each subscript, pass by
262 					     * bounds and width
263 					     */
264 					    p1 = p1->chain->chain->chain;
265 					}
266 				    }
267 				    ptype = ctype = NLNIL;
268 				    chk = FALSE;
269 				    break;
270 				}
271 				/*
272 				 * Save array type for all parameters with same
273 				 * specification.
274 				 */
275 				ctype = q;
276 				ptype = p2;
277 				/*
278 				 * If at end of conformant array list,
279 				 * get bounds.
280 				 */
281 				if (p1->chain->type->class == CRANGE) {
282 				    /* check each subscript, put on stack */
283 				    d = ptype->value[0];
284 				    q = ctype;
285 				    for (i = 1; i <= d; i++) {
286 					p1 = p1->chain;
287 					q = q->chain;
288 					if (incompat(q, p1->type, TR_NIL)){
289 					    error("Subscript type not conformable with parameter %s of %s", p1->symbol, p->symbol);
290 					    chk = FALSE;
291 					    break;
292 					}
293 					/* Put lower and upper bound & width */
294 #					ifdef OBJ
295 					if (q->type->class == CRANGE) {
296 					    putcbnds(q->type);
297 					} else {
298 					    put(2, width(p1->type) <= 2 ? O_CON2
299 						: O_CON4, q->range[0]);
300 					    put(2, width(p1->type) <= 2 ? O_CON2
301 						: O_CON4, q->range[1]);
302 					    put(2, width(p1->type) <= 2 ? O_CON2
303 						: O_CON4, aryconst(ctype,i));
304 					}
305 #					endif OBJ
306 #					ifdef PC
307 					if (q->type->class == CRANGE) {
308 					    for (j = 1; j <= 3; j++) {
309 						p2 = p->nptr[j];
310 						putRV(p2->symbol, (p2->nl_block
311 						    & 037), p2->value[0],
312 						    p2->extra_flags,p2type(p2));
313 						putop(PCC_CM, PCCT_INT);
314 					    }
315 					} else {
316 					    putleaf(PCC_ICON, q->range[0], 0,PCCT_INT,0);
317 					    putop( PCC_CM , PCCT_INT );
318 					    putleaf(PCC_ICON, q->range[1], 0,PCCT_INT,0);
319 					    putop( PCC_CM , PCCT_INT );
320 					    putleaf(PCC_ICON,aryconst(ctype,i),0,PCCT_INT,0);
321 					    putop( PCC_CM , PCCT_INT );
322 					}
323 #					endif PC
324 					p1 = p1->chain->chain;
325 				    }
326 				}
327 			    }
328 			}
329 			break;
330 		case VAR:
331 			/*
332 			 * Value parameter
333 			 */
334 #			ifdef OBJ
335 			    q = rvalue(argv_node->list_node.list,
336 					p1->type , RREQ );
337 #			endif OBJ
338 #			ifdef PC
339 				/*
340 				 * structure arguments require lvalues,
341 				 * scalars use rvalue.
342 				 */
343 			    switch( classify( p1 -> type ) ) {
344 				case TFILE:
345 				case TARY:
346 				case TREC:
347 				case TSET:
348 				case TSTR:
349 				q = stkrval(argv_node->list_node.list,
350 						p1 -> type , (long) LREQ );
351 				    break;
352 				case TINT:
353 				case TSCAL:
354 				case TBOOL:
355 				case TCHAR:
356 				    precheck( p1 -> type , "_RANG4" , "_RSNG4" );
357 				q = stkrval(argv_node->list_node.list,
358 						p1 -> type , (long) RREQ );
359 				    postcheck(p1 -> type, nl+T4INT);
360 				    break;
361 				case TDOUBLE:
362 				q = stkrval(argv_node->list_node.list,
363 						p1 -> type , (long) RREQ );
364 				    sconv(p2type(q), PCCT_DOUBLE);
365 				    break;
366 				default:
367 				    q = rvalue(argv_node->list_node.list,
368 						p1 -> type , RREQ );
369 				    break;
370 			    }
371 #			endif PC
372 			if (q == NIL) {
373 				chk = FALSE;
374 				break;
375 			}
376 			if (incompat(q, p1->type,
377 				argv_node->list_node.list)) {
378 				cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol);
379 				chk = FALSE;
380 				break;
381 			}
382 #			ifdef OBJ
383 			    if (isa(p1->type, "bcsi"))
384 				    rangechk(p1->type, q);
385 			    if (q->class != STR)
386 				    convert(q, p1->type);
387 #			endif OBJ
388 #			ifdef PC
389 			    switch( classify( p1 -> type ) ) {
390 				case TFILE:
391 				case TARY:
392 				case TREC:
393 				case TSET:
394 				case TSTR:
395 					putstrop( PCC_STARG
396 					    , p2type( p1 -> type )
397 					    , (int) lwidth( p1 -> type )
398 					    , align( p1 -> type ) );
399 			    }
400 #			endif PC
401 			break;
402 		case FFUNC:
403 			/*
404 			 * function parameter
405 			 */
406 			q = flvalue(argv_node->list_node.list, p1 );
407 			/*chk = (chk && fcompat(q, p1));*/
408 			if ((chk) && (fcompat(q, p1)))
409 			    chk = TRUE;
410 			else
411 			    chk = FALSE;
412 			break;
413 		case FPROC:
414 			/*
415 			 * procedure parameter
416 			 */
417 			q = flvalue(argv_node->list_node.list, p1 );
418 			/* chk = (chk && fcompat(q, p1)); */
419 			if ((chk) && (fcompat(q, p1)))
420 			    chk = TRUE;
421 			else chk = FALSE;
422 			break;
423 		default:
424 			panic("call");
425 	    }
426 #	    ifdef PC
427 		    /*
428 		     *	if this is the nth (>1) argument,
429 		     *	hang it on the left linear list of arguments
430 		     */
431 		if ( noarguments ) {
432 			noarguments = FALSE;
433 		} else {
434 			putop( PCC_CM , PCCT_INT );
435 		}
436 #	    endif PC
437 	    argv_node = argv_node->list_node.next;
438 	}
439 	if (argv_node != TR_NIL) {
440 		error("Too many arguments to %s", p->symbol);
441 		rvlist(argv_node);
442 		return (NLNIL);
443 	}
444 	if (chk == FALSE)
445 		return NLNIL;
446 #	ifdef OBJ
447 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
448 		(void) put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]);
449  		(void) put(2, O_LV | cbn << 8 + INDX ,
450  			(int) savedispnp -> value[ NL_OFFS ] );
451 		(void) put(1, O_FCALL);
452 		(void) put(2, O_FRTN, roundup(width(p->type), (long) A_STACK));
453 	    } else {
454 		(void) put(2, O_CALL | psbn << 8, (long)p->value[NL_ENTLOC]);
455 	    }
456 #	endif OBJ
457 #	ifdef PC
458 		/*
459 		 *	for formal calls: add the hidden argument
460 		 *	which is the formal struct describing the
461 		 *	environment of the routine.
462 		 *	and the argument which is the address of the
463 		 *	space into which to save the display.
464 		 */
465 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
466 		putRV((char *) 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
467 			tempdescrp -> extra_flags , PCCTM_PTR|PCCT_STRTY );
468 		if ( !noarguments ) {
469 		    putop( PCC_CM , PCCT_INT );
470 		}
471 		noarguments = FALSE;
472  		putLV((char *) 0 , cbn , savedispnp -> value[ NL_OFFS ] ,
473  			savedispnp -> extra_flags , PCCTM_PTR | PCCT_STRTY );
474  		putop( PCC_CM , PCCT_INT );
475 	    }
476 		/*
477 		 *	do the actual call:
478 		 *	    either	... p( ... ) ...
479 		 *	    or		... ( t -> entryaddr )( ... ) ...
480 		 *	and maybe an assignment.
481 		 */
482 	    if ( porf == FUNC ) {
483 		switch ( p_type_class ) {
484 		    case TBOOL:
485 		    case TCHAR:
486 		    case TINT:
487 		    case TSCAL:
488 		    case TDOUBLE:
489 		    case TPTR:
490 			putop( ( noarguments ? PCCOM_UNARY PCC_CALL : PCC_CALL ) ,
491 				(int) p_type_p2type );
492 			if ( p -> class == FFUNC ) {
493 			    putop( PCC_ASSIGN , (int) p_type_p2type );
494 			}
495 			break;
496 		    default:
497 			putstrop( ( noarguments ? PCCOM_UNARY PCC_STCALL : PCC_STCALL ),
498 				(int) PCCM_ADDTYPE( p_type_p2type , PCCTM_PTR ) ,
499 				(int) p_type_width ,(int) p_type_align );
500 			putstrop(PCC_STASG, (int) PCCM_ADDTYPE(p_type_p2type, PCCTM_PTR),
501 				(int) lwidth(p -> type), align(p -> type));
502 			break;
503 		}
504 	    } else {
505 		putop( ( noarguments ? PCCOM_UNARY PCC_CALL : PCC_CALL ) , PCCT_INT );
506 	    }
507 		/*
508 		 *	( t=p , ... , FRTN( t ) ...
509 		 */
510 	    if ( p -> class == FFUNC || p -> class == FPROC ) {
511 		putop( PCC_COMOP , PCCT_INT );
512 		putleaf( PCC_ICON , 0 , 0 , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR ) ,
513 			"_FRTN" );
514 		putRV((char *) 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
515 			tempdescrp -> extra_flags , PCCTM_PTR | PCCT_STRTY );
516  		putLV((char *) 0 , cbn , savedispnp -> value[ NL_OFFS ] ,
517  			savedispnp -> extra_flags , PCCTM_PTR | PCCT_STRTY );
518  		putop( PCC_CM , PCCT_INT );
519 		putop( PCC_CALL , PCCT_INT );
520 		putop( PCC_COMOP , PCCT_INT );
521 	    }
522 		/*
523 		 *	if required:
524 		 *	either	... , temp )
525 		 *	or	... , &temp )
526 		 */
527 	    if ( porf == FUNC && temptype != PCCT_UNDEF ) {
528 		if ( temptype != PCCT_STRTY ) {
529 		    putRV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
530 			    tempnlp -> extra_flags , (int) p_type_p2type );
531 		} else {
532 		    putLV((char *) 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
533 			    tempnlp -> extra_flags , (int) p_type_p2type );
534 		}
535 		putop( PCC_COMOP , PCCT_INT );
536 	    }
537 	    if ( porf == PROC ) {
538 		putdot( filename , line );
539 	    }
540 #	endif PC
541 	return (p->type);
542 }
543 
544 rvlist(al)
545 	register struct tnode *al;
546 {
547 
548 	for (; al != TR_NIL; al = al->list_node.next)
549 		(void) rvalue( al->list_node.list, NLNIL , RREQ );
550 }
551 
552     /*
553      *	check that two function/procedure namelist entries are compatible
554      */
555 bool
556 fcompat( formal , actual )
557     struct nl	*formal;
558     struct nl	*actual;
559 {
560     register struct nl	*f_chain;
561     register struct nl	*a_chain;
562     extern struct nl	*plist();
563     bool compat = TRUE;
564 
565     if ( formal == NLNIL || actual == NLNIL ) {
566 	return FALSE;
567     }
568     for (a_chain = plist(actual), f_chain = plist(formal);
569          f_chain != NLNIL;
570 	 f_chain = f_chain->chain, a_chain = a_chain->chain) {
571 	if (a_chain == NIL) {
572 	    error("%s %s declared on line %d has more arguments than",
573 		parnam(formal->class), formal->symbol,
574 		(char *) linenum(formal));
575 	    cerror("%s %s declared on line %d",
576 		parnam(actual->class), actual->symbol,
577 		(char *) linenum(actual));
578 	    return FALSE;
579 	}
580 	if ( a_chain -> class != f_chain -> class ) {
581 	    error("%s parameter %s of %s declared on line %d is not identical",
582 		parnam(f_chain->class), f_chain->symbol,
583 		formal->symbol, (char *) linenum(formal));
584 	    cerror("with %s parameter %s of %s declared on line %d",
585 		parnam(a_chain->class), a_chain->symbol,
586 		actual->symbol, (char *) linenum(actual));
587 	    compat = FALSE;
588 	} else if (a_chain->class == FFUNC || a_chain->class == FPROC) {
589 	    /*compat = (compat && fcompat(f_chain, a_chain));*/
590 	    if ((compat) && (fcompat(f_chain, a_chain)))
591 		compat = TRUE;
592 	    else compat = FALSE;
593 	}
594 	if ((a_chain->class != FPROC && f_chain->class != FPROC) &&
595 	    (a_chain->type != f_chain->type)) {
596 	    error("Type of %s parameter %s of %s declared on line %d is not identical",
597 		parnam(f_chain->class), f_chain->symbol,
598 		formal->symbol, (char *) linenum(formal));
599 	    cerror("to type of %s parameter %s of %s declared on line %d",
600 		parnam(a_chain->class), a_chain->symbol,
601 		actual->symbol, (char *) linenum(actual));
602 	    compat = FALSE;
603 	}
604     }
605     if (a_chain != NIL) {
606 	error("%s %s declared on line %d has fewer arguments than",
607 	    parnam(formal->class), formal->symbol,
608 	    (char *) linenum(formal));
609 	cerror("%s %s declared on line %d",
610 	    parnam(actual->class), actual->symbol,
611 	    (char *) linenum(actual));
612 	return FALSE;
613     }
614     return compat;
615 }
616 
617 char *
618 parnam(nltype)
619     int nltype;
620 {
621     switch(nltype) {
622 	case REF:
623 	    return "var";
624 	case VAR:
625 	    return "value";
626 	case FUNC:
627 	case FFUNC:
628 	    return "function";
629 	case PROC:
630 	case FPROC:
631 	    return "procedure";
632 	default:
633 	    return "SNARK";
634     }
635 }
636 
637 struct nl *plist(p)
638     struct nl *p;
639 {
640     switch (p->class) {
641 	case FFUNC:
642 	case FPROC:
643 	    return p->ptr[ NL_FCHAIN ];
644 	case PROC:
645 	case FUNC:
646 	    return p->chain;
647 	default:
648 	    {
649 		panic("plist");
650 		return(NLNIL); /* this is here only so lint won't complain
651 				  panic actually aborts */
652 	    }
653 
654     }
655 }
656 
657 linenum(p)
658     struct nl *p;
659 {
660     if (p->class == FUNC)
661 	return p->ptr[NL_FVAR]->value[NL_LINENO];
662     return p->value[NL_LINENO];
663 }
664