Skip to content

Instantly share code, notes, and snippets.

@spot62
Created December 29, 2015 07:36
Show Gist options
  • Save spot62/3d71e0702bcb4f435698 to your computer and use it in GitHub Desktop.
Save spot62/3d71e0702bcb4f435698 to your computer and use it in GitHub Desktop.
Extended Schildt's calculator
#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