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