This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  Calculator Class
  Submitted by



I'm submitting my "calculator" class to you for code-of-the-day. What my class does is take a text string, and evaluates it into another text string.

For instance, you can do this:
calculator Calc;
char *result=calc.calculate("2+2+2");
MessageBox(result); 

It will return a string containing "6". It also evaluates parenthesis, like (2+2)*3... but it doesn't follow order of operations. Without parenthesis, it will simply go left to right. It evaluates most c/c++ operators (&,|,!=,==,>>,<<, etc) also. I originally developed this class as a part of a scripting language I was writing. It doesn't follow any class or MFC programming conventions, though, so some people might find it a little offensive to read. You can add variables to the class, so that you could evaluate a text string like (2+THING+3). You can even add a variable that points to a variable in your program-- so in a scripting language, it would allow the user to access your data.

John Raptis
www.raptisoft.com

Currently browsing [calculator.zip] (36,563 bytes) - [calculator.h] - (1,745 bytes)

class variable {
	private:
		void *m_pPointer;
		int m_nType;

public: variable(char *name, void *ptr, int type); ~variable();

char *m_pName; void Get(char *where); };

class calculator { private: char cstring[256]; char workstring[256];

int base; int precision;

int variables; long *variablelist; char vnull;

void DeBone(void); void CutString(long pos, long len); void InsertString(long pos, char *str); long GetOps(long pos, double *op1, double *op2); double GetOp(char *data); void Calc(void); void MakeFloat(char *result,double number); unsigned int StringToHex(char *str); unsigned int StringToBinary(char *str); void LongToBinary(long lNumber, char *pString); void InsertVariable(variable *v); variable *Check(char *string);

public: #define CALC_OK 0 #define CALC_BADDECIMAL 1 #define CALC_BADHEXADECIMAL 2 #define CALC_BADBINARY 3 #define CALC_BADVARIABLE 4 #define CALC_OPENPARENTHESIS 5 #define CALC_ALREADYEXISTS 6 #define CALC_NOTFOUND 7 #define CALC_INVALIDVARIABLE 8

calculator(); ~calculator();

int result;

char *calculate(char *string); char *calculate(char *string, char flag);

BOOL SetBase(int rbase); BOOL SetPrecision(int precision); int GetBase(); int GetPrecision();

int AddVariable_char(char *name, char *ptr); int AddVariable_short(char *name, short *ptr); int AddVariable_int(char *name, int *ptr); int AddVariable_long(char *name, long *ptr); int AddVariable_float(char *name, float *ptr); int AddVariable_double(char *name, double *ptr); int AddVariable_string(char *name, char *ptr); int RemoveVariable(char *name); };

Currently browsing [calculator.zip] (36,563 bytes) - [calculator.cpp] - (17,992 bytes)

#include "stdafx.h"
#include "resource.h"

#include <stdarg.h> #include <conio.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <memory.h> #include <dos.h> #include <math.h> #include <fcntl.h> #include <io.h> #include <sys\types.h> #include <sys\stat.h> #include <malloc.h> #include <float.h> #include <mmsystem.h> #include <assert.h> #include <commctrl.h> #include <commdlg.h> #include <windows.h>

#include "calculator.h"

calculator::calculator(void) { base=10; precision=2; variables=0; vnull=1; }

calculator::~calculator(void) { long *pLong; variable *v; int count=0;

if (vnull==1) { pLong=this->variablelist; while (count++<this->variables) { v=(variable *)*pLong; delete v; pLong++; } }

// Free up the variable list... }

void calculator::DeBone(void) { char *sptr,*cptr; char *newstr; short pcount; calculator *c;

sptr=&cstring[0]; pcount=0;

while (*sptr!=0) { if (*sptr=='(') { if (pcount==0) cptr=sptr+1; pcount++; } if (*sptr==')') { pcount--; if (pcount==0) { strncpy(workstring,cptr,sptr-cptr); workstring[sptr-cptr]=0;

c=new calculator(); c->precision=this->precision; c->base=this->base; c->vnull=0;

c->variables=this->variables; c->variablelist=this->variablelist;

newstr=c->calculate(workstring,1);

CutString(((cptr-1)-&cstring[0]),(sptr-cptr)+2); InsertString(((cptr-1)-&cstring[0]),newstr);

delete c; sptr=&cstring[0]; } } sptr++; } }

void calculator::CutString(long pos, long len) { strcpy(&cstring[pos],&cstring[pos+len]); }

void calculator::InsertString(long pos, char *str) { char hold[255]; hold[0]=0; strcpy(hold,&cstring[pos]); cstring[pos]=0; strcat(cstring,str); strcat(cstring,hold); }

long calculator::GetOps(long pos, double *op1, double *op2) { char *sptr,*basesptr;

char hold[255]; char *holdptr;

*op1=0; *op2=0;

sptr=&cstring[0]; while (sptr>&cstring[0] && (isalnum(*sptr) || *sptr=='.' || *sptr==127 || *sptr=='!'/*CHANGE*/)) sptr--; basesptr=sptr;

holdptr=&hold[0]; for (;;) { if (isalnum(*sptr) || *sptr=='.' || *sptr==127 || *sptr=='!'/*CHANGE*/) { *holdptr=*sptr; holdptr++; sptr++; } else break; } *holdptr=0; *op1=GetOp(hold);

hold[0]=0; holdptr=&hold[0]; for (;;) { if (isalnum(*sptr) || *sptr=='.' || *sptr==0 || *sptr==127 || *sptr=='!'/*CHANGE*/) break; sptr++; } while (*sptr!=0) { if (isalnum(*sptr) || *sptr=='.' || *sptr==127 || *sptr=='!'/*CHANGE*/) { *holdptr=*sptr; holdptr++; sptr++; } else break; } *holdptr=0; *op2=GetOp(hold);

return (sptr-basesptr); }

#define PI (3.1415926535) char tstring[256];

double calculator::GetOp(char *data) { char *dptr; char compliment; variable *v;

if (strlen(data)==0) return 0;

// Degrees and radians? Should I? So I would type sin(rad(45)) to do it correctly? dptr=data;

compliment=0; if (*dptr=='!') { dptr++; compliment=1; }

v=this->Check(dptr); if (v!=NULL) { v->Get(tstring); return GetOp(tstring); }

if (*(dptr+(strlen(dptr)-1))=='b') { *(dptr+(strlen(dptr)-1))=0; return (float)StringToBinary(dptr); }

if (strnicmp(dptr,"0x",2)==0) { dptr+=2; return (float)StringToHex(dptr); }

// Go through any of our pre-defined variables, and we can get a calculator class out of // it. // NOTE: We have an issue with the complement! if (strnicmp(dptr,"rad",3)==0) { dptr+=3; return (atof(dptr)*(PI/180)); } if (strnicmp(dptr,"deg",3)==0) { dptr+=3; return (atof(dptr)*(180/PI)); }

if (strnicmp(dptr,"sin",3)==0) { dptr+=3; return sin(GetOp(dptr)); } if (strnicmp(dptr,"cos",3)==0) { dptr+=3; return cos(atof(dptr)); } if (strnicmp(dptr,"tan",3)==0) { dptr+=3; return tan(atof(dptr)); } if (strnicmp(dptr,"atan",4)==0) { dptr+=4; return atan(atof(dptr)); } if (strnicmp(dptr,"asin",4)==0) { dptr+=4; return asin(atof(dptr)); } if (strnicmp(dptr,"acos",4)==0) { dptr+=4; return acos(atof(dptr)); } if (strnicmp(dptr,"sqrt",4)==0) { dptr+=4; return sqrt(atof(dptr)); }

if (*dptr==127/*CHANGE*/) { dptr++; if (compliment==1) { if (atof(dptr)==0) return 1; else return 0; } return -atof(dptr); }

if (compliment==1) { if (atof(dptr)==0) return 1; else return 0; } return atof(dptr); }

void calculator::Calc(void) { char *sptr; char hold[255]; double op1,op2,result; long len;

sptr=&cstring[0]; while (*sptr!=0) { switch (*sptr) { case '+': len=GetOps(sptr-&cstring[0],&op1,&op2); result=op1+op2; MakeFloat(hold,result);

CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; break; case '-': len=GetOps(sptr-&cstring[0],&op1,&op2); result=op1-op2;

MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; break; case '*': len=GetOps(sptr-&cstring[0],&op1,&op2); result=op1*op2;

MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; break; case '/': len=GetOps(sptr-&cstring[0],&op1,&op2); result=op1/op2; MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; break; case '^': len=GetOps(sptr-&cstring[0],&op1,&op2); result=pow(op1,op2); MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; break; case '&': len=GetOps(sptr-&cstring[0],&op1,&op2); result=(long)op1&(long)op2; MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; break; case '%': len=GetOps(sptr-&cstring[0],&op1,&op2); result=(long)op1%(long)op2; MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; break; case '|': len=GetOps(sptr-&cstring[0],&op1,&op2); result=(long)op1|(long)op2; MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; break; case '<': sptr++; if (*sptr=='<') { len=GetOps(sptr-&cstring[0],&op1,&op2); result=(long)op1<<(long)op2; MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; } else if (*sptr=='=') { len=GetOps(sptr-&cstring[0],&op1,&op2); result=(long)op1<=(long)op2; MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; } else { len=GetOps(sptr-&cstring[0],&op1,&op2); result=op1<op2; MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; } break; case '>': sptr++; if (*sptr=='>') { len=GetOps(sptr-&cstring[0],&op1,&op2); result=(long)op1>>(long)op2; MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; } else if (*sptr=='=') { len=GetOps(sptr-&cstring[0],&op1,&op2); result=(long)op1>=(long)op2; MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; } else { len=GetOps(sptr-&cstring[0],&op1,&op2); result=op1>op2; MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; } break; case '=': sptr++; if (*sptr=='=') { len=GetOps(sptr-&cstring[0],&op1,&op2); result=(long)op1==(long)op2; MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; } break; case '!': sptr++; if (*sptr=='=') { len=GetOps(sptr-&cstring[0],&op1,&op2); result=(long)op1!=(long)op2; MakeFloat(hold,result); CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; } else sptr--; // Otherwise, don't eliminate it, right? break; case '~': long temp; len=GetOps(sptr-&cstring[0],&op1,&op2); temp=(long)op1; temp^=(long)op2; result=(float)temp; MakeFloat(hold,result);

CutString(0,len); InsertString(0,hold); sptr=&cstring[0]; break; } sptr++; } }

char *calculator::calculate(char *string) { char *sptr;

result=CALC_OK;

strcpy(cstring,string); strcat(cstring,"+0"); DeBone(); Calc();

sptr=&cstring[0]; while (*sptr!=0) { if (*sptr==127/*CHANGE*/) *sptr='-'; sptr++; }

switch (base) { case 16: double fResult; long lResult; char string[255];

fResult=atof(cstring); lResult=(long)fResult; sprintf(string,"%.2x",lResult);

strupr(string);

if (strlen(string)%2!=0) sprintf(cstring,"0x0%s",string); else sprintf(cstring,"0x%s",string); break; case 2: fResult=atof(cstring); lResult=(long)fResult;

LongToBinary(lResult,cstring); break; }

return &cstring[0]; }

char *calculator::calculate(char *string, char flag) { result=CALC_OK;

strcpy(cstring,string); strcat(cstring,"+0");

DeBone(); Calc(); return &cstring[0]; }

void calculator::MakeFloat(char *string, double number) { switch (precision) { case 0: if (number>=0) sprintf(string,"%.0f",number); else sprintf(string,"%c%.0f",127,fabs(number)); break; case 1: if (number>=0) sprintf(string,"%.1f",number); else sprintf(string,"%c%.1f",127,fabs(number)); break; case 2: if (number>=0) sprintf(string,"%.2f",number); else sprintf(string,"%c%.2f",127,fabs(number)); //FUNK break; case 3: if (number>=0) sprintf(string,"%.3f",number); else sprintf(string,"%c%.3f",127,fabs(number)); break; case 4: if (number>=0) sprintf(string,"%.4f",number); else sprintf(string,"%c%.4f",127,fabs(number)); break; case 5: if (number>=0) sprintf(string,"%.5f",number); else sprintf(string,"%c%.5f",127,fabs(number)); break; case 6: if (number>=0) sprintf(string,"%.6f",number); else sprintf(string,"%c%.6f",127,fabs(number)); break; case 7: if (number>=0) sprintf(string,"%.7f",number); else sprintf(string,"%c%.7f",127,fabs(number)); break; case 8: if (number>=0) sprintf(string,"%.8f",number); else sprintf(string,"%c%.8f",127,fabs(number)); break; case 9: if (number>=0) sprintf(string,"%.9f",number); else sprintf(string,"%c%.9f",127,fabs(number)); break; case 10: if (number>=0) sprintf(string,"%.10f",number); else sprintf(string,"%c%.10f",127,fabs(number)); break; } }

unsigned int calculator::StringToHex(char *str) { unsigned int i, j = 0;

strupr(str);

while (str && *str && isxdigit(*str)) { i = *str++ - '0'; if (9<i) i-=7; j<<=4; j|=(i&0x0f); } return(j); }

unsigned int calculator::StringToBinary(char *str) { unsigned int result=0; unsigned int multi=1; char *pstr; pstr=str+(strlen(str)-1);

while (pstr>=str) { if (*pstr=='1') { result|=multi; multi<<=1; } else if (*pstr=='0') { multi<<=1; } pstr--; } return result; }

BOOL calculator::SetBase(int rbase) { if (rbase!=10 && rbase!=16 && rbase!=2) return FALSE;

this->base=rbase; return TRUE; }

BOOL calculator::SetPrecision(int nPrecision) { if (nPrecision<0) return FALSE; if (nPrecision>10) return FALSE;

precision=nPrecision; return TRUE; }

void calculator::LongToBinary(long lNumber, char *pString) { char *pStr; pStr=pString;

*pStr='0'; if (lNumber&0x00000001) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00000002) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00000004) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00000008) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00000010) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00000020) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00000040) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00000080) *pStr='1'; pStr++;

if (lNumber&0xFFFFFF00) { *pStr='0'; if (lNumber&0x00000100) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00000200) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00000400) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00000800) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00001000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00002000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00004000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00008000) *pStr='1'; pStr++; }

if (lNumber&0xFFFF0000) { *pStr='0'; if (lNumber&0x00010000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00020000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00040000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00080000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00100000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00200000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00400000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x00800000) *pStr='1'; pStr++; }

if (lNumber&0xFF000000) { *pStr='0'; if (lNumber&0x01000000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x02000000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x04000000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x08000000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x10000000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x20000000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x40000000) *pStr='1'; pStr++; *pStr='0'; if (lNumber&0x80000000) *pStr='1'; pStr++; }

*pStr=0; strrev(pString); strcat(pString,"b"); }

int calculator::GetBase(void) { return base; }

int calculator::GetPrecision(void) { return precision; }

#define VTYPE_CHAR 0 #define VTYPE_SHORT 1 #define VTYPE_INT 2 #define VTYPE_LONG 3 #define VTYPE_FLOAT 4 #define VTYPE_DOUBLE 5 #define VTYPE_STRING 6

void calculator::InsertVariable(variable *v) { long *ptr; if (this->variables==0) { this->variablelist=(long*)malloc(4); ptr=this->variablelist; this->variables=1; } else { this->variables++; this->variablelist=(long*)realloc(this->variablelist,this->variables*4); ptr=(this->variablelist+(this->variables-1)); }

*ptr=(long)v; }

BOOL calculator::RemoveVariable(char *name) { variable *v,*vv; long *pLong; int count=0;

v=this->Check(name); if (v==NULL) return CALC_NOTFOUND;

pLong=this->variablelist; while (count++<this->variables) { vv=(variable *)*pLong; if (vv==v) break; pLong++; } while (count++<this->variables) { *pLong=*(pLong+1); pLong++; } this->variables--; this->variablelist=(long*)realloc(this->variablelist,this->variables*4);

delete v; return CALC_OK; }

variable *calculator::Check(char *string) { long *pLong; variable *v; int count=0;

pLong=this->variablelist; while (count++<this->variables) { v=(variable *)*pLong; if (strcmp(v->m_pName,string)==0) return v;

pLong++; } return NULL; }

BOOL calculator::AddVariable_char(char *name, char *ptr) { variable *v;

v=this->Check(name); if (v!=NULL) return CALC_ALREADYEXISTS;

v=new variable(name,ptr,VTYPE_CHAR); InsertVariable(v); return CALC_OK; }

BOOL calculator::AddVariable_short(char *name, short *ptr) { variable *v;

v=this->Check(name); if (v!=NULL) return CALC_ALREADYEXISTS;

v=new variable(name,ptr,VTYPE_SHORT); InsertVariable(v); return CALC_OK; }

BOOL calculator::AddVariable_int(char *name, int *ptr) { variable *v;

v=this->Check(name); if (v!=NULL) return CALC_ALREADYEXISTS;

v=new variable(name,ptr,VTYPE_INT); InsertVariable(v); return CALC_OK; }

BOOL calculator::AddVariable_long(char *name, long *ptr) { variable *v;

v=this->Check(name); if (v!=NULL) return CALC_ALREADYEXISTS;

v=new variable(name,ptr,VTYPE_LONG); InsertVariable(v); return CALC_OK; }

BOOL calculator::AddVariable_float(char *name, float *ptr) { variable *v;

v=this->Check(name); if (v!=NULL) return CALC_ALREADYEXISTS; v=new variable(name,ptr,VTYPE_FLOAT); InsertVariable(v); return CALC_OK; }

BOOL calculator::AddVariable_double(char *name, double *ptr) { variable *v;

v=this->Check(name); if (v!=NULL) return CALC_ALREADYEXISTS; v=new variable(name,ptr,VTYPE_DOUBLE); InsertVariable(v); return CALC_OK; }

BOOL calculator::AddVariable_string(char *name, char *ptr) { variable *v;

v=this->Check(name); if (v!=NULL) return CALC_ALREADYEXISTS; v=new variable(name,ptr,VTYPE_STRING); InsertVariable(v); return CALC_OK; }



variable::variable(char *name, void *ptr, int type) { this->m_pName=(char*)malloc(strlen(name)+1); strcpy(this->m_pName,name);

this->m_pPointer=ptr; this->m_nType=type; }

variable::~variable() { free(this->m_pName); }

void variable::Get(char *where) { switch (this->m_nType) { case VTYPE_CHAR: sprintf(where,"%d",*(char*)this->m_pPointer); break; case VTYPE_SHORT: sprintf(where,"%d",*(short*)this->m_pPointer); break; case VTYPE_INT: sprintf(where,"%d",*(int*)this->m_pPointer); break; case VTYPE_LONG: sprintf(where,"%d",*(long*)this->m_pPointer); break; case VTYPE_FLOAT: sprintf(where,"%.10f",*(float*)this->m_pPointer); break; case VTYPE_DOUBLE: sprintf(where,"%.10f",*(double*)this->m_pPointer); break; case VTYPE_STRING: strncpy(where,(char*)this->m_pPointer,255); break; } }




The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.