15515Slinton /* Copyright (c) 1982 Regents of the University of California */
25515Slinton 
3*5659Slinton static char sccsid[] = "@(#)callproc.c 1.2 02/02/82";
45515Slinton 
55515Slinton /*
65515Slinton  * Evaluate a call to a procedure.
75515Slinton  *
85515Slinton  * This file is a botch as far as modularity is concerned.
95515Slinton  */
105515Slinton 
115515Slinton #include "defs.h"
125515Slinton #include "runtime.h"
135515Slinton #include "sym.h"
145515Slinton #include "tree.h"
155515Slinton #include "breakpoint.h"
165515Slinton #include "machine.h"
175515Slinton #include "process.h"
185515Slinton #include "source.h"
195515Slinton #include "frame.rep"
205515Slinton #include "sym/classes.h"
215515Slinton #include "sym/sym.rep"
225515Slinton #include "tree/tree.rep"
235515Slinton #include "process/process.rep"
245515Slinton #include "process/pxinfo.h"
255515Slinton 
265515Slinton LOCAL ADDRESS retaddr;
275515Slinton 
285515Slinton /*
295515Slinton  * Controlling logic of procedure calling.
305515Slinton  * Calling a procedure before ever executing the program must
315515Slinton  * be special cased.
325515Slinton  */
335515Slinton 
345515Slinton callproc(procnode, arglist)
355515Slinton NODE *procnode;
365515Slinton NODE *arglist;
375515Slinton {
385515Slinton 	SYM *proc;
395515Slinton 
405515Slinton 	if (pc == 0) {
415515Slinton 		curline = firstline(program);
425515Slinton 		setbp(curline);
435515Slinton 		resume();
445515Slinton 		unsetbp(curline);
455515Slinton 	}
465515Slinton 	proc = procnode->nameval;
475515Slinton 	if (!isblock(proc)) {
485515Slinton 		error("\"%s\" is not a procedure or function", proc->symbol);
495515Slinton 	}
50*5659Slinton 	pushargs(proc, arglist);
515515Slinton 	pushenv(proc->symvalue.funcv.codeloc);
525515Slinton 	pushframe(proc->blkno);
535515Slinton 	execute(proc);
545515Slinton 	/* NOTREACHED */
555515Slinton }
565515Slinton 
575515Slinton /*
585515Slinton  * Push the arguments on the process' stack.  We do this by first
595515Slinton  * evaluating them on the "eval" stack, then copying into the process'
605515Slinton  * space.
615515Slinton  */
625515Slinton 
635515Slinton LOCAL pushargs(proc, arglist)
645515Slinton SYM *proc;
655515Slinton NODE *arglist;
665515Slinton {
675515Slinton 	STACK *savesp;
685515Slinton 	int args_size;
695515Slinton 
705515Slinton 	savesp = sp;
715515Slinton 	evalargs(proc->symbol, proc->chain, arglist);
725515Slinton 	args_size = sp - savesp;
735515Slinton 	process->sp -= args_size;
745515Slinton 	dwrite(savesp, process->sp, args_size);
755515Slinton 	sp = savesp;
765515Slinton }
775515Slinton 
785515Slinton /*
795515Slinton  * Evaluate arguments right-to-left because the eval stack
805515Slinton  * grows up, px's stack grows down.
815515Slinton  */
825515Slinton 
835515Slinton LOCAL evalargs(procname, arg, explist)
845515Slinton char *procname;
855515Slinton SYM *arg;
865515Slinton NODE *explist;
875515Slinton {
885515Slinton 	NODE *exp;
895515Slinton 	STACK *savesp;
905515Slinton 	ADDRESS addr;
915515Slinton 
925515Slinton 	if (arg == NIL) {
935515Slinton 		if (explist != NIL) {
945515Slinton 			error("too many parameters to \"%s\"", procname);
955515Slinton 		}
965515Slinton 	} else if (explist == NIL) {
975515Slinton 		error("not enough parameters to \"%s\"", procname);
985515Slinton 	} else {
995515Slinton 		if (explist->op != O_COMMA) {
1005515Slinton 			panic("evalargs: arglist missing comma");
1015515Slinton 		}
1025515Slinton 		savesp = sp;
1035515Slinton 		evalargs(procname, arg->chain, explist->right);
1045515Slinton 		exp = explist->left;
1055515Slinton 		if (!compatible(arg->type, exp->nodetype)) {
1065515Slinton 			sp = savesp;
1075515Slinton 			trerror("%t is not the same type as parameter \"%s\"",
1085515Slinton 				exp, arg->symbol);
1095515Slinton 		}
1105515Slinton 		if (arg->class == REF) {
1115515Slinton 			if (exp->op != O_RVAL) {
1125515Slinton 				sp = savesp;
1135515Slinton 				error("variable expected for parameter \"%s\"", arg->symbol);
1145515Slinton 			}
1155515Slinton 			addr = lval(exp->left);
1165515Slinton 			push(ADDRESS, addr);
1175515Slinton 		} else {
1185515Slinton 			eval(exp);
1195515Slinton 		}
1205515Slinton 	}
1215515Slinton }
1225515Slinton 
1235515Slinton /*
1245515Slinton  * Simulate a CALL instruction by pushing the appropriate
1255515Slinton  * stack frame information.
1265515Slinton  *
1275515Slinton  * Massage register 10 appropriately since it contains the
1285515Slinton  * stack frame pointer.
1295515Slinton  */
1305515Slinton 
1315515Slinton LOCAL pushframe(b)
1325515Slinton int b;
1335515Slinton {
1345515Slinton 	ADDRESS *newdp;
1355515Slinton 	FRAME callframe;
1365515Slinton 
1375515Slinton 	retaddr = program->symvalue.funcv.codeloc;
1385515Slinton 
1395515Slinton /*
1405515Slinton  * This stuff is set by the callee, just here to take up space.
1415515Slinton  */
1425515Slinton 	callframe.stackref = 0;
1435515Slinton 	callframe.file = 0;
1445515Slinton 	callframe.blockp = 0;
1455515Slinton 	callframe.save_loc = NIL;
1465515Slinton 	callframe.save_disp = NIL;
1475515Slinton 
1485515Slinton /*
1495515Slinton  * This is the useful stuff.
1505515Slinton  */
1515515Slinton 	callframe.save_dp = curdp();
1525515Slinton 	callframe.save_pc = retaddr + ENDOFF;
1535515Slinton 	callframe.save_lino = 0;
1545515Slinton 	newdp = DISPLAY + (2 * b);
1555515Slinton 	dwrite(&newdp, DP, sizeof(newdp));
1565515Slinton 	process->sp -= sizeof(callframe);
1575515Slinton 	dwrite(&callframe, process->sp, sizeof(callframe));
1585515Slinton 	process->reg[10] = process->sp;
1595515Slinton }
1605515Slinton 
1615515Slinton /*
1625515Slinton  * Execute the procedure.  This routine does NOT return because it
1635515Slinton  * calls "cont", which doesn't return.  We set a CALLPROC breakpoint
1645515Slinton  * at "retaddr", the address where the called routine will return.
1655515Slinton  *
1665515Slinton  * The action for a CALLPROC is to call "procreturn" where we restore
1675515Slinton  * the environment.
1685515Slinton  */
1695515Slinton 
1705515Slinton LOCAL execute(f)
1715515Slinton SYM *f;
1725515Slinton {
1735515Slinton 	isstopped = TRUE;
1745515Slinton 	addbp(retaddr, CALLPROC, f, NIL, NIL, 0);
1755515Slinton 	cont();
1765515Slinton 	/* NOTREACHED */
1775515Slinton }
1785515Slinton 
1795515Slinton procreturn(f)
1805515Slinton SYM *f;
1815515Slinton {
1825515Slinton 	int len;
1835515Slinton 
1845515Slinton 	printf("%s returns ", f->symbol);
1855515Slinton 	if (f->class == FUNC) {
1865515Slinton 		len = size(f->type);
1875515Slinton 		dread(sp, process->sp, len);
1885515Slinton 		sp += len;
1895515Slinton 		printval(f->type);
1905515Slinton 		putchar('\n');
1915515Slinton 	} else {
1925515Slinton 		printf("successfully\n");
1935515Slinton 	}
1945515Slinton 	popenv();
1955515Slinton }
1965515Slinton 
1975515Slinton /*
1985515Slinton  * Push the current environment.
1995515Slinton  *
2005515Slinton  * This involves both saving pdx and interpreter values.
2015515Slinton  * LOOPADDR is the address of the main interpreter loop.
2025515Slinton  */
2035515Slinton 
2045515Slinton LOCAL pushenv(newpc)
2055515Slinton ADDRESS newpc;
2065515Slinton {
2075515Slinton 	push(ADDRESS, pc);
2085515Slinton 	push(LINENO, curline);
2095515Slinton 	push(char *, cursource);
2105515Slinton 	push(BOOLEAN, isstopped);
2115515Slinton 	push(SYM *, curfunc);
2125515Slinton 	push(WORD, process->pc);
2135515Slinton 	push(WORD, process->sp);
2145515Slinton 	process->pc = LOOPADDR;
2155515Slinton 	pc = newpc;
2165515Slinton 	process->reg[11] = pc + ENDOFF;
2175515Slinton }
2185515Slinton 
2195515Slinton /*
2205515Slinton  * Pop back to the real world.
2215515Slinton  */
2225515Slinton 
2235515Slinton popenv()
2245515Slinton {
2255515Slinton 	register PROCESS *p;
2265515Slinton 	char *filename;
2275515Slinton 
2285515Slinton 	p = process;
2295515Slinton 	p->sp = pop(WORD);
2305515Slinton 	p->pc = pop(WORD);
2315515Slinton 	curfunc = pop(SYM *);
2325515Slinton 	isstopped = pop(BOOLEAN);
2335515Slinton 	filename = pop(char *);
2345515Slinton 	curline = pop(LINENO);
2355515Slinton 	pc = pop(ADDRESS);
2365515Slinton 	if (filename != cursource) {
2375515Slinton 		skimsource(filename);
2385515Slinton 	}
2395515Slinton }
240