Advertisement
Guest User

Untitled

a guest
Apr 20th, 2014
47
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.63 KB | None | 0 0
  1. // Source: http://www.daniweb.com/software-development/cpp/code/427500/calculator-using-shunting-yard-algorithm#
  2. // Author: Jesse Brown
  3. // Modifications: Brandon Amos
  4.  
  5. #include <cstdlib>
  6. #include <iostream>
  7. #include <sstream>
  8. #include <stdexcept>
  9.  
  10. #include "shunting_yard.h"
  11.  
  12. using namespace std;
  13.  
  14. #define isvariablechar(c) (isalpha(c) || c == '_')
  15. TokenQueue_t calculator::toRPN(const char* expr,
  16. map<string, string>* vars,
  17. map<string, int> opPrecedence) {
  18. TokenQueue_t rpnQueue; stack<string> operatorStack;
  19. bool lastTokenWasOp = true;
  20.  
  21. // In one pass, ignore whitespace and parse the expression into RPN
  22. // using Dijkstra's Shunting-yard algorithm.
  23. while (*expr && isspace(*expr)) ++expr;
  24. while (*expr) {
  25. if (isdigit(*expr)) {
  26. // If the token is a number, add it to the output queue.
  27. char* nextChar = 0;
  28. double digit = strtod(expr, &nextChar);
  29. # ifdef DEBUG
  30. cout << digit << endl;
  31. # endif
  32. rpnQueue.push(new Token<double>(digit));
  33. expr = nextChar;
  34. lastTokenWasOp = false;
  35. }
  36. else if (isvariablechar(*expr)) {
  37. // If the function is a variable, resolve it and
  38. // add the parsed number to the output queue.
  39. if (!vars) {
  40. //throw domain_error(
  41. //"Detected variable, but the variable map is null.");
  42. }
  43.  
  44. stringstream ss;
  45. ss << *expr;
  46. ++expr;
  47. while (isvariablechar(*expr)) {
  48. ss << *expr;
  49. ++expr;
  50. }
  51. string key = ss.str();
  52. map<string, string>::iterator it = vars->find(key);
  53. if (it == vars->end()) {
  54. //throw domain_error(
  55. //"Unable to find the variable '" + key + "'.");
  56. }
  57. string val = vars->find(key)->second;
  58. # ifdef DEBUG
  59. cout << val << endl;
  60. # endif
  61. rpnQueue.push(new Token<string>(val));;
  62. lastTokenWasOp = false;
  63. }
  64. else {
  65. // Otherwise, the variable is an operator or paranthesis.
  66. switch (*expr) {
  67. case '(':
  68. operatorStack.push("(");
  69. ++expr;
  70. break;
  71. case ')':
  72. while (operatorStack.top().compare("(")) {
  73. rpnQueue.push(new Token<string>(operatorStack.top()));
  74. operatorStack.pop();
  75. }
  76. operatorStack.pop();
  77. ++expr;
  78. break;
  79. default:
  80. {
  81. // The token is an operator.
  82. //
  83. // Let p(o) denote the precedence of an operator o.
  84. //
  85. // If the token is an operator, o1, then
  86. // While there is an operator token, o2, at the top
  87. // and p(o1) <= p(o2), then
  88. // pop o2 off the stack onto the output queue.
  89. // Push o1 on the stack.
  90. stringstream ss;
  91. ss << *expr;
  92. ++expr;
  93. while (*expr && !isspace(*expr) && !isdigit(*expr)
  94. && !isvariablechar(*expr) && *expr != '(' && *expr != ')') {
  95. ss << *expr;
  96. ++expr;
  97. }
  98. ss.clear();
  99. string str;
  100. ss >> str;
  101. # ifdef DEBUG
  102. cout << str << endl;
  103. # endif
  104.  
  105. if (lastTokenWasOp) {
  106. // Convert unary operators to binary in the RPN.
  107. if (!str.compare("-") || !str.compare("+")) {
  108. rpnQueue.push(new Token<double>(0));
  109. }
  110. else {
  111. //throw domain_error(
  112. //"Unrecognized unary operator: '" + str + "'.");
  113. }
  114. }
  115.  
  116. while (!operatorStack.empty() &&
  117. opPrecedence[str] <= opPrecedence[operatorStack.top()]) {
  118. rpnQueue.push(new Token<string>(operatorStack.top()));
  119. operatorStack.pop();
  120. }
  121. operatorStack.push(str);
  122. lastTokenWasOp = true;
  123. }
  124. }
  125. }
  126. while (*expr && isspace(*expr)) ++expr;
  127. }
  128. while (!operatorStack.empty()) {
  129. rpnQueue.push(new Token<string>(operatorStack.top()));
  130. operatorStack.pop();
  131. }
  132. return rpnQueue;
  133. }
  134.  
  135. double calculator::calculate(const char* expr,
  136. map<string, string>* vars) {
  137. // 1. Create the operator precedence map.
  138. map<string, int> opPrecedence;
  139. opPrecedence["("] = -1;
  140. opPrecedence["<<"] = 1; opPrecedence[">>"] = 1;
  141. opPrecedence["+"] = 2; opPrecedence["-"] = 2;
  142. opPrecedence["*"] = 3; opPrecedence["/"] = 3;
  143.  
  144. // 2. Convert to RPN with Dijkstra's Shunting-yard algorithm.
  145. TokenQueue_t rpn = toRPN(expr, vars, opPrecedence);
  146.  
  147. // 3. Evaluate the expression in RPN form.
  148. stack<double> evaluation;
  149. while (!rpn.empty()) {
  150. TokenBase* base = rpn.front();
  151. rpn.pop();
  152.  
  153. Token<string>* strTok = dynamic_cast<Token<string>*>(base);
  154. Token<double>* doubleTok = dynamic_cast<Token<double>*>(base);
  155. if (strTok) {
  156. string str = strTok->val;
  157. /*if (evaluation.size() < 2) {
  158. throw domain_error("Invalid equation.");
  159. }*/
  160.  
  161. if (str.compare("pi")){
  162. cout << "its pi!" << endl;
  163. }
  164.  
  165. double right = evaluation.top(); evaluation.pop();
  166. double left = evaluation.top(); evaluation.pop();
  167. if (!str.compare("+")) {
  168. evaluation.push(left + right);
  169. }
  170. else if (!str.compare("*")) {
  171. evaluation.push(left * right);
  172. }
  173. else if (!str.compare("-")) {
  174. evaluation.push(left - right);
  175. }
  176. else if (!str.compare("/")) {
  177. evaluation.push(left / right);
  178. }
  179. else if (!str.compare("<<")) {
  180. evaluation.push((int)left << (int)right);
  181. }
  182. else if (!str.compare(">>")) {
  183. evaluation.push((int)left >> (int)right);
  184. }
  185. else {
  186. cout << "Unknown Operator" << endl;
  187. //throw domain_error("Unknown operator: '" + str + "'.");
  188. }
  189. }
  190. else if (doubleTok) {
  191. evaluation.push(doubleTok->val);
  192. }
  193. else {
  194. //throw domain_error("Invalid token.");
  195. }
  196. delete base;
  197. }
  198. return evaluation.top();
  199. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement