|
|
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: 10174 (0x27be)
Types: TextFile
Names: »bas2.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/euug-87hel/sec1/basic/bas2.c«
/*
* BASIC by Phil Cockcroft
*/
#include "bas.h"
/*
* This file contains the routines to get a variable from its name
* To dimension arrays and assignment to a variable.
*
* A variable name consists of a letter followed by an optional
* letter or digit followed by the type specifier.
* A type specifier is a '%' for an integer a '$' for a string
* or is absent if the variable is a real ( Default ).
* An integer variable also has the top bit of its second letter
* set this is used to distinguish between real and integer variables.
* A variable name can be optionally followed by a subscript
* turning the variable into a subscripted variable.
* A subscript is specified by a list of indexes in square brackets
* e.g. [1,2,3] , a maximum of three subscripts may be used.
* All arrays must be specified before use.
*
* The variable to be accessed has its name in the array nm[],
* and its type in the variable 'vartype'.
*
* 'vartype' is very important as it is used all over the place
*
* The value in 'vartype' can have the following values:-
* 0: real variable (Default ).
* 1: integer variable.
* 2: string variable.
*
*/
#ifdef V6
#define LBRACK '['
#define RBRACK ']'
#else
#define LBRACK '('
#define RBRACK ')'
#endif
/*
* getnm will return with nm[] and vartype set appropriately but without
* any regard for subscript parameters. Called by dimensio() only.
*/
getnm()
{
#ifdef LNAMES
register char *p,*q;
register struct entry *ep,*np;
register int c;
register int l;
nam[0]=c=getch();
if(!isletter(c))
error(VARREQD);
p = &nam[1];
for(l =c,c = *point;isletter(c) || isnumber(c) ; c = *++point)
if(p < &nam[MAXNAME-1] ){
l +=c;
*p++ = c;
}
*p = 0;
for(np = 0,ep=hshtab[l%HSHTABSIZ]; ep ; np = ep,ep=ep->link)
if(l == ep->ln_hash)
for(p = ep->_name,q = nam ; *q == *p++ ; )
if(!*q++)
goto got;
ep = (struct entry *)xpand(&enames,sizeof(struct entry));
if(!np)
hshtab[l%HSHTABSIZ] = ep;
else
np->link = ep;
for(p = ep->_name , q = nam ; *p++ = *q++ ; );
ep->ln_hash = l;
got:
nm = (char *)ep - estring;
#else
register int c;
nm=c=getch();
if(!isletter(c))
error(VARREQD);
c= *point;
if(isletter(c) ||isnumber(c)){
nm |= c<<8;
do
c= *++point;
while(isletter(c) || isnumber(c));
}
#endif
vartype=0;
if(c=='$'){
point++;
vartype=02;
}
else if(c=='%'){
point++;
vartype++;
nm |=0200<<8;
}
}
/*
* getname() will return a pointer to a variable with vartype
* set to the correct type. If the variable is subscripted getarray
* is called and the subscripts are evaluated and depending upon
* the type of variable the index into that array is returned.
* Any simple variable that is not already declared is defined
* and has a value of 0 or null (for strings) assigned to it.
* In all instances a valid pointer is returned.
*/
memp getname()
{
memp getstring();
#ifdef LNAMES
register char *p,*q;
register struct entry *ep;
register int c;
register struct vardata *pt;
struct entry *np;
register int l;
nam[0]=c=getch();
if(!isletter(c))
error(VARREQD);
p = &nam[1];
for(l =c,c = *point;isletter(c) || isnumber(c) ; c = *++point)
if(p < &nam[MAXNAME-1] ){
l +=c;
*p++ = c;
}
*p = 0;
for(np = 0,ep=hshtab[l%HSHTABSIZ]; ep ; np = ep,ep=ep->link)
if(l == ep->ln_hash)
for(p = ep->_name,q = nam ; *q == *p++ ; )
if(!*q++)
goto got;
ep = (struct entry *)xpand(&enames,sizeof(struct entry));
if(!np)
hshtab[l%HSHTABSIZ] = ep;
else
np->link = ep;
for(p = ep->_name ,q = nam ; *p++ = *q++ ; );
ep->ln_hash = l;
got:
nm = (char *)ep - estring;
#else
register int c;
register struct vardata *pt;
nm=c=getch();
if(!isletter(c))
error(VARREQD);
c= *point;
if(isletter(c) ||isnumber(c)){
nm |=c<<8;
do{ c= *++point; }while(isletter(c) || isnumber(c));
}
#endif
vartype=0;
if(c=='$'){
vartype=02;
if(*++point==LBRACK)
getarray();
return(getstring());
}
else if(c=='%'){
point++;
vartype++;
nm |= 0200<<8;
}
if(*point==LBRACK)
return( (memp) getarray());
#ifdef LNAMES
/*
* now do hashing of the variables
*/
if( (c = varshash[l % HSHTABSIZ]) >= 0){
pt = (vardp)earray;
for(pt += c; pt < (vardp) vend;pt++)
if(pt->nam ==nm )
return( (memp) &pt->dt);
/*
* not found ****
*/
}
/*
* really look for it - will force varshash to be the lowest
* value. The hassle of chaining.
*/
if(chained)
for(pt = (vardp)earray; pt < (vardp) vend;pt++)
if(pt->nam ==nm ){
varshash[l % HSHTABSIZ] = pt - (vardp)earray;
return((memp) &pt->dt);
}
/*
* not found ****
*/
pt= (vardp) xpand(&vend,sizeof(struct vardata));
if(c < 0)
varshash[l % HSHTABSIZ] = pt - (vardp)earray;
#else
for(pt = (vardp)earray; pt < (vardp) vend;pt++)
if(pt->nam ==nm )
return( (memp) &pt->dt);
pt= (vardp) xpand(&vend,sizeof(struct vardata));
#endif
pt->nam=nm;
return( (memp) &pt->dt);
}
/*
* getstring() returns a pointer to a string structure if the string
* is not declared then it is defined.
*/
memp
getstring()
{
register struct stdata *p;
vartype=02;
for(p= (stdatap)estdt ; p < (stdatap)estring ; p++)
if(p->snam == nm )
return( (memp) p);
if( estdt - sizeof(struct stdata) < eostring){
garbage();
if(estdt - sizeof(struct stdata) <eostring)
error(OUTOFSTRINGSPACE);
}
p = (stdatap)estdt;
--p; estdt = (memp)p;
p->snam = nm;
p->stpt=0;
return( (memp) p);
}
/*
* getarray() evaluates the subscripts of an array and the tries
* to access it. getarray() returns different things dependent
* on the type of variable. For an integer or real then the pointer to
* the element of the array is returned.
* For a string array element then the nm[] array is filled out
* with a unique number and then getstring() is called to access it.
* The variable hash (in the strarr structure ) is used as the
* offset to the next array if the array is real or integer, but
* is the base for the unique number to access the string structure.
*
* This is a piece of 'hairy' codeing.
*/
getarray()
{
register struct strarr *p;
register int l;
short *m;
int c;
int i=1;
register int j=0;
char vty;
#ifdef LNAMES
memp savee;
#endif
point++;
vty=vartype;
if(vty==02){
for(p= (strarrp) edefns ; p < (strarrp) estarr ; p++)
if(p->snm ==nm )
goto got;
}
else {
for( p = (strarrp) estarr ; p < (strarrp)earray ;
p = (strarrp)((memp)p + p->hash) )
if(p->snm ==nm )
goto got;
}
error(19);
got: m = p->dim;
i=1;
do{
#ifdef LNAMES
savee = edefns;
#endif
l=evalint()-baseval;
#ifdef LNAMES
p = (strarrp)((memp)p + (edefns - savee));
#endif
if(l >= *m || l <0)
error(17);
j= l + j * *m;
if((c=getch())!=',')
break;
m++,i++;
} while(i <= p->dimens);
if(i!=p->dimens || c!=RBRACK)
error(16);
vartype=vty;
if(vty==02){
j += p->hash;
j |= 0100000;
nm = j;
}
else {
j <<= (vty ? 1 : 3 );
p++;
return( (int) ((char *)p+j) );
}
}
/*
* dimensio() executes the dim command. It sets up the strarr structure
* as needed. If the array is a string array then only the structure
* is filled in. This means that elements of a string array do not have
* storage allocated until assigned to. If the array is real or integer
* then the array is allocated space as well as the strarr array.
* This is why the hash element is needed so as to be able to access
* the next array.
*/
dimensio()
{
int dims[3];
int nmm;
long j;
int c;
char vty;
register int i;
register int *r;
register struct strarr *p;
for(;;){
r=dims;
i=0;
j=1;
getnm();
nmm = nm;
vty=vartype; /* save copy of type of array */
if(*point++!=LBRACK)
error(SYNTAX);
do{
*r=evalint() + 1 - baseval;
#ifndef pdp11
if( (j *= *r) <= 0 || j > 32767)
#else
if( (j=dimmul( (int)j , *r)) <= 0)
#endif
error(17);
if((c=getch())!=',')
break;
r++;i++;
}while(i<3);
if(i ==3 || c!=RBRACK)
error(16);
i++;
if(vty== 02){
for(p= (strarrp) edefns ;p < (strarrp) estarr;p++)
if(p->snm == nmm )
error(20);
if(j+shash > 32767)
error(17);
p = (strarrp) xpand(&estarr,sizeof(struct strarr));
p->hash= shash;
shash+=j;
}
else {
for(p = (strarrp)estarr ; p < (strarrp)earray ;
p = (strarrp)((memp)p + p->hash) )
if(p->snm == nmm )
error(20);
j<<= (vty ? 1 : 3);
j += sizeof(struct strarr);
#ifdef ALIGN4
j = (j + 3) & ~03;
#endif
if(nospace(j))
error(17);
p = (strarrp) xpand(&earray,(int)j);
p->hash = j; /* offset to next array */
}
p->snm = nmm; /* fill in common stuff */
p->dimens=i;
p->dim[0]=dims[0];
p->dim[1]=dims[1];
p->dim[2]=dims[2];
if(getch()!=',') /* any more arrays */
break;
}
point--;
normret;
}
/*
* Assign() is called if there is no keyword at the start of a
* statement ( Default assignment statement ) and by let.
* it just calls the relevent evaluation routine and leaves all the
* hard work to stringassign() and putin() to actualy assign the variables.
*/
assign()
{
register memp p;
register char vty;
register int c;
int i;
value t1;
extern int (*mbin[])();
#ifdef LNAMES
memp savee;
#endif
p= getname();
vty=vartype;
if(vty==02){
if(getch()!='=')
error(4);
stringeval(gblock);
stringassign( (stdatap)p );
return;
}
#ifdef LNAMES
savee = edefns;
#endif
if((c = getch()) != '='){
i = 6;
switch(c){
default:
error(4);
case '*':
case '/':
i += 2;
break;
case '+':
case '-':
break;
}
if(*point++ != '=')
error(4);
#ifndef V6C
t1 = *((value *)p);
#else
movein(p,&t1);
#endif
eval();
if(vty != vartype){
if(vty)
cvt(&t1);
else
cvt(&res);
vartype = 0;
}
(*mbin[i+vartype])(&t1,&res,c);
}
else
eval();
#ifdef LNAMES
/*
* cope with adding new names - pushes space up
*/
p += edefns - savee;
#endif
putin(p,vty);
}