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.

evaluator.cpp 5.8KB

8 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /* This file was part of the SpeedCrunch project
  2. Copyright (C) 2004 Ariya Hidayat <ariya@kde.org>
  3. And is now part of abakus.
  4. Copyright (c) 2005 Michael Pyne <michael.pyne@kdemail.net>
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. */
  17. #include "evaluator.h"
  18. #include "function.h"
  19. #include "node.h" // For parser_yacc.hpp below
  20. #include "parser.h"
  21. #include <tqapplication.h>
  22. #include <tqmap.h>
  23. #include <tqstring.h>
  24. #include <tqstringlist.h>
  25. #include <tqvaluevector.h>
  26. #include <kdebug.h>
  27. //
  28. // Reimplementation of goodies from Evaluator follows.
  29. //
  30. Evaluator::Evaluator()
  31. {
  32. }
  33. Evaluator::~Evaluator()
  34. {
  35. }
  36. void Evaluator::setExpression(const TQString &expr)
  37. {
  38. kdError() << k_funcinfo << " not implemented.\n";
  39. }
  40. TQString Evaluator::expression() const
  41. {
  42. kdError() << k_funcinfo << " not implemented.\n";
  43. return TQString();
  44. }
  45. void Evaluator::clear()
  46. {
  47. kdError() << k_funcinfo << " not implemented.\n";
  48. // Yeah, whatever.
  49. }
  50. bool Evaluator::isValid() const
  51. {
  52. return true;
  53. }
  54. Tokens Evaluator::tokens() const
  55. {
  56. kdError() << k_funcinfo << " not implemented.\n";
  57. return Tokens();
  58. }
  59. Tokens Evaluator::scan(const TQString &expr)
  60. {
  61. Lexer l(expr);
  62. Tokens tokens;
  63. while(l.hasNext())
  64. {
  65. int t = l.nextType();
  66. Token::Type type = Token::Unknown;
  67. switch(t)
  68. {
  69. case POWER:
  70. case '*':
  71. case '(':
  72. case ')':
  73. case '-':
  74. case '+':
  75. case ',':
  76. case '=':
  77. type = Token::Operator;
  78. break;
  79. case NUM:
  80. type = Token::Number;
  81. break;
  82. case SET:
  83. case REMOVE:
  84. case DERIV:
  85. case FN:
  86. case ID:
  87. type = Token::Identifier;
  88. break;
  89. default:
  90. type = Token::Unknown;
  91. break;
  92. }
  93. tokens.append(Token(type, l.tokenValue(), l.tokenPos()));
  94. }
  95. return tokens;
  96. }
  97. TQString Evaluator::error() const
  98. {
  99. kdError() << k_funcinfo << " not implemented.\n";
  100. return "No Error Yet";
  101. }
  102. ///
  103. /// ARIYA'S CLASS CODE FOLLOWS
  104. ///
  105. // for null token
  106. const Token Token::null;
  107. // helper function: return operator of given token text
  108. // e.g. "*" yields Operator::Asterisk, and so on
  109. static Token::Op matchOperator( const TQString& text )
  110. {
  111. Token::Op result = Token::InvalidOp;
  112. if( text.length() == 1 )
  113. {
  114. TQChar p = text[0];
  115. switch( p.unicode() )
  116. {
  117. case '+': result = Token::Plus; break;
  118. case '-': result = Token::Minus; break;
  119. case '*': result = Token::Asterisk; break;
  120. case '/': result = Token::Slash; break;
  121. case '^': result = Token::Caret; break;
  122. case ',': result = Token::Comma; break;
  123. case '(': result = Token::LeftPar; break;
  124. case ')': result = Token::RightPar; break;
  125. case '%': result = Token::Percent; break;
  126. case '=': result = Token::Equal; break;
  127. default : result = Token::InvalidOp; break;
  128. }
  129. }
  130. if( text.length() == 2 )
  131. {
  132. if( text == "**" ) result = Token::Caret;
  133. }
  134. return result;
  135. }
  136. // creates a token
  137. Token::Token( Type type, const TQString& text, int pos )
  138. {
  139. m_type = type;
  140. m_text = text;
  141. m_pos = pos;
  142. }
  143. // copy constructor
  144. Token::Token( const Token& token )
  145. {
  146. m_type = token.m_type;
  147. m_text = token.m_text;
  148. m_pos = token.m_pos;
  149. }
  150. // assignment operator
  151. Token& Token::operator=( const Token& token )
  152. {
  153. m_type = token.m_type;
  154. m_text = token.m_text;
  155. m_pos = token.m_pos;
  156. return *this;
  157. }
  158. Abakus::number_t Token::asNumber() const
  159. {
  160. if( isNumber() )
  161. return Abakus::number_t( m_text.latin1() );
  162. else
  163. return Abakus::number_t();
  164. }
  165. Token::Op Token::asOperator() const
  166. {
  167. if( isOperator() ) return matchOperator( m_text );
  168. else return InvalidOp;
  169. }
  170. TQString Token::description() const
  171. {
  172. TQString desc;
  173. switch (m_type )
  174. {
  175. case Number: desc = "Number"; break;
  176. case Identifier: desc = "Identifier"; break;
  177. case Operator: desc = "Operator"; break;
  178. default: desc = "Unknown"; break;
  179. }
  180. while( desc.length() < 10 ) desc.prepend( ' ' );
  181. desc.prepend( " " );
  182. desc.prepend( TQString::number( m_pos ) );
  183. desc.append( " : " ).append( m_text );
  184. return desc;
  185. }
  186. TQString Evaluator::autoFix( const TQString& expr )
  187. {
  188. int par = 0;
  189. TQString result;
  190. // strip off all funny characters
  191. for( unsigned c = 0; c < expr.length(); c++ )
  192. if( expr[c] >= TQChar(32) )
  193. result.append( expr[c] );
  194. // automagically close all parenthesis
  195. Tokens tokens = Evaluator::scan( result );
  196. for( unsigned i=0; i<tokens.count(); i++ )
  197. if( tokens[i].asOperator() == Token::LeftPar ) par++;
  198. else if( tokens[i].asOperator() == Token::RightPar ) par--;
  199. for(; par > 0; par-- )
  200. result.append( ')' );
  201. // special treatment for simple function
  202. // e.g. "cos" is regarded as "cos(ans)"
  203. if( !result.isEmpty() )
  204. {
  205. Tokens tokens = Evaluator::scan( result );
  206. if( (tokens.count() == 1) &&
  207. FunctionManager::instance()->isFunction(tokens[0].text())
  208. )
  209. {
  210. result.append( "(ans)" );
  211. }
  212. }
  213. return result;
  214. }
  215. // vim: set et ts=8 sw=4: