1*5515Slinton /* Copyright (c) 1982 Regents of the University of California */
2*5515Slinton 
3*5515Slinton static char sccsid[] = "@(#)callproc.c 1.1 01/18/82";
4*5515Slinton 
5*5515Slinton /*
6*5515Slinton  * Evaluate a call to a procedure.
7*5515Slinton  *
8*5515Slinton  * This file is a botch as far as modularity is concerned.
9*5515Slinton  */
10*5515Slinton 
11*5515Slinton #include "defs.h"
12*5515Slinton #include "runtime.h"
13*5515Slinton #include "sym.h"
14*5515Slinton #include "tree.h"
15*5515Slinton #include "breakpoint.h"
16*5515Slinton #include "machine.h"
17*5515Slinton #include "process.h"
18*5515Slinton #include "source.h"
19*5515Slinton #include "frame.rep"
20*5515Slinton #include "sym/classes.h"
21*5515Slinton #include "sym/sym.rep"
22*5515Slinton #include "tree/tree.rep"
23*5515Slinton #include "process/process.rep"
24*5515Slinton #include "process/pxinfo.h"
25*5515Slinton 
26*5515Slinton LOCAL ADDRESS retaddr;
27*5515Slinton 
28*5515Slinton /*
29*5515Slinton  * Controlling logic of procedure calling.
30*5515Slinton  * Calling a procedure before ever executing the program must
31*5515Slinton  * be special cased.
32*5515Slinton  */
33*5515Slinton 
34*5515Slinton callproc(procnode, arglist)
35*5515Slinton NODE *procnode;
36*5515Slinton NODE *arglist;
37*5515Slinton {
38*5515Slinton 	SYM *proc;
39*5515Slinton 
40*5515Slinton 	if (pc == 0) {
41*5515Slinton 		curline = firstline(program);
42*5515Slinton 		setbp(curline);
43*5515Slinton 		resume();
44*5515Slinton 		unsetbp(curline);
45*5515Slinton 	}
46*5515Slinton 	proc = procnode->nameval;
47*5515Slinton 	if (!isblock(proc)) {
48*5515Slinton 		error("\"%s\" is not a procedure or function", proc->symbol);
49*5515Slinton 	}
50*5515Slinton 	pushenv(proc->symvalue.funcv.codeloc);
51*5515Slinton 	pushargs(proc, arglist);
52*5515Slinton 	pushframe(proc->blkno);
53*5515Slinton 	execute(proc);
54*5515Slinton 	/* NOTREACHED */
55*5515Slinton }
56*5515Slinton 
57*5515Slinton /*
58*5515Slinton  * Push the arguments on the process' stack.  We do this by first
59*5515Slinton  * evaluating them on the "eval" stack, then copying into the process'
60*5515Slinton  * space.
61*5515Slinton  */
62*5515Slinton 
63*5515Slinton LOCAL pushargs(proc, arglist)
64*5515Slinton SYM *proc;
65*5515Slinton NODE *arglist;
66*5515Slinton {
67*5515Slinton 	STACK *savesp;
68*5515Slinton 	int args_size;
69*5515Slinton 
70*5515Slinton 	savesp = sp;
71*5515Slinton 	evalargs(proc->symbol, proc->chain, arglist);
72*5515Slinton 	args_size = sp - savesp;
73*5515Slinton 	process->sp -= args_size;
74*5515Slinton 	dwrite(savesp, process->sp, args_size);
75*5515Slinton 	sp = savesp;
76*5515Slinton }
77*5515Slinton 
78*5515Slinton /*
79*5515Slinton  * Evaluate arguments right-to-left because the eval stack
80*5515Slinton  * grows up, px's stack grows down.
81*5515Slinton  */
82*5515Slinton 
83*5515Slinton LOCAL evalargs(procname, arg, explist)
84*5515Slinton char *procname;
85*5515Slinton SYM *arg;
86*5515Slinton NODE *explist;
87*5515Slinton {
88*5515Slinton 	NODE *exp;
89*5515Slinton 	STACK *savesp;
90*5515Slinton 	ADDRESS addr;
91*5515Slinton 
92*5515Slinton 	if (arg == NIL) {
93*5515Slinton 		if (explist != NIL) {
94*5515Slinton 			error("too many parameters to \"%s\"", procname);
95*5515Slinton 		}
96*5515Slinton 	} else if (explist == NIL) {
97*5515Slinton 		error("not enough parameters to \"%s\"", procname);
98*5515Slinton 	} else {
99*5515Slinton 		if (explist->op != O_COMMA) {
100*5515Slinton 			panic("evalargs: arglist missing comma");
101*5515Slinton 		}
102*5515Slinton 		savesp = sp;
103*5515Slinton 		evalargs(procname, arg->chain, explist->right);
104*5515Slinton 		exp = explist->left;
105*5515Slinton 		if (!compatible(arg->type, exp->nodetype)) {
106*5515Slinton 			sp = savesp;
107*5515Slinton 			trerror("%t is not the same type as parameter \"%s\"",
108*5515Slinton 				exp, arg->symbol);
109*5515Slinton 		}
110*5515Slinton 		if (arg->class == REF) {
111*5515Slinton 			if (exp->op != O_RVAL) {
112*5515Slinton 				sp = savesp;
113*5515Slinton 				error("variable expected for parameter \"%s\"", arg->symbol);
114*5515Slinton 			}
115*5515Slinton 			addr = lval(exp->left);
116*5515Slinton 			push(ADDRESS, addr);
117*5515Slinton 		} else {
118*5515Slinton 			eval(exp);
119*5515Slinton 		}
120*5515Slinton 	}
121*5515Slinton }
122*5515Slinton 
123*5515Slinton /*
124*5515Slinton  * Simulate a CALL instruction by pushing the appropriate
125*5515Slinton  * stack frame information.
126*5515Slinton  *
127*5515Slinton  * Massage register 10 appropriately since it contains the
128*5515Slinton  * stack frame pointer.
129*5515Slinton  */
130*5515Slinton 
131*5515Slinton LOCAL pushframe(b)
132*5515Slinton int b;
133*5515Slinton {
134*5515Slinton 	ADDRESS *newdp;
135*5515Slinton 	FRAME callframe;
136*5515Slinton 
137*5515Slinton 	retaddr = program->symvalue.funcv.codeloc;
138*5515Slinton 
139*5515Slinton /*
140*5515Slinton  * This stuff is set by the callee, just here to take up space.
141*5515Slinton  */
142*5515Slinton 	callframe.stackref = 0;
143*5515Slinton 	callframe.file = 0;
144*5515Slinton 	callframe.blockp = 0;
145*5515Slinton 	callframe.save_loc = NIL;
146*5515Slinton 	callframe.save_disp = NIL;
147*5515Slinton 
148*5515Slinton /*
149*5515Slinton  * This is the useful stuff.
150*5515Slinton  */
151*5515Slinton 	callframe.save_dp = curdp();
152*5515Slinton 	callframe.save_pc = retaddr + ENDOFF;
153*5515Slinton 	callframe.save_lino = 0;
154*5515Slinton 	newdp = DISPLAY + (2 * b);
155*5515Slinton 	dwrite(&newdp, DP, sizeof(newdp));
156*5515Slinton 	process->sp -= sizeof(callframe);
157*5515Slinton 	dwrite(&callframe, process->sp, sizeof(callframe));
158*5515Slinton 	process->reg[10] = process->sp;
159*5515Slinton }
160*5515Slinton 
161*5515Slinton /*
162*5515Slinton  * Execute the procedure.  This routine does NOT return because it
163*5515Slinton  * calls "cont", which doesn't return.  We set a CALLPROC breakpoint
164*5515Slinton  * at "retaddr", the address where the called routine will return.
165*5515Slinton  *
166*5515Slinton  * The action for a CALLPROC is to call "procreturn" where we restore
167*5515Slinton  * the environment.
168*5515Slinton  */
169*5515Slinton 
170*5515Slinton LOCAL execute(f)
171*5515Slinton SYM *f;
172*5515Slinton {
173*5515Slinton 	isstopped = TRUE;
174*5515Slinton 	addbp(retaddr, CALLPROC, f, NIL, NIL, 0);
175*5515Slinton 	cont();
176*5515Slinton 	/* NOTREACHED */
177*5515Slinton }
178*5515Slinton 
179*5515Slinton procreturn(f)
180*5515Slinton SYM *f;
181*5515Slinton {
182*5515Slinton 	int len;
183*5515Slinton 
184*5515Slinton 	printf("%s returns ", f->symbol);
185*5515Slinton 	if (f->class == FUNC) {
186*5515Slinton 		len = size(f->type);
187*5515Slinton 		dread(sp, process->sp, len);
188*5515Slinton 		sp += len;
189*5515Slinton 		printval(f->type);
190*5515Slinton 		putchar('\n');
191*5515Slinton 	} else {
192*5515Slinton 		printf("successfully\n");
193*5515Slinton 	}
194*5515Slinton 	popenv();
195*5515Slinton }
196*5515Slinton 
197*5515Slinton /*
198*5515Slinton  * Push the current environment.
199*5515Slinton  *
200*5515Slinton  * This involves both saving pdx and interpreter values.
201*5515Slinton  * LOOPADDR is the address of the main interpreter loop.
202*5515Slinton  */
203*5515Slinton 
204*5515Slinton LOCAL pushenv(newpc)
205*5515Slinton ADDRESS newpc;
206*5515Slinton {
207*5515Slinton 	push(ADDRESS, pc);
208*5515Slinton 	push(LINENO, curline);
209*5515Slinton 	push(char *, cursource);
210*5515Slinton 	push(BOOLEAN, isstopped);
211*5515Slinton 	push(SYM *, curfunc);
212*5515Slinton 	push(WORD, process->pc);
213*5515Slinton 	push(WORD, process->sp);
214*5515Slinton 	process->pc = LOOPADDR;
215*5515Slinton 	pc = newpc;
216*5515Slinton 	process->reg[11] = pc + ENDOFF;
217*5515Slinton }
218*5515Slinton 
219*5515Slinton /*
220*5515Slinton  * Pop back to the real world.
221*5515Slinton  */
222*5515Slinton 
223*5515Slinton popenv()
224*5515Slinton {
225*5515Slinton 	register PROCESS *p;
226*5515Slinton 	char *filename;
227*5515Slinton 
228*5515Slinton 	p = process;
229*5515Slinton 	p->sp = pop(WORD);
230*5515Slinton 	p->pc = pop(WORD);
231*5515Slinton 	curfunc = pop(SYM *);
232*5515Slinton 	isstopped = pop(BOOLEAN);
233*5515Slinton 	filename = pop(char *);
234*5515Slinton 	curline = pop(LINENO);
235*5515Slinton 	pc = pop(ADDRESS);
236*5515Slinton 	if (filename != cursource) {
237*5515Slinton 		skimsource(filename);
238*5515Slinton 	}
239*5515Slinton }
240