1 /** \file
2 \brief Implementation of the muParserX engine.
3
4 <pre>
5 __________ ____ ___
6 _____ __ _\______ \_____ _______ ______ __________\ \/ /
7 / \| | \ ___/\__ \\_ __ \/ ___// __ \_ __ \ /
8 | Y Y \ | / | / __ \| | \/\___ \\ ___/| | \/ \
9 |__|_| /____/|____| (____ /__| /____ >\___ >__| /___/\ \
10 \/ \/ \/ \/ \_/
11 Copyright (C) 2021 Ingo Berg
12 All rights reserved.
13
14 Redistribution and use in source and binary forms, with or without
15 modification, are permitted provided that the following conditions are met:
16
17 * Redistributions of source code must retain the above copyright notice,
18 this list of conditions and the following disclaimer.
19 * Redistributions in binary form must reproduce the above copyright notice,
20 this list of conditions and the following disclaimer in the documentation
21 and/or other materials provided with the distribution.
22
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 POSSIBILITY OF SUCH DAMAGE.
33 </pre>
34 */
35 #include "mpParserBase.h"
36
37 #include <cmath>
38 #include <memory>
39 #include <vector>
40 #include <sstream>
41
42 #include "utGeneric.h"
43 #include "mpDefines.h"
44 #include "mpIfThenElse.h"
45 #include "mpScriptTokens.h"
46 #include "mpOprtBinShortcut.h"
47
48 using namespace std;
49
50 MUP_NAMESPACE_START
51
52 //------------------------------------------------------------------------------
53 const char_type* g_sCmdCode[] = {
54 _T("BRCK. OPEN "),
55 _T("BRCK. CLOSE "),
56 _T("IDX OPEN "),
57 _T("IDX CLOSE "),
58 _T("CURLY BRCK. OPEN "),
59 _T("CURLY BRCK. CLOSE"),
60 _T("ARG_SEP "),
61 _T("IF "),
62 _T("ELSE "),
63 _T("ENDIF "),
64 _T("JMP "),
65 _T("VAL "),
66 _T("FUNC "),
67 _T("OPRT_BIN "),
68 _T("OPRT_IFX "),
69 _T("OPRT_PFX "),
70 _T("SC_BEGIN "),
71 _T("SC_END "),
72 _T("END "),
73 _T("SCR_ENDL "),
74 _T("SCR_CMT "),
75 _T("SCR_WHILE "),
76 _T("SCR_GOTO "),
77 _T("SCR_LABEL "),
78 _T("SCR_FOR "),
79 _T("SCR_IF "),
80 _T("SCR_ELSE "),
81 _T("SCR_ELIF "),
82 _T("SCR_ENDIF "),
83 _T("SCR_FUNC "),
84 _T("UNKNOWN "),
85 nullptr };
86
87 //------------------------------------------------------------------------------
88 bool ParserXBase::s_bDumpStack = false;
89 bool ParserXBase::s_bDumpRPN = false;
90
91 //------------------------------------------------------------------------------
92 /** \brief Identifiers for built in binary operators.
93
94 When defining custom binary operators with AddOprt(...) make sure not to choose
95 names conflicting with these definitions.
96 */
97 const char_type* ParserXBase::c_DefaultOprt[] = {
98 _T("("),
99 _T(")"),
100 _T("["),
101 _T("]"),
102 _T("{"),
103 _T("}"),
104 _T(","),
105 _T("?"),
106 _T(":"),
107 0 };
108
109 //------------------------------------------------------------------------------
110 /** \brief Default constructor. */
ParserXBase()111 ParserXBase::ParserXBase()
112 :m_FunDef()
113 , m_PostOprtDef()
114 , m_InfixOprtDef()
115 , m_OprtDef()
116 , m_OprtShortcutDef()
117 , m_valDef()
118 , m_varDef()
119 , m_pParserEngine(&ParserXBase::ParseFromString)
120 , m_pTokenReader()
121 , m_valDynVarShadow()
122 , m_sNameChars()
123 , m_sOprtChars()
124 , m_sInfixOprtChars()
125 , m_bIsQueryingExprVar(false)
126 , m_bAutoCreateVar(false)
127 , m_rpn()
128 , m_vStackBuffer()
129 {
130 InitTokenReader();
131 }
132
133 //---------------------------------------------------------------------------
134 /** \brief Copy constructor.
135 \param a_Parser Reference to the other parser object
136
137 Implemented by calling Assign(a_Parser)
138 */
ParserXBase(const ParserXBase & a_Parser)139 ParserXBase::ParserXBase(const ParserXBase& a_Parser)
140 :m_FunDef()
141 , m_PostOprtDef()
142 , m_InfixOprtDef()
143 , m_OprtDef()
144 , m_OprtShortcutDef()
145 , m_valDef()
146 , m_varDef()
147 , m_pParserEngine(&ParserXBase::ParseFromString)
148 , m_pTokenReader()
149 , m_valDynVarShadow()
150 , m_sNameChars()
151 , m_sOprtChars()
152 , m_sInfixOprtChars()
153 , m_bAutoCreateVar()
154 , m_rpn()
155 , m_vStackBuffer()
156 {
157 m_pTokenReader.reset(new TokenReader(this));
158 Assign(a_Parser);
159 }
160
161 //---------------------------------------------------------------------------
162 /** \brief Destructor.
163 \throw nothrow
164 */
~ParserXBase()165 ParserXBase::~ParserXBase()
166 {
167 // It is important to release the stack buffer before
168 // releasing the value cache. Since it may contain
169 // Values referencing the cache.
170 m_vStackBuffer.clear();
171 m_cache.ReleaseAll();
172 }
173
174 //---------------------------------------------------------------------------
175 /** \brief Assignement operator.
176 \param a_Parser Object to copy to this.
177 \return *this
178 \throw nothrow
179
180 Implemented by calling Assign(a_Parser). Self assignement is suppressed.
181 */
operator =(const ParserXBase & a_Parser)182 ParserXBase& ParserXBase::operator=(const ParserXBase& a_Parser)
183 {
184 Assign(a_Parser);
185 return *this;
186 }
187
188 //---------------------------------------------------------------------------
189 /** \brief Copy state of a parser object to this.
190 \param a_Parser the source object.
191
192 Clears Variables and Functions of this parser.
193 Copies the states of all internal variables.
194 Resets parse function to string parse mode.
195 */
Assign(const ParserXBase & ref)196 void ParserXBase::Assign(const ParserXBase& ref)
197 {
198 if (&ref == this)
199 return;
200
201 // Don't copy bytecode instead cause the parser to create new bytecode
202 // by resetting the parse function.
203 ReInit();
204
205 m_pTokenReader.reset(ref.m_pTokenReader->Clone(this));
206
207 m_OprtDef = ref.m_OprtDef;
208 m_OprtShortcutDef = ref.m_OprtShortcutDef;
209 m_FunDef = ref.m_FunDef;
210 m_PostOprtDef = ref.m_PostOprtDef;
211 m_InfixOprtDef = ref.m_InfixOprtDef;
212 m_valDef = ref.m_valDef;
213 m_valDynVarShadow = ref.m_valDynVarShadow;
214 m_varDef = ref.m_varDef; // Copy user defined variables
215
216 // Copy charsets
217 m_sNameChars = ref.m_sNameChars;
218 m_sOprtChars = ref.m_sOprtChars;
219 m_sInfixOprtChars = ref.m_sInfixOprtChars;
220
221 m_bAutoCreateVar = ref.m_bAutoCreateVar;
222
223 // Things that should not be copied:
224 // - m_vStackBuffer
225 // - m_cache
226 // - m_rpn
227 }
228
229 //---------------------------------------------------------------------------
230 /** \brief Evaluate the expression.
231 \pre A formula must be set.
232 \pre Variables must have been set (if needed)
233 \sa SetExpr
234 \return The evaluation result
235 \throw ParseException if no Formula is set or in case of any other error related to the formula.
236
237 A note on const correctness:
238 I consider it important that Calc is a const function.
239 Due to caching operations Calc changes only the state of internal variables with one exception
240 m_UsedVar this is reset during string parsing and accessible from the outside. Instead of making
241 Calc non const GetExprVar is non const because it explicitely calls Eval() forcing this update.
242 */
Eval() const243 const IValue& ParserXBase::Eval() const
244 {
245 return (this->*m_pParserEngine)();
246 }
247
248 //---------------------------------------------------------------------------
249 /** \brief Return the strings of all Operator identifiers.
250 \return Returns a pointer to the c_DefaultOprt array of const char *.
251 \throw nothrow
252
253 GetOprt is a const function returning a pinter to an array of const char pointers.
254 */
GetOprtDef() const255 const char_type** ParserXBase::GetOprtDef() const
256 {
257 return (const char_type**)(&c_DefaultOprt[0]);
258 }
259
260 //---------------------------------------------------------------------------
261 /** \brief Define the set of valid characters to be used in names of
262 functions, variables, constants.
263 */
DefineNameChars(const char_type * a_szCharset)264 void ParserXBase::DefineNameChars(const char_type* a_szCharset)
265 {
266 m_sNameChars = a_szCharset;
267 }
268
269 //---------------------------------------------------------------------------
270 /** \brief Define the set of valid characters to be used in names of
271 binary operators and postfix operators.
272 \param a_szCharset A string containing all characters that can be used
273 in operator identifiers.
274 */
DefineOprtChars(const char_type * a_szCharset)275 void ParserXBase::DefineOprtChars(const char_type* a_szCharset)
276 {
277 m_sOprtChars = a_szCharset;
278 }
279
280 //---------------------------------------------------------------------------
281 /** \brief Define the set of valid characters to be used in names of
282 infix operators.
283 \param a_szCharset A string containing all characters that can be used
284 in infix operator identifiers.
285 */
DefineInfixOprtChars(const char_type * a_szCharset)286 void ParserXBase::DefineInfixOprtChars(const char_type* a_szCharset)
287 {
288 m_sInfixOprtChars = a_szCharset;
289 }
290
291 //---------------------------------------------------------------------------
292 /** \brief Virtual function that defines the characters allowed in name identifiers.
293 \sa #ValidOprtChars, #ValidPrefixOprtChars
294 */
ValidNameChars() const295 const char_type* ParserXBase::ValidNameChars() const
296 {
297 MUP_VERIFY(m_sNameChars.size());
298 return m_sNameChars.c_str();
299 }
300
301 //---------------------------------------------------------------------------
302 /** \brief Virtual function that defines the characters allowed in operator definitions.
303 \sa #ValidNameChars, #ValidPrefixOprtChars
304 */
ValidOprtChars() const305 const char_type* ParserXBase::ValidOprtChars() const
306 {
307 MUP_VERIFY(m_sOprtChars.size());
308 return m_sOprtChars.c_str();
309 }
310
311 //---------------------------------------------------------------------------
312 /** \brief Virtual function that defines the characters allowed in infix operator definitions.
313 \sa #ValidNameChars, #ValidOprtChars
314 */
ValidInfixOprtChars() const315 const char_type* ParserXBase::ValidInfixOprtChars() const
316 {
317 MUP_VERIFY(m_sInfixOprtChars.size());
318 return m_sInfixOprtChars.c_str();
319 }
320
321 //---------------------------------------------------------------------------
322 /** \brief Initialize the token reader.
323 \post m_pTokenReader.Get()!=0
324 \throw nothrow
325
326 Create new token reader object and submit pointers to function, operator,
327 constant and variable definitions.
328 */
InitTokenReader()329 void ParserXBase::InitTokenReader()
330 {
331 m_pTokenReader.reset(new TokenReader(this));
332 }
333
334 //---------------------------------------------------------------------------
335 /** \brief Reset parser to string parsing mode and clear internal buffers.
336 \throw nothrow
337
338 Resets the token reader.
339 */
ReInit() const340 void ParserXBase::ReInit() const
341 {
342 m_pParserEngine = &ParserXBase::ParseFromString;
343 m_pTokenReader->ReInit();
344 m_rpn.Reset();
345 m_vStackBuffer.clear();
346 m_nPos = 0;
347 }
348
349 //---------------------------------------------------------------------------
350 /** \brief Adds a new package to the parser.
351
352 The parser becomes the owner of the package pointer and is responsible for
353 its deletion.
354 */
AddPackage(IPackage * p)355 void ParserXBase::AddPackage(IPackage* p)
356 {
357 p->AddToParser(this);
358 }
359
360 //---------------------------------------------------------------------------
361 /** \brief Add a value reader object to muParserX.
362 \param a_pReader Pointer to the value reader object.
363 */
AddValueReader(IValueReader * a_pReader)364 void ParserXBase::AddValueReader(IValueReader* a_pReader)
365 {
366 m_pTokenReader->AddValueReader(a_pReader);
367 }
368
369 //---------------------------------------------------------------------------
370 /** \brief Check if a given name contains invalid characters.
371 \param a_strName The name to check
372 \param a_szCharSet The characterset
373 \throw ParserException if the name contains invalid charakters.
374 */
CheckName(const string_type & a_strName,const string_type & a_szCharSet) const375 void ParserXBase::CheckName(const string_type& a_strName,
376 const string_type& a_szCharSet) const
377 {
378 if (!a_strName.length() ||
379 (a_strName.find_first_not_of(a_szCharSet) != string_type::npos) ||
380 (a_strName[0] >= (char_type)'0' && a_strName[0] <= (char_type)'9'))
381 {
382 Error(ecINVALID_NAME);
383 }
384 }
385
386 //---------------------------------------------------------------------------
387 /** \brief Set the mathematical expression.
388 \param a_sExpr String with the expression
389 \throw ParserException in case of syntax errors.
390
391 Triggers first time calculation thus the creation of the bytecode and
392 scanning of used variables.
393 */
SetExpr(const string_type & a_sExpr)394 void ParserXBase::SetExpr(const string_type& a_sExpr)
395 {
396 m_pTokenReader->SetExpr(a_sExpr);
397 ReInit();
398 }
399
400 //---------------------------------------------------------------------------
401 /** \brief Add a user defined variable.
402 \param a_sName The variable name
403 \param a_Var The variable to be added to muParserX
404 */
DefineVar(const string_type & ident,const Variable & var)405 void ParserXBase::DefineVar(const string_type& ident, const Variable& var)
406 {
407 CheckName(ident, ValidNameChars());
408
409 CheckForEntityExistence(ident, ecVARIABLE_DEFINED);
410
411 m_varDef[ident] = ptr_tok_type(var.Clone());
412 }
413
CheckForEntityExistence(const string_type & ident,EErrorCodes error_code)414 void ParserXBase::CheckForEntityExistence(const string_type& ident, EErrorCodes error_code)
415 {
416 if (IsVarDefined(ident) ||
417 IsConstDefined(ident) ||
418 IsFunDefined(ident) ||
419 IsOprtDefined(ident) ||
420 IsPostfixOprtDefined(ident) ||
421 IsInfixOprtDefined(ident))
422 throw ParserError(ErrorContext(error_code, 0, ident));
423 }
424
425 //---------------------------------------------------------------------------
426 /** \brief Define a parser Constant.
427 \param a_sName The name of the constant
428 \param a_Val Const reference to the constants value
429
430 Parser constants are handed over by const reference as opposed to variables
431 which are handed over by reference. Consequently the parser can not change
432 their value.
433 */
DefineConst(const string_type & ident,const Value & val)434 void ParserXBase::DefineConst(const string_type& ident, const Value& val)
435 {
436 CheckName(ident, ValidNameChars());
437
438 CheckForEntityExistence(ident, ecCONSTANT_DEFINED);
439
440 m_valDef[ident] = ptr_tok_type(val.Clone());
441 }
442
443 //---------------------------------------------------------------------------
444 /** \brief Add a callback object to the parser.
445 \param a_pFunc Pointer to the intance of a parser callback object
446 representing the function.
447 \sa GetFunDef, functions
448
449 The parser takes ownership over the callback object.
450 */
DefineFun(const ptr_cal_type & fun)451 void ParserXBase::DefineFun(const ptr_cal_type& fun)
452 {
453 if (IsFunDefined(fun->GetIdent()))
454 throw ParserError(ErrorContext(ecFUNOPRT_DEFINED, 0, fun->GetIdent()));
455
456 fun->SetParent(this);
457 m_FunDef[fun->GetIdent()] = ptr_tok_type(fun->Clone());
458 }
459
460 //---------------------------------------------------------------------------
461 /** \brief Define a binary operator.
462 \param a_pCallback Pointer to the callback object
463 */
DefineOprt(const TokenPtr<IOprtBin> & oprt)464 void ParserXBase::DefineOprt(const TokenPtr<IOprtBin>& oprt)
465 {
466 if (IsOprtDefined(oprt->GetIdent()))
467 throw ParserError(ErrorContext(ecFUNOPRT_DEFINED, 0, oprt->GetIdent()));
468
469 oprt->SetParent(this);
470 m_OprtDef[oprt->GetIdent()] = ptr_tok_type(oprt->Clone());
471 }
472
473 //---------------------------------------------------------------------------
474 /** \brief Define a short circuit operator.
475 \param a_pCallback Pointer to the callback object
476 */
DefineOprt(const TokenPtr<IOprtBinShortcut> & oprt)477 void ParserXBase::DefineOprt(const TokenPtr<IOprtBinShortcut> &oprt)
478 {
479 if (IsOprtDefined(oprt->GetIdent()))
480 throw ParserError(ErrorContext(ecFUNOPRT_DEFINED, 0, oprt->GetIdent()));
481
482 //oprt->SetParent(this);
483 m_OprtShortcutDef[oprt->GetIdent()] = ptr_tok_type(oprt->Clone());
484 }
485
486 //---------------------------------------------------------------------------
487 /** \brief Add a user defined operator.
488 \post Will reset the Parser to string parsing mode.
489 \param a_pOprt Pointer to a unary postfix operator object. The parser will
490 become the new owner of this object hence will destroy it.
491 */
DefinePostfixOprt(const TokenPtr<IOprtPostfix> & oprt)492 void ParserXBase::DefinePostfixOprt(const TokenPtr<IOprtPostfix>& oprt)
493 {
494 if (IsPostfixOprtDefined(oprt->GetIdent()))
495 throw ParserError(ErrorContext(ecFUNOPRT_DEFINED, 0, oprt->GetIdent()));
496
497 // Operator is not added yet, add it.
498 oprt->SetParent(this);
499 m_PostOprtDef[oprt->GetIdent()] = ptr_tok_type(oprt->Clone());
500 }
501
502 //---------------------------------------------------------------------------
503 /** \brief Add a user defined operator.
504 \param a_pOprt Pointer to a unary postfix operator object. The parser will
505 become the new owner of this object hence will destroy it.
506 */
DefineInfixOprt(const TokenPtr<IOprtInfix> & oprt)507 void ParserXBase::DefineInfixOprt(const TokenPtr<IOprtInfix>& oprt)
508 {
509 if (IsInfixOprtDefined(oprt->GetIdent()))
510 throw ParserError(ErrorContext(ecFUNOPRT_DEFINED, 0, oprt->GetIdent()));
511
512 // Function is not added yet, add it.
513 oprt->SetParent(this);
514 m_InfixOprtDef[oprt->GetIdent()] = ptr_tok_type(oprt->Clone());
515 }
516
517 //---------------------------------------------------------------------------
RemoveVar(const string_type & ident)518 void ParserXBase::RemoveVar(const string_type& ident)
519 {
520 m_varDef.erase(ident);
521 ReInit();
522 }
523
524 //---------------------------------------------------------------------------
RemoveConst(const string_type & ident)525 void ParserXBase::RemoveConst(const string_type& ident)
526 {
527 m_valDef.erase(ident);
528 ReInit();
529 }
530
531 //---------------------------------------------------------------------------
RemoveFun(const string_type & ident)532 void ParserXBase::RemoveFun(const string_type& ident)
533 {
534 m_FunDef.erase(ident);
535 ReInit();
536 }
537
538 //---------------------------------------------------------------------------
RemoveOprt(const string_type & ident)539 void ParserXBase::RemoveOprt(const string_type& ident)
540 {
541 m_OprtDef.erase(ident);
542 m_OprtShortcutDef.erase(ident);
543 ReInit();
544 }
545
546 //---------------------------------------------------------------------------
RemovePostfixOprt(const string_type & ident)547 void ParserXBase::RemovePostfixOprt(const string_type& ident)
548 {
549 m_PostOprtDef.erase(ident);
550 ReInit();
551 }
552
553 //---------------------------------------------------------------------------
RemoveInfixOprt(const string_type & ident)554 void ParserXBase::RemoveInfixOprt(const string_type& ident)
555 {
556 m_InfixOprtDef.erase(ident);
557 ReInit();
558 }
559
560 //---------------------------------------------------------------------------
IsVarDefined(const string_type & ident) const561 bool ParserXBase::IsVarDefined(const string_type& ident) const
562 {
563 return m_varDef.find(ident) != m_varDef.end();
564 }
565
566 //---------------------------------------------------------------------------
IsConstDefined(const string_type & ident) const567 bool ParserXBase::IsConstDefined(const string_type& ident) const
568 {
569 return m_valDef.find(ident) != m_valDef.end();
570 }
571
572 //---------------------------------------------------------------------------
IsFunDefined(const string_type & ident) const573 bool ParserXBase::IsFunDefined(const string_type& ident) const
574 {
575 return m_FunDef.find(ident) != m_FunDef.end();
576 }
577
578 //---------------------------------------------------------------------------
IsOprtDefined(const string_type & ident) const579 bool ParserXBase::IsOprtDefined(const string_type& ident) const
580 {
581 return m_OprtDef.find(ident) != m_OprtDef.end() || m_OprtShortcutDef.find(ident) != m_OprtShortcutDef.end();
582 }
583
584 //---------------------------------------------------------------------------
IsPostfixOprtDefined(const string_type & ident) const585 bool ParserXBase::IsPostfixOprtDefined(const string_type& ident) const
586 {
587 return m_PostOprtDef.find(ident) != m_PostOprtDef.end();
588 }
589
590 //---------------------------------------------------------------------------
IsInfixOprtDefined(const string_type & ident) const591 bool ParserXBase::IsInfixOprtDefined(const string_type& ident) const
592 {
593 return m_InfixOprtDef.find(ident) != m_InfixOprtDef.end();
594 }
595
596 //---------------------------------------------------------------------------
597 /** \brief Return a map containing the used variables only. */
GetExprVar() const598 const var_maptype& ParserXBase::GetExprVar() const
599 {
600 utils::scoped_setter<bool> guard(m_bIsQueryingExprVar, true);
601
602 // Create RPN, but do not compute the result or switch to RPN
603 // parsing mode. The expression may contain yet to be defined variables.
604 CreateRPN();
605 return m_pTokenReader->GetUsedVar();
606 }
607
608 //---------------------------------------------------------------------------
609 /** \brief Return a map containing the used variables only. */
GetVar() const610 const var_maptype& ParserXBase::GetVar() const
611 {
612 return m_varDef;
613 }
614
615 //---------------------------------------------------------------------------
616 /** \brief Return a map containing all parser constants. */
GetConst() const617 const val_maptype& ParserXBase::GetConst() const
618 {
619 return m_valDef;
620 }
621
622 //---------------------------------------------------------------------------
623 /** \brief Return prototypes of all parser functions.
624 \return #m_FunDef
625 \sa FunProt, functions
626 \throw nothrow
627
628 The return type is a map of the public type #funmap_type containing the prototype
629 definitions for all numerical parser functions. String functions are not part of
630 this map. The Prototype definition is encapsulated in objects of the class FunProt
631 one per parser function each associated with function names via a map construct.
632 */
GetFunDef() const633 const fun_maptype& ParserXBase::GetFunDef() const
634 {
635 return m_FunDef;
636 }
637
638 //---------------------------------------------------------------------------
639 /** \brief Retrieve the mathematical expression. */
GetExpr() const640 const string_type& ParserXBase::GetExpr() const
641 {
642 return m_pTokenReader->GetExpr();
643 }
644
645 //---------------------------------------------------------------------------
646 /** \brief Get the version number of muParserX.
647 \return A string containing the version number of muParserX.
648 */
GetVersion()649 string_type ParserXBase::GetVersion()
650 {
651 return MUP_PARSER_VERSION;
652 }
653
654 //---------------------------------------------------------------------------
ApplyRemainingOprt(Stack<ptr_tok_type> & stOpt) const655 void ParserXBase::ApplyRemainingOprt(Stack<ptr_tok_type>& stOpt) const
656
657 {
658 while (stOpt.size() &&
659 stOpt.top()->GetCode() != cmBO &&
660 stOpt.top()->GetCode() != cmIO &&
661 stOpt.top()->GetCode() != cmCBO &&
662 stOpt.top()->GetCode() != cmIF)
663 {
664 ptr_tok_type& op = stOpt.top();
665 switch (op->GetCode())
666 {
667 case cmOPRT_INFIX:
668 case cmOPRT_BIN: ApplyFunc(stOpt, 2); break;
669 case cmSHORTCUT_END: ApplyOprtShortcut(stOpt); break;
670 case cmELSE: ApplyIfElse(stOpt); break;
671 default: Error(ecINTERNAL_ERROR);
672 } // switch operator token type
673 } // While operator stack not empty
674 }
675
676 //---------------------------------------------------------------------------
677 /** \brief Simulates the call of a parser function with its corresponding arguments.
678 \param a_stOpt The operator stack
679 \param a_stVal The value stack
680 \param a_iArgCount The number of function arguments
681 */
ApplyFunc(Stack<ptr_tok_type> & a_stOpt,int a_iArgCount) const682 void ParserXBase::ApplyFunc(Stack<ptr_tok_type>& a_stOpt,
683 int a_iArgCount) const
684 {
685 if (a_stOpt.empty())
686 return;
687
688 ptr_tok_type tok = a_stOpt.pop();
689 ICallback* pFun = tok->AsICallback();
690
691 int iArgCount = (pFun->GetArgc() >= 0) ? pFun->GetArgc() : a_iArgCount;
692 pFun->SetNumArgsPresent(iArgCount);
693
694 m_nPos -= (iArgCount - 1);
695 m_rpn.Add(tok);
696 }
697
ApplyOprtShortcut(Stack<ptr_tok_type> & a_stOpt) const698 void ParserXBase::ApplyOprtShortcut(Stack<ptr_tok_type> &a_stOpt) const
699 {
700 if (a_stOpt.empty())
701 return;
702
703 ptr_tok_type tok = a_stOpt.pop();
704 m_nPos -= 1;
705 m_rpn.Add(tok);
706 }
707
708 //---------------------------------------------------------------------------
709 /** \brief Simulates the effect of the execution of an if-then-else block.
710 */
ApplyIfElse(Stack<ptr_tok_type> & a_stOpt) const711 void ParserXBase::ApplyIfElse(Stack<ptr_tok_type>& a_stOpt) const
712 {
713 while (a_stOpt.size() && a_stOpt.top()->GetCode() == cmELSE)
714 {
715 MUP_VERIFY(a_stOpt.size() > 0);
716 MUP_VERIFY(m_nPos >= 3);
717 MUP_VERIFY(a_stOpt.top()->GetCode() == cmELSE);
718
719 ptr_tok_type opElse = a_stOpt.pop();
720 ptr_tok_type opIf = a_stOpt.pop();
721 MUP_VERIFY(opElse->GetCode() == cmELSE)
722
723 if (opIf->GetCode() != cmIF)
724 {
725 ErrorContext err;
726 err.Expr = m_pTokenReader->GetExpr();
727 err.Errc = ecMISPLACED_COLON;
728 err.Pos = m_pTokenReader->GetPos();
729 throw ParserError(err);
730 }
731
732 // If then else hat 3 argumente und erzeugt einen rückgabewert (3-1=2)
733 m_nPos -= 2;
734 m_rpn.Add(ptr_tok_type(new TokenIfThenElse(cmENDIF)));
735 }
736 }
737
738 //---------------------------------------------------------------------------
DumpRPN() const739 void ParserXBase::DumpRPN() const
740 {
741 m_rpn.AsciiDump();
742 }
743
744 //---------------------------------------------------------------------------
CreateRPN() const745 void ParserXBase::CreateRPN() const
746 {
747 if (!m_pTokenReader->GetExpr().length())
748 Error(ecUNEXPECTED_EOF, 0);
749
750 // The Stacks take the ownership over the tokens
751 Stack<ptr_tok_type> stOpt;
752 Stack<int> stArgCount;
753 Stack<int> stIdxCount;
754 ptr_tok_type pTok, pTokPrev;
755 Value val;
756
757 ReInit();
758
759 for (;;)
760 {
761 pTokPrev = pTok;
762 pTok = m_pTokenReader->ReadNextToken();
763
764 #if defined(MUP_DUMP_TOKENS)
765 console() << pTok->AsciiDump() << endl;
766 #endif
767
768 ECmdCode eCmd = pTok->GetCode();
769 switch (eCmd)
770 {
771 case cmVAL:
772 m_nPos++;
773 m_rpn.Add(pTok);
774 break;
775
776 case cmCBC:
777 case cmIC:
778 {
779 ECmdCode eStarter = (ECmdCode)(eCmd - 1);
780 MUP_VERIFY(eStarter == cmCBO || eStarter == cmIO);
781
782 // The argument count for parameterless functions is zero
783 // by default an opening bracket sets parameter count to 1
784 // in preparation of arguments to come. If the last token
785 // was an opening bracket we know better...
786 if (pTokPrev.Get() != nullptr && pTokPrev->GetCode() == eStarter)
787 --stArgCount.top();
788
789 ApplyRemainingOprt(stOpt);
790
791 // if opt is "]" and opta is "[" the bracket content has been evaluated.
792 // Now check whether there is an index operator on the stack.
793 if (stOpt.size() && stOpt.top()->GetCode() == eStarter)
794 {
795 //
796 // Find out how many dimensions were used in the index operator.
797 //
798 int iArgc = stArgCount.pop();
799 stOpt.pop(); // Take opening bracket from stack
800
801 ICallback* pOprtIndex = pTok->AsICallback();
802 MUP_VERIFY(pOprtIndex != nullptr);
803
804 pOprtIndex->SetNumArgsPresent(iArgc);
805 m_rpn.Add(pOprtIndex);
806
807 // If this is an index operator there must be something else in the register (the variable to index)
808 MUP_VERIFY(eCmd != cmIC || m_nPos >= (int)iArgc + 1);
809
810 // Reduce the index into the value registers accordingly
811 m_nPos -= iArgc;
812
813 if (eCmd == cmCBC)
814 {
815 ++m_nPos;
816 }
817 } // if opening index bracket is on top of operator stack
818 }
819 break;
820
821 case cmBC:
822 {
823 // The argument count for parameterless functions is zero
824 // by default an opening bracket sets parameter count to 1
825 // in preparation of arguments to come. If the last token
826 // was an opening bracket we know better...
827 if (pTokPrev.Get() != nullptr && pTokPrev->GetCode() == cmBO)
828 --stArgCount.top();
829
830 ApplyRemainingOprt(stOpt);
831
832 // if opt is ")" and opta is "(" the bracket content has been evaluated.
833 // Now its time to check if there is either a function or a sign pending.
834 // - Neither the opening nor the closing bracket will be pushed back to
835 // the operator stack
836 // - Check if a function is standing in front of the opening bracket,
837 // if so evaluate it afterwards to apply an infix operator.
838 if (stOpt.size() && stOpt.top()->GetCode() == cmBO)
839 {
840 //
841 // Here is the stuff to evaluate a function token
842 //
843 int iArgc = stArgCount.pop();
844
845 stOpt.pop(); // Take opening bracket from stack
846 if (stOpt.empty())
847 break;
848
849 if ((stOpt.top()->GetCode() != cmFUNC) && (stOpt.top()->GetCode() != cmOPRT_INFIX))
850 break;
851
852 ICallback* pFun = stOpt.top()->AsICallback();
853
854 if (pFun->GetArgc() != -1 && iArgc > pFun->GetArgc())
855 Error(ecTOO_MANY_PARAMS, pTok->GetExprPos(), pFun);
856
857 if (iArgc < pFun->GetArgc())
858 Error(ecTOO_FEW_PARAMS, pTok->GetExprPos(), pFun);
859
860 // Apply function, if present
861 if (stOpt.size() &&
862 stOpt.top()->GetCode() != cmOPRT_INFIX &&
863 stOpt.top()->GetCode() != cmOPRT_BIN)
864 {
865 ApplyFunc(stOpt, iArgc);
866 }
867 }
868 }
869 break;
870
871 case cmELSE:
872 ApplyRemainingOprt(stOpt);
873 m_rpn.Add(pTok);
874 stOpt.push(pTok);
875 break;
876
877 case cmSCRIPT_NEWLINE:
878 ApplyRemainingOprt(stOpt);
879 m_rpn.AddNewline(pTok, m_nPos);
880 stOpt.clear();
881 m_nPos = 0;
882 break;
883
884 case cmARG_SEP:
885 if (stArgCount.empty())
886 Error(ecUNEXPECTED_COMMA, m_pTokenReader->GetPos() - 1);
887
888 ++stArgCount.top();
889
890 ApplyRemainingOprt(stOpt);
891 break;
892
893 case cmEOE:
894 ApplyRemainingOprt(stOpt);
895 m_rpn.Finalize();
896 break;
897
898 case cmIF:
899 case cmOPRT_BIN:
900 case cmSHORTCUT_BEGIN:
901 {
902 while (stOpt.size() &&
903 stOpt.top()->GetCode() != cmBO &&
904 stOpt.top()->GetCode() != cmIO &&
905 stOpt.top()->GetCode() != cmCBO &&
906 stOpt.top()->GetCode() != cmELSE &&
907 stOpt.top()->GetCode() != cmIF)
908 {
909 IToken* pOprt1 = stOpt.top().Get();
910 IToken* pOprt2 = pTok.Get();
911 MUP_VERIFY(pOprt1 != nullptr && pOprt2 != nullptr);
912 MUP_VERIFY(pOprt1->AsIPrecedence() && pOprt2->AsIPrecedence());
913
914 int nPrec1 = pOprt1->AsIPrecedence()->GetPri(),
915 nPrec2 = pOprt2->AsIPrecedence()->GetPri();
916
917 if (pOprt1->GetCode() == pOprt2->GetCode())
918 {
919 // Deal with operator associativity
920 EOprtAsct eOprtAsct = pOprt1->AsIPrecedence()->GetAssociativity();
921 if ((eOprtAsct == oaRIGHT && (nPrec1 <= nPrec2)) ||
922 (eOprtAsct == oaLEFT && (nPrec1 < nPrec2)))
923 {
924 break;
925 }
926 }
927 else if (nPrec1 < nPrec2)
928 {
929 break;
930 }
931
932 if (pOprt1->GetCode() == cmSHORTCUT_END)
933 {
934 ApplyOprtShortcut(stOpt);
935 break;
936 }
937 // apply the operator now
938 // (binary operators are identic to functions with two arguments)
939 ApplyFunc(stOpt, 2);
940 } // while ( ... )
941
942 if (pTok->GetCode() == cmIF || pTok->GetCode() == cmSHORTCUT_BEGIN)
943 m_rpn.Add(pTok);
944
945 if (pTok->GetCode() == cmSHORTCUT_BEGIN)
946 {
947 if(pTok->AsIPrecedence()->GetPri() == prLOGIC_OR)
948 {
949 stOpt.push(ptr_tok_type(new OprtShortcutLogicOrEnd));
950 }
951 else
952 {
953 stOpt.push(ptr_tok_type(new OprtShortcutLogicAndEnd));
954 }
955 }
956 else
957 {
958 stOpt.push(pTok);
959 }
960 }
961 break;
962
963 //
964 // Postfix Operators
965 //
966 case cmOPRT_POSTFIX:
967 MUP_VERIFY(m_nPos);
968 m_rpn.Add(pTok);
969 break;
970
971 case cmCBO:
972 case cmIO:
973 case cmBO:
974 stOpt.push(pTok);
975 stArgCount.push(1);
976 break;
977
978 //
979 // Functions
980 //
981 case cmOPRT_INFIX:
982 case cmFUNC:
983 {
984 ICallback* pFunc = pTok->AsICallback();
985 MUP_VERIFY(pFunc != nullptr);
986 stOpt.push(pTok);
987 }
988 break;
989
990 default:
991 Error(ecINTERNAL_ERROR);
992 } // switch Code
993
994 if (ParserXBase::s_bDumpStack)
995 {
996 StackDump(stOpt);
997 }
998
999 if (pTok->GetCode() == cmEOE)
1000 break;
1001 } // for (all tokens)
1002
1003 if (ParserXBase::s_bDumpRPN)
1004 {
1005 m_rpn.AsciiDump();
1006 }
1007
1008 if (m_nPos > 1)
1009 {
1010 Error(ecUNEXPECTED_COMMA, -1);
1011 }
1012 }
1013
1014 //---------------------------------------------------------------------------
1015 /** \brief One of the two main parse functions.
1016 \sa ParseCmdCode(), ParseValue()
1017
1018 Parse expression from input string. Perform syntax checking and create bytecode.
1019 After parsing the string and creating the bytecode the function pointer
1020 #m_pParseFormula will be changed to the second parse routine the uses bytecode instead of string parsing.
1021 */
ParseFromString() const1022 const IValue& ParserXBase::ParseFromString() const
1023 {
1024 CreateRPN();
1025
1026 // Umsachalten auf RPN
1027 m_vStackBuffer.assign(m_rpn.GetRequiredStackSize(), ptr_val_type());
1028 for (std::size_t i = 0; i < m_vStackBuffer.size(); ++i)
1029 {
1030 Value* pValue = new Value;
1031 pValue->BindToCache(&m_cache);
1032 m_vStackBuffer[i].Reset(pValue);
1033 }
1034
1035 m_pParserEngine = &ParserXBase::ParseFromRPN;
1036
1037 return (this->*m_pParserEngine)();
1038 }
1039
1040 //---------------------------------------------------------------------------
ParseFromRPN() const1041 const IValue& ParserXBase::ParseFromRPN() const
1042 {
1043 ptr_val_type* pStack = &m_vStackBuffer[0];
1044 if (m_rpn.GetSize() == 0)
1045 {
1046 // Passiert bei leeren strings oder solchen, die nur Leerzeichen enthalten
1047 ErrorContext err;
1048 err.Expr = m_pTokenReader->GetExpr();
1049 err.Errc = ecUNEXPECTED_EOF;
1050 err.Pos = 0;
1051 throw ParserError(err);
1052 }
1053
1054 const ptr_tok_type* pRPN = &(m_rpn.GetData()[0]);
1055
1056 int sidx = -1;
1057 std::size_t lenRPN = m_rpn.GetSize();
1058 for (std::size_t i = 0; i < lenRPN; ++i)
1059 {
1060 IToken* pTok = pRPN[i].Get();
1061 ECmdCode eCode = pTok->GetCode();
1062
1063 switch (eCode)
1064 {
1065 case cmSCRIPT_NEWLINE:
1066 sidx = -1;
1067 continue;
1068
1069 case cmVAL:
1070 {
1071 IValue* pVal = static_cast<IValue*>(pTok);
1072
1073 sidx++;
1074 MUP_VERIFY(sidx < (int)m_vStackBuffer.size());
1075 if (pVal->IsVariable())
1076 {
1077 pStack[sidx].Reset(pVal);
1078 }
1079 else
1080 {
1081 ptr_val_type& val = pStack[sidx];
1082 if (val->IsVariable())
1083 val.Reset(m_cache.CreateFromCache());
1084
1085 *val = *(static_cast<IValue*>(pTok));
1086 }
1087 }
1088 continue;
1089
1090 case cmIC:
1091 {
1092 ICallback* pIdxOprt = static_cast<ICallback*>(pTok);
1093 int nArgs = pIdxOprt->GetArgsPresent();
1094 sidx -= nArgs - 1;
1095 MUP_VERIFY(sidx >= 0);
1096
1097 ptr_val_type& idx = pStack[sidx]; // Pointer to the first index
1098 ptr_val_type& val = pStack[--sidx]; // Pointer to the variable or value beeing indexed
1099 pIdxOprt->Eval(val, &idx, nArgs);
1100 }
1101 continue;
1102
1103 case cmCBC:
1104 case cmOPRT_POSTFIX:
1105 case cmFUNC:
1106 case cmOPRT_BIN:
1107 case cmOPRT_INFIX:
1108 {
1109 ICallback* pFun = static_cast<ICallback*>(pTok);
1110 int nArgs = pFun->GetArgsPresent();
1111 sidx -= nArgs - 1;
1112
1113 // most likely cause: Comma in if-then-else sum(false?1,0,0:3)
1114 if (sidx < 0)
1115 {
1116 ErrorContext err;
1117 err.Expr = m_pTokenReader->GetExpr();
1118 err.Errc = ecUNEXPECTED_COMMA;
1119 err.Pos = m_pTokenReader->GetPos();
1120 throw ParserError(err);
1121 }
1122
1123 ptr_val_type& val = pStack[sidx];
1124 try
1125 {
1126 if (val->IsVariable())
1127 {
1128 ptr_val_type buf(m_cache.CreateFromCache());
1129 pFun->Eval(buf, &val, nArgs);
1130 val = buf;
1131 }
1132 else
1133 {
1134 pFun->Eval(val, &val, nArgs);
1135 }
1136 }
1137 catch (ParserError& exc)
1138 {
1139 // <ibg 20130131> Not too happy about that:
1140 // Multiarg functions may throw specific error codes when evaluating.
1141 // These codes would be converted to ecEVAL here. I omit the conversion
1142 // for certain handpicked errors. (The reason this catch block exists is
1143 // that not all exceptions contain proper metadata when thrown out of
1144 // a function.)
1145 if (exc.GetCode() == ecTOO_FEW_PARAMS ||
1146 exc.GetCode() == ecDOMAIN_ERROR ||
1147 exc.GetCode() == ecOVERFLOW ||
1148 exc.GetCode() == ecINVALID_NUMBER_OF_PARAMETERS ||
1149 exc.GetCode() == ecASSIGNEMENT_TO_VALUE)
1150 {
1151 exc.GetContext().Pos = pFun->GetExprPos();
1152 throw;
1153 }
1154 // </ibg>
1155 else
1156 {
1157 ErrorContext err;
1158 err.Expr = m_pTokenReader->GetExpr();
1159 err.Ident = pFun->GetIdent();
1160 err.Errc = ecEVAL;
1161 err.Pos = pFun->GetExprPos();
1162 err.Hint = exc.GetMsg();
1163 throw ParserError(err);
1164 }
1165 }
1166 catch (MatrixError& /*exc*/)
1167 {
1168 ErrorContext err;
1169 err.Expr = m_pTokenReader->GetExpr();
1170 err.Ident = pFun->GetIdent();
1171 err.Errc = ecMATRIX_DIMENSION_MISMATCH;
1172 err.Pos = pFun->GetExprPos();
1173 throw ParserError(err);
1174 }
1175 }
1176 continue;
1177
1178 case cmIF:
1179 MUP_VERIFY(sidx >= 0);
1180 if (pStack[sidx--]->GetBool() == false)
1181 i += static_cast<TokenIfThenElse*>(pTok)->GetOffset();
1182 continue;
1183
1184 case cmELSE:
1185 case cmJMP:
1186 i += static_cast<TokenIfThenElse*>(pTok)->GetOffset();
1187 continue;
1188
1189 case cmENDIF:
1190 continue;
1191
1192 case cmSHORTCUT_BEGIN:
1193 if (pTok->AsIPrecedence()->GetPri() == prLOGIC_OR)
1194 {
1195 // occur short circuit feature
1196 if (pStack[sidx]->GetBool() == true)
1197 {
1198 i += static_cast<IOprtBinShortcut*>(pTok)->GetOffset();
1199 } else {
1200 // pop stack ,becuase this value had used
1201 --sidx;
1202 }
1203 }
1204 else // logic and
1205 {
1206 // occur short circuit feature
1207 if (pStack[sidx]->GetBool() == false)
1208 {
1209 i += static_cast<IOprtBinShortcut*>(pTok)->GetOffset();
1210 } else {
1211 // pop stack ,becuase this value had used
1212 --sidx;
1213 }
1214 }
1215 continue;
1216
1217 case cmSHORTCUT_END:
1218 continue;
1219
1220 default:
1221 Error(ecINTERNAL_ERROR);
1222 } // switch token
1223 } // for all RPN tokens
1224
1225 return *pStack[0];
1226 }
1227
1228 //---------------------------------------------------------------------------
Error(EErrorCodes a_iErrc,int a_iPos,const IToken * a_pTok) const1229 void ParserXBase::Error(EErrorCodes a_iErrc, int a_iPos, const IToken* a_pTok) const
1230 {
1231 ErrorContext err;
1232 err.Errc = a_iErrc;
1233 err.Pos = a_iPos;
1234 err.Expr = m_pTokenReader->GetExpr();
1235 err.Ident = (a_pTok) ? a_pTok->GetIdent() : _T("");
1236 throw ParserError(err);
1237 }
1238
1239 //------------------------------------------------------------------------------
1240 /** \brief Clear all user defined variables.
1241 \throw nothrow
1242
1243 Resets the parser to string parsing mode by calling #ReInit.
1244 */
ClearVar()1245 void ParserXBase::ClearVar()
1246 {
1247 m_varDef.clear();
1248 m_valDynVarShadow.clear();
1249 ReInit();
1250 }
1251
1252 //------------------------------------------------------------------------------
1253 /** \brief Clear the expression.
1254 \throw nothrow
1255
1256 Clear the expression and existing bytecode.
1257 */
ClearExpr()1258 void ParserXBase::ClearExpr()
1259 {
1260 m_pTokenReader->SetExpr(_T(""));
1261 ReInit();
1262 }
1263
1264 //------------------------------------------------------------------------------
1265 /** \brief Clear all function definitions.
1266 \throw nothrow
1267 */
ClearFun()1268 void ParserXBase::ClearFun()
1269 {
1270 m_FunDef.clear();
1271 ReInit();
1272 }
1273
1274 //------------------------------------------------------------------------------
1275 /** \brief Clear all user defined constants.
1276 \throw nothrow
1277
1278 Both numeric and string constants will be removed from the internal storage.
1279 */
ClearConst()1280 void ParserXBase::ClearConst()
1281 {
1282 m_valDef.clear();
1283 ReInit();
1284 }
1285
1286 //------------------------------------------------------------------------------
1287 /** \brief Clear all user defined postfix operators.
1288 \throw nothrow
1289 */
ClearPostfixOprt()1290 void ParserXBase::ClearPostfixOprt()
1291 {
1292 m_PostOprtDef.clear();
1293 ReInit();
1294 }
1295
1296 //------------------------------------------------------------------------------
1297 /** \brief Clear all user defined binary operators.
1298 \throw nothrow
1299 */
ClearOprt()1300 void ParserXBase::ClearOprt()
1301 {
1302 m_OprtDef.clear();
1303 m_OprtShortcutDef.clear();
1304 ReInit();
1305 }
1306
1307 //------------------------------------------------------------------------------
1308 /** \brief Clear the user defined Prefix operators.
1309 \throw nothrow
1310 */
ClearInfixOprt()1311 void ParserXBase::ClearInfixOprt()
1312 {
1313 m_InfixOprtDef.clear();
1314 ReInit();
1315 }
1316
1317 //------------------------------------------------------------------------------
EnableAutoCreateVar(bool bStat)1318 void ParserXBase::EnableAutoCreateVar(bool bStat)
1319 {
1320 m_bAutoCreateVar = bStat;
1321 }
1322
1323 //------------------------------------------------------------------------------
EnableOptimizer(bool bStat)1324 void ParserXBase::EnableOptimizer(bool bStat)
1325 {
1326 m_rpn.EnableOptimizer(bStat);
1327 }
1328
1329 //---------------------------------------------------------------------------
1330 /** \brief Enable the dumping of bytecode amd stack content on the console.
1331 \param bDumpCmd Flag to enable dumping of the current bytecode to the console.
1332 \param bDumpStack Flag to enable dumping of the stack content is written to the console.
1333
1334 This function is for debug purposes only!
1335 */
EnableDebugDump(bool bDumpRPN,bool bDumpStack)1336 void ParserXBase::EnableDebugDump(bool bDumpRPN, bool bDumpStack)
1337 {
1338 ParserXBase::s_bDumpRPN = bDumpRPN;
1339 ParserXBase::s_bDumpStack = bDumpStack;
1340 }
1341
1342 //------------------------------------------------------------------------------
IsAutoCreateVarEnabled() const1343 bool ParserXBase::IsAutoCreateVarEnabled() const
1344 {
1345 return m_bAutoCreateVar;
1346 }
1347
1348 //------------------------------------------------------------------------------
1349 /** \brief Dump stack content.
1350
1351 This function is used for debugging only.
1352 */
StackDump(const Stack<ptr_tok_type> & a_stOprt) const1353 void ParserXBase::StackDump(const Stack<ptr_tok_type>& a_stOprt) const
1354 {
1355 using std::cout;
1356 Stack<ptr_tok_type> stOprt(a_stOprt);
1357
1358 string_type sInfo = _T("StackDump> ");
1359 console() << sInfo;
1360
1361 if (stOprt.empty())
1362 console() << _T("\n") << sInfo << _T("Operator stack is empty.\n");
1363 else
1364 console() << _T("\n") << sInfo << _T("Operator stack:\n");
1365
1366 while (!stOprt.empty())
1367 {
1368 ptr_tok_type tok = stOprt.pop();
1369 console() << sInfo << _T(" ") << g_sCmdCode[tok->GetCode()] << _T(" \"") << tok->GetIdent() << _T("\" \n");
1370 }
1371
1372 console() << endl;
1373 }
1374 } // namespace mu
1375