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