00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <e32std.h>
00017 #include <e32cons.h>
00018
00019 const TInt KMaxCalcCommandBuffer=80;
00020
00021
00022
00023
00024 _LIT(KTxtErrInExpress," Error in expression, cannot evaluate. ");
00025
00026
00027 CConsoleBase* console;
00028
00029
00031
00033
00034
00035
00036
00037
00038 class CRpnStackElement : public CBase
00039 {
00040 friend class CRpnStack ;
00041
00042 private:
00043 CRpnStackElement* iNext ;
00044 TReal iValue ;
00045
00046 public:
00047 static CRpnStackElement* NewL ( const TReal& aReal, CRpnStackElement* aStackElement) ;
00048 void ConstructL (const TReal& aReal, CRpnStackElement* aStackElement) ;
00049
00050 public:
00051 CRpnStackElement() {} ;
00052 } ;
00053
00054
00055
00056
00057
00058
00059 class CRpnStack : public CBase
00060 {
00061 private:
00062 CRpnStackElement* iTop ;
00063
00064 public:
00065 static CRpnStack* NewL () ;
00066 void ConstructL () ;
00067
00068 ~CRpnStack() ;
00069 TReal Pop () ;
00070 void Push (TReal aReal) ;
00071 TBool IsEmpty () ;
00072 } ;
00073
00074
00076
00078
00079
00080 CRpnStackElement* CRpnStackElement::NewL(const TReal& aReal, CRpnStackElement* aStackElement)
00081 {
00082 CRpnStackElement* self = new (ELeave) CRpnStackElement ;
00083 CleanupStack::PushL(self);
00084 self->ConstructL(aReal, aStackElement);
00085 CleanupStack::Pop();
00086 return self;
00087 }
00088
00089
00090 void CRpnStackElement::ConstructL(const TReal& aReal, CRpnStackElement* aStackElement)
00091 {
00092 iValue = aReal;
00093 iNext = aStackElement ;
00094 }
00095
00096
00097
00098 CRpnStack* CRpnStack::NewL()
00099 {
00100 CRpnStack* self = new (ELeave) CRpnStack ;
00101 CleanupStack::PushL(self);
00102 self->ConstructL();
00103 CleanupStack::Pop();
00104 return self;
00105 }
00106
00107
00108 void CRpnStack::ConstructL()
00109 {
00110 iTop = 0 ;
00111 }
00112
00113
00114
00115 CRpnStack::~CRpnStack()
00116 {
00117 while (!IsEmpty())
00118 Pop() ;
00119 }
00120
00121
00122
00123 TReal CRpnStack::Pop ()
00124 {
00125 TReal value = iTop->iValue ;
00126 CRpnStackElement* old = iTop ;
00127 iTop = iTop->iNext;
00128 delete old ;
00129 old = 0 ;
00130 return value ;
00131 }
00132
00133
00134
00135 void CRpnStack::Push (TReal aReal)
00136 {
00137 TRAPD(err,iTop = CRpnStackElement::NewL(aReal, iTop)) ;
00138 if(err)
00139 {
00140 _LIT(KFormat2,"Push failed: leave code=%d");
00141 console->Printf(KFormat2,err);
00142 }
00143 }
00144
00145
00146
00147 TBool CRpnStack::IsEmpty ()
00148 {
00149 return (iTop == 0) ;
00150 }
00151
00152
00154
00156
00157 class CRpnCalculator
00158 {
00159 private:
00160 static TReal GetIntegerPart(TLex& aInput) ;
00161 static TReal GetFractionalPart(TLex& aInput) ;
00162 static TInt DealWithNum(CRpnStack* aStack, TLex& aInput) ;
00163 static TInt RPNCalcEngineL(const TDesC& aCommand, TReal& aReturnValue) ;
00164 static TInt doRPNCalcEngine(TLex& aInput,CRpnStack* stack,TReal& aReturnValue);
00165 static void DisplayAnswer(TReal aValue) ;
00166 static TBool TextInput(TDes& aBuf) ;
00167 public:
00168 static void RunRPNCalculatorL() ;
00169 } ;
00170
00171
00173
00175
00176 TReal CRpnCalculator::GetIntegerPart(TLex& aInput)
00177
00178 {
00179 TReal accumulator = 0 ;
00180
00181 while ((aInput.Peek()).IsDigit())
00182 {
00183 accumulator = (accumulator * 10) + ( (TReal)aInput.Get() - (TReal)'0' ) ;
00184 }
00185 return accumulator ;
00186 }
00187
00188
00189 TReal CRpnCalculator::GetFractionalPart(TLex& aInput)
00190
00191 {
00192 TReal accumulator = 0 ;
00193 TReal multiplier = 0.1 ;
00194
00195 while ((aInput.Peek()).IsDigit())
00196 {
00197 accumulator += ( (TReal)aInput.Get() - (TReal)'0' ) * multiplier ;
00198 multiplier /= 10 ;
00199 }
00200 return accumulator ;
00201 }
00202
00203
00204 TInt CRpnCalculator::DealWithNum(CRpnStack* aStack, TLex& aInput)
00205
00206 {
00207 TBool negative = EFalse ;
00208 TReal answer = 0 ;
00209 TLexMark startMark ;
00210
00211
00212 if (aInput.Eos())
00213 return KErrNotFound ;
00214 if (!(aInput.Peek().IsDigit() || (aInput.Peek() == '.') ) )
00215 return KErrNotFound ;
00216
00217
00218 aInput.Mark(startMark) ;
00219
00220
00221 if (aInput.Peek() == '+')
00222 aInput.Inc() ;
00223 if (aInput.Peek() == '-')
00224 {
00225 aInput.Inc() ;
00226 negative = ETrue ;
00227 }
00228
00229
00230 if (aInput.Eos())
00231 return KErrNotFound ;
00232
00233
00234 if ((aInput.Peek()).IsDigit())
00235 answer = CRpnCalculator::GetIntegerPart(aInput) ;
00236
00237
00238 if (negative)
00239 answer *= -1 ;
00240
00241
00242 if (aInput.Peek() == '.')
00243 {
00244 aInput.Inc() ;
00245 if (!(aInput.Peek()).IsDigit())
00246 {
00247 aInput.UnGetToMark(startMark) ;
00248 return KErrCancel ;
00249 }
00250
00251 answer += CRpnCalculator::GetFractionalPart(aInput) ;
00252 aStack->Push(answer) ;
00253 return KErrNone ;
00254 }
00255 else
00256 {
00257 aStack->Push(answer) ;
00258 return KErrNone ;
00259 }
00260 }
00261
00262
00264
00266
00267 TInt CRpnCalculator::doRPNCalcEngine(TLex& aInput,CRpnStack* stack,TReal& aReturnValue)
00268 {
00269
00270
00271
00272 TInt Err = KErrNone;
00273 TReal operand1 = 0;
00274 TReal operand2 = 0 ;
00275 TReal memory = 0 ;
00276
00277 do
00278 {
00279 aInput.SkipSpace() ;
00280
00281 if (CRpnCalculator::DealWithNum(stack, aInput)== KErrNone) ;
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291 else switch ( aInput.Get() )
00292 {
00293 case'+' :
00294 if (!stack->IsEmpty()) operand2 = stack->Pop() ; else Err = KErrGeneral ;
00295 if (!stack->IsEmpty()) operand1 = stack->Pop() ; else Err = KErrGeneral;
00296 if (Err==KErrNone) stack->Push (operand1 + operand2) ;
00297 break ;
00298
00299 case'-' :
00300 if (!stack->IsEmpty()) operand2 = stack->Pop() ; else Err = KErrGeneral ;
00301 if (!stack->IsEmpty()) operand1 = stack->Pop() ; else Err = KErrGeneral;
00302 if (Err==KErrNone) stack->Push (operand1 - operand2) ;
00303 break ;
00304
00305 case '*' :
00306 if (!stack->IsEmpty()) operand2 = stack->Pop() ; else Err = KErrGeneral ;
00307 if (!stack->IsEmpty()) operand1 = stack->Pop() ; else Err = KErrGeneral;
00308 if (Err==KErrNone) stack->Push (operand1 * operand2) ;
00309 break ;
00310
00311 case'/' :
00312 if (!stack->IsEmpty()) operand2 = stack->Pop() ; else Err = KErrGeneral ;
00313 if (!stack->IsEmpty()) operand1 = stack->Pop() ; else Err = KErrGeneral;
00314 if (Err==KErrNone) stack->Push (operand1 / operand2) ;
00315 break ;
00316
00317 case '=' :
00318 if ( !(stack->IsEmpty() ) )
00319 { aReturnValue = stack->Pop() ;
00320 return KErrNone ;
00321 }
00322 else return KErrArgument ;
00323
00324
00325 default :
00326 if (aInput.Offset() > 0)
00327 aInput.UnGet() ;
00328
00329 aInput.Mark() ;
00330 aInput.SkipCharacters() ;
00331
00332
00333 if ( aInput.TokenLength() != 0 )
00334 {
00335 _LIT(KTxtMEMSET,"MEMSET");
00336 _LIT(KTxtMEMGET,"MEMGET");
00337 TPtrC token = aInput.MarkedToken() ;
00338 if ( token.CompareF(KTxtMEMSET) == 0)
00339 {
00340 if ( !(stack->IsEmpty()) )
00341 memory = stack->Pop() ;
00342 if ( stack->IsEmpty() )
00343 stack->Push(memory) ;
00344 }
00345 else if ( token.CompareF(KTxtMEMGET) == 0)
00346 stack->Push (memory) ;
00347 else
00348 return KErrNotSupported ;
00349 }
00350 else
00351 {
00352 return KErrGeneral ;
00353 }
00354 } ;
00355 if (Err == KErrGeneral)
00356
00357 return KErrArgument ;
00358
00359 } while (!aInput.Eos()) ;
00360
00361 if ( !(stack->IsEmpty() ) )
00362 {
00363 aReturnValue = stack->Pop() ;
00364 return KErrNone ;
00365 }
00366 else return KErrArgument ;
00367 }
00368
00369
00370
00372
00374
00375 TInt CRpnCalculator::RPNCalcEngineL(const TDesC& aCommand, TReal& aReturnValue)
00376 {
00377 TInt ret;
00378 TLex input(aCommand);
00379
00380 CRpnStack* stack = CRpnStack::NewL();
00381 CleanupStack::PushL(stack);
00382 ret = CRpnCalculator::doRPNCalcEngine(input,stack,aReturnValue);
00383 CleanupStack::PopAndDestroy();
00384 return ret;
00385 }
00386
00387
00388
00390
00392
00393 void CRpnCalculator::DisplayAnswer(TReal aValue)
00394 {
00395 TRealFormat format ;
00396 TBuf<0x100> convertRealToString;
00397
00398
00399
00400 if (convertRealToString.Num(aValue,format) < KErrNone )
00401 console->Printf(KTxtErrInExpress);
00402 else
00403 {
00404 convertRealToString.ZeroTerminate();
00405
00406 TLex string(convertRealToString) ;
00407
00408
00409 TLexMark start ;
00410 string.Mark (start) ;
00411
00412
00413 while (!string.Eos() )
00414 {
00415 if ( !(string.Get() == '0') ) string.Mark() ;
00416 }
00417
00418 string.UnGetToMark() ;
00419
00420 if ( string.Get() == '.' && !string.Eos() )
00421 string.Mark() ;
00422
00423
00424 _LIT(KTxtSpaces," ");
00425 console->Write(KTxtSpaces) ;
00426
00427 console->Write( string.MarkedToken(start) ) ;
00428 }
00429 }
00430
00431
00433
00435
00436 _LIT(KTxtBackSlashSeven,"\7");
00437 _LIT(KTxtCursor,"_");
00438
00439 TBool CRpnCalculator::TextInput(TDes& aBuf)
00440 {
00441 TInt pos;
00442
00443 pos = 0;
00444 aBuf.Zero();
00445 console->SetPos(0);
00446 console->Write(KTxtCursor) ;
00447 console->SetPos(0);
00448
00449 FOREVER
00450 {
00451 TChar gChar=console->Getch();
00452 switch (gChar)
00453 {
00454 case EKeyEscape:
00455 return (EFalse);
00456 case EKeyEnter:
00457 return (ETrue);
00458 case EKeyBackspace:
00459 if (pos)
00460 {
00461 pos--;
00462 aBuf.Delete(pos,1);
00463 }
00464 break;
00465 default:
00466 if (!gChar.IsPrint())
00467 break;
00468 else
00469 if ((aBuf.Length()<KMaxCalcCommandBuffer)&&(pos<KDefaultConsWidth-3))
00470 {
00471 TBuf<0x02> b;
00472 b.Append(gChar);
00473 aBuf.Insert(pos++,b);
00474 }
00475 else
00476 {
00477 console->Write(KTxtBackSlashSeven);
00478 break;
00479 }
00480 }
00481 console->SetPos(pos) ;
00482 console->ClearToEndOfLine();
00483 console->SetPos(0);
00484 console->Write(aBuf);
00485 console->Write(KTxtCursor) ;
00486 console->SetPos(pos);
00487 }
00488 }
00489
00490
00492
00494
00495 _LIT(KTxtStartingRPNCalc,"Starting RPN Calculator\n\n");
00496 _LIT(KTxtNewLine," \n");
00497 _LIT(KTxtInvite,"Type in a Reverse Polish\nexpression.\nPress ENTER to evaluate it\nPress ESC to end\n");
00498
00499
00500
00501 void CRpnCalculator::RunRPNCalculatorL()
00502 {
00503 TBuf<KMaxCalcCommandBuffer> command;
00504
00505 console->Printf(KTxtStartingRPNCalc);
00506 console->Printf(KTxtInvite);
00507
00508 while (CRpnCalculator::TextInput(command) )
00509 {
00510 TReal answer;
00511
00512 if (CRpnCalculator::RPNCalcEngineL(command, answer) == KErrNone )
00513 CRpnCalculator::DisplayAnswer(answer) ;
00514 else
00515 console->Printf(KTxtErrInExpress) ;
00516
00517 console->Printf(KTxtNewLine) ;
00518 console->Printf(KTxtInvite);
00519 }
00520 }
00521
00522
00524
00526
00527
00528 void SetupConsoleL();
00529
00530 _LIT(KTxtRPNCalcErr,"RPN Calculator example error");
00531
00532 GLDEF_C TInt E32Main()
00533 {
00534 CTrapCleanup* cleanup=CTrapCleanup::New();
00535 TRAPD(error,SetupConsoleL());
00536 __ASSERT_ALWAYS(!error,User::Panic(KTxtRPNCalcErr,error));
00537 delete cleanup;
00538 return 0;
00539 }
00540
00541
00542 void SetupConsoleL()
00543 {
00544 _LIT(KTxtIntro,"eulexrpn - RPN Calculator");
00545 _LIT(KFormat1,"failed: leave code=%d");
00546 _LIT(KTxtPressAnyKey,"[Press any key to exit]");
00547
00548 console=Console::NewL(KTxtIntro,TSize(KConsFullScreen,KConsFullScreen));
00549 CleanupStack::PushL(console);
00550 TRAPD(error, CRpnCalculator::RunRPNCalculatorL());
00551 if (error)
00552 console->Printf(KFormat1, error);
00553 console->Printf(KTxtPressAnyKey);
00554 console->Getch();
00555 CleanupStack::PopAndDestroy();
00556 }
00557
00558