AbaKus – a complex calculator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

268 lines
7.0KB

  1. /*
  2. * rpnmuncher.cpp - part of abakus
  3. * Copyright (C) 2004, 2005 Michael Pyne <michael.pyne@kdemail.net>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. */
  19. #include <math.h>
  20. #include <kdebug.h>
  21. #include <klocale.h>
  22. #include <tqvaluestack.h>
  23. #include <tqregexp.h>
  24. #include <tqstring.h>
  25. #include <tqstringlist.h>
  26. #include "rpnmuncher.h"
  27. #include "valuemanager.h"
  28. #include "function.h"
  29. /**
  30. * Holds either a textual identifier, or a numeric value.
  31. */
  32. class Operand
  33. {
  34. public:
  35. Operand() : m_isValue(true), m_value(0) { }
  36. Operand(const TQString &ident) : m_isValue(false), m_text(ident) { }
  37. Operand(Abakus::number_t value) : m_isValue(true), m_value(value) { }
  38. Abakus::number_t value() const
  39. {
  40. if(m_isValue)
  41. return m_value;
  42. return ValueManager::instance()->value(m_text);
  43. }
  44. operator Abakus::number_t() const
  45. {
  46. return value();
  47. }
  48. TQString text() const { return m_text; }
  49. private:
  50. bool m_isValue;
  51. TQString m_text;
  52. Abakus::number_t m_value;
  53. };
  54. typedef enum { Number = 256, Func, Ident, Power, Set, Remove, Pop, Clear, Unknown } Token;
  55. static int tokenize (const TQString &token);
  56. TQString RPNParser::m_errorStr;
  57. bool RPNParser::m_error(false);
  58. OperandStack RPNParser::m_stack;
  59. struct Counter
  60. {
  61. ~Counter() {
  62. Abakus::number_t count( static_cast<int>(RPNParser::stack().count()) );
  63. ValueManager::instance()->setValue("stackCount", count);
  64. }
  65. };
  66. Abakus::number_t RPNParser::rpnParseString(const TQString &text)
  67. {
  68. TQStringList tokens = TQStringList::split(TQRegExp("\\s"), text);
  69. Counter counter; // Will update stack count when we leave proc.
  70. (void) counter; // Avoid warnings about it being unused.
  71. // Used in the case statements below
  72. Operand l, r;
  73. FunctionManager *manager = FunctionManager::instance();
  74. Function *fn = 0;
  75. m_error = false;
  76. m_errorStr = TQString();
  77. for(TQStringList::ConstIterator it = tokens.begin(); it != tokens.end(); ++it) {
  78. switch(tokenize(*it))
  79. {
  80. case Number:
  81. m_stack.push(Abakus::number_t((*it).latin1()));
  82. break;
  83. case Pop:
  84. if(m_stack.isEmpty()) {
  85. m_error = true;
  86. m_errorStr = i18n("Can't pop from an empty stack.");
  87. return Abakus::number_t::nan();
  88. }
  89. m_stack.pop();
  90. break;
  91. case Clear:
  92. m_stack.clear();
  93. break;
  94. case Func:
  95. if(m_stack.count() < 1) {
  96. m_error = true;
  97. m_errorStr = i18n("Insufficient operands for function %1").arg(*it);
  98. return Abakus::number_t::nan();
  99. }
  100. fn = manager->function(*it);
  101. l = m_stack.pop();
  102. m_stack.push(evaluateFunction(fn, l));
  103. break;
  104. case Ident:
  105. m_stack.push(*it);
  106. break;
  107. case Set:
  108. case Remove:
  109. m_error = true;
  110. m_errorStr = i18n("The set and remove commands can only be used in normal mode.");
  111. return Abakus::number_t::nan();
  112. break;
  113. case Power:
  114. if(m_stack.count() < 2) {
  115. m_error = true;
  116. m_errorStr = i18n("Insufficient operands for exponentiation operator.");
  117. return Abakus::number_t::nan();
  118. }
  119. r = m_stack.pop();
  120. l = m_stack.pop();
  121. m_stack.push(l.value().pow(r));
  122. break;
  123. case Unknown:
  124. m_error = true;
  125. m_errorStr = i18n("Unknown token %1").arg(*it);
  126. return Abakus::number_t::nan();
  127. break;
  128. case '=':
  129. r = m_stack.pop();
  130. l = m_stack.pop();
  131. ValueManager::instance()->setValue(l.text(), r);
  132. m_stack.push(l);
  133. break;
  134. case '+':
  135. if(m_stack.count() < 2) {
  136. m_error = true;
  137. m_errorStr = i18n("Insufficient operands for addition operator.");
  138. return Abakus::number_t::nan();
  139. }
  140. r = m_stack.pop();
  141. l = m_stack.pop();
  142. m_stack.push(l.value() + r.value());
  143. break;
  144. case '-':
  145. if(m_stack.count() < 2) {
  146. m_error = true;
  147. m_errorStr = i18n("Insufficient operands for subtraction operator.");
  148. return Abakus::number_t::nan();
  149. }
  150. r = m_stack.pop();
  151. l = m_stack.pop();
  152. m_stack.push(l.value() - r.value());
  153. break;
  154. case '*':
  155. if(m_stack.count() < 2) {
  156. m_error = true;
  157. m_errorStr = i18n("Insufficient operands for multiplication operator.");
  158. return Abakus::number_t::nan();
  159. }
  160. r = m_stack.pop();
  161. l = m_stack.pop();
  162. m_stack.push(l.value() * r.value());
  163. break;
  164. case '/':
  165. if(m_stack.count() < 2) {
  166. m_error = true;
  167. m_errorStr = i18n("Insufficient operands for division operator.");
  168. return Abakus::number_t::nan();
  169. }
  170. r = m_stack.pop();
  171. l = m_stack.pop();
  172. m_stack.push(l.value() / r.value());
  173. break;
  174. default:
  175. // Impossible case happened.
  176. kdError() << "Impossible case happened in " << k_funcinfo << endl;
  177. m_error = true;
  178. m_errorStr = "Bug found in program, please report.";
  179. return Abakus::number_t::nan();
  180. }
  181. }
  182. // TODO: Should this be an error?
  183. if(m_stack.isEmpty())
  184. return Abakus::number_t::nan();
  185. return m_stack.top();
  186. }
  187. static int tokenize (const TQString &token)
  188. {
  189. bool isOK;
  190. token.toDouble(&isOK);
  191. if(isOK)
  192. return Number;
  193. if(token == "**" || token == "^")
  194. return Power;
  195. if(FunctionManager::instance()->isFunction(token))
  196. return Func;
  197. if(token.lower() == "set")
  198. return Set;
  199. if(token.lower() == "pop")
  200. return Pop;
  201. if(token.lower() == "clear")
  202. return Clear;
  203. if(token.lower() == "remove")
  204. return Remove;
  205. if(TQRegExp("^\\w+$").search(token) != -1 &&
  206. TQRegExp("\\d").search(token) == -1)
  207. {
  208. return Ident;
  209. }
  210. if(TQRegExp("^[-+*/=]$").search(token) != -1)
  211. return token[0];
  212. return Unknown;
  213. }
  214. // vim: set et sw=4 ts=8: