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