📄 lcalc.c
字号:
/* calc.c *//* Keyboard command interpreter *//* by Stephen L. Moshier */#include <unistd.h>int system();void e113toasc(), asctoe113(), init();/* 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 squirrel printf: */#define INIPRINTF 0#if DECPDP#define TRUE 1#endif#include <stdio.h>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();#include "lcalc.h"#include "ehead.h"/* space for working precision numbers */static long double vs[22];/* the symbol table of temporary variables: */#define NTEMP 4struct varent temp[NTEMP] = {{"T", OPR | TEMP, &vs[14]},{"T", OPR | TEMP, &vs[15]},{"T", OPR | TEMP, &vs[16]},{"\0", OPR | TEMP, &vs[17]}};/* 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 long double PIL;struct varent indtbl[] = {{"t", VAR | IND, &vs[21]},{"u", VAR | IND, &vs[20]}, {"v", VAR | IND, &vs[19]},{"w", VAR | IND, &vs[18]}, {"x", VAR | IND, &vs[10]},{"y", VAR | IND, &vs[11]},{"z", VAR | IND, &vs[12]},{"pi", VAR | IND, &PIL},{"\0", ILLEG, 0}};/* the symbol table of constants: */#define NCONST 10struct varent contbl[NCONST] = {{"C",CONST,&vs[0]},{"C",CONST,&vs[1]},{"C",CONST,&vs[2]},{"C",CONST,&vs[3]},{"C",CONST,&vs[4]},{"C",CONST,&vs[5]},{"C",CONST,&vs[6]},{"C",CONST,&vs[7]},{"C",CONST,&vs[8]},{"\0",CONST,&vs[9]}};/* the symbol table of string variables: */static char strngs[160] = {0};#define NSTRNG 5struct strent strtbl[NSTRNG] = {{0, VAR | STRING, 0},{0, VAR | STRING, 0},{0, VAR | STRING, 0},{0, VAR | STRING, 0},{"\0",ILLEG,0},};/* Help messages */#if INTHELPstatic 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 SALONElong double hex(), cmdh(), cmdhlp();long double cmddm(), cmdtm(), cmdem();long double take(), mxit(), bits(), csys();long double cmddig(), prhlst(), abmac();long double ifrac();long double floorl(), logl(), powl(), sqrtl(), tanhl(), expl();long double asinl(), acosl(), atanl(), sinl(), cosl(), tanl();long double sinhl(), asinhl(), coshl(), acoshl(), atanhl(), cbrtl();long double log10l(), exp10l(), log2l(), exp2l(), compare();struct funent funtbl[] = {{"h", OPR | FUNC, cmdh},{"help", OPR | FUNC, cmdhlp},{"hex", OPR | FUNC, hex},/*"view", OPR | FUNC, view,*/{"asin", OPR | FUNC, asinl},{"sin", OPR | FUNC, sinl},{"acos", OPR | FUNC, acosl},{"cos", OPR | FUNC, cosl},{"atan", OPR | FUNC, atanl},{"tan", OPR | FUNC, tanl},{"asinh", OPR | FUNC, asinhl},{"sinh", OPR | FUNC, sinhl},{"acosh", OPR | FUNC, acoshl},{"cosh", OPR | FUNC, coshl},{"atanh", OPR | FUNC, atanhl},{"tanh", OPR | FUNC, tanhl},{"exp", OPR | FUNC, expl},{"exptwo", OPR | FUNC, exp2l},{"expten", OPR | FUNC, exp10l},{"log", OPR | FUNC, logl},{"logtwo", OPR | FUNC, log2l},{"logten", OPR | FUNC, log10l},{"pow", OPR | FUNC, powl},{"sqrt", OPR | FUNC, sqrtl},{"cbrt", OPR | FUNC, cbrtl},{"ifrac", OPR | FUNC, ifrac},{"floor", OPR | FUNC, floorl},{"cmp", OPR | FUNC, compare},{"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},{"system", OPR | FUNC | COMMAN, csys},{"exit", OPR | FUNC, mxit},/*"remain", OPR | FUNC, eremain,*/{"\0", OPR | FUNC, 0}};/* the symbol table of key words */struct funent keytbl[] = {{"\0", ILLEG, 0}};#endifvoid zgets();/* Number of decimals to display */#define DEFDIS 70static 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 */static long double qnc;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 long double comstk[5]; /* 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 */int 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 */#elseint asclev[NSCAN];int *al;int symval;#endiflong double acc; /* the accumulator, for arithmetic */int accflg; /* flags accumulator in use */long double val; /* 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 *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 */acc = 0.0L; /* 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; }pstr = &strtbl[0];for( i=0; i<NSTRNG; i++ ) { pstr->spel = &strngs[ 40*i ]; pstr->attrib = STRING | VAR; pstr->string = &strngs[ 40*i ]; ++pstr; }/* 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;/* if( pvar->attrib & STRING ) strcpy( (char *)&acc, (char *)pvar->value ); else*/ acc = *pvar->value; --as; accflg = 1; }/* handle beginning of line type cases, where the symbol * list ascsym[] may be empty. */ switch( *ao ) { case BOL: /* printf( "%.16e\n", (double )acc ); *//* e64toasc( &acc, str, 100 );*/ e113toasc( &acc, str, 100 ); printf( "%s\n", str ); goto getcmd; /* all finished */ case UMINUS: acc = -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 ) val = 0.0L; else {/* if( att & STRING ) strcpy( (char *)&val, (char *)pvar->value ); else*/ val = *pvar->value; }/* 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: acc = ( *(pfun->fun) )(acc); break; case 1: acc = ( *(pfun->fun) )(acc, comstk[comptr-1]); break; case 2: acc = ( *(pfun->fun) )(acc, comstk[comptr-2], comstk[comptr-1]); break; case 3: acc = ( *(pfun->fun) )(acc, comstk[comptr-3], comstk[comptr-2], comstk[comptr-1]); 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; *pvar->value = acc; break; case PLUS: acc = acc + val; break; case MINUS: acc = val - acc; break; case MULT: acc = acc * val; break; case DIV: if( acc == 0.0L ) {/*divzer:*/ errcod = 10; goto synerr; } 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; comstk[comptr++] = acc;/* printf( "\ncomptr: %d narptr: %d %d\n", comptr, narptr, acc );*/ acc = val; 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; }/* 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; *pvar->value = acc; /*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 INTHELPprintf( "%s ", intmsg[errcod] );#endifprintf( " 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[128];struct symbol *parser( ){register struct symbol *psym;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -