/* * Procedure and function invocation. */ #include #include "..\h\config.h" #include "..\h\rt.h" #include "rproto.h" #ifdef TraceBack extern dptr xargp; extern word xnargs; #endif /* TraceBack */ /* * invoke -- Perform setup for invocation. */ invoke(nargs,cargp,n) dptr *cargp; int nargs, *n; { register struct pf_marker *newpfp; register dptr newargp; register word *newsp = sp; #ifdef SCO_XENIX register dptr p; #endif /* SCO_XENIX */ register word i; struct b_proc *proc; int nparam; char strbuf[MaxCvtLen]; /* * Point newargp at Arg0 and dereference it. */ newargp = (dptr )(sp - 1) - nargs; #ifdef TraceBack xnargs = nargs; xargp = newargp; #endif /* TraceBack */ if (DeRef(newargp[0]) == Error) { runerr(0, NULL); return I_Fail; } /* * See what course the invocation is to take. */ if (newargp->dword != D_Proc) { /* * Arg0 is not a procedure. */ if (cvint(&newargp[0]) == T_Integer) { /* * Arg0 is an integer, select result. */ i = cvpos(IntVal(newargp[0]), (word)nargs); if (i == CvtFail || i > nargs) return I_Fail; #ifdef SCO_XENIX p = newargp + i; newargp[0] = *p; #else /* SCO_XENIX */ newargp[0] = newargp[i]; #endif /* SCO_XENIX */ sp = (word *)newargp + 1; return I_Continue; } else { /* * See if Arg0 can be converted to a string that names a procedure * or operator. If not, generate run-time error 106. */ if (cvstr(&newargp[0],strbuf) == CvtFail || strprc(&newargp[0], (word)nargs) == CvtFail) { runerr(106, newargp); return I_Fail; } } } /* * newargp[0] is now a descriptor suitable for invocation. Dereference * the supplied arguments. */ proc = (struct b_proc *)BlkLoc(newargp[0]); if (proc->nstatic >= 0) /* if negative, don't reference arguments */ for (i = 1; i <= nargs; i++) if (DeRef(newargp[i]) == Error) { runerr(0, NULL); return I_Fail; } /* * Adjust the argument list to conform to what the routine being invoked * expects (proc->nparam). If nparam is less than 0, the number of * arguments is variable. For functions (ndynam = -1) with a * variable number of arguments, nothing need be done. For Icon procedures * with a variable number of arguments, arguments beyond abs(nparam) are * put in a list which becomes the last argument. For fix argument * routines, if too many arguments were supplied, adjusting the stack * pointer is all that is necessary. If too few arguments were supplied, * null descriptors are pushed for each missing argument. */ proc = (struct b_proc *)BlkLoc(newargp[0]); nparam = (int)proc->nparam; if (nparam >= 0) { if (nargs > nparam) newsp -= (nargs - nparam) * 2; else if (nargs < nparam) { i = nparam - nargs; while (i--) { *++newsp = D_Null; *++newsp = 0; } } nargs = nparam; #ifdef TraceBack xnargs = nargs; #endif /* TraceBack */ } else { if (proc->ndynam >= 0) { int lelems; dptr llargp; if (nargs < abs(nparam) - 1) { i = abs(nparam) - 1 - nargs; while (i--) { *++newsp = D_Null; *++newsp = 0; } nargs = abs(nparam) - 1; } lelems = nargs - (abs(nparam) - 1); llargp = &newargp[abs(nparam)]; tended[1] = llargp[-1]; ntended = 1; Ollist(lelems, &llargp[-1]); llargp[0] = llargp[-1]; llargp[-1] = tended[1]; ntended = 0; /* * Reload proc pointer in case Ollist triggered a garbage collection. */ proc = (struct b_proc *)BlkLoc(newargp[0]); newsp = (word *)llargp + 1; nargs = abs(nparam); } } if (proc->ndynam < 0) { /* * A function is being invoked, so nothing else here needs to be done. */ *n = nargs; *cargp = newargp; sp = newsp; if ((nparam == -1) || (proc->ndynam == -2)) return I_Vararg; else return I_Builtin; } /* * Make a stab at catching interpreter stack overflow. This does * nothing for invocation in a co-expression other than &main. */ if (BlkLoc(k_current) == BlkLoc(k_main) && ((char *)sp + PerilDelta) > (char *)stackend) fatalerr(-301, NULL); /* * Build the procedure frame. */ newpfp = (struct pf_marker *)(newsp + 1); newpfp->pf_nargs = nargs; newpfp->pf_argp = argp; newpfp->pf_pfp = pfp; newpfp->pf_ilevel = ilevel; newpfp->pf_scan = NULL; newpfp->pf_ipc = ipc; newpfp->pf_gfp = gfp; newpfp->pf_efp = efp; argp = newargp; pfp = newpfp; newsp += Vwsizeof(*pfp); /* * If tracing is on, use ctrace to generate a message. */ if (k_trace) { k_trace--; ctrace(&(proc->pname), nargs, &newargp[1]); } /* * Point ipc at the icode entry point of the procedure being invoked. */ ipc.opnd = (word *)proc->entryp.icode; efp = 0; gfp = 0; /* * Push a null descriptor on the stack for each dynamic local. */ for (i = proc->ndynam; i > 0; i--) { *++newsp = D_Null; *++newsp = 0; } sp = newsp; k_level++; return I_Continue; }