1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
|
//calculator.cpp
//keyboard string arithmatic program
#include <iostream>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cmath>
using std::cin;
using std::cout;
using std::endl;
char* extract(char* str, int& index); //function to extract a substring
void eatspaces(char* str); //function to remove spaces
double expr(char* str); //function evaluating an expression
double term(char* str, int& index); //function analyzing a term. the second parameter is a reference.
double number(char* str, int& index);
void error(char* str, int index); //function to identify an error
double doOperation(char* op, double value); //execute math function
const int MAX = 80; //maximum expression length including '\0'
const double degToRad = 57.295779; //conversion factor, degrees to radians
int main()
{
char buffer[MAX] = {0}; //input area for expression to be evaluated
cout << endl
<< "Welcome to your friendly calculator."
<< endl
<< "Enter an expression, or an empty line to quit." << endl
<< "sin(value), cos(value), tan(value) for radians." << endl
<< "sind(value), cosd(value), tand(value) for degrees." << endl
<< "sqrt(value) for square root. '^' is used for power." << endl
<< "example: 2 + (2-1) / 3 * sin(6)"
<< endl;
for(;;)
{
cin.getline(buffer, sizeof buffer); //read input line
eatspaces(buffer); //remove blanks from input
if(!buffer[0]) //empty line ends here
return 0;
cout << "\t = " << expr(buffer) //output value of expression
<< endl << endl;
}
}
//function to eliminate spaces from a string
void eatspaces(char* str)
{
int i = 0; //'copy to' index to string
int j = 0; //'copy from' index to string
while((*(str + i) = *(str + j++)) != '\0') //loop while character is not \0. the loop condition copies the string by moving the character at
if(*(str + i) != ' ') //position j to the character at position i and then increments j to the next character
i++; //increment i as long as character is not space
return;
}
//function to evaluate an arithmetic expression
double expr(char* str)
{
double value = 0.0; //store result here
int index = 0; //keeps track of current character position. initialized to zero which is the first character in string
value = term(str, index); //get first term. to get the value of the first term by calling the function term()
for(;;) //indefinite for loop; the action is determined by a switch statement, which is controlled by the current char in the string.
{
switch(*(str + index++))
{
case '\0': //end of string
return value; //so return what we got
case '+': // + found so add in the next term
value += term(str, index);
break;
case '-': // - found so subtract the value returned by term() from the variable value
value -= term(str, index);
break;
default: //if default then the string is junk. As long as either + or - the loop continues. each call to term() moves value of index variable
cout << endl //to the character following the term that was executed
<< "Arrgh!*#!! There's an error"
<< endl;
error(str, index-1);
exit(1); //#include <cstdlib>
}
}
}
//function to get the value of a term
double term(char* str, int& index)
{
double value = 0.0; //somewhere to accumulate the result
value = number(str, index); //get the first number in the term
//loop as long as we have a good operator
while((*(str + index) == '*') || (*(str + index) == '/') || (*(str + index) == '^'))
{
if(*(str + index) == '*') //if it's a multiply
value *= number(str, ++index); //multiply by next number
if(*(str + index) == '/') //if it's divide
value /= number(str, ++index); //divide by next number
if(*(str + index)== '^') // if it's exponentiation
value = pow(value, number(str, ++index)); // raise to power of next number
}
return value;
}
//function to recognize a number in a string
//function to recognize an expression in parentheses or a number in a string
double number(char* str, int& index)
{
double value = 0.0; //store the resulting value
// Look for a math function name
char op[6];
int ip = 0;
while (isalpha(*(str+index))) //copy the function name
op[ip++] = *(str+index++);
op[ip] = '\0'; //append terminator
// you get as many nested parentheses as you need. An example of recursion.
if(*(str + index) == '(') //start of parentheses
{
char* psubstr = 0; //pointer for a substring
psubstr = extract(str, ++index);//extract substring in brackets
value = expr(psubstr); //get the value of substring
// If we have a math operation saved, go and do it
if(op[0])
value = doOperation(op, value);
delete[]psubstr; //clean up free store
return value; //return substring value
}
while(isdigit(*(str + index))) //loop acumulating leading digits. isdigit(int c) returns nonzero if the argument is a digit, 0 otherwise
value = 10 * value + (*(str + index++) - 48); //as the number in the string is a series of digits as ASCII characters the function steps through
//the string accumulating the value of the number digit by digit. first accumulates digits before decimal point
//an ASCII character has ASCII value between 48, thus if you subtract the ASCII code from 0 you
//convert it to its equivelent digit value from 0 to 9
if(*(str + index) != '.') //not a digit when we get to here so check for decimal point and if not, return value
return value;
double factor = 1.0; //factor decimal places for number
while(isdigit(*(str + (++index)))) //loop as long as we have digits
{
factor *= 0.1; //decrease factor of 10
value = value + (*(str + index) - '0') * factor; //add decimal place.Is for fractional part so for 54, 48, 56, is 6,0,8
}
return value; //on loop exit we are done
}
//function to extract a substring between parentheses
//requires <cstring> header file
char* extract(char* str, int& index)
{
char buffer[MAX]; //temporary space for substring
char* pstr = 0; //pointer to new string for return
int numL = 0; //count of left parentheses found
int bufindex = index; //save starting value for index
do
{
buffer[index - bufindex] = *(str + index);
switch(buffer[index - bufindex])
{
case ')':
if(numL == 0)
{
buffer[index - bufindex] = '\0'; //replace ')' with '\0'
++index;
pstr = new char[index - bufindex];
if(!pstr)
{
cout << "Memory allocation failed,"
<< " program terminated.";
exit(1);
}
strcpy_s(pstr, index - bufindex, buffer); //copy substring to new memory
return pstr; //return substring in new memory
}
else
numL--; //reduce count of '(' to be matched
break;
case '(':
numL++; //increase count of '(' to be matched
break;
}
}while(*(str + index++) != '\0'); //loop-don't overrun end of string.
cout << "Ran off the end of the expression, must be bad input."
<< endl;
exit(1);
return pstr;
}
// Function to identify an error
void error(char* str, int index)
{
cout << str << endl;
for (int i = 0; i < index; i++)
cout << ' ';
cout << '^' << endl;
}
// Execute math function
double doOperation(char* op, double value)
{
if (!_stricmp(op, "sin")) //_stricmp(); funciton compares string to "term"
return sin(value);
else if (!_stricmp(op, "sind"))
return sin(value/degToRad);
else if (!_stricmp(op, "cos"))
return cos(value);
else if (!_stricmp(op, "cosd"))
return cos(value/degToRad);
else if (!_stricmp(op, "tan"))
return tan(value);
else if (!_stricmp(op, "tand"))
return tan(value/degToRad);
else if (!_stricmp(op, "sqrt"))
return sqrt(value);
else
{
cout << "Error: unknown operation '" << op << "'" << endl;
exit(1);
}
return 0;
}
|