home *** CD-ROM | disk | FTP | other *** search
- /*
- * Procedure and function invocation.
- */
-
- #include <math.h>
- #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;
- }
-