/* * File: omisc.c * Contents: refresh, size, tabmat, toby */ #include "..\h\config.h" #include "..\h\rt.h" #include "rproto.h" /* * ^x - return an entry block for co-expression x from the refresh block. */ OpDcl(refresh,1,"^") { #ifdef Coexpr register struct b_coexpr *sblkp; register struct b_refresh *rblkp; register dptr dp, dsp; register word *newsp; int na, nl, i; /* * Be sure a co-expression is being refreshed. */ if (Qual(Arg1) || Arg1.dword != D_Coexpr) RunErr(118, &Arg1); /* * Get a new co-expression stack and initialize. */ if ((sblkp = alccoexp()) == NULL) RunErr(0, NULL); sblkp->freshblk = BlkLoc(Arg1)->coexpr.freshblk; if (ChkNull(sblkp->freshblk)) /* &main cannot be refreshed */ RunErr(215, &Arg1); /* * The interpreter stack starts at word after co-expression stack block. * C stack starts at end of stack region on machines with down-growing C * stacks and somewhere in the middle of the region. * * The C stack is aligned on a doubleword boundary. For upgrowing * stacks, the C stack starts in the middle of the stack portion * of the static block. For downgrowing stacks, the C stack starts * at the last word of the static block. */ newsp = (word *)((word)(char *)sblkp + sizeof(struct b_coexpr)); #ifdef UpStack sblkp->cstate[0] = ((word)((word)(char *)sblkp + (stksize - sizeof(*sblkp))/2) &~(WordSize*StackAlign-1)); #else /* UpStack */ sblkp->cstate[0] = ((word)((word)(char *)sblkp + stksize - WordSize)&~(WordSize*StackAlign-1)); #endif /* UpStack */ #ifdef CoProcesses sblkp->cstate[1] = 0; #endif sblkp->es_argp = (dptr)newsp; /* * Get pointer to refresh block and get number of arguments and locals. */ rblkp = (struct b_refresh *)BlkLoc(sblkp->freshblk); na = (rblkp->pfmkr).pf_nargs + 1; nl = (int)rblkp->numlocals; /* * Copy arguments onto new stack. */ dp = &rblkp->elems[0]; dsp = (dptr)newsp; for (i = 1; i <= na; i++) *dsp++ = *dp++; /* * Copy procedure frame to new stack and point dsp to word after frame. */ *((struct pf_marker *)dsp) = rblkp->pfmkr; sblkp->es_pfp = (struct pf_marker *)dsp; /* dsp = (dptr)((word *)dsp + Vwsizeof(*pfp)); */ dsp = (dptr)((word)dsp + sizeof(word) * Vwsizeof(*pfp)); sblkp->es_ipc.opnd = rblkp->ep; sblkp->es_gfp = 0; sblkp->es_efp = 0; sblkp->tvalloc = NULL; sblkp->es_ilevel = 0; /* * Copy locals to new stack and refresh block. */ for (i = 1; i <= nl; i++) *dsp++ = *dp++; /* * Push two null descriptors on the stack. */ *dsp++ = nulldesc; *dsp++ = nulldesc; sblkp->es_sp = (word *)dsp - 1; /* * Return the new co-expression. */ Arg0.dword = D_Coexpr; BlkLoc(Arg0) = (union block *) sblkp; Return; #else /* Coexpr */ RunErr(-401, NULL); #endif /* Coexpr */ } /* * *x - return size of string or object x. */ OpDcl(size,1,"*") { char sbuf[MaxCvtLen]; word i; int j; union block *bp; if (Qual(Arg1)) { /* * If Arg1 is a string, return the length of the string. */ i = StrLen(Arg1); } else { /* * Arg1 is not a string. For most types, the size is in the size * field of the block. * structure. */ switch (Type(Arg1)) { case T_List: i = BlkLoc(Arg1)->list.size; break; case T_Table: i = BlkLoc(Arg1)->table.size; break; case T_Set: i = BlkLoc(Arg1)->set.size; break; case T_Cset: { register unsigned int w; i = BlkLoc(Arg1)->cset.size; if (i >= 0) break; bp = (union block *)BlkLoc(Arg1); i = 0; for (j = 0; j < CsetSize; j++) for (w=bp->cset.bits[j]; w; w >>= 1) if (w & 01) i++; bp->cset.size = i; break; } case T_Record: i = BlkLoc(Arg1)->record.recdesc->proc.nfields; break; case T_Coexpr: i = BlkLoc(Arg1)->coexpr.size; break; default: /* * Try to convert it to a string. */ if (cvstr(&Arg1, sbuf) == CvtFail) RunErr(112, &Arg1); /* no notion of size */ i = StrLen(Arg1); } } MakeInt(i, &Arg0); Return; } /* * =x - tab(match(x)). Reverses effects if resumed. */ OpDcl(tabmat,1,"=") { register word l; register char *s1, *s2; word i, j; char sbuf[MaxCvtLen]; int type; /* * Arg1 must be a string. */ if ((type = cvstr(&Arg1,sbuf)) == CvtFail) RunErr(103, &Arg1); /* * Make a copy of &pos. */ i = k_pos; /* * Fail if &subject[&pos:0] is not of sufficient length to contain Arg1. */ j = StrLen(k_subject) - i + 1; if (j < StrLen(Arg1)) Fail; /* * Get pointers to Arg1 (s1) and &subject (s2). Compare them on a bytewise * basis and fail if s1 doesn't match s2 for *s1 characters. */ s1 = StrLoc(Arg1); s2 = StrLoc(k_subject) + i - 1; l = StrLen(Arg1); while (l-- > 0) { if (*s1++ != *s2++) Fail; } /* * Increment &pos to tab over the matched string and suspend the * matched string. */ l = StrLen(Arg1); k_pos += l; Arg0 = Arg1; if (type == Cvt) { /* string is in buffer, copy */ if (strreq(StrLen(Arg0)) == Error) RunErr(0, NULL); StrLoc(Arg0) = alcstr(StrLoc(Arg0), StrLen(Arg0)); } Suspend; /* * tabmat has been resumed, restore &pos and fail. */ if (i > StrLen(k_subject) + 1) { RunErr(205, &tvky_pos.kyval); } else k_pos = i; Fail; } /* * i to j by k - generate successive values. */ OpDcl(toby,3,"...") { long from; /* * Arg1 (from), Arg2 (to), and Arg3 (by) must be integers. * Also, Arg3 must not be zero. */ if (cvint(&Arg1) == CvtFail) RunErr(101, &Arg1); if (cvint(&Arg2) == CvtFail) RunErr(101, &Arg2); if (cvint(&Arg3) == CvtFail) RunErr(101, &Arg3); if (IntVal(Arg3) == 0) RunErr(211, &Arg3); /* * Count up or down (depending on relationship of from and to) and * suspend each value in sequence, failing when the limit has been * exceeded. */ from = IntVal(Arg1); if (IntVal(Arg3) > 0) for ( ; from <= IntVal(Arg2); from += IntVal(Arg3)) { MakeInt(from, &Arg0); Suspend; } else for ( ; from >= IntVal(Arg2); from += IntVal(Arg3)) { MakeInt(from, &Arg0); Suspend; } Fail; }