#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define LINE 256
#define OPER 10
#define NUMS 20
#define EXPR 512
#define KEY_AMNT 27
#define KEY(x) g_aiTable[x][0]
#define VAL(x) g_aiTable[x][1]
/* COMMAND LIST */
#define CMD_LIST ":vars"
#define CMD_CLR ":clear"
#define CMD_QUIT ":quit"
#define CMD_ASGN ":="
/* CHECK MACROS */
#define IS_OPER(x) (x=='*')\
||(x=='/')\
||(x=='+')\
||(x=='-')\
||(x=='^')\
||(x=='%')
#define IS_FUNC(x) 0==strncmp(x, "log", 3)\
||0==strncmp(x, "exp", 3)\
||0==strncmp(x, "cos", 3)\
||0==strncmp(x, "sin", 3)\
||0==strncmp(x, "sqrt", 4)\
||0==strncmp(x, "tan", 3)
typedef enum
{
false = 0,
true,
} bool;
typedef unsigned int ui;
void init( void );
void trim( char* str );
void evaluate( char* str );
void parse( int var, char* calcstr );
bool skip_space( char** str );
bool is_operator( char** str, char* op );
void calc_func( int var, char* str );
bool calc_expr( int var, char* expr, double* val );
double calc( char op, double a, double b );
double g_aiTable[27][2]; // _ and a-z with
bool g_bQuit = false;
int main( void )
{
char iaCalculation[LINE] = {0};
init();
while( false == g_bQuit )
{
fputs( "> ", stdout );
memset( iaCalculation, 0x00, LINE );
fgets( iaCalculation, LINE, stdin );
trim(iaCalculation);
evaluate(iaCalculation);
}
return 0;
}
void init( void )
{
ui it = 1;
KEY(0) = '_';
VAL(0) = 0.0f;
for(;it<(ui)KEY_AMNT; it++)
{
KEY(it) = 0x60+it;
VAL(it) = 0.0f;
}
}
void trim( char* str )
{
while( *str != 0x0A ){ str++; };// remove newline
*str = 0x00;
return;
}
void evaluate( char* str )
{
ui it = 0;
char* temp = NULL;
ui found = false;
if( !strcmp( CMD_LIST, str ) ) /* list vars? */
{
for(;it<(ui)KEY_AMNT; it++)
{
if( VAL(it) )
{
found = true;
printf( "%c\t=\t%f\n", (char)KEY(it), VAL(it) );
}
}
if( true != found )
{
printf("No Vars found\n");
}
}
else if( !strcmp( CMD_CLR, str ) ) /* clear vars? */
{
for(;it<(ui)KEY_AMNT; it++)
{
VAL(it) = 0;
}
printf("Vars removed\n");
}
else if( !strcmp( CMD_QUIT, str ) ) /* quit application? */
{
printf("Byebye.\n");
g_bQuit = true;
}
else if( IS_FUNC(str) ) /* is a func? */
{
calc_func(0, str);
}
else if( 1 == strlen(str) ) /* is var to print? */
{
if( *str == '_' )
{
printf("%c = %f\n",(char)KEY(0),VAL(0));
}
else if( isalpha(*str) )
{
while((*str!=KEY(found)) && (found!=KEY_AMNT))
found++;
if( found == KEY_AMNT )
{
printf( "Invalid Var\n" );
return;
}
else
{
if( !VAL(found) )
{
printf( "%c not set.\n", (char)KEY(found) );
return;
}
printf( "%c = %f\n", (char)KEY(found), VAL(found) );
}
}
else
{
printf("Invalid Operation\n");
return;
}
}
else /* is func to assign a var, or just calc with or without assigning to a var */
{
if( (temp=strstr(str, CMD_ASGN)) )
{
temp = temp+strlen(CMD_ASGN);
while((*str!=KEY(found)) && (found!=KEY_AMNT))
found++;
if( found == KEY_AMNT )
{
printf("Invalid Operation\n");
return;
}
if( IS_FUNC(temp) )
{
calc_func(found,temp);
return;
}
}
else
{
temp = str;
}
parse( found, temp );
}
return;
}
bool skip_space( char** str )
{
if( (**str) == 0x20 )
{
*str=*str+1;
return true;
}
return false;
}
bool is_operator( char** str, char *op )
{
if( IS_OPER(**str) )
{
if(NULL!=op) *op = **str;
*str=*str+1;
return true;
}
return false;
}
void parse( int var, char* calcstr )
{
char expression[EXPR] = {0}; ui expr_cnt = 0;
double expr_val[NUMS] = {0.0f}; ui val_cnt = 0;
char* check = calcstr; // ptr -> ptr
char oper[OPER] = {0}; ui oper_cnt = 0;
bool bvar = false;
ui found = 0;
bool op_found = false;
bool arg1 = false;
/* string empty? */
if( !calcstr || !strlen(calcstr) )
{
printf("Invalid Operation\n");
return;
}
/* check if operator is inserted */
while( *check != 0x00 )
{
if( IS_OPER(*check) ) { op_found = true; break; }
else { check++; }
}
/* no operator inserted, just assign */
if( !op_found )
{
if( isalpha(*calcstr) )
{
found = 0;
while((*calcstr!=(char)KEY(found)) && (found!=KEY_AMNT))
found++;
if( found == KEY_AMNT )
{
printf("Var not found.");
}
VAL(0) = VAL(found);
VAL(var) = VAL(0);
}
else
{
VAL(0) = atof(calcstr);
VAL(var) = VAL(0);
}
printf ("%c = %f\n", (char)KEY(var), VAL(0));
return;
}
/* calc */
else
{
while( *calcstr != 0x00 )
{
if( skip_space( &calcstr ) )
continue;
if( is_operator( &calcstr, &oper[oper_cnt] ) )
{
oper_cnt++;
continue;
}
/* check if char is not a var and not a number */
if( !isalnum( *calcstr ) && *calcstr != '_' )
{
printf("\n%c: Undefiniert.\n", *calcstr);
return;
}
/* getting first operand */
if( arg1 == false )
{
arg1 = true;
/* a var is used */
if( isalpha(*calcstr) )
{
bvar = true;
found = 0;
/* get var number */
while((*calcstr!=(char)KEY(found)) && (found!=KEY_AMNT))
found++;
/* check if found */
if( found != KEY_AMNT )
{
/* var doesnt seem to have a value */
if( !VAL(found) )
{
printf( "Var not set!\n" );
return;
}
/* add to the expression string */
if( (expr_cnt+2)<EXPR )
{
strcat(expression+expr_cnt,"(i");
expr_cnt += 2;
}
/* and add the var value to the value table */
if( val_cnt<NUMS )
expr_val[val_cnt++] = VAL(found);
}
else
{
printf( "Invalid Var\n" );
return;
}
}
else
{
/* same as above */
if( (expr_cnt+2)<EXPR )
{
strcat(expression+expr_cnt,"(i");
expr_cnt += 2;
}
if( val_cnt<NUMS )
expr_val[val_cnt++] = atof(calcstr);
}
}
/* getting second operand */
else if( oper_cnt != 0 )
{
/* insert the operator to the list */
if( (expr_cnt+1)<EXPR )
{
*(expression+expr_cnt)=oper[oper_cnt-1];
expr_cnt++;
}
oper[--oper_cnt] = 0x00;
/* same as above */
if( isalpha(*calcstr) )
{
bvar = true;
found = 0;
while((*calcstr!=KEY(found)) &&(found!=KEY_AMNT))
found++;
if( found != KEY_AMNT )
{
if( !VAL(found) )
{
printf( "Var not set!\n" );
return;
}
if( (expr_cnt+2)<EXPR )
{
strcat(expression+expr_cnt,"i)");
expr_cnt += 2;
}
if( val_cnt<NUMS )
expr_val[val_cnt++] = VAL(found);
}
else
{
printf( "Invalid Var\n" );
return;
}
}
else
{
if( (expr_cnt+2)<EXPR )
{
strcat(expression+expr_cnt,"i)");
expr_cnt += 2;
}
if( val_cnt<NUMS )
expr_val[val_cnt++] = atof(calcstr);
}
if( oper_cnt > 0)
{
if( (expr_cnt+2)<EXPR )
{
*(expression+expr_cnt) = oper[oper_cnt-1];
expr_cnt++;
}
oper[--oper_cnt] = 0x00;
}
arg1 = false;
}
else
{
printf("No Operation set\n");
return;
}
/* if a var value was used just increment the string by one */
if( bvar )
{
bvar = false;
calcstr = calcstr+1;
}
/* else do it till a space is found and the string is still valid */
else if( !(calcstr=strchr(calcstr,0x20)) && !bvar )
break;
}
/* if at the end just one operand is left, close it */
if( arg1 == true )
{
if( (expr_cnt+1)<EXPR )
{
*(expression+expr_cnt) = ')';
expr_cnt++;
}
}
}
/* calculate the expression created */
if( false == calc_expr( var, expression, expr_val ) )
{
printf("Invalid Expression.\n");
}
return;
}
void calc_func( int var, char* str )
{
char *num = strtok(str, "( )");
double arg = 0.0f;
/* get the number by removing space or braces */
num = strtok(NULL,"( )");
if( NULL == num )
{
printf( "Missing Number.\n" );
return;
}
arg = atof(num);
/* check which function was called */
if( strstr(str,"log") )
{
VAL(0) = log(arg);
printf( "log(%.2f) = %.2f\n", arg, VAL(0) );
}
else if( strstr(str,"exp") )
{
VAL(0) = exp(arg);
printf( "exp(%.2f) = %.2f\n", arg, VAL(0) );
}
else if( strstr(str,"cos") )
{
VAL(0) = cos(arg);
printf( "cos(%.2f) = %.2f\n", arg, VAL(0) );
}
else if( strstr(str,"sin") )
{
VAL(0) = sin(arg);
printf( "sin(%.2f) = %.2f\n", arg, VAL(0) );
}
else if( strstr(str,"sqrt") )
{
VAL(0) = sqrt(arg);
printf( "sqrt(%.2f) = %.2f\n", arg, VAL(0) );
}
else if( strstr(str,"tan") )
{
VAL(0) = tan(arg);
printf( "tan(%.2f) = %.2f\n", arg, VAL(0) );
}
/* set the var. standard: _ */
VAL(var) = VAL(0);
return;
}
bool calc_expr( int var, char* expr, double* val )
{
ui expr_it = 0,
val_it = 0,
oper_cnt= 0;
double oper[2] = {0.0f};
char operator= 0x00,
brack_op= 0x00;
bool bracket = false;
/* go through each byte */
for(; (expr_it<EXPR)&&(expr[expr_it]!=0x00); expr_it++ )
{
switch(expr[expr_it])
{
/* bracket: open */
case '(':
{
if( bracket || expr[expr_it-1] == ')' )
{
return false;
}
bracket = true;
} break;
/* bracket: close ( calculating the subtotal */
case ')':
{
/* check if the bracket is open and has at least one operand with operator */
if( (!bracket || oper_cnt < 1 ) && ( !operator || !brack_op ) )
{
return false;
}
bracket = false;
/* calculate the 2 operands and calculate it with the last result */
if( oper_cnt == 2 )
{
if( brack_op )
{
VAL(0) = calc( brack_op, VAL(0), calc( operator, oper[0], oper[1] ) );
brack_op = 0;
}
else
{
VAL(0) = calc( operator, oper[0], oper[1] );
}
}
/* calculate the number with the last */
else
{
VAL(0) = calc( brack_op, oper[0], VAL(0) );
brack_op = 0;
}
oper_cnt= 0;
oper[0] = 0.0f; oper[1] = 0.0f;
operator= 0;
} break;
/* number */
case 'i':
{
/* check if this is the third number in series ( error )
or if no val is left ( error ) */
if( oper_cnt==2 || val[val_it] <= 0.0f )
{
return false;
}
oper[oper_cnt++] = val[val_it++];
} break;
/* operator */
default:
{
if( val[val_it] <= 0.0f )
{
return false;
}
/* check if the operator is within a bracket or out of a bracket */
if( bracket )
operator = expr[expr_it];
else
brack_op = expr[expr_it];
} break;
}
}
/* and assign the result to a var or dont do if not set */
if( var )
{
VAL(var) = VAL(0);
printf( "%c = %s = %.3f\n", (char)KEY(var), expr, VAL(0) );
}
else
{
printf( "%s = %.3f\n", expr, VAL(0) );
}
return true;
}
double calc( char op, double a, double b )
{
switch( op )
{
case '+': return (a+b);
case '-': return (a-b);
case '/': return (a/b);
case '*': return (a*b);
case '^': return pow( a, b );
default: return 0.0f;
}
}