|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 5062 (0x13c6) Types: TextFile Notes: UNIX file Names: »bcmutil.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦f4b8d8c84⟧ UNIX Filesystem └─ ⟦this⟧ »cmd/bc/bcmutil.c«
#include <stdio.h> #include <assert.h> #include "bc.h" /* * Newscalar takes the rvalue pointed to by lval and initializes * it to have a value of zero. */ newscalar(lval) register rvalue *lval; { minit(&lval->mantissa); mcopy(mzero, &lval->mantissa); lval->scale = 0; } /* * Newarray takes the array pointed to by alval and initializes it * to have one element, which will have the value of zero. */ newarray(alval) register array *alval; { alval->size = 1; alval->avalue = (rvalue *)mpalc(sizeof (rvalue)); newscalar(alval->avalue); } /* * Arfree frees all space associated with the array pointed to by * `alv'. */ arfree(alv) register array *alv; { register rvalue *rp; register int left; for (rp = alv->avalue, left = alv->size; --left >= 0; ++rp) mvfree(&rp->mantissa); mpfree(alv->avalue); } /* * Pow10 returns a pointer to a mint which is 10 ^ `power'. * Note that this pointer is to a static region, and hence * should not be saved, but should be used immediately. * Since pow10 is frequently used for scaleing, it first * checks to see if the value being requested is the same * as last time, and if so, simply returns it. */ mint * pow10(power) register int power; { static int oldpow = -1; static mint oldres; if (power != oldpow) { if (power == 0) return (mone); spow(&ten, power, &oldres); oldpow = power; } return (&oldres); } /* * Select returns the lvalue of the `indx'th item in the array * `arry'. */ rvalue * select(arry, indx) register array *arry; int indx; { register rvalue *ptr; register int nsize; if (indx < 0) bcmerr("Negative subscript"); if (indx >= arry->size) { nsize = indx + ABUMP - indx % ABUMP; /* * Should be: * ptr = (rvalue *)realloc(arry->avalue, * nsize * (sizeof (rvalue))); * if (ptr == NULL) * die("Out of space"); * But is: */ ptr = (rvalue *)mpalc(nsize * (sizeof (rvalue))); copy((char *)arry->avalue, (char *)ptr, arry->size * sizeof (rvalue)); mpfree(arry->avalue); /* * End of kludge. */ arry->avalue = ptr; ptr += arry->size; do { newscalar(ptr++); } while (++arry->size < nsize); } return (&arry->avalue[indx]); } /* * Shift sets the mint `b' to the mint `a' times 10 ^ `scnt'. * If `scnt' is negative, then a divide (with truncation) is * done. If `scnt' is zero and `a' and `b' are the same, then * no action is taken. */ shift(a, scnt, b) register int scnt; mint *a, *b; { mint temp; if (scnt > 0) mult(a, pow10(scnt), b); else if (scnt < 0) { minit(&temp); mdiv(a, pow10(-scnt), b, &temp); mvfree(&temp); } else if (a != b) mcopy(a, b); } /* * Rescale adjusts the scale of the rvalue pointed to by `a' * to `newsc'. */ rescale(a, newsc) register rvalue *a; register int newsc; { shift(a, newsc - a->scale, a); a->scale = newsc; } /* * Rtoint returns an int equal to the rvalue `a'. Any * fractional part is truncated. If `a' is too large, * then rtoint exits via bcerr. */ int rtoint(a) rvalue *a; { register int res; mint temp; minit(&temp); shift(&a->mantissa, - a->scale, &temp); if (mcmp(mminint, &temp) > 0 || mcmp(&temp, mmaxint) > 0) bcmerr("Too big for int"); res = mtoi(&temp); mvfree(&temp); return (res); } /* * Chkcall checks to make sure that a function is defined and has * the right number of arguments. `fnc' is a pointer to the * dictionary entry for the function and `npars' is the number * of parameters with which it is called. */ chkcall(fnc, npars) register dicent *fnc; register int npars; { if (fnc->globalt != FUNCTION) bcmerr("`%s' not function", fnc->word); if (fnc->globalv.fvalue.body == NULL) bcmerr("Function `%s' not defined", fnc->word); if (fnc->globalv.fvalue.nparams != npars) bcmerr("Function `%s' needs %d arguments, got %d", fnc->word, fnc->globalv.fvalue.nparams, npars); } /* * Pauto intializes the automatic variables needed by a bc function * as part of the CALL instruction. It also checks to make sure that * there is room for them on the stack. Pauto returns the value * for tos after the CALL is completed (which is a pointer to the * return state). `fnc' is the function being called, tos is the * old tos and limit is the last available stack entry. */ stkent * pauto(fnc, tos, limit) register func *fnc; register stkent *tos; stkent *limit; { register type *tp; int left; left = fnc->nautos; if (tos + left >= limit) bcmerr("Out of runtime stack"); ++tos; for (tp = &fnc->types[fnc->nparams]; --left >= 0; ++tp, ++tos) switch (*tp) { case SCALAR: newscalar(&tos->rvalue); break; case ARRAY: tos->alvalue = (array *)mpalc(sizeof (array)); newarray(tos->alvalue); break; default: assert(FALSE); } return (tos); } /* * Newframe returns the new value for the frame pointer after * calling the function `fcn'. `tos' is the top of the stack * after the CALL (note, this points to the saved state). */ stkent * newframe(fcn, tos) register func *fcn; stkent *tos; { return (tos - (fcn->nparams + fcn->nautos)); }