Created
December 29, 2015 07:36
-
-
Save spot62/3d71e0702bcb4f435698 to your computer and use it in GitHub Desktop.
Extended Schildt's calculator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <ctype.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <math.h> | |
#include "expcalc.h" | |
enum | |
{ | |
DELIMITER=1, | |
NUMBER=2, | |
VARIABLE=3, | |
FUNCTION=4, | |
}; | |
static char *prog; /* pointer to expression */ | |
static char token[80]; | |
static char tok_type; | |
double (*func)(double)=NULL; | |
static int error=0; | |
/* 26 user variables, A-Z */ | |
static double vars[26] = { | |
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, | |
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, | |
0.0, 0.0, 0.0, 0.0, 0.0, 0.0 | |
}; | |
static void serror(int error); | |
static int isdelim(char c); | |
static void get_token(void), putback(void); | |
static double find_var(char *s); | |
static void find_func(char *s); | |
static void atom(double *answer); | |
static void eval_exp1(double *result); | |
static void eval_exp2(double *answer); | |
static void eval_exp3(double *answer); | |
static void eval_exp4(double *answer); | |
static void eval_exp5(double *answer); | |
static void eval_exp6(double *answer); | |
static int isdelim(char c) | |
{ | |
return (strchr(" +-/*%^=()", c) || c==9 || c=='\r' || c==0)?1:0; | |
} | |
static void get_token(void) | |
{ | |
register char *temp; | |
tok_type = 0; | |
temp = token; | |
*temp = '\0'; | |
if(!*prog) | |
return; /* end of expression */ | |
while(isspace(*prog)) | |
++prog; /* skip space etc */ | |
if(isdelim(*prog)) | |
{ | |
tok_type = DELIMITER; | |
/* go to next char */ | |
*temp++ = *prog++; | |
} | |
else if(isalpha(*prog)) | |
{ | |
while(!isdelim(*prog)) | |
*temp++ = *prog++; | |
if(*prog =='(') | |
{ | |
tok_type = FUNCTION; | |
} | |
else | |
{ | |
tok_type = VARIABLE; | |
} | |
} | |
else if(isdigit(*prog)) | |
{ | |
while(!isdelim(*prog)) | |
*temp++ = *prog++; | |
tok_type = NUMBER; | |
} | |
*temp = '\0'; | |
} | |
static void eval_exp(double *answer) | |
{ | |
get_token(); | |
if(!*token) | |
{ | |
serror(2); | |
return; | |
} | |
eval_exp1(answer); | |
if(*token) | |
serror(0); /* last must be zero */ | |
} | |
static void eval_exp1(double *answer) | |
{ | |
int slot; | |
char ttok_type; | |
char temp_token[80]; | |
if(tok_type == VARIABLE) | |
{ | |
strcpy(temp_token, token); | |
ttok_type = tok_type; | |
slot = toupper(*token) - 'A'; | |
get_token(); | |
if(*token != '=') | |
{ | |
putback(); | |
strcpy(token, temp_token); | |
tok_type = ttok_type; | |
} | |
else | |
{ | |
get_token(); | |
eval_exp2(answer); | |
vars[slot] = *answer; | |
return; | |
} | |
} | |
eval_exp2(answer); | |
} | |
static void eval_exp2(double *answer) | |
{ | |
register char op; | |
double temp; | |
eval_exp3(answer); | |
while((op = *token) == '+' || op == '-') | |
{ | |
get_token(); | |
eval_exp3(&temp); | |
switch(op) | |
{ | |
case '-': | |
*answer = *answer - temp; | |
break; | |
case '+': | |
*answer = *answer + temp; | |
break; | |
} | |
} | |
} | |
static void eval_exp3(double *answer) | |
{ | |
register char op; | |
double temp; | |
eval_exp4(answer); | |
while((op = *token) == '*' || op == '/' || op == '%') | |
{ | |
get_token(); | |
eval_exp4(&temp); | |
switch(op) | |
{ | |
case '*': | |
*answer = *answer * temp; | |
break; | |
case '/': | |
if(temp == 0.0) | |
{ | |
serror(3); /* divide by zero */ | |
*answer = 0.0; | |
} | |
else | |
{ | |
*answer = *answer / temp; | |
} | |
break; | |
case '%': | |
*answer = (int) *answer % (int) temp; | |
break; | |
} | |
} | |
} | |
static void eval_exp4(double *answer) | |
{ | |
double temp; | |
__attribute__ ((unused)) double ex; | |
//register int t; | |
eval_exp5(answer); | |
if(*token == '^') | |
{ | |
get_token(); | |
eval_exp4(&temp); | |
ex = *answer; | |
if(temp==0.0) | |
{ | |
*answer = 1.0; | |
return; | |
} | |
*answer = pow(*answer, temp); | |
} | |
} | |
static void eval_exp5(double *answer) | |
{ | |
register char op; | |
op = 0; | |
if((tok_type == DELIMITER) | |
&& (*token == '+' || *token == '-')) | |
{ | |
op = *token; | |
get_token(); | |
} | |
eval_exp6(answer); | |
if(op == '-') | |
*answer = -(*answer); | |
} | |
static void eval_exp6(double *answer) | |
{ | |
double (*lfunc)(double)=NULL; | |
if(*token == '(') | |
{ | |
if(func) | |
{ | |
lfunc=func; | |
func=NULL; | |
} | |
get_token(); | |
eval_exp2(answer); | |
if(*token == ')') | |
{ | |
if(lfunc) | |
{ | |
*answer=lfunc(*answer); | |
lfunc=NULL; | |
} | |
} | |
else | |
{ | |
serror(1); | |
} | |
get_token(); | |
} | |
else | |
{ | |
atom(answer); | |
} | |
} | |
static void atom(double *answer) | |
{ | |
switch(tok_type) | |
{ | |
case VARIABLE: | |
*answer = find_var(token); | |
get_token(); | |
return; | |
case NUMBER: | |
*answer = atof(token); | |
get_token(); | |
return; | |
case FUNCTION: | |
find_func(token); | |
get_token(); | |
eval_exp2(answer); | |
return; | |
default: | |
serror(0); | |
} | |
} | |
/* Возврат лексемы во входной поток. */ | |
static void putback(void) | |
{ | |
char *t; | |
t = token; | |
for(; *t; t++) | |
prog--; | |
} | |
/* Отображение сообщения о синтаксической ошибке. */ | |
static void serror(int err) | |
{ | |
static __attribute__ ((unused)) char *e[]= | |
{ | |
"syntax error", | |
"parentheses unbalanced ", | |
"no expression", | |
"divide by zero" | |
}; | |
error = -1 - err; | |
printf("%s\n", e[err]); | |
} | |
static double find_var(char *s) | |
{ | |
double res; | |
if(!isalpha(*s)) | |
{ | |
serror(1); | |
return 0.0; | |
} | |
if(!strcasecmp(token, "pi") ) | |
{ | |
res=3.1415926535897932384626433832795028841971693993751058209749; | |
} | |
else if(!strcasecmp(token, "e") ) | |
{ | |
res=2.7182818284590452353602874713526624977572470936999595749669; | |
} | |
else | |
{ | |
res=vars[toupper(*token)-'A']; | |
} | |
return res; | |
} | |
static void find_func(char *s) | |
{ | |
if(!strcasecmp(s, "abs") ) | |
{ | |
func=fabs; | |
} | |
else if(!strcasecmp(s, "sqrt") ) | |
{ | |
func=sqrt; | |
} | |
else if(!strcasecmp(s, "exp") ) | |
{ | |
func=exp; | |
} | |
else if(!strcasecmp(s, "ln") ) | |
{ | |
func=log; | |
} | |
else if(!strcasecmp(s, "log") ) | |
{ | |
func=log10; | |
} | |
else if(!strcasecmp(s, "sin") ) | |
{ | |
func=sin; | |
} | |
else if(!strcasecmp(s, "cos") ) | |
{ | |
func=cos; | |
} | |
else if(!strcasecmp(s, "tan") ) | |
{ | |
func=tan; | |
} | |
else if(!strcasecmp(s, "asin") ) | |
{ | |
func=asin; | |
} | |
else if(!strcasecmp(s, "acos") ) | |
{ | |
func=acos; | |
} | |
else if(!strcasecmp(s, "atan") ) | |
{ | |
func=atan; | |
} | |
else | |
{ | |
func=NULL; | |
} | |
} | |
int expcalc(char* exp, double *answer) | |
{ | |
error = 0; | |
prog = exp; | |
eval_exp(answer); | |
if(error) | |
*answer=0; | |
return error; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment