00001 /********************************************************************** 00002 ** Copyright (C) 2000 Trolltech AS. All rights reserved. 00003 ** 00004 ** This file is part of Qtopia Environment. 00005 ** 00006 ** This file may be distributed and/or modified under the terms of the 00007 ** GNU General Public License version 2 as published by the Free Software 00008 ** Foundation and appearing in the file LICENSE.GPL included in the 00009 ** packaging of this file. 00010 ** 00011 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00012 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00013 ** 00014 ** See http://www.trolltech.com/gpl/ for GPL licensing information. 00015 ** 00016 ** Contact info@trolltech.com if any conditions of this licensing are 00017 ** not clear to you. 00018 ** 00019 **********************************************************************/ 00020 00021 #include "engine.h" 00022 00023 /* OPIE */ 00024 #include <opie2/odebug.h> 00025 00026 /* QT */ 00027 #include <qstring.h> 00028 #include <qlcdnumber.h> 00029 00030 /* STD */ 00031 #include <math.h> 00032 00033 Data Engine::evalStack (Data num, bool inbrace = FALSE) 00034 { 00035 if (state != sError) { 00036 Instruction *i; 00037 00038 // Pop the next op from the stack 00039 while (!stack.isEmpty () && (braces || !inbrace)) { 00040 i = stack.pop (); 00041 00042 // Check this ops prec vs next ops prec 00043 if (!stack.isEmpty ()) 00044 if (i->precedence <= stack.top()->precedence) 00045 i->acc = evalStack (i->acc, inbrace); 00046 00047 // Evaluate this instruction 00048 num = i->eval (num); 00049 00050 // Error-check ( change this to work for all types ) 00051 if (isnan (num.dbl) || isinf (num.dbl)) { 00052 odebug << "bad result from operation" << oendl; 00053 state = sError; 00054 clearData(&num); 00055 return num; 00056 } 00057 } 00058 } 00059 return num; 00060 } 00061 00062 // Plugins call this to request the stack be evaluated 00063 void Engine::eval () 00064 { 00065 num = evalStack (num); 00066 if (state != sError) { 00067 displayData(num); 00068 state = sStart; 00069 } 00070 // if the user didnt close all their braces, its no big deal 00071 braces = 0; 00072 } 00073 00074 void Engine::immediateInstruction (Instruction * i) 00075 { 00076 if (state != sError) { 00077 i->setRep(currentRep); 00078 num = i->eval (num); 00079 displayData(num); 00080 state = sStart; 00081 } 00082 } 00083 00084 void Engine::pushInstruction (Instruction * i) 00085 { 00086 if (state != sError) { 00087 i->setRep(currentRep); 00088 i->acc = num; 00089 stack.push (i); 00090 state = sStart; 00091 } 00092 } 00093 00094 void Engine::pushValue (char v) 00095 { 00096 if (state == sAppend) { 00097 bool ok = FALSE; 00098 switch (currentRep) { 00099 case rDouble: 00100 displayString.append(v); 00101 num.dbl=displayString.toDouble(&ok); 00102 break; 00103 case rFraction: 00104 break; 00105 default: 00106 displayString.append(v); 00107 num.i=displayString.toInt(&ok, calcBase()); 00108 }; 00109 if (!ok) { 00110 state = sError; 00111 odebug << "pushValue() - num->string conversion" << oendl; 00112 } else { 00113 const QString constString = displayString; 00114 emit(display(constString)); 00115 }; 00116 00117 } else if (state == sStart) { 00118 softReset(); 00119 displayString.truncate(0); 00120 state = sAppend; 00121 pushValue (v); 00122 } else if (state == sError) { 00123 odebug << "in error state" << oendl; 00124 return; 00125 } 00126 } 00127 00128 void Engine::del () 00129 { 00130 bool ok; 00131 switch (currentRep) { 00132 case rDouble: 00133 displayString.truncate(displayString.length()); 00134 num.dbl=displayString.toDouble(&ok); 00135 break; 00136 case rFraction: 00137 odebug << "not available" << oendl; 00138 break; 00139 default: 00140 displayString.truncate(displayString.length()); 00141 num.i = displayString.toInt(&ok, calcBase()); 00142 }; 00143 00144 if (!ok) { 00145 state = sError; 00146 odebug << "del() - num->string conversion" << oendl; 00147 } else { 00148 const QString constString = displayString; 00149 emit(display(constString)); 00150 }; 00151 } 00152 00153 void Engine::displayData(Data d) { 00154 switch (currentRep) { 00155 case rDouble: 00156 displayString.setNum(d.dbl); 00157 break; 00158 case rFraction: 00159 odebug << "fractional display not yet impl" << oendl; 00160 break; 00161 default: 00162 displayString.setNum(d.i, calcBase()); 00163 break; 00164 }; 00165 const QString constString= displayString; 00166 emit(display(constString)); 00167 } 00168 00169 // Returns the base when Rep is an integer type 00170 int Engine::calcBase () { 00171 switch (currentRep) { 00172 case rBin: 00173 return 2; 00174 case rOct: 00175 return 8; 00176 case rDec: 00177 return 10; 00178 case rHex: 00179 return 16; 00180 default: 00181 state = sError; 00182 odebug << "Error - attempt to calc base for non-integer" << oendl; 00183 return 10; 00184 }; 00185 } 00186 00187 // Special instruction for internal use only 00188 class iOpenBrace:public Instruction { 00189 public: 00190 iOpenBrace (Engine *e):Instruction (100) {engine = e;}; 00191 ~iOpenBrace () {}; 00192 00193 Data eval (Data num) { 00194 engine->decBraces(); 00195 return num; 00196 }; 00197 private: 00198 Engine *engine; 00199 }; 00200 00201 void Engine::openBrace() { 00202 pushInstruction(new iOpenBrace(this)); 00203 } 00204 00205 void Engine::closeBrace() { 00206 braces++;evalStack(num,TRUE); 00207 } 00208 00209 // will need to show and hide display widgets 00210 void Engine::setRepresentation(Representation r) { 00211 currentRep = r; 00212 clearData(&num); 00213 clearData(&mem); 00214 state = sStart; 00215 } 00216 00217 void Engine::clearData(Data *d) { 00218 d->i = d->fraction.numerator = d->fraction.denominator = 0; 00219 d->dbl = 0; 00220 } 00221
1.4.2