|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T b
Length: 13261 (0x33cd)
Types: TextFile
Names: »bas3.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/euug-87hel/sec1/basic/bas3.c«
/*
* BASIC by Phil Cockcroft
*/
#include "bas.h"
/*
* This file contains the numeric evaluation routines and some
* of the numeric functions.
*/
/*
* evalint() is called by a routine that requires an integer value
* e.g. string functions. It will always return an integer. If
* the result will not overflow an integer -1 is returned.
* N.B. most ( all ) routines assume that a negative return is an
* error.
*/
evalint()
{
eval();
if(vartype)
return(res.i);
if(conv(&res))
return(-1);
return(res.i);
}
/*
* This structure is only ever used by eval() and so is not declared
* in 'bas.h' with the others.
*/
struct m {
value r1;
int lastop;
char value;
char vty;
};
/*
* eval() will evaluate any numeric expression and return the result
* in the UNION 'res'.
* A valid expression can be any numeric expression or a string
* comparison expression e.g. "as" <> "gh" . String expressions can
* themselves be used in relational tests and also be used with the
* logical operators. e.g. "a" <> "b" and "1" <> a$ is a valid
* expression.
*/
eval()
{
extern (*mbin[])();
register int i;
register int c;
register struct m *j;
value *pp;
char firsttime=1;
char minus=0,noting=0;
struct m restab[6];
checksp();
j=restab;
j->value=0;
for(;;){
c=getch();
if(c=='-' && firsttime){
if(minus)
error(SYNTAX);
minus++;
continue;
}
else if(c==NOTT){
if(noting)
error(SYNTAX);
noting++;
firsttime++;
continue;
}
else if(c&0200){
if(c<MINFUNC || c>MAXFUNC) /* we have a function */
goto err1; /* possibly a string function */
if(c>= RND ) /* functions that don't */
(*functs[c-RND])(); /* require arguments */
else {
if(*point++ !='(')
error(SYNTAX); /* functions that do */
(*functb[c-MINFUNC])();
if(getch()!=')')
error(SYNTAX);
}
}
else if(isletter(c)){
char *sp = --point;
pp= (value *)getname(); /* we have a variable */
if(vartype== 02){ /* a string !!!!!! */
if(firsttime){ /* no need for checktype() since */
point = sp; /* we know it's a string */
stringcompare();
goto ex;
}
else error(2); /* variable required */
}
#ifdef V6C
getv(pp);
#else
res = *pp;
#endif
}
else if(isnumber(c) || c=='.'){
point--;
if(!getop()) /* we have a number */
error(36); /* bad number */
}
else if(c=='('){ /* bracketed expression */
eval(); /* recursive call of eval() */
if(getch()!=')')
error(SYNTAX);
}
else {
err1: /* get here if the function we tried to access was not */
/* a legal maths func. or a string variable */
/* stringcompare() will give a syntax error if not a valid */
/* string. therefore this works ok */
point--;
if(!firsttime)
error(SYNTAX);
stringcompare();
}
ex:
if(minus){ /* do the unary minus */
minus=0;
negate();
}
if(noting){ /* do the not */
noting=0;
notit();
}
i=0;
switch(c=getch()){ /* get the precedence of the */
case '^': i++; /* operator */
case '*':
case '/':
case MODD: i++;
case '+':
case '-': i++;
case EQL: /* comparison operators */
case LTEQ:
case NEQE:
case LTTH:
case GTEQ:
case GRTH: i++; /* logical operators */
case ANDD:
case ORR:
case XORR: i++;
}
if(i>2)
firsttime = 0;
ame: if(j->value< (char)i){ /* current operator has higher */
(++j)->lastop=c; /* precedence */
#ifndef V6C
j->r1 = res;
#else
push(&j->r1); /* block moving */
#endif
j->value=i;
j->vty=vartype;
continue;
}
if(! j->value ){ /* end of expression */
point--;
return;
}
if(j->vty!=vartype){ /* make both parameters */
if(vartype) /* the same type */
cvt(&res);
else
cvt(&j->r1); /* if changed then they must be */
vartype=0; /* changed to reals */
}
(*mbin[(j->value<<1)+vartype])(&j->r1,&res,j->lastop);
j--; /* execute it then pop the stack and */
goto ame; /* deal with the next operator */
}
}
/*
* The rest of the routines in this file evaluate functions and are
* relatively straight forward.
*/
tim()
{
time(&overfl);
#ifndef SOFTFP
res.f = overfl;
vartype = 0;
#else
over(0,&res); /* convert from long to real */
#endif
}
rnd()
{
static double recip32 = 32767.0;
value temp;
register int rn;
rn = rand() & 077777;
if(*point!='('){
res.i=rn;
vartype=01;
return;
}
point++;
eval();
if(getch()!=')')
error(SYNTAX);
#ifdef PORTABLE
if(vartype ? res.i : res.f){
#else
if(res.i){
#endif
if(!vartype && conv(&res))
error(FUNCT);
res.i= rn % res.i + 1;
vartype=01;
return;
}
#ifndef SOFTFP
res.f = (double)rn / recip32;
#else
temp.i=rn;
cvt(&temp);
#ifndef V6C
res = *( (value *)( &recip32 ) );
#else
movein(&recip32,&res);
#endif
fdiv(&temp,&res); /* horrible */
#endif
vartype =0;
}
/*
* This routine is the command 'random' and is placed here for some
* unknown reason it just sets the seed to rnd to the value from
* the time system call ( is a random number ).
*/
random()
{
long m;
time(&m);
srand((int)m);
normret;
}
erlin()
{
res.i = elinnumb;
vartype=01;
if(res.i < 0 ){ /* make large linenumbers */
#ifndef SOFTFP
res.f = (unsigned)elinnumb;
vartype = 0;
#else
overfl=(unsigned)elinnumb; /* into reals as they */
over(0,&res); /* overflow integers */
#endif
}
}
erval()
{
res.i =ecode;
vartype=01;
}
sgn()
{
eval();
#ifdef PORTABLE
if(!vartype){
if(res.f < 0)
res.i = -1;
else if(res.f > 0)
res.i = 1;
else res.i = 0;
vartype = 1;
return;
}
#endif
if(res.i<0) /* bit twiddling */
res.i = -1; /* real numbers have the top bit set if */
else if(res.i>0) /* negative and the top word is non-zero */
res.i= 1; /* for all non-zero numbers */
vartype=01;
}
abs()
{
eval();
#ifdef PORTABLE
if(!vartype){
if(res.f < 0)
negate();
return;
}
#endif
if(res.i<0)
negate();
}
len()
{
stringeval(gblock);
res.i =gcursiz;
vartype=01;
}
ascval()
{
stringeval(gblock);
if(!gcursiz)
error(FUNCT);
res.i = *gblock & 0377;
vartype=01;
}
sqrtf()
{
#ifndef SOFTFP
double sqrt();
#endif
eval();
if(vartype)
cvt(&res);
vartype=0;
#ifdef PORTABLE
if(res.f < 0)
#else
if(res.i < 0)
#endif
error(37); /* negative square root */
#ifndef SOFTFP
res.f = sqrt(res.f);
#else
sqrt(&res);
#endif
}
logf()
{
#ifndef SOFTFP
double log();
#endif
eval();
if(vartype)
cvt(&res);
vartype=0;
#ifdef PORTABLE
if(res.f <= 0)
#else
if(res.i <= 0)
#endif
error(38); /* bad log value */
#ifndef SOFTFP
res.f = log(res.f);
#else
log(&res);
#endif
}
expf()
{
#ifndef SOFTFP
double exp();
#endif
eval();
if(vartype)
cvt(&res);
vartype=0;
#ifndef SOFTFP
if(res.f > 88.02969)
error(39);
res.f = exp(res.f);
#else
if(!exp(&res))
error(39); /* overflow in exp */
#endif
}
pii()
{
#ifndef SOFTFP
res.f = pivalue;
#else
movein(&pivalue,&res);
#endif
vartype=0;
}
/*
* This routine will deal with the eval() function. It has to do
* a lot of moving of data. to enable it to 'compile' an expression
* so that it can be evaluated.
*/
evalu()
{
register char *tmp;
char chblck1[256];
char chblck2[256];
checksp();
if(evallock>5)
error(43); /* mutually recursive eval */
evallock++;
stringeval(gblock);
gblock[gcursiz]=0;
strcpy(nline,chblck2); /* save nline */
line[0]='\01'; /* stop a line number being created */
strcpy(gblock,&line[1]);
compile(0);
strcpy(&nline[1],chblck1); /* restore nline ( eval in immeadiate */
strcpy(chblck2,nline); /* mode ). */
tmp=point;
point=chblck1;
eval();
if(getch())
error(SYNTAX);
point=tmp;
evallock--;
}
ffn()
{
register struct deffn *p;
value ovrs[3];
value nvrs[3];
char vttys[3];
char *spoint;
register int i;
if(!isletter(*point))
error(SYNTAX);
getnm();
#ifdef LNAMES
for(p = (deffnp)enames ; p < (deffnp)edefns ;
p = (deffnp)((memp)p + p->offs) )
#else
for( p = (deffnp)estring ; p < (deffnp)edefns ;
p = (deffnp)((memp)p + p->offs) )
#endif
if(p->dnm ==nm )
goto got;
error(UNDEFFN);
got:
for(i=0;i<p->narg;i++) /* save values */
#ifndef V6C
ovrs[i] = *((value *) (p->vargs[i] + earray) );
#else
movein( (double *)(p->vargs[i] + earray) ,&ovrs[i]);
#endif
if(p->narg){
if(*point++!='(')
error(SYNTAX);
for(i=0;;){
eval();
#ifndef V6C
nvrs[i] = res;
#else
movein(&res,&nvrs[i]);
#endif
vttys[i] = vartype;
if(++i >= p->narg )
break;
if( getch() != ',' )
error(SYNTAX);
}
if( getch() != ')' )
error(SYNTAX);
} /* got arguments in nvrs[] */
for(i=0;i<p->narg;i++){ /* put in new values */
#ifndef V6C
res = nvrs[i];
#else
movein(&nvrs[i],&res);
#endif
vartype=vttys[i];
putin((value *)(p->vargs[i] + earray),((p->vtys>>i)&01));
}
spoint=point;
point=p->exp;
eval();
for(i=0;i<p->narg;i++)
#ifndef V6C
*( (value *)(p->vargs[i] + earray)) = ovrs[i];
#else
movein(&ovrs[i], (double *) (p->vargs[i] + earray) );
#endif
if(getch())
error(SYNTAX);
point= spoint;
i= p->vtys>>4;
if(vartype != (char)i){
if(vartype)
cvt(&res);
else if(conv(&res))
error(INTOVER);
vartype=i;
}
}
/* int() - return the greatest integer less than x */
intf()
{
#ifndef SOFTFP
double floor();
eval();
if(!vartype)
res.f = floor(res.f);
if(!conv(&res))
vartype=01;
#else
value temp;
static double ONE = 1.0;
eval();
if(vartype) /* conv and integ truncate not round */
return;
#ifdef PORTABLE
if(res.f>=0){
#else
if(res.i>=0){ /* positive easy */
#endif
if(!conv(&res))
vartype=01;
else integ(&res);
return;
}
#ifndef V6C
temp = res;
#else
movein(&res,&temp);
#endif
integ(&res);
if(cmp(&res,&temp)){ /* not got an integer subtract one */
#ifndef V6C
res = *((value *)&ONE);
#else
movein(&ONE,&res);
#endif
fsub(&temp,&res);
integ(&res);
}
if(!conv(&res))
vartype=01;
#endif /* not floating point */
}
peekf(sp)
{
register char *p;
#ifndef pdp11
register long l;
eval();
if(vartype)
cvt(&res);
l = res.f;
if(res.f > 0x7fff000 || res.f < 0) /* check this */
error(FUNCT);
p = (char *)l;
#else
eval();
if(!vartype && conv(&res))
error(FUNCT);
p= (char *)res.i; /* horrible - fix for a Vax */
#endif
vartype=01;
if(p>vvend && p < (char *)&sp )
res.i=0;
else res.i = *p & 0377;
}
poke(sp) /* sp = approx position of stack */
{ /* can give bus errors */
#ifndef pdp11 /* why are you poking any way ??? */
register long l;
#endif
register char *p;
register int i;
eval();
if(getch()!=',')
error(SYNTAX);
#ifndef pdp11
if(vartype)
cvt(&res);
l = res.f;
if(res.f > 0x7fff000 || res.f < 0) /* check this */
error(FUNCT);
p = (char *)l;
#else
if(!vartype && conv(&res))
error(FUNCT);
p= (char *)res.i;
#endif
i= evalint();
check();
if(i<0)
error(FUNCT);
if(p< vvend || p > (char *)&sp)
*p = i;
normret;
}
sinf()
{
#ifndef SOFTFP
double sin();
#endif
eval();
if(vartype)
cvt(&res);
vartype=0;
#ifndef SOFTFP
res.f = sin(res.f);
#else
sin(&res);
#endif
}
cosf()
{
#ifndef SOFTFP
double cos();
#endif
eval();
if(vartype)
cvt(&res);
vartype=0;
#ifndef SOFTFP
res.f = cos(res.f);
#else
cos(&res);
#endif
}
atanf()
{
#ifndef SOFTFP
double atan();
#endif
eval();
if(vartype)
cvt(&res);
vartype=0;
#ifndef SOFTFP
res.f = atan(res.f);
#else
atan(&res);
#endif
}
/*
* the "system" function, returns the status of the command it executes
*/
ssystem()
{
register int i;
register int (*q)() , (*p)();
int (*signal())();
char *s;
int status;
#ifdef SIGTSTP
int (*t)();
#endif
stringeval(gblock); /* get the command */
gblock[gcursiz] = 0;
flushall();
#ifdef SIGTSTP
t = signal(SIGTSTP, SIG_DFL);
#endif
#ifdef VFORK
i = vfork();
#else
i=fork();
#endif
if(i==0){
rset_term(1);
setuid(getuid()); /* stop user getting clever */
#ifdef V7
s = getenv("SHELL");
if(!s || !*s)
s = "/bin/sh";
#else
s = "/bin/sh";
#endif
execl(s, "sh (from basic)", "-c", gblock, 0);
exit(-1); /* problem */
}
if(i != -1){
p=signal(SIGINT,SIG_IGN); /* ignore some signals */
q=signal(SIGQUIT, SIG_IGN);
while(i != wait(&status) ); /* wait on the 'child' */
signal(SIGINT,p); /* resignal to what they */
signal(SIGQUIT,q); /* were before */
/* in a mode fit for basic */
set_term(); /* reset terminal modes */
rset_term(0);
i = status;
}
#ifdef SIGTSTP
signal(SIGTSTP, t);
#endif
vartype = 1;
res.i = i;
}