home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Stars of Shareware: Programmierung
/
SOURCE.mdf
/
programm
/
msdos
/
c
/
cephes22
/
qfloat
/
qcalc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-17
|
26KB
|
1,404 lines
/* calc.c */
/* Keyboard command interpreter */
/* Copyright 1985 by S. L. Moshier */
#include <stdio.h>
#include "qhead.h"
/*
*#include "config.h"
*/
/* length of command line: */
#define LINLEN 128
#define XON 0x11
#define XOFF 0x13
#define SALONE 1
#define DECPDP 0
#define INTLOGIN 0
#define INTHELP 1
#ifndef TRUE
#define TRUE 1
#endif
/* initialize printf: */
#define INIPRINTF 0
#if DECPDP
#define TRUE 1
#endif
static char idterp[] = {
"\n\nSteve Moshier's command interpreter V1.3\n"};
#define ISLOWER(c) ((c >= 'a') && (c <= 'z'))
#define ISUPPER(c) ((c >= 'A') && (c <= 'Z'))
#define ISALPHA(c) (ISLOWER(c) || ISUPPER(c))
#define ISDIGIT(c) ((c >= '0') && (c <= '9'))
#define ISATF(c) (((c >= 'a')&&(c <= 'f')) || ((c >= 'A')&&(c <= 'F')))
#define ISXDIGIT(c) (ISDIGIT(c) || ISATF(c))
#define ISOCTAL(c) ((c >= '0') && (c < '8'))
#define ISALNUM(c) (ISALPHA(c) || (ISDIGIT(c))
FILE *fopen();
/* I/O log file: */
static char *savnam = 0;
static FILE *savfil = 0;
#include "qcalc.h"
/* space for double precision numbers */
static int vsp = 13;
static short vs[22][NQ] = {0};
/* the symbol table of temporary variables: */
#define NTEMP 4
struct varent temp[NTEMP] = {
"T", OPR | TEMP, &vs[14][0],
"T", OPR | TEMP, &vs[15][0],
"T", OPR | TEMP, &vs[16][0],
"\0", OPR | TEMP, &vs[17][0]
};
/* the symbol table of operators */
/* EOL is interpreted on null, newline, or ; */
struct symbol oprtbl[] = {
"BOL", OPR | BOL, 0,
"EOL", OPR | EOL, 0,
"-", OPR | UMINUS, 8,
/*"~", OPR | COMP, 8,*/
",", OPR | EOE, 1,
"=", OPR | EQU, 2,
/*"|", OPR | LOR, 3,*/
/*"^", OPR | LXOR, 4,*/
/*"&", OPR | LAND, 5,*/
"+", OPR | PLUS, 6,
"-", OPR | MINUS, 6,
"*", OPR | MULT, 7,
"/", OPR | DIV, 7,
/*"%", OPR | MOD, 7,*/
"(", OPR | LPAREN, 11,
")", OPR | RPAREN, 11,
"\0", ILLEG, 0
};
#define NOPR 8
/* the symbol table of indirect variables: */
extern short qpi[];
struct varent indtbl[] = {
"t", VAR | IND, &vs[21][0],
"u", VAR | IND, &vs[20][0],
"v", VAR | IND, &vs[19][0],
"w", VAR | IND, &vs[18][0],
"x", VAR | IND, &vs[10][0],
"y", VAR | IND, &vs[11][0],
"z", VAR | IND, &vs[12][0],
"pi", VAR | IND, &qpi[0],
"\0", ILLEG, 0
};
/* the symbol table of constants: */
#define NCONST 10
struct varent contbl[NCONST] = {
"C",CONST,&vs[0][0],
"C",CONST,&vs[1][0],
"C",CONST,&vs[2][0],
"C",CONST,&vs[3][0],
"C",CONST,&vs[4][0],
"C",CONST,&vs[5][0],
"C",CONST,&vs[6][0],
"C",CONST,&vs[7][0],
"C",CONST,&vs[8][0],
"\0",CONST,&vs[9][0]
};
/* the symbol table of string variables: */
static char strngs[4][40] = {0};
#define NSTRNG 5
struct strent strtbl[NSTRNG] = {
#if DECPDP
&strngs[0][0], VAR | STRING, &strngs[0][0],
&strngs[1][0], VAR | STRING, &strngs[1][0],
&strngs[2][0], VAR | STRING, &strngs[2][0],
&strngs[3][0], VAR | STRING, &strngs[3][0],
#else
&strngs[0][0], VAR | STRING, &strngs[0][0],
&strngs[1][0], VAR | STRING, &strngs[1][0],
&strngs[2][0], VAR | STRING, &strngs[2][0],
&strngs[3][0], VAR | STRING, &strngs[3][0],
#endif
"\0",ILLEG,0,
};
/* Help messages */
#if INTHELP
static char *intmsg[] = {
"?",
"Unkown symbol",
"Expression ends in illegal operator",
"Precede ( by operator",
")( is illegal",
"Unmatched )",
"Missing )",
"Illegal left hand side",
"Missing symbol",
"Must assign to a variable",
"Divide by zero",
"Missing symbol",
"Missing operator",
"Precede quantity by operator",
"Quantity preceded by )",
"Function syntax",
"Too many function args",
"No more temps",
"Arg list"
};
#endif
/* the symbol table of functions: */
#if SALONE
int hex(), cmdh(), cmdhlp();
/*int view();*/
int cmddm(), cmdtm(), cmdem();
/*int printf();*/
int take(), mxit(), exit(), bits();
int cmddig(), qfloor(), todbl();
int qsqrt(), qlog(), qexp(), qtanh(), qpow();
int qsave(), qsys();
/*
int qsin(), qcos(), qatn(), qjn(), qyn();
int qasin(), qtan(), qcosh(), qsinh(), qasinh(), qacosh();
int qacos(), qatanh(), qcot(), qgamma(), qcbrt(), qfac();
*/
/* log10(), exp10(), ndtr(), ndtri();*/
struct funent funtbl[] = {
"h", OPR | FUNC, cmdh,
"help", OPR | FUNC, cmdhlp,
"hex", OPR | FUNC, hex,
/*"view", OPR | FUNC, view,*/
/*
"acos", OPR | FUNC, qacos,
"acosh", OPR | FUNC, qacosh,
"asin", OPR | FUNC, qasin,
"asinh", OPR | FUNC, qasinh,
"atan", OPR | FUNC, qatn,
"atanh", OPR | FUNC, qatanh,
"cbrt", OPR | FUNC, qcbrt,
"cos", OPR | FUNC, qcos,
"cosh", OPR | FUNC, qcosh,
"cot", OPR | FUNC, qcot,
*/
"exp", OPR | FUNC, qexp,
/*"fac", OPR | FUNC, qfac,*/
"floor", OPR | FUNC, qfloor,
/*
"gamma", OPR | FUNC, qgamma,
"jv", OPR | FUNC, qjn,
"yn", OPR | FUNC, qyn,
"logten", OPR | FUNC, qlog10,
"expten", OPR | FUNC, qexp10,
*/
"log", OPR | FUNC, qlog,
/*
"ndtr", OPR | FUNC, ndtr,
"ndtri", OPR | FUNC, ndtri,
*/
"pow", OPR | FUNC, qpow,
/*
"sin", OPR | FUNC, qsin,
"sinh", OPR | FUNC, qsinh,
*/
"sqrt", OPR | FUNC, qsqrt,
/*"tan", OPR | FUNC, qtan,*/
"tanh", OPR | FUNC, qtanh,
"bits", OPR | FUNC, bits,
"digits", OPR | FUNC, cmddig,
"dm", OPR | FUNC, cmddm,
"tm", OPR | FUNC, cmdtm,
"em", OPR | FUNC, cmdem,
"take", OPR | FUNC | COMMAN, take,
"save", OPR | FUNC | COMMAN, qsave,
"system", OPR | FUNC | COMMAN, qsys,
"exit", OPR | FUNC, mxit,
"\0", OPR | FUNC, 0
};
/* the symbol table of key words */
struct funent keytbl[] = {
"\0", ILLEG, 0
};
#endif
/* Number of decimals to display */
#define DEFDIS 70
static int ndigits = DEFDIS;
/* Menu stack */
struct funent *menstk[5] = {&funtbl[0], NULL, NULL, NULL, NULL};
int menptr = 0;
/* Take file stack */
FILE *takstk[10] = {0};
int takptr = -1;
/* size of the expression scan list: */
#define NSCAN 20
/* previous token, saved for syntax checking: */
struct symbol *lastok = 0;
/* variables used by parser: */
static char str[128] = {0};
int uposs = 0; /* possible unary operator */
double nc = 0; /* numeric value of symbol */
static short qnc[NQ] = {0};
char lc[40] = { '\n' }; /* ASCII string of token symbol */
static char line[LINLEN] = { '\n','\0' }; /* input command line */
static char maclin[LINLEN] = { '\n','\0' }; /* macro command */
char *interl = line; /* pointer into line */
extern char *interl;
static int maccnt = 0; /* number of times to execute macro command */
static int comptr = 0; /* comma stack pointer */
static int comstk[5][NQ] = {0}; /* comma argument stack */
static int narptr = 0; /* pointer to number of args */
static int narstk[5] = {0}; /* stack of number of function args */
/* main() */
/* Entire program starts here */
main()
{
/* the scan table: */
/* array of pointers to symbols which have been parsed: */
struct symbol *ascsym[NSCAN];
/* current place in ascsym: */
register struct symbol **as;
/* array of attributes of operators parsed: */
int ascopr[NSCAN];
/* current place in ascopr: */
register int *ao;
#if LARGEMEM
/* array of precedence levels of operators: */
long asclev[NSCAN];
/* current place in asclev: */
long *al;
long symval; /* value of symbol just parsed */
#else
int asclev[NSCAN];
int *al;
int symval;
#endif
short acc[NQ]; /* the accumulator, for arithmetic */
int accflg; /* flags accumulator in use */
int val[NQ]; /* value to be combined into accumulator */
register struct symbol *psym; /* pointer to symbol just parsed */
struct varent *pvar; /* pointer to an indirect variable symbol */
struct funent *pfun; /* pointer to a function symbol */
struct strent *pstr; /* pointer to a string symbol */
int att; /* attributes of symbol just parsed */
int i; /* counter */
int offset; /* parenthesis level */
int lhsflg; /* kluge to detect illegal assignments */
struct symbol *tsym; /* pointer to temporary symbol */
struct symbol *parser(); /* parser returns pointer to symbol */
int errcod; /* for syntax error printout */
/* Perform general initialization */
init();
menstk[0] = &funtbl[0];
menptr = 0;
cmdhlp(); /* print out list of symbols */
/* Return here to get next command line to execute */
getcmd:
/* initialize registers and mutable symbols */
accflg = 0; /* Accumulator not in use */
qclear(acc); /* Clear the accumulator */
offset = 0; /* Parenthesis level zero */
comptr = 0; /* Start of comma stack */
narptr = -1; /* Start of function arg counter stack */
psym = (struct symbol *)&contbl[0];
for( i=0; i<NCONST; i++ )
{
psym->attrib = CONST; /* clearing the busy bit */
++psym;
}
psym = (struct symbol *)&temp[0];
for( i=0; i<NTEMP; i++ )
{
psym->attrib = VAR | TEMP; /* clearing the busy bit */
++psym;
}
psym = (struct symbol *)&strtbl[0];
for( i=0; i<NSTRNG; i++ )
{
psym->attrib = STRING | VAR;
++psym;
}
/* List of scanned symbols is empty: */
as = &ascsym[0];
*as = 0;
--as;
/* First item in scan list is Beginning of Line operator */
ao = &ascopr[0];
*ao = oprtbl[0].attrib & 0xf; /* BOL */
/* value of first item: */
al = &asclev[0];
*al = oprtbl[0].sym;
lhsflg = 0; /* illegal left hand side flag */
psym = &oprtbl[0]; /* pointer to current token */
/* get next token from input string */
gettok:
lastok = psym; /* last token = current token */
psym = parser(); /* get a new current token */
/*printf( "%s attrib %7o value %7o\n", psym->spel, psym->attrib & 0xffff,
psym->sym );*/
/* Examine attributes of the symbol returned by the parser */
att = psym->attrib;
if( att == ILLEG )
{
errcod = 1;
goto synerr;
}
/* Push functions onto scan list without analyzing further */
if( att & FUNC )
{
/* A command is a function whose argument is
* a pointer to the rest of the input line.
* A second argument is also passed: the address
* of the last token parsed.
*/
if( att & COMMAN )
{
pfun = (struct funent *)psym;
( *(pfun->fun))( interl, lastok );
abmac(); /* scrub the input line */
goto getcmd; /* and ask for more input */
}
++narptr; /* offset to number of args */
narstk[narptr] = 0;
i = lastok->attrib & 0xffff; /* attrib=short, i=int */
if( ((i & OPR) == 0)
|| (i == (OPR | RPAREN))
|| (i == (OPR | FUNC)) )
{
errcod = 15;
goto synerr;
}
++lhsflg;
++as;
*as = psym;
++ao;
*ao = FUNC;
++al;
*al = offset + UMINUS;
goto gettok;
}
/* deal with operators */
if( att & OPR )
{
att &= 0xf;
/* expression cannot end with an operator other than
* (, ), BOL, or a function
*/
if( (att == RPAREN) || (att == EOL) || (att == EOE))
{
i = lastok->attrib & 0xffff; /* attrib=short, i=int */
if( (i & OPR)
&& (i != (OPR | RPAREN))
&& (i != (OPR | LPAREN))
&& (i != (OPR | FUNC))
&& (i != (OPR | BOL)) )
{
errcod = 2;
goto synerr;
}
}
++lhsflg; /* any operator but ( and = is not a legal lhs */
/* operator processing, continued */
switch( att )
{
case EOE:
lhsflg = 0;
break;
case LPAREN:
/* ( must be preceded by an operator of some sort. */
if( ((lastok->attrib & OPR) == 0) )
{
errcod = 3;
goto synerr;
}
/* also, a preceding ) is illegal */
if( (unsigned short )lastok->attrib == (OPR|RPAREN))
{
errcod = 4;
goto synerr;
}
/* Begin looking for illegal left hand sides: */
lhsflg = 0;
offset += RPAREN; /* new parenthesis level */
goto gettok;
case RPAREN:
offset -= RPAREN; /* parenthesis level */
if( offset < 0 )
{
errcod = 5; /* parenthesis error */
goto synerr;
}
goto gettok;
case EOL:
if( offset != 0 )
{
errcod = 6; /* parenthesis error */
goto synerr;
}
break;
case EQU:
if( --lhsflg ) /* was incremented before switch{} */
{
errcod = 7;
goto synerr;
}
case UMINUS:
case COMP:
goto pshopr; /* evaluate right to left */
default: ;
}
/* evaluate expression whenever precedence is not increasing */
symval = psym->sym + offset;
while( symval <= *al )
{
/* if just starting, must fill accumulator with last
* thing on the line
*/
if( (accflg == 0) && (as >= ascsym) && (((*as)->attrib & FUNC) == 0 ))
{
pvar = (struct varent *)*as;
qmov( pvar->value, acc );
--as;
accflg = 1;
}
/* handle beginning of line type cases, where the symbol
* list ascsym[] may be empty.
*/
switch( *ao )
{
case BOL:
qtoasc( acc, str, ndigits );
printf( "%s\n", str ); /* This is the answer */
if( savfil )
fprintf( savfil, "%s\n", str );
goto getcmd; /* all finished */
case UMINUS:
qneg( acc );
goto nochg;
/*
case COMP:
acc = ~acc;
goto nochg;
*/
default: ;
}
/* Now it is illegal for symbol list to be empty,
* because we are going to need a symbol below.
*/
if( as < &ascsym[0] )
{
errcod = 8;
goto synerr;
}
/* get attributes and value of current symbol */
att = (*as)->attrib;
pvar = (struct varent *)*as;
if( att & FUNC )
qclear( val );
else
qmov( pvar->value, val );
/* Expression evaluation, continued. */
switch( *ao )
{
case FUNC:
pfun = (struct funent *)*as;
/* Call the function with appropriate number of args */
i = narstk[ narptr ];
--narptr;
switch(i)
{
case 0:
( *(pfun->fun) )(acc, acc);
break;
case 1:
( *(pfun->fun) )(acc,comstk[comptr-1],acc);
break;
case 2:
( *(pfun->fun) )(acc, comstk[comptr-2],
comstk[comptr-1],acc);
break;
case 3:
( *(pfun->fun) )(acc, comstk[comptr-3],
comstk[comptr-2], comstk[comptr-1],acc);
break;
default:
errcod = 16;
goto synerr;
}
comptr -= i;
accflg = 1; /* in case at end of line */
break;
case EQU:
if( ( att & TEMP) || ((att & VAR) == 0) || (att & STRING) )
{
errcod = 9;
goto synerr; /* can only assign to a variable */
}
pvar = (struct varent *)*as;
qmov( acc, pvar->value );
break;
case PLUS:
qadd( acc, val, acc ); break;
case MINUS:
qsub( acc, val, acc ); break;
case MULT:
qmul( acc, val, acc ); break;
case DIV:
if( acc[1] == 0 )
{
divzer:
errcod = 10;
goto synerr;
}
qdiv( acc, val, acc ); break;
/*
case MOD:
if( acc == 0 )
goto divzer;
acc = val % acc; break;
case LOR:
acc |= val; break;
case LXOR:
acc ^= val; break;
case LAND:
acc &= val; break;
*/
case EOE:
if( narptr < 0 )
{
errcod = 18;
goto synerr;
}
narstk[narptr] += 1;
qmov( acc, comstk[comptr++] );
/* printf( "\ncomptr: %d narptr: %d %d\n", comptr, narptr, acc );*/
qmov( val, acc );
break;
}
/* expression evaluation, continued */
/* Pop evaluated tokens from scan list: */
/* make temporary variable not busy */
if( att & TEMP )
(*as)->attrib &= ~BUSY;
if( as < &ascsym[0] ) /* can this happen? */
{
errcod = 11;
goto synerr;
}
--as;
nochg:
--ao;
--al;
if( ao < &ascopr[0] ) /* can this happen? */
{
errcod = 12;
goto synerr;
}
noval:
/* If precedence level will now increase, then */
/* save accumulator in a temporary location */
if( symval > *al )
{
/* find a free temp location */
pvar = &temp[0];
for( i=0; i<NTEMP; i++ )
{
if( (pvar->attrib & BUSY) == 0)
goto temfnd;
++pvar;
}
errcod = 17;
printf( "no more temps\n" );
pvar = &temp[0];
goto synerr;
temfnd:
pvar->attrib |= BUSY;
qmov( acc, pvar->value );
/*printf( "temp %d\n", acc );*/
accflg = 0;
++as; /* push the temp onto the scan list */
*as = (struct symbol *)pvar;
}
} /* End of evaluation loop */
/* Push operator onto scan list when precedence increases */
pshopr:
++ao;
*ao = psym->attrib & 0xf;
++al;
*al = psym->sym + offset;
goto gettok;
} /* end of OPR processing */
/* Token was not an operator. Push symbol onto scan list. */
if( (lastok->attrib & OPR) == 0 )
{
errcod = 13;
goto synerr; /* quantities must be preceded by an operator */
}
if( (unsigned short )lastok->attrib == (OPR | RPAREN) ) /* ...but not by ) */
{
errcod = 14;
goto synerr;
}
++as;
*as = psym;
goto gettok;
synerr:
#if INTHELP
printf( "%s ", intmsg[errcod] );
#endif
printf( " error %d\n", errcod );
if( savfil )
fprintf( savfil, " error %d\n", errcod );
abmac(); /* flush the command line */
goto getcmd;
} /* end of program */
/* parser() */
/* Get token from input string and identify it. */
static char number[40] = {0};
struct symbol *parser( )
{
register struct symbol *psym;
register char *pline;
struct varent *pvar;
struct strent *pstr;
char *cp, *plc, *pn;
int i;
/* reference for old Whitesmiths compiler: */
/*
*extern FILE *stdout;
*/
pline = interl; /* get current location in command string */
/* If at beginning of string, must ask for more input */
if( pline == line )
{
if( maccnt > 0 )
{
--maccnt;
cp = maclin;
plc = pline;
while( (*plc++ = *cp++) != 0 )
;
goto mstart;
}
if( takptr < 0 )
{ /* no take file active: prompt keyboard input */
printf("* ");
if( savfil )
fprintf( savfil, "* " );
}
/* Various ways of typing in a command line. */
/*
* Old Whitesmiths call to print "*" immediately
* use RT11 .GTLIN to get command string
* from command file or terminal
*/
/*
* fflush(stdout);
* gtlin(line);
*/
zgets( line, TRUE ); /* keyboard input for other systems: */
mstart:
uposs = 1; /* unary operators possible at start of line */
}
ignore:
/* Skip over spaces */
while( *pline == ' ' )
++pline;
/* unary minus after operator */
if( uposs && (*pline == '-') )
{
psym = &oprtbl[2]; /* UMINUS */
++pline;
goto pdon3;
}
/* COMP */
/*
if( uposs && (*pline == '~') )
{
psym = &oprtbl[3];
++pline;
goto pdon3;
}
*/
if( uposs && (*pline == '+') ) /* ignore leading plus sign */
{
++pline;
goto ignore;
}
/* end of null terminated input */
if( (*pline == '\n') || (*pline == '\0') || (*pline == '\r') )
{
pline = line;
goto endlin;
}
if( *pline == ';' )
{
++pline;
endlin:
psym = &oprtbl[1]; /* EOL */
goto pdon2;
}
/* parser() */
/* Test for numeric input */
if( (ISDIGIT(*pline)) || (*pline == '.') )
{
nc = 0.0; /* initialize numeric input to zero */
qclear( qnc );
/*******/
if( *pline == '0' )
{ /* leading "0" may mean octal or hex radix */
++pline;
if( *pline == '.' )
goto decimal; /* 0.ddd */
/* leading "0x" means hexadecimal radix */
if( (*pline == 'x') || (*pline == 'X') )
{
++pline;
while( ISXDIGIT(*pline) )
{
i = *pline++ & 0xff;
if( i >= 'a' )
i -= 047;
if( i >= 'A' )
i -= 07;
i -= 060;
nc = (nc * 16.0) + i;
etoq( &nc, qnc );
}
goto numdon;
}
else
{
while( ISOCTAL( *pline ) )
{
i = *pline++ & 0xff - 060;
nc = ( nc * 8.0) + i;
etoq( &nc, qnc );
}
goto numdon;
}
}
else
{
/* no leading "0" means decimal radix */
/******/
decimal:
pn = number;
while( (ISDIGIT(*pline)) || (*pline == '.') )
*pn++ = *pline++;
/* get possible exponent field */
if( (*pline == 'e') || (*pline == 'E') )
*pn++ = *pline++;
else
goto numcvt;
if( (*pline == '-') || (*pline == '+') )
*pn++ = *pline++;
while( ISDIGIT(*pline) )
*pn++ = *pline++;
numcvt:
*pn++ = ' ';
*pn++ = 0;
asctoq( number, qnc );
/* sscanf( number, "%le", &nc );*/
}
/* output the number */
numdon:
/* search the symbol table of constants */
pvar = &contbl[0];
for( i=0; i<NCONST; i++ )
{
if( (pvar->attrib & BUSY) == 0 )
goto confnd;
if( qcmp( pvar->value, qnc) == 0 )
{
psym = (struct symbol *)pvar;
goto pdon2;
}
++pvar;
}
printf( "no room for constant\n" );
psym = (struct symbol *)&contbl[0];
goto pdon2;
confnd:
pvar->spel= contbl[0].spel;
pvar->attrib = CONST | BUSY;
qmov( qnc, pvar->value );
psym = (struct symbol *)pvar;
goto pdon2;
}
/* check for operators */
psym = &oprtbl[3];
for( i=0; i<NOPR; i++ )
{
if( *pline == *(psym->spel) )
goto pdon1;
++psym;
}
/* if quoted, it is a string variable */
if( *pline == '"' )
{
/* find an empty slot for the string */
pstr = strtbl; /* string table */
for( i=0; i<NSTRNG-1; i++ )
{
if( (pstr->attrib & BUSY) == 0 )
goto fndstr;
++pstr;
}
printf( "No room for string\n" );
pstr->attrib |= ILLEG;
psym = (struct symbol *)pstr;
goto pdon0;
fndstr:
plc = (char *)(pstr->string);
++pline;
for( i=0; i<39; i++ )
{
*plc++ = *pline;
if( (*pline == '\n') || (*pline == '\0') || (*pline == '\r') )
{
illstr:
pstr = &strtbl[NSTRNG-1];
pstr->attrib |= ILLEG;
printf( "Missing string terminator\n" );
psym = (struct symbol *)pstr;
goto pdon0;
}
if( *pline++ == '"' )
goto finstr;
}
goto illstr; /* no terminator found */
finstr:
*(--plc) = '\0';
pstr->attrib |= BUSY;
psym = (struct symbol *)pstr;
goto pdon2;
}
/* If none of the above, search function and symbol tables: */
/* copy character string to array lc[] */
plc = &lc[0];
while( ISALPHA(*pline) )
{
/* convert to lower case characters */
if( ISUPPER( *pline ) )
*pline += 040;
*plc++ = *pline++;
}
*plc = 0; /* Null terminate the output string */
/* parser() */
psym = (struct symbol *)menstk[menptr]; /* function table */
plc = &lc[0];
cp = psym->spel;
do
{
if( strcmp( plc, cp ) == 0 )
goto pdon3; /* following unary minus is possible */
++psym;
cp = psym->spel;
}
while( *cp != '\0' );
psym = (struct symbol *)&indtbl[0]; /* indirect symbol table */
plc = &lc[0];
cp = psym->spel;
do
{
if( strcmp( plc, cp ) == 0 )
goto pdon2;
++psym;
cp = psym->spel;
}
while( *cp != '\0' );
pdon0:
pline = line; /* scrub line if illegal symbol */
goto pdon2;
pdon1:
++pline;
if( (psym->attrib & 0xf) == RPAREN )
pdon2: uposs = 0;
else
pdon3: uposs = 1;
interl = pline;
return( psym );
} /* end of parser */
/* exit from current menu */
cmdex()
{
if( menptr == 0 )
{
printf( "Main menu is active.\n" );
}
else
--menptr;
cmdh();
return(0);
}
/* gets() */
zgets( gline, echo )
char *gline;
int echo;
{
register char *pline;
register int i;
scrub:
pline = gline;
getsl:
if( (pline - gline) >= LINLEN )
{
printf( "\nLine too long\n *" );
goto scrub;
}
if( takptr < 0 )
{ /* get character from keyboard */
#if DECPDP
gtlin( gline );
return(0);
#else
*pline = getchar();
#endif
}
else
{ /* get a character from take file */
i = fgetc( takstk[takptr] );
if( i == -1 )
{ /* end of take file */
if( takptr >= 0 )
{ /* close file and bump take stack */
fclose( takstk[takptr] );
takptr -= 1;
}
if( takptr < 0 ) /* no more take files: */
printf( "*" ); /* prompt keyboard input */
goto scrub; /* start a new input line */
}
*pline = i;
}
*pline &= 0x7f;
/* xon or xoff characters need filtering out. */
if ( *pline == XON || *pline == XOFF )
goto getsl;
/* control U or control C */
if( (*pline == 025) || (*pline == 03) )
{
printf( "\n" );
goto scrub;
}
/* Backspace or rubout */
if( (*pline == 010) || (*pline == 0177) )
{
pline -= 1;
if( pline >= gline )
{
if ( echo )
printf( "\010\040\010" );
goto getsl;
}
else
goto scrub;
}
if ( echo )
printf( "%c", *pline );
if( (*pline != '\n') && (*pline != '\r') )
{
++pline;
goto getsl;
}
*pline = 0;
if ( echo )
printf( "%c", '\n' ); /* \r already echoed */
if( savfil )
fprintf( savfil, "%s\n", gline );
}
/* help function */
cmdhlp()
{
printf( "%s", idterp );
printf( "\nFunctions:\n" );
prhlst( &funtbl[0] );
printf( "\nVariables:\n" );
prhlst( &indtbl[0] );
printf( "\nOperators:\n" );
prhlst( &oprtbl[2] );
printf("\n");
return(0.0);
}
cmdh()
{
prhlst( menstk[menptr] );
printf( "\n" );
return(0.0);
}
/* print keyword spellings */
prhlst(ps)
register struct symbol *ps;
{
register int j, k;
int m;
j = 0;
while( *(ps->spel) != '\0' )
{
k = strlen( ps->spel ) - 1;
/* size of a tab field is 2**3 chars */
m = ((k >> 3) + 1) << 3;
j += m;
if( j > 72 )
{
printf( "\n" );
j = m;
}
printf( "%s\t", ps->spel );
++ps;
}
}
#if SALONE
init(){}
#endif
/* macro commands */
/* define macro */
cmddm(arg)
int arg;
{
zgets( maclin, TRUE );
return(0.0);
}
/* type (i.e., display) macro */
cmdtm(arg)
int arg;
{
printf( "%s\n", maclin );
return(0.0);
}
/* execute macro # times */
cmdem( arg )
int *arg;
{
double dn;
int n;
qtoe( arg, &dn );
n = dn;
if( n <= 0 )
n = 1;
maccnt = n;
return( n );
}
/* open a take file */
take( fname )
char *fname;
{
FILE *f;
register int i;
while( *fname == ' ' )
fname += 1;
f = fopen( fname, "r" );
if( f == 0 )
{
takerr:
printf( "Can't open take file %s\n", fname );
takptr = -1; /* terminate all take file input */
return(-1);
}
takptr += 1;
takstk[ takptr ] = f;
printf( "Running %s\n", fname );
return(0.0);
}
/* abort macro execution */
abmac()
{
maccnt = 0;
interl = line;
}
/* display integer part in hex, octal, and decimal
*/
hex(qx)
short *qx;
{
long z;
double x;
double fabs();
qtoe( qx, &x );
if( fabs(x) >= 2.147483648e9 )
{
printf( "hex: too large\n" );
return(x);
}
z = x;
printf( "0%lo 0x%lx %ld.\n", z, z, z );
return(x);
}
int bits( x )
short x[];
{
int i, j;
j = 0;
for( i=0; i<NQ; i++ )
{
printf( "0x%04x,", x[i] & 0xffff );
if( ++j > 7 )
{
j = 0;
printf( "\n" );
}
}
printf( "\n" );
/* display IEEE format double precision version */
todbl( x );
return(0);
}
/* Exit to monitor. */
mxit()
{
if( savfil )
fclose( savfil );
exit(0);
}
cmddig( x )
short x[];
{
double dx;
qtoe( x, &dx );
ndigits = dx;
if( ndigits <= 0 )
ndigits = DEFDIS;
return(0);
}
todbl( u )
short u[];
{
short x[NQ+1];
long e;
int i;
qmovz( u, x );
shup1(x);
shup1(x);
shup1(x);
shup1(x);
shup1(x);
e = x[1];
e = e - 040001 + 0x3ff;
if( e < -101 )
{
qclear(x );
goto display;
}
/* denormalize if exponent is nonpositive */
if( e <= 0 )
{
while( e <= 0 )
{
shdn1(x);
e += 1;
}
e = 0;
}
e = (e << 4) & 0x7ff0;
if( x[0] )
e |= 0x8000;
x[2] &= 0xf;
x[2] |= e;
display:
for( i=0; i<6; i++ )
printf( "%04x ", x[7-i] & 0xffff );
printf( "\n" );
qtoe( u, x );
for( i=0; i<4; i++ )
printf( "%04x ", x[i] & 0xffff );
printf( "\n" );
}
qsave(x)
char *x;
{
if( savfil )
fclose( savfil );
while( *x == ' ' )
x += 1;
if( *x == '\0' )
savnam = "calc.sav";
else
savnam = x;
savfil = fopen( savnam, "w" );
if( savfil <= 0 )
printf( "Error opening %s\n", savnam );
}
qsys(x)
char *x;
{
system( x+1 );
cmdh();
}