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
|
// Soln6_04.cpp
// A program to implement a calculator accepting parentheses
// There are no problems or limitations with this.
// Implementing exponentiation just requires one additional
// else-if statement in the term() function.
#include <iostream> // For stream input/output
#include <cstdlib> // For the exit() function
#include <cctype> // For the isdigit() function
#include <cstring> // For the strcpy() function
using std::cin;
using std::cout;
using std::cerr;
using std::endl;
void eatspaces(char* str); // Function to eliminate blanks
double expr(char* str); // Function evaluating an expression
double term(char* str, int& index); // Function analyzing a term
double number(char* str, int& index); // Function to recognize a number
char* extract(char* str, int& index); // Function to extract a substring
void error(int index); // Function to identify an error
const int MAX(80); // Maximum expression length, including '\0'
char input[MAX]; // Stores input string for error flagging
int inputIndex(0); // Save input index
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;
for(;;)
{
cin.getline(buffer, sizeof buffer); // Read an input line
eatspaces(buffer); // Remove blanks from input
strcpy_s(input, buffer); // Copy input for error flagging
inputIndex = 0;
if(!buffer[0]) // Empty line ends calculator
return 0;
try
{
cout << "\t= " << expr(buffer) // Output value of expression
<< endl << endl;
}
catch( const char* pEx)
{
cerr << pEx << endl;
cerr << "Ending program." << endl;
return 1;
}
}
}
// 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
// copied is not \0
if(*(str + i) != ' ') // Increment i as long as
i++; // character is not a 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
value = term(str, index); // Get first term
for(;;) // Indefinite loop, all exits inside
{
switch(*(str + index++)) // Choose action based on current character
{
case '\0': // We're at the end of the string
return value; // so return what we have got
case '+': // + found so add in the
value += term(str, index); // next term
break;
case '-': // - found so subtract
value -= term(str, index); // the next term
break;
default: // If we reach here the string
error(index-1);
char message[38] = "Expression evaluation error. Found: ";
strncat_s(message, str + index - 1, 1); // Append the character
throw message;
break;
}
}
}
// 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(true)
{
if(*(str + index) == '*') // If it's multiply,
value *= number(str, ++index); // multiply by next number
else if(*(str + index) == '/') // If it's divide,
value /= number(str, ++index); // divide by next number
else if(*(str + index)=='^') // If it's exponentiation
value = pow(value, number(str, ++index)); // Raise to power of next number
else
break;
}
return value; // We've finished, so return what
// we've got
}
// Function to recognize a number in a string
double number(char* str, int& index)
{
double value(0.0); // Store the resulting value
if(*(str + index) == '(') // Start of parentheses
{
int oldIndex = inputIndex; // Save current for restoring later
inputIndex += index+1; // Record index position for error flagging
char* psubstr(nullptr); // Pointer for substring
psubstr = extract(str, ++index); // Extract substring in brackets
value = expr(psubstr); // Get the value of the substring
delete[]psubstr; // Clean up the free store
inputIndex = oldIndex; // Restore old index
return value; // Return substring value
}
// There must be at least one digit...
if(!isdigit(*(str + index)))
{ // There's no digits so input is junk...
error(index);
char message[31] = "Invalid character in number: ";
strncat_s(message, str+index, 1); // Append the character
throw message;
}
while(isdigit(*(str + index))) // Loop accumulating leading digits
value = 10*value + (*(str + index++) - '0');
// Not a digit when we get to here
if(*(str + index) != '.') // so check for decimal point
return value; // and if not, return value
double factor(1.0); // Factor for decimal places
while(isdigit(*(str + (++index)))) // Loop as long as we have digits
{
factor *= 0.1; // Decrease factor by factor of 10
value = value + (*(str + index) - '0')*factor; // Add decimal place
}
return value; // On loop exit we are done
}
// Function to extract a substring between parentheses
// (requires cstring)
char* extract(char* str, int& index)
{
char* pstr(nullptr); // Pointer to new string for return
int numL(0); // Count of left parentheses found
int bufindex(index); // Save starting value for index
do
{
switch(*(str + index))
{
case ')':
if(0 == numL)
{
++index;
pstr = new char[index - bufindex];
if(!pstr)
{
throw "Memory allocation failed.";
}
strncpy_s(pstr, index-bufindex, str+bufindex, index-bufindex-1); // 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
error(index);
throw "Ran off the end of the expression, must be bad input.";
}
// Function to identify an error
void error(int index)
{
cout << input << endl;
for (int i = 0; i < inputIndex + index; i++)
cout << ' ';
cout << '^' << endl;
}
| |