|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.