OpcUaCanOpen
CANopen OPC-UA server
muParserTokenReader.cpp
Go to the documentation of this file.
1 /*
2  __________
3  _____ __ __\______ \_____ _______ ______ ____ _______
4  / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \
5  | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/
6  |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__|
7  \/ \/ \/ \/
8  Copyright (C) 2013 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 #include <cassert>
26 #include <cstdio>
27 #include <cstring>
28 #include <map>
29 #include <stack>
30 #include <string>
31 
32 #include "muParserTokenReader.h"
33 #include "muParserBase.h"
34 
40 namespace mu
41 {
42 
43  // Forward declaration
44  class ParserBase;
45 
46  //---------------------------------------------------------------------------
53  {
54  Assign(a_Reader);
55  }
56 
57  //---------------------------------------------------------------------------
66  {
67  if (&a_Reader!=this)
68  Assign(a_Reader);
69 
70  return *this;
71  }
72 
73  //---------------------------------------------------------------------------
80  {
81  m_pParser = a_Reader.m_pParser;
82  m_strFormula = a_Reader.m_strFormula;
83  m_iPos = a_Reader.m_iPos;
84  m_iSynFlags = a_Reader.m_iSynFlags;
85 
86  m_UsedVar = a_Reader.m_UsedVar;
87  m_pFunDef = a_Reader.m_pFunDef;
88  m_pConstDef = a_Reader.m_pConstDef;
89  m_pVarDef = a_Reader.m_pVarDef;
90  m_pStrVarDef = a_Reader.m_pStrVarDef;
91  m_pPostOprtDef = a_Reader.m_pPostOprtDef;
93  m_pOprtDef = a_Reader.m_pOprtDef;
95  m_vIdentFun = a_Reader.m_vIdentFun;
96  m_pFactory = a_Reader.m_pFactory;
97  m_pFactoryData = a_Reader.m_pFactoryData;
98  m_iBrackets = a_Reader.m_iBrackets;
99  m_cArgSep = a_Reader.m_cArgSep;
100  m_fZero = a_Reader.m_fZero;
101  m_lastTok = a_Reader.m_lastTok;
102  }
103 
104  //---------------------------------------------------------------------------
114  :m_pParser(a_pParent)
115  ,m_strFormula()
116  ,m_iPos(0)
117  ,m_iSynFlags(0)
118  ,m_bIgnoreUndefVar(false)
119  ,m_pFunDef(NULL)
120  ,m_pPostOprtDef(NULL)
121  ,m_pInfixOprtDef(NULL)
122  ,m_pOprtDef(NULL)
123  ,m_pConstDef(NULL)
124  ,m_pStrVarDef(NULL)
125  ,m_pVarDef(NULL)
126  ,m_pFactory(NULL)
127  ,m_pFactoryData(NULL)
128  ,m_vIdentFun()
129  ,m_UsedVar()
130  ,m_fZero(0)
131  ,m_iBrackets(0)
132  ,m_lastTok()
133  ,m_cArgSep(',')
134  {
135  assert(m_pParser);
137  }
138 
139  //---------------------------------------------------------------------------
149  {
150  std::unique_ptr<ParserTokenReader> ptr(new ParserTokenReader(*this));
151  ptr->SetParent(a_pParent);
152  return ptr.release();
153  }
154 
155  //---------------------------------------------------------------------------
157  {
158  m_lastTok = tok;
159  return m_lastTok;
160  }
161 
162  //---------------------------------------------------------------------------
164  {
165  // Use push_front is used to give user defined callbacks a higher priority than
166  // the built in ones. Otherwise reading hex numbers would not work
167  // since the "0" in "0xff" would always be read first making parsing of
168  // the rest impossible.
169  // reference:
170  // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/4824956
171  m_vIdentFun.push_front(a_pCallback);
172  }
173 
174  //---------------------------------------------------------------------------
176  {
179  }
180 
181  //---------------------------------------------------------------------------
188  {
189  return m_iPos;
190  }
191 
192  //---------------------------------------------------------------------------
199  {
200  return m_strFormula;
201  }
202 
203  //---------------------------------------------------------------------------
206  {
207  return m_UsedVar;
208  }
209 
210  //---------------------------------------------------------------------------
216  void ParserTokenReader::SetFormula(const string_type &a_strFormula)
217  {
218  m_strFormula = a_strFormula;
219  ReInit();
220  }
221 
222  //---------------------------------------------------------------------------
232  {
233  m_bIgnoreUndefVar = bIgnore;
234  }
235 
236  //---------------------------------------------------------------------------
246  {
247  m_iPos = 0;
249  m_iBrackets = 0;
250  m_UsedVar.clear();
251  m_lastTok = token_type();
252  }
253 
254  //---------------------------------------------------------------------------
257  {
258  assert(m_pParser);
259 
260  const char_type *szFormula = m_strFormula.c_str();
261  token_type tok;
262 
263  // Ignore all non printable characters when reading the expression
264  while (szFormula[m_iPos]>0 && szFormula[m_iPos]<=0x20)
265  ++m_iPos;
266 
267  if ( IsEOF(tok) ) return SaveBeforeReturn(tok); // Check for end of formula
268  if ( IsOprt(tok) ) return SaveBeforeReturn(tok); // Check for user defined binary operator
269  if ( IsFunTok(tok) ) return SaveBeforeReturn(tok); // Check for function token
270  if ( IsBuiltIn(tok) ) return SaveBeforeReturn(tok); // Check built in operators / tokens
271  if ( IsArgSep(tok) ) return SaveBeforeReturn(tok); // Check for function argument separators
272  if ( IsValTok(tok) ) return SaveBeforeReturn(tok); // Check for values / constant tokens
273  if ( IsVarTok(tok) ) return SaveBeforeReturn(tok); // Check for variable tokens
274  if ( IsStrVarTok(tok) ) return SaveBeforeReturn(tok); // Check for string variables
275  if ( IsString(tok) ) return SaveBeforeReturn(tok); // Check for String tokens
276  if ( IsInfixOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators
277  if ( IsPostOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators
278 
279  // Check String for undefined variable token. Done only if a
280  // flag is set indicating to ignore undefined variables.
281  // This is a way to conditionally avoid an error if
282  // undefined variables occur.
283  // (The GetUsedVar function must suppress the error for
284  // undefined variables in order to collect all variable
285  // names including the undefined ones.)
286  if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) )
287  return SaveBeforeReturn(tok);
288 
289  // Check for unknown token
290  //
291  // !!! From this point on there is no exit without an exception possible...
292  //
293  string_type strTok;
294  int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
295  if (iEnd!=m_iPos)
297 
299  return token_type(); // never reached
300  }
301 
302  //---------------------------------------------------------------------------
304  {
305  m_pParser = a_pParent;
306  m_pFunDef = &a_pParent->m_FunDef;
307  m_pOprtDef = &a_pParent->m_OprtDef;
308  m_pInfixOprtDef = &a_pParent->m_InfixOprtDef;
309  m_pPostOprtDef = &a_pParent->m_PostOprtDef;
310  m_pVarDef = &a_pParent->m_VarDef;
311  m_pStrVarDef = &a_pParent->m_StrVarDef;
312  m_pConstDef = &a_pParent->m_ConstDef;
313  }
314 
315  //---------------------------------------------------------------------------
325  string_type &a_sTok,
326  int a_iPos) const
327  {
328  int iEnd = (int)m_strFormula.find_first_not_of(a_szCharSet, a_iPos);
329 
330  if (iEnd==(int)string_type::npos)
331  iEnd = (int)m_strFormula.length();
332 
333  // Assign token string if there was something found
334  if (a_iPos!=iEnd)
335  a_sTok = string_type( m_strFormula.begin()+a_iPos, m_strFormula.begin()+iEnd);
336 
337  return iEnd;
338  }
339 
340  //---------------------------------------------------------------------------
349  int a_iPos) const
350  {
351  // Changed as per Issue 6: https://code.google.com/p/muparser/issues/detail?id=6
352  int iEnd = (int)m_strFormula.find_first_not_of(m_pParser->ValidOprtChars(), a_iPos);
353  if (iEnd==(int)string_type::npos)
354  iEnd = (int)m_strFormula.length();
355 
356  // Assign token string if there was something found
357  if (a_iPos!=iEnd)
358  {
359  a_sTok = string_type( m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd);
360  return iEnd;
361  }
362  else
363  {
364  // There is still the chance of having to deal with an operator consisting exclusively
365  // of alphabetic characters.
366  return ExtractToken(MUP_CHARS, a_sTok, a_iPos);
367  }
368  }
369 
370  //---------------------------------------------------------------------------
376  {
377  const char_type **const pOprtDef = m_pParser->GetOprtDef(),
378  *const szFormula = m_strFormula.c_str();
379 
380  // Compare token with function and operator strings
381  // check string for operator/function
382  for (int i=0; pOprtDef[i]; i++)
383  {
384  std::size_t len( std::char_traits<char_type>::length(pOprtDef[i]) );
385  if ( string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len) )
386  {
387  switch(i)
388  {
389  //case cmAND:
390  //case cmOR:
391  //case cmXOR:
392  case cmLAND:
393  case cmLOR:
394  case cmLT:
395  case cmGT:
396  case cmLE:
397  case cmGE:
398  case cmNEQ:
399  case cmEQ:
400  case cmADD:
401  case cmSUB:
402  case cmMUL:
403  case cmDIV:
404  case cmPOW:
405  case cmASSIGN:
406  //if (len!=sTok.length())
407  // continue;
408 
409  // The assignment operator need special treatment
410  if (i==cmASSIGN && m_iSynFlags & noASSIGN)
411  Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);
412 
413  if (!m_pParser->HasBuiltInOprt()) continue;
414  if (m_iSynFlags & noOPT)
415  {
416  // Maybe its an infix operator not an operator
417  // Both operator types can share characters in
418  // their identifiers
419  if ( IsInfixOpTok(a_Tok) )
420  return true;
421 
422  Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]);
423  }
424 
426  break;
427 
428  case cmBO:
429  if (m_iSynFlags & noBO)
430  Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
431 
432  if (m_lastTok.GetCode()==cmFUNC)
434  else
436 
437  ++m_iBrackets;
438  break;
439 
440  case cmBC:
441  if (m_iSynFlags & noBC)
442  Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
443 
445 
446  if (--m_iBrackets<0)
447  Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]);
448  break;
449 
450  case cmELSE:
451  if (m_iSynFlags & noELSE)
452  Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]);
453 
455  break;
456 
457  case cmIF:
458  if (m_iSynFlags & noIF)
459  Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]);
460 
462  break;
463 
464  default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing...
466  } // switch operator id
467 
468  m_iPos += (int)len;
469  a_Tok.Set( (ECmdCode)i, pOprtDef[i] );
470  return true;
471  } // if operator string found
472  } // end of for all operator strings
473 
474  return false;
475  }
476 
477  //---------------------------------------------------------------------------
479  {
480  const char_type* szFormula = m_strFormula.c_str();
481 
482  if (szFormula[m_iPos]==m_cArgSep)
483  {
484  // copy the separator into null terminated string
485  char_type szSep[2];
486  szSep[0] = m_cArgSep;
487  szSep[1] = 0;
488 
489  if (m_iSynFlags & noARG_SEP)
491 
493  m_iPos++;
494  a_Tok.Set(cmARG_SEP, szSep);
495  return true;
496  }
497 
498  return false;
499  }
500 
501  //---------------------------------------------------------------------------
510  {
511  const char_type* szFormula = m_strFormula.c_str();
512 
513  // check for EOF
514  if ( !szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/)
515  {
516  if ( m_iSynFlags & noEND )
518 
519  if (m_iBrackets>0)
521 
522  m_iSynFlags = 0;
523  a_Tok.Set(cmEND);
524  return true;
525  }
526 
527  return false;
528  }
529 
530  //---------------------------------------------------------------------------
535  {
536  string_type sTok;
537  int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_iPos);
538  if (iEnd==m_iPos)
539  return false;
540 
541  // iterate over all postfix operator strings
542  funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin();
543  for ( ; it!=m_pInfixOprtDef->rend(); ++it)
544  {
545  if (sTok.find(it->first)!=0)
546  continue;
547 
548  a_Tok.Set(it->second, it->first);
549  m_iPos += (int)it->first.length();
550 
551  if (m_iSynFlags & noINFIXOP)
553 
555  return true;
556  }
557 
558  return false;
559 
560 /*
561  a_Tok.Set(item->second, sTok);
562  m_iPos = (int)iEnd;
563 
564  if (m_iSynFlags & noINFIXOP)
565  Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
566 
567  m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN;
568  return true;
569 */
570  }
571 
572  //---------------------------------------------------------------------------
580  {
581  string_type strTok;
582  int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
583  if (iEnd==m_iPos)
584  return false;
585 
586  funmap_type::const_iterator item = m_pFunDef->find(strTok);
587  if (item==m_pFunDef->end())
588  return false;
589 
590  // Check if the next sign is an opening bracket
591  const char_type *szFormula = m_strFormula.c_str();
592  if (szFormula[iEnd]!='(')
593  return false;
594 
595  a_Tok.Set(item->second, strTok);
596 
597  m_iPos = (int)iEnd;
598  if (m_iSynFlags & noFUN)
599  Error(ecUNEXPECTED_FUN, m_iPos-(int)a_Tok.GetAsString().length(), a_Tok.GetAsString());
600 
601  m_iSynFlags = noANY ^ noBO;
602  return true;
603  }
604 
605  //---------------------------------------------------------------------------
611  {
612  const char_type *const szExpr = m_strFormula.c_str();
613  string_type strTok;
614 
615  int iEnd = ExtractOperatorToken(strTok, m_iPos);
616  if (iEnd==m_iPos)
617  return false;
618 
619  // Check if the operator is a built in operator, if so ignore it here
620  const char_type **const pOprtDef = m_pParser->GetOprtDef();
621  for (int i=0; m_pParser->HasBuiltInOprt() && pOprtDef[i]; ++i)
622  {
623  if (string_type(pOprtDef[i])==strTok)
624  return false;
625  }
626 
627  // Note:
628  // All tokens in oprt_bin_maptype are have been sorted by their length
629  // Long operators must come first! Otherwise short names (like: "add") that
630  // are part of long token names (like: "add123") will be found instead
631  // of the long ones.
632  // Length sorting is done with ascending length so we use a reverse iterator here.
633  funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin();
634  for ( ; it!=m_pOprtDef->rend(); ++it)
635  {
636  const string_type &sID = it->first;
637  if ( sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length()) )
638  {
639  a_Tok.Set(it->second, strTok);
640 
641  // operator was found
642  if (m_iSynFlags & noOPT)
643  {
644  // An operator was found but is not expected to occur at
645  // this position of the formula, maybe it is an infix
646  // operator, not a binary operator. Both operator types
647  // can share characters in their identifiers.
648  if ( IsInfixOpTok(a_Tok) )
649  return true;
650  else
651  {
652  // nope, no infix operator
653  return false;
654  //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString());
655  }
656 
657  }
658 
659  m_iPos += (int)sID.length();
661  return true;
662  }
663  }
664 
665  return false;
666  }
667 
668  //---------------------------------------------------------------------------
671  {
672  // <ibg 20110629> Do not check for postfix operators if they are not allowed at
673  // the current expression index.
674  //
675  // This will fix the bug reported here:
676  //
677  // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979
678  //
679  if (m_iSynFlags & noPOSTOP)
680  return false;
681  // </ibg>
682 
683  // Tricky problem with equations like "3m+5":
684  // m is a postfix operator, + is a valid sign for postfix operators and
685  // for binary operators parser detects "m+" as operator string and
686  // finds no matching postfix operator.
687  //
688  // This is a special case so this routine slightly differs from the other
689  // token readers.
690 
691  // Test if there could be a postfix operator
692  string_type sTok;
693  int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_iPos);
694  if (iEnd==m_iPos)
695  return false;
696 
697  // iterate over all postfix operator strings
698  funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin();
699  for ( ; it!=m_pPostOprtDef->rend(); ++it)
700  {
701  if (sTok.find(it->first)!=0)
702  continue;
703 
704  a_Tok.Set(it->second, sTok);
705  m_iPos += (int)it->first.length();
706 
708  return true;
709  }
710 
711  return false;
712  }
713 
714  //---------------------------------------------------------------------------
723  {
724  assert(m_pConstDef);
725  assert(m_pParser);
726 
727  string_type strTok;
728  value_type fVal(0);
729  int iEnd(0);
730 
731  // 2.) Check for user defined constant
732  // Read everything that could be a constant name
733  iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
734  if (iEnd!=m_iPos)
735  {
736  valmap_type::const_iterator item = m_pConstDef->find(strTok);
737  if (item!=m_pConstDef->end())
738  {
739  m_iPos = iEnd;
740  a_Tok.SetVal(item->second, strTok);
741 
742  if (m_iSynFlags & noVAL)
743  Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);
744 
746  return true;
747  }
748  }
749 
750  // 3.call the value recognition functions provided by the user
751  // Call user defined value recognition functions
752  std::list<identfun_type>::const_iterator item = m_vIdentFun.begin();
753  for (item = m_vIdentFun.begin(); item!=m_vIdentFun.end(); ++item)
754  {
755  int iStart = m_iPos;
756  if ( (*item)(m_strFormula.c_str() + m_iPos, &m_iPos, &fVal)==1 )
757  {
758  // 2013-11-27 Issue 2: https://code.google.com/p/muparser/issues/detail?id=2
759  strTok.assign(m_strFormula.c_str(), iStart, m_iPos-iStart);
760 
761  if (m_iSynFlags & noVAL)
762  Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok);
763 
764  a_Tok.SetVal(fVal, strTok);
766  return true;
767  }
768  }
769 
770  return false;
771  }
772 
773  //---------------------------------------------------------------------------
779  {
780  if (m_pVarDef->empty())
781  return false;
782 
783  string_type strTok;
784  int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
785  if (iEnd==m_iPos)
786  return false;
787 
788  varmap_type::const_iterator item = m_pVarDef->find(strTok);
789  if (item==m_pVarDef->end())
790  return false;
791 
792  if (m_iSynFlags & noVAR)
793  Error(ecUNEXPECTED_VAR, m_iPos, strTok);
794 
796 
797  m_iPos = iEnd;
798  a_Tok.SetVar(item->second, strTok);
799  m_UsedVar[item->first] = item->second; // Add variable to used-var-list
800 
802 
803 // Zur Info hier die SynFlags von IsVal():
804 // m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN;
805  return true;
806  }
807 
808  //---------------------------------------------------------------------------
810  {
811  if (!m_pStrVarDef || m_pStrVarDef->empty())
812  return false;
813 
814  string_type strTok;
815  int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos);
816  if (iEnd==m_iPos)
817  return false;
818 
819  strmap_type::const_iterator item = m_pStrVarDef->find(strTok);
820  if (item==m_pStrVarDef->end())
821  return false;
822 
823  if (m_iSynFlags & noSTR)
824  Error(ecUNEXPECTED_VAR, m_iPos, strTok);
825 
826  m_iPos = iEnd;
827  if (!m_pParser->m_vStringVarBuf.size())
829 
830  a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size() );
831 
832  m_iSynFlags = noANY ^ ( noBC | noOPT | noEND | noARG_SEP);
833  return true;
834  }
835 
836 
837  //---------------------------------------------------------------------------
845  {
846  string_type strTok;
847  int iEnd( ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos) );
848  if ( iEnd==m_iPos )
849  return false;
850 
851  if (m_iSynFlags & noVAR)
852  {
853  // <ibg/> 20061021 added token string strTok instead of a_Tok.GetAsString() as the
854  // token identifier.
855  // related bug report:
856  // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979
857  Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok);
858  }
859 
860  // If a factory is available implicitely create new variables
861  if (m_pFactory)
862  {
863  value_type *fVar = m_pFactory(strTok.c_str(), m_pFactoryData);
864  a_Tok.SetVar(fVar, strTok );
865 
866  // Do not use m_pParser->DefineVar( strTok, fVar );
867  // in order to define the new variable, it will clear the
868  // m_UsedVar array which will kill previously defined variables
869  // from the list
870  // This is safe because the new variable can never override an existing one
871  // because they are checked first!
872  (*m_pVarDef)[strTok] = fVar;
873  m_UsedVar[strTok] = fVar; // Add variable to used-var-list
874  }
875  else
876  {
877  a_Tok.SetVar((value_type*)&m_fZero, strTok);
878  m_UsedVar[strTok] = 0; // Add variable to used-var-list
879  }
880 
881  m_iPos = iEnd;
882 
883  // Call the variable factory in order to let it define a new parser variable
885  return true;
886  }
887 
888 
889  //---------------------------------------------------------------------------
897  {
898  if (m_strFormula[m_iPos]!='"')
899  return false;
900 
901  string_type strBuf(&m_strFormula[m_iPos+1]);
902  std::size_t iEnd(0), iSkip(0);
903 
904  // parser over escaped '\"' end replace them with '"'
905  for(iEnd=(int)strBuf.find( _T('\"') ); iEnd!=0 && iEnd!=string_type::npos; iEnd=(int)strBuf.find( _T('\"'), iEnd))
906  {
907  if (strBuf[iEnd-1]!='\\') break;
908  strBuf.replace(iEnd-1, 2, _T("\"") );
909  iSkip++;
910  }
911 
912  if (iEnd==string_type::npos)
914 
915  string_type strTok(strBuf.begin(), strBuf.begin()+iEnd);
916 
917  if (m_iSynFlags & noSTR)
918  Error(ecUNEXPECTED_STR, m_iPos, strTok);
919 
920  m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer
921  a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size());
922 
923  m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 for quotes; +iSkip for escape characters
924  m_iSynFlags = noANY ^ ( noARG_SEP | noBC | noOPT | noEND );
925 
926  return true;
927  }
928 
929  //---------------------------------------------------------------------------
940  int a_iPos,
941  const string_type &a_sTok) const
942  {
943  m_pParser->Error(a_iErrc, a_iPos, a_sTok);
944  }
945 
946  //---------------------------------------------------------------------------
948  {
949  m_cArgSep = cArgSep;
950  }
951 
952  //---------------------------------------------------------------------------
954  {
955  return m_cArgSep;
956  }
957 } // namespace mu
958