// Soln6_5ANSI.cpp // A program to implement a calculator accepting parentheses #include // For stream input/output #include // For the exit() function #include // For the isdigit() function #include // For the strcpy() function #include // For the pow() function using std::cin; using std::cout; 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(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; for(;;) { cin.getline(buffer, sizeof buffer); // Read an input line eatspaces(buffer); // Remove blanks from input if(!buffer[0]) // Empty line ends calculator 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 // 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 cout << endl // is junk << "Arrrgh!*#!! There's an error" << endl; error(str, index-1); exit(1); } } } // 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 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)=='^') value = pow(value, number(str, ++index)); } 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 // 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 if(*(str + index) == '(') // Start of parentheses { char* psubstr = 0; // Pointer for substring psubstr = extract(str, ++index); // Extract substring in brackets value = expr(psubstr); // Get the value of the substring // If we have a math operation saved, go and do it if(op[0]) value = doOperation(op, value); delete[]psubstr; // Clean up the free store return value; // Return substring value } 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 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) { size_t size = index - bufindex; 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