diff -r f345bda72bc4 -r 43e37759235e Symbian3/Examples/guid-6013a680-57f9-415b-8851-c4fa63356636/_lexer_8cpp_source.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Symbian3/Examples/guid-6013a680-57f9-415b-8851-c4fa63356636/_lexer_8cpp_source.html Tue Mar 30 16:16:55 2010 +0100 @@ -0,0 +1,554 @@ + + +
+ +00001 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). +00002 // All rights reserved. +00003 // This component and the accompanying materials are made available +00004 // under the terms of "Eclipse Public License v1.0" +00005 // which accompanies this distribution, and is available +00006 // at the URL "http://www.eclipse.org/legal/epl-v10.html". +00007 // +00008 // Initial Contributors: +00009 // Nokia Corporation - initial contribution. +00010 // +00011 // Contributors: +00012 // +00013 // Description: +00014 // +00015 +00016 #include <e32std.h> +00017 #include <e32cons.h> +00018 +00019 const TInt KMaxCalcCommandBuffer=80; +00020 +00021 //Common literal text +00022 +00023 +00024 _LIT(KTxtErrInExpress," Error in expression, cannot evaluate. "); +00025 +00026 +00027 CConsoleBase* console; +00028 +00029 +00031 // Stack classes +00033 +00034 // +00035 // Stack element class - linked list of TReals +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 // Stack class - just constructor, destructor, push, pop & empty-test. +00057 // +00058 +00059 class CRpnStack : public CBase +00060 { +00061 private: +00062 CRpnStackElement* iTop ; // pointer to top of stack element +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 // Stack class implementations +00078 +00079 // stack element construction (2-part) +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 // stack construction +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 // stack destructor +00115 CRpnStack::~CRpnStack() +00116 { +00117 while (!IsEmpty()) +00118 Pop() ; +00119 } +00120 +00121 +00122 // stack pop & delete top element +00123 TReal CRpnStack::Pop () +00124 { +00125 TReal value = iTop->iValue ; // get return value +00126 CRpnStackElement* old = iTop ; // keep old top of stack pointer +00127 iTop = iTop->iNext; // move top of stack pointer to next element +00128 delete old ; // delete old top of stack element +00129 old = 0 ; // don't want old used again +00130 return value ; // return the value +00131 } +00132 +00133 +00134 // stack push new element +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 // stack empty test +00147 TBool CRpnStack::IsEmpty () +00148 { +00149 return (iTop == 0) ; +00150 } +00151 +00152 +00154 // RPN calculator engine class +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 // RPN calculator engine : numeric routines +00175 +00176 TReal CRpnCalculator::GetIntegerPart(TLex& aInput) +00177 // Finds a UInt. Also used before decimal point for RPN TReal processing +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 // Finds a UInt. Used after decimal point for RPN TReal processing +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 // VERY basic scanning to extract and push a (Uint or real) number. +00206 { +00207 TBool negative = EFalse ; +00208 TReal answer = 0 ; +00209 TLexMark startMark ; +00210 +00211 // need something to parse +00212 if (aInput.Eos()) +00213 return KErrNotFound ; +00214 if (!(aInput.Peek().IsDigit() || (aInput.Peek() == '.') ) ) +00215 return KErrNotFound ; +00216 +00217 // mark where we are, so can unwind +00218 aInput.Mark(startMark) ; +00219 +00220 // deal with sign +00221 if (aInput.Peek() == '+') +00222 aInput.Inc() ; +00223 if (aInput.Peek() == '-') +00224 { +00225 aInput.Inc() ; +00226 negative = ETrue ; +00227 } +00228 +00229 // check there's something to parse +00230 if (aInput.Eos()) +00231 return KErrNotFound ; +00232 +00233 // get number (may be complete integer or first part of a real) +00234 if ((aInput.Peek()).IsDigit()) +00235 answer = CRpnCalculator::GetIntegerPart(aInput) ; +00236 +00237 // negate if necessary +00238 if (negative) +00239 answer *= -1 ; +00240 +00241 // look for decimal point - if found, parse real number +00242 if (aInput.Peek() == '.') +00243 { // may be dealing with real number. +00244 aInput.Inc() ; +00245 if (!(aInput.Peek()).IsDigit()) +00246 { // found non-digit after decimal point. Error, so rewind & exit +00247 aInput.UnGetToMark(startMark) ; +00248 return KErrCancel ; +00249 } +00250 // now must parse digit(s) after decimal point +00251 answer += CRpnCalculator::GetFractionalPart(aInput) ; +00252 aStack->Push(answer) ; +00253 return KErrNone ; +00254 } +00255 else +00256 { // dealing with integer +00257 aStack->Push(answer) ; +00258 return KErrNone ; +00259 } +00260 } +00261 +00262 +00264 // Main body of the RPN calculator engine : calculator +00266 +00267 TInt CRpnCalculator::doRPNCalcEngine(TLex& aInput,CRpnStack* stack,TReal& aReturnValue) +00268 { +00269 // extract a number if possible & push +00270 // extract token, perform operation & push result +00271 // if token is '=' or at end of string, pop & print value +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) ; // parse for number +00282 +00283 /* above line can be replaced by the following equivalent code: +00284 +00285 if (aInput.Val(extractReal) == KErrNone) +00286 stack->Push(extractReal) ; +00287 else if (aInput.Val(extractUint) == KErrNone) +00288 stack->Push(TReal(extractUint)) ; +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 // not found a valid one-character symbol, try key words... +00325 default : +00326 if (aInput.Offset() > 0) // if not at start of line +00327 aInput.UnGet() ; // restore 'got' character +00328 +00329 aInput.Mark() ; // remember where we are +00330 aInput.SkipCharacters() ; // move to end of character token +00331 +00332 +00333 if ( aInput.TokenLength() != 0 ) // if valid potential token +00334 { +00335 _LIT(KTxtMEMSET,"MEMSET"); +00336 _LIT(KTxtMEMGET,"MEMGET"); +00337 TPtrC token = aInput.MarkedToken() ; // extract token +00338 if ( token.CompareF(KTxtMEMSET) == 0) +00339 { +00340 if ( !(stack->IsEmpty()) ) // MEMSET - store top stack element +00341 memory = stack->Pop() ; +00342 if ( stack->IsEmpty() ) // valid command, but empty stack will cause error, so +00343 stack->Push(memory) ; +00344 } +00345 else if ( token.CompareF(KTxtMEMGET) == 0) +00346 stack->Push (memory) ; // MEMGET - push memory value +00347 else +00348 return KErrNotSupported ; // unrecognised token +00349 } +00350 else // exit - can't be anything else +00351 { +00352 return KErrGeneral ; +00353 } +00354 } ; // end switch +00355 if (Err == KErrGeneral) +00356 // error in expression (usually as there aren't 2 stack elements for token to operate on) +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 // RPN calculator engine : calculator +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 // RPN calculator UI : display routines +00392 +00393 void CRpnCalculator::DisplayAnswer(TReal aValue) +00394 { +00395 TRealFormat format ; +00396 TBuf<0x100> convertRealToString; +00397 +00398 // want a TLex from the value +00399 +00400 if (convertRealToString.Num(aValue,format) < KErrNone ) // if -ve, is an error, not a string length +00401 console->Printf(KTxtErrInExpress); +00402 else +00403 { +00404 convertRealToString.ZeroTerminate(); +00405 +00406 TLex string(convertRealToString) ; +00407 // got a TLex +00408 +00409 TLexMark start ; +00410 string.Mark (start) ; // remember start of string position +00411 +00412 // run through string, setting 'end' to last digit found +00413 while (!string.Eos() ) +00414 { +00415 if ( !(string.Get() == '0') ) string.Mark() ; +00416 } +00417 +00418 string.UnGetToMark() ; // reset next character pointer to last digit +00419 // if Mark points to decimal point and not at Eos (i.e. a zero follows), include the zero +00420 if ( string.Get() == '.' && !string.Eos() ) +00421 string.Mark() ; +00422 +00423 // display spaces after entered line +00424 _LIT(KTxtSpaces," "); +00425 console->Write(KTxtSpaces) ; +00426 // set Mark to start of string and display answer +00427 console->Write( string.MarkedToken(start) ) ; +00428 } +00429 } +00430 +00431 +00433 // RPN calculator UI : line input routine (adapted from tuiedit) +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) ; // "cursor" +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) ; // "cursor" +00486 console->SetPos(pos); +00487 } +00488 } +00489 +00490 +00492 // finally the RPN calculator's driver code +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 // This section deals with Symbian platform initialisation and ensuring we have a console active +00526 +00527 +00528 void SetupConsoleL(); +00529 +00530 _LIT(KTxtRPNCalcErr,"RPN Calculator example error"); +00531 +00532 GLDEF_C TInt E32Main() // main function called by E32 +00533 { +00534 CTrapCleanup* cleanup=CTrapCleanup::New(); // get clean-up stack +00535 TRAPD(error,SetupConsoleL()); // more initialization, then do example +00536 __ASSERT_ALWAYS(!error,User::Panic(KTxtRPNCalcErr,error)); +00537 delete cleanup; // destroy clean-up stack +00538 return 0; // and return +00539 } +00540 +00541 +00542 void SetupConsoleL() // initialize and call example code under cleanup stack +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()); // perform example function +00551 if (error) +00552 console->Printf(KFormat1, error); +00553 console->Printf(KTxtPressAnyKey); +00554 console->Getch(); // get and ignore character +00555 CleanupStack::PopAndDestroy(); // close console +00556 } +00557 +00558 +