1 /*
2                  __________
3     _____   __ __\______   \_____  _______  ______  ____ _______
4    /     \ |  |  \|     ___/\__  \ \_  __ \/  ___/_/ __ \\_  __ \
5   |  Y Y  \|  |  /|    |     / __ \_|  | \/\___ \ \  ___/ |  | \/
6   |__|_|  /|____/ |____|    (____  /|__|  /____  > \___  >|__|
7         \/                       \/            \/      \/
8   Copyright (C) 2004-2008 Ingo Berg
9 
10   Permission is hereby granted, free of charge, to any person obtaining a copy of this
11   software and associated documentation files (the "Software"), to deal in the Software
12   without restriction, including without limitation the rights to use, copy, modify,
13   merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
14   permit persons to whom the Software is furnished to do so, subject to the following conditions:
15 
16   The above copyright notice and this permission notice shall be included in all copies or
17   substantial portions of the Software.
18 
19   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
20   NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22   DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 
26 #ifndef MU_PARSER_TOKEN_H
27 #define MU_PARSER_TOKEN_H
28 
29 #include <cassert>
30 #include <string>
31 #include <stack>
32 #include <vector>
33 #include <memory>
34 
35 #include "muParserError.h"
36 #include "muParserCallback.h"
37 
38 /** \file
39     \brief This file contains the parser token definition.
40 */
41 
42 namespace mu
43 {
44   /** \brief Encapsulation of the data for a single formula token.
45 
46     Formula token implementation. Part of the Math Parser Package.
47     Formula tokens can be either one of the following:
48     <ul>
49       <li>value</li>
50       <li>variable</li>
51       <li>function with numerical arguments</li>
52       <li>functions with a string as argument</li>
53       <li>prefix operators</li>
54       <li>infix operators</li>
55 	    <li>binary operator</li>
56     </ul>
57 
58    \author (C) 2004 Ingo Berg
59   */
60   template<typename TBase, typename TString>
61   class ParserToken
62   {
63   public:
64 
65       /** \brief Additional token flags. */
66       enum ETokFlags
67 	    {
68 	      flVOLATILE = 1    ///< Mark a token that depends on a variable or a function that is not conservative
69 	    };
70 
71   private:
72 
73       ECmdCode  m_iCode;  ///< Type of the token; The token type is a constant of type #ECmdCode.
74       ETypeCode m_iType;
75       void  *m_pTok;      ///< Stores Token pointer; not applicable for all tokens
76   	  int  m_iFlags;      ///< Additional flags for the token.
77       int  m_iIdx;        ///< An otional index to an external buffer storing the token data
78       TString m_strTok;   ///< Token string
79       TString m_strVal;   ///< Value for string variables
80       value_type m_fVal;
81       std::auto_ptr<ParserCallback> m_pCallback;
82 
83   public:
84 
85       //---------------------------------------------------------------------------
86       /** \brief Constructor (default).
87 
88           Sets token to an neutral state of type cmUNKNOWN.
89           \throw nothrow
90           \sa ECmdCode
91       */
ParserToken()92       ParserToken()
93         :m_iCode(cmUNKNOWN)
94         ,m_iType(tpVOID)
95         ,m_pTok(0)
96         ,m_iFlags(0)
97         ,m_iIdx(-1)
98         ,m_strTok()
99         ,m_pCallback()
100       {}
101 
102       //------------------------------------------------------------------------------
103       /** \brief Create token from another one.
104 
105           Implemented by calling Assign(...)
106           \throw nothrow
107           \post m_iType==cmUNKNOWN
108           \sa #Assign
109       */
ParserToken(const ParserToken & a_Tok)110       ParserToken(const ParserToken &a_Tok)
111       {
112         Assign(a_Tok);
113       }
114 
115       //------------------------------------------------------------------------------
116       /** \brief Assignement operator.
117 
118           Copy token state from another token and return this.
119           Implemented by calling Assign(...).
120           \throw nothrow
121       */
122       ParserToken& operator=(const ParserToken &a_Tok)
123       {
124         Assign(a_Tok);
125         return *this;
126       }
127 
128       //------------------------------------------------------------------------------
129       /** \brief Copy token information from argument.
130 
131           \throw nothrow
132       */
Assign(const ParserToken & a_Tok)133       void Assign(const ParserToken &a_Tok)
134       {
135         m_iCode = a_Tok.m_iCode;
136         m_pTok = a_Tok.m_pTok;
137         m_iFlags = a_Tok.m_iFlags;
138         m_strTok = a_Tok.m_strTok;
139         m_iIdx = a_Tok.m_iIdx;
140         m_strVal = a_Tok.m_strVal;
141         m_iType = a_Tok.m_iType;
142         m_fVal = a_Tok.m_fVal;
143         // create new callback object if a_Tok has one
144         m_pCallback.reset(a_Tok.m_pCallback.get() ? a_Tok.m_pCallback->Clone() : 0);
145       }
146 
147       //------------------------------------------------------------------------------
148       /** \brief Add additional flags to the token.
149 
150           Flags are currently used to mark volatile (non optimizeable) functions.
151           \sa m_iFlags, ETokFlags
152       */
AddFlags(int a_iFlags)153       void AddFlags(int a_iFlags)
154       {
155         m_iFlags |= a_iFlags;
156       }
157 
158       //------------------------------------------------------------------------------
159       /** \brief Check if a certain flag ist set.
160 
161           \throw nothrow
162       */
IsFlagSet(int a_iFlags)163       bool IsFlagSet(int a_iFlags) const
164       {
165         #if defined(_MSC_VER)
166           #pragma warning( disable : 4800 )
167         #endif
168 
169         return (bool)(m_iFlags & a_iFlags);
170 
171         #if defined(_MSC_VER)
172           #pragma warning( default : 4800 ) // int: Variable set to boolean value (may degrade performance)
173         #endif
174       }
175 
176       //------------------------------------------------------------------------------
177       /** \brief Assign a token type.
178 
179         Token may not be of type value, variable or function. Those have seperate set functions.
180 
181         \pre [assert] a_iType!=cmVAR
182         \pre [assert] a_iType!=cmVAL
183         \pre [assert] a_iType!=cmFUNC
184         \post m_fVal = 0
185         \post m_pTok = 0
186       */
187       ParserToken& Set(ECmdCode a_iType, const TString &a_strTok=TString())
188       {
189         // The following types cant be set this way, they have special Set functions
190         assert(a_iType!=cmVAR);
191         assert(a_iType!=cmVAL);
192         assert(a_iType!=cmFUNC);
193 
194         m_iCode = a_iType;
195         m_iType = tpVOID;
196         m_pTok = 0;
197         m_iFlags = 0;
198         m_strTok = a_strTok;
199         m_iIdx = -1;
200 
201         return *this;
202       }
203 
204       //------------------------------------------------------------------------------
205       /** \brief Set Callback type. */
Set(const ParserCallback & a_pCallback,const TString & a_sTok)206       ParserToken& Set(const ParserCallback &a_pCallback, const TString &a_sTok)
207       {
208         assert(a_pCallback.GetAddr());
209 
210         m_iCode = a_pCallback.GetCode();
211         m_iType = tpVOID;
212         m_strTok = a_sTok;
213         m_pCallback.reset(new ParserCallback(a_pCallback));
214 
215         m_pTok = 0;
216         m_iFlags = 0;
217         m_iIdx = -1;
218 
219         if (!m_pCallback->IsOptimizable())
220           AddFlags(flVOLATILE);
221 
222         return *this;
223       }
224 
225       //------------------------------------------------------------------------------
226       /** \brief Make this token a value token.
227 
228           Member variables not necessary for value tokens will be invalidated.
229           \throw nothrow
230       */
231       ParserToken& SetVal(TBase a_fVal, const TString &a_strTok=TString())
232       {
233         m_iCode = cmVAL;
234         m_iType = tpDBL;
235         m_fVal = a_fVal;
236         m_iFlags = 0;
237         m_strTok = a_strTok;
238         m_iIdx = -1;
239 
240         m_pTok = 0;
241         m_pCallback.reset(0);
242 
243         return *this;
244       }
245 
246       //------------------------------------------------------------------------------
247       /** \brief make this token a variable token.
248 
249           Member variables not necessary for variable tokens will be invalidated.
250           \throw nothrow
251       */
SetVar(TBase * a_pVar,const TString & a_strTok)252       ParserToken& SetVar(TBase *a_pVar, const TString &a_strTok)
253       {
254         m_iCode = cmVAR;
255         m_iType = tpDBL;
256         m_iFlags = 0;
257         m_strTok = a_strTok;
258         m_iIdx = -1;
259         m_pTok = (void*)a_pVar;
260         m_pCallback.reset(0);
261 
262         AddFlags(ParserToken::flVOLATILE);
263         return *this;
264       }
265 
266       //------------------------------------------------------------------------------
267       /** \brief Make this token a variable token.
268 
269           Member variables not necessary for variable tokens will be invalidated.
270           \throw nothrow
271       */
SetString(const TString & a_strTok,std::size_t a_iSize)272       ParserToken& SetString(const TString &a_strTok, std::size_t a_iSize)
273       {
274         m_iCode = cmSTRING;
275         m_iType = tpSTR;
276         m_iFlags = 0;
277         m_strTok = a_strTok;
278         m_iIdx = static_cast<int>(a_iSize);
279 
280         m_pTok = 0;
281         m_pCallback.reset(0);
282 
283         AddFlags(ParserToken::flVOLATILE);
284         return *this;
285       }
286 
287       //------------------------------------------------------------------------------
288       /** \brief Set an index associated with the token related data.
289 
290           In cmSTRFUNC - This is the index to a string table in the main parser.
291           \param a_iIdx The index the string function result will take in the bytecode parser.
292           \throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING
293       */
SetIdx(int a_iIdx)294       void SetIdx(int a_iIdx)
295       {
296         if (m_iCode!=cmSTRING || a_iIdx<0)
297 	        throw ParserError(ecINTERNAL_ERROR);
298 
299         m_iIdx = a_iIdx;
300       }
301 
302       //------------------------------------------------------------------------------
303       /** \brief Return Index associated with the token related data.
304 
305           In cmSTRFUNC - This is the index to a string table in the main parser.
306 
307           \throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING
308           \return The index the result will take in the Bytecode calculatin array (#m_iIdx).
309       */
GetIdx()310       int GetIdx() const
311       {
312         if (m_iIdx<0 || m_iCode!=cmSTRING )
313           throw ParserError(ecINTERNAL_ERROR);
314 
315         return m_iIdx;
316       }
317 
318       //------------------------------------------------------------------------------
319       /** \brief Return the token type.
320 
321           \return #m_iType
322           \throw nothrow
323       */
GetCode()324       ECmdCode GetCode() const
325       {
326         if (m_pCallback.get())
327         {
328           return m_pCallback->GetCode();
329         }
330         else
331         {
332           return m_iCode;
333         }
334       }
335 
336       //------------------------------------------------------------------------------
GetType()337       ETypeCode GetType() const
338       {
339         if (m_pCallback.get())
340         {
341           return m_pCallback->GetType();
342         }
343         else
344         {
345           return m_iType;
346         }
347       }
348 
349       //------------------------------------------------------------------------------
GetPri()350       int GetPri() const
351       {
352         if ( !m_pCallback.get())
353 	        throw ParserError(ecINTERNAL_ERROR);
354 
355         if ( m_pCallback->GetCode()!=cmOPRT_BIN && m_pCallback->GetCode()!=cmOPRT_INFIX)
356 	        throw ParserError(ecINTERNAL_ERROR);
357 
358         return m_pCallback->GetPri();
359       }
360 
361       //------------------------------------------------------------------------------
362       /** \brief Return the address of the callback function assoziated with
363                  function and operator tokens.
364 
365           \return The pointer stored in #m_pTok.
366           \throw exception_type if token type is non of:
367                  <ul>
368                    <li>cmFUNC</li>
369                    <li>cmSTRFUNC</li>
370                    <li>cmPOSTOP</li>
371                    <li>cmINFIXOP</li>
372                    <li>cmOPRT_BIN</li>
373                  </ul>
374           \sa ECmdCode
375       */
GetFuncAddr()376       void* GetFuncAddr() const
377       {
378         return (m_pCallback.get()) ? m_pCallback->GetAddr() : 0;
379       }
380 
381       //------------------------------------------------------------------------------
382       /** \brief Get value of the token.
383 
384           Only applicable to variable and value tokens.
385           \throw exception_type if token is no value/variable token.
386       */
GetVal()387       TBase GetVal() const
388       {
389         switch (m_iCode)
390         {
391           case cmVAL:  return m_fVal;
392           case cmVAR:  return *((TBase*)m_pTok);
393           default:     throw ParserError(ecVAL_EXPECTED);
394         }
395       }
396 
397       //------------------------------------------------------------------------------
398       /** \brief Get address of a variable token.
399 
400         Valid only if m_iType==CmdVar.
401         \throw exception_type if token is no variable token.
402       */
GetVar()403       TBase* GetVar() const
404       {
405         if (m_iCode!=cmVAR)
406 	        throw ParserError(ecINTERNAL_ERROR);
407 
408         return (TBase*)m_pTok;
409       }
410 
411       //------------------------------------------------------------------------------
412       /** \brief Return the number of function arguments.
413 
414         Valid only if m_iType==CmdFUNC.
415       */
GetArgCount()416       int GetArgCount() const
417       {
418         assert(m_pCallback.get());
419 
420         if (!m_pCallback->GetAddr())
421 	        throw ParserError(ecINTERNAL_ERROR);
422 
423         return m_pCallback->GetArgc();
424       }
425 
426       //------------------------------------------------------------------------------
427       /** \brief Return the token identifier.
428 
429           If #m_iType is cmSTRING the token identifier is the value of the string argument
430           for a string function.
431           \return #m_strTok
432           \throw nothrow
433           \sa m_strTok
434       */
GetAsString()435       const TString& GetAsString() const
436       {
437         return m_strTok;
438       }
439   };
440 } // namespace mu
441 
442 #endif
443