Cppcheck
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
tokenize.h
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2014 Daniel Marjam√§ki and Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 //---------------------------------------------------------------------------
20 #ifndef tokenizeH
21 #define tokenizeH
22 //---------------------------------------------------------------------------
23 
24 #include "errorlogger.h"
25 #include "tokenlist.h"
26 #include "config.h"
27 
28 #include <string>
29 #include <map>
30 #include <list>
31 #include <ctime>
32 
33 class Settings;
34 class SymbolDatabase;
35 class TimerResults;
36 
37 /// @addtogroup Core
38 /// @{
39 
40 /** @brief The main purpose is to tokenize the source code. It also has functions that simplify the token list */
42 public:
43  Tokenizer();
44  Tokenizer(const Settings * settings, ErrorLogger *errorLogger);
45  ~Tokenizer();
46 
48  m_timerResults = tr;
49  }
50 
51  /** Is the code C. Used for bailouts */
52  bool isC() const {
53  return list.isC();
54  }
55 
56  /** Is the code CPP. Used for bailouts */
57  bool isCPP() const {
58  return list.isCPP();
59  }
60 
61  /**
62  * Check if inner scope ends with a call to a noreturn function
63  * \param endScopeToken The '}' token
64  * \param unknown set to true if it's unknown if the scope is noreturn
65  * \return true if scope ends with a function call that might be 'noreturn'
66  */
67  bool IsScopeNoReturn(const Token *endScopeToken, bool *unknown = nullptr) const;
68 
69  /**
70  * Tokenize code
71  * @param code input stream for code, e.g.
72  * \code
73  * #file "p.h"
74  * class Foo
75  * {
76  * private:
77  * void Bar();
78  * };
79  *
80  * #endfile
81  * void Foo::Bar()
82  * {
83  * }
84  * \endcode
85  *
86  * @param FileName The filename
87  * @param configuration E.g. "A" for code where "#ifdef A" is true
88  * @param noSymbolDB_AST Disable creation of SymbolDatabase and AST
89  * @return false if source code contains syntax errors
90  */
91  bool tokenize(std::istream &code,
92  const char FileName[],
93  const std::string &configuration = emptyString,
94  bool noSymbolDB_AST = false);
95  /**
96  * tokenize condition and run simple simplifications on it
97  * @param code code
98  * @return true if success.
99  */
100  bool tokenizeCondition(const std::string &code);
101 
102  /** Set variable id */
103  void setVarId();
104 
105  /**
106  * Basic simplification of tokenlist
107  *
108  * @param FileName The filename to run; used to do
109  * markup checks.
110  *
111  * @return false if there is an error that requires aborting
112  * the checking of this file.
113  */
114  bool simplifyTokenList1(const char FileName[]);
115 
116  /**
117  * Most aggressive simplification of tokenlist
118  *
119  * @return false if there is an error that requires aborting
120  * the checking of this file.
121  */
122  bool simplifyTokenList2();
123 
124  /**
125  * Deletes dead code between 'begin' and 'end'.
126  * In general not everything can be erased, such as:
127  * - code after labels;
128  * - code outside the scope where the function is called;
129  * - code after a change of scope caused by 'switch(...);'
130  * instructions, like 'case %any%;' or 'default;'
131  * Also, if the dead code contains a 'switch' block
132  * and inside it there's a label, the function removes all
133  * the 'switch(..)' tokens and every occurrence of 'case %any%; | default;'
134  * expression, such as the 'switch' block is reduced to a simple block.
135  *
136  * @param begin Tokens after this have a possibility to be erased.
137  * @param end Tokens before this have a possibility to be erased.
138  */
139  static void eraseDeadCode(Token *begin, const Token *end);
140 
141  /**
142  * Simplify '* & ( %var% ) =' or any combination of '* &' and '()'
143  * parentheses around '%var%' to '%var% ='
144  */
145  void simplifyMulAndParens();
146 
147  /**
148  * Calculates sizeof value for given type.
149  * @param type Token which will contain e.g. "int", "*", or string.
150  * @return sizeof for given type, or 0 if it can't be calculated.
151  */
152  unsigned int sizeOfType(const Token *type) const;
153 
154  /**
155  * Try to determine if function parameter is passed by value by looking
156  * at the function declaration.
157  * @param fpar token for function parameter in the function call
158  * @return true if the parameter is passed by value. if unsure, false is returned
159  */
160  bool isFunctionParameterPassedByValue(const Token *fpar) const;
161 
162  /**
163  * get error messages that the tokenizer generate
164  */
165  static void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings);
166 
167  /** Simplify assignment in function call "f(x=g());" => "x=g();f(x);"
168  */
169  void simplifyAssignmentInFunctionCall();
170 
171  /** Simplify assignment where rhs is a block : "x=({123;});" => "{x=123;}" */
172  void simplifyAssignmentBlock();
173 
174  /**
175  * Simplify constant calculations such as "1+2" => "3"
176  * @return true if modifications to token-list are done.
177  * false if no modifications are done.
178  */
179  bool simplifyCalculations();
180 
181  /**
182  * Simplify dereferencing a pointer offset by a number:
183  * "*(ptr + num)" => "ptr[num]"
184  * "*(ptr - num)" => "ptr[-num]"
185  */
186  void simplifyOffsetPointerDereference();
187 
188  /** Insert array size where it isn't given */
189  void arraySize();
190 
191  /** Simplify labels and 'case|default' syntaxes.
192  */
193  void simplifyLabelsCaseDefault();
194 
195  /** Remove macros in global scope */
196  void removeMacrosInGlobalScope();
197 
198  /** Remove unknown macro in variable declarations: PROGMEM char x; */
199  void removeMacroInVarDecl();
200 
201  /** Remove redundant assignment */
202  void removeRedundantAssignment();
203 
204  /** Simplifies some realloc usage like
205  * 'x = realloc (0, n);' => 'x = malloc(n);'
206  * 'x = realloc (y, 0);' => 'x = 0; free(y);'
207  */
208  void simplifyRealloc();
209 
210  /** Add parentheses for sizeof: sizeof x => sizeof(x) */
211  void sizeofAddParentheses();
212 
213  /**
214  * Replace sizeof() to appropriate size.
215  * @return true if modifications to token-list are done.
216  * false if no modifications are done.
217  */
218  bool simplifySizeof();
219 
220  /**
221  * Simplify variable declarations (split up)
222  * \param only_k_r_fpar Only simplify K&R function parameters
223  */
224  void simplifyVarDecl(bool only_k_r_fpar);
225  void simplifyVarDecl(Token * tokBegin, Token * tokEnd, bool only_k_r_fpar);
226 
227  /**
228  * Simplify variable initialization
229  * '; int *p(0);' => '; int *p = 0;'
230  */
231  void simplifyInitVar();
232  Token * initVar(Token * tok);
233 
234  /**
235  * Convert platform dependent types to standard types.
236  * 32 bits: size_t -> unsigned long
237  * 64 bits: size_t -> unsigned long long
238  */
239  void simplifyPlatformTypes();
240 
241  /**
242  * Collapse compound standard types into a single token.
243  * unsigned long long int => long _isUnsigned=true,_isLong=true
244  */
245  void simplifyStdType();
246 
247  /**
248  * Simplify easy constant '?:' operation
249  * Example: 0 ? (2/0) : 0 => 0
250  * @return true if something is modified
251  * false if nothing is done.
252  */
253  bool simplifyConstTernaryOp();
254 
255  /**
256  * Simplify compound assignments
257  * Example: ";a+=b;" => ";a=a+b;"
258  */
259  void simplifyCompoundAssignment();
260 
261  /**
262  * Simplify the location of "static" and "const" qualifiers in
263  * a variable declaration or definition.
264  * Example: "int static const a;" => "static const a;"
265  * Example: "long long const static b;" => "static const long long b;"
266  */
267  void simplifyStaticConst();
268 
269  /**
270  * Simplify assignments in "if" and "while" conditions
271  * Example: "if(a=b);" => "a=b;if(a);"
272  * Example: "while(a=b) { f(a); }" => "a = b; while(a){ f(a); a = b; }"
273  * Example: "do { f(a); } while(a=b);" => "do { f(a); a = b; } while(a);"
274  */
275  void simplifyIfAndWhileAssign();
276 
277  /**
278  * Simplify multiple assignments.
279  * Example: "a = b = c = 0;" => "a = 0; b = 0; c = 0;"
280  */
281  void simplifyVariableMultipleAssign();
282 
283  /**
284  * simplify if-not
285  * Example: "if(0==x);" => "if(!x);"
286  */
287  void simplifyIfNot();
288 
289  /**
290  * simplify if-not NULL
291  * Example: "if(0!=x);" => "if(x);"
292  * Special case: 'x = (0 != x);' is removed.
293  */
294  void simplifyIfNotNull();
295 
296  /** @brief simplify if (a) { if (a) */
297  void simplifyIfSameInnerCondition();
298 
299  /**
300  * Simplify the 'C Alternative Tokens'
301  * Examples:
302  * "if(s and t)" => "if(s && t)"
303  * "while((r bitand s) and not t)" => while((r & s) && !t)"
304  * "a and_eq b;" => "a &= b;"
305  */
306  bool simplifyCAlternativeTokens();
307 
308  /**
309  * Simplify comma into a semicolon when possible:
310  * - "delete a, delete b" => "delete a; delete b;"
311  * - "a = 0, b = 0;" => "a = 0; b = 0;"
312  * - "return a(), b;" => "a(); return b;"
313  */
314  void simplifyComma();
315 
316  /** Add braces to an if-block, for-block, etc.
317  * @return true if no syntax errors
318  */
319  bool simplifyAddBraces();
320 
321  /** Add braces to an if-block, for-block, etc.
322  * for command starting at token including else-block
323  * @return last token of command
324  * or input token in case of an error where no braces are added
325  * or NULL when syntaxError is called
326  */
327  Token * simplifyAddBracesToCommand(Token * tok);
328 
329  /** Add pair of braces to an single if-block, else-block, for-block, etc.
330  * for command starting at token
331  * @return last token of command
332  * or input token in case of an error where no braces are added
333  * or NULL when syntaxError is called
334  */
335  Token * simplifyAddBracesPair(Token *tok, bool commandWithCondition);
336 
337  /**
338  * typedef A mytype;
339  * mytype c;
340  *
341  * Becomes:
342  * typedef A mytype;
343  * A c;
344  */
345  void simplifyTypedef();
346 
347  /**
348  * Simplify float casts (float)1 => 1.0
349  */
350  void simplifyFloatCasts();
351 
352  /**
353  * Simplify casts
354  */
355  void simplifyCasts();
356 
357  /**
358  * Change (multiple) arrays to (multiple) pointers.
359  */
360  void simplifyUndefinedSizeArray();
361 
362  /**
363  * A simplify function that replaces a variable with its value in cases
364  * when the value is known. e.g. "x=10; if(x)" => "x=10;if(10)"
365  *
366  * @return true if modifications to token-list are done.
367  * false if no modifications are done.
368  */
369  bool simplifyKnownVariables();
370 
371  /**
372  * Utility function for simplifyKnownVariables. Get data about an
373  * assigned variable.
374  */
375  static bool simplifyKnownVariablesGetData(unsigned int varid, Token **_tok2, Token **_tok3, std::string &value, unsigned int &valueVarId, bool &valueIsPointer, bool floatvar);
376 
377  /**
378  * utility function for simplifyKnownVariables. Perform simplification
379  * of a given variable
380  */
381  bool simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel) const;
382 
383  /** Simplify useless C++ empty namespaces, like: 'namespace %var% { }'*/
384  void simplifyEmptyNamespaces();
385 
386  /** Simplify redundant code placed after control flow statements :
387  * 'return', 'throw', 'goto', 'break' and 'continue'
388  */
389  void simplifyFlowControl();
390 
391  /** Expand nested strcat() calls. */
392  void simplifyNestedStrcat();
393 
394  /** Simplify "if else" */
395  void elseif();
396 
397  /** Simplify conditions
398  * @return true if something is modified
399  * false if nothing is done.
400  */
401  bool simplifyConditions();
402 
403  /** Remove redundant code, e.g. if( false ) { int a; } should be
404  * removed, because it is never executed.
405  * @return true if something is modified
406  * false if nothing is done.
407  */
408  bool removeRedundantConditions();
409 
410  /**
411  * Remove redundant for:
412  * "for (x=0;x<1;x++) { }" => "{ x = 1; }"
413  */
414  void removeRedundantFor();
415 
416 
417  /**
418  * Reduces "; ;" to ";", except in "( ; ; )"
419  */
420  void removeRedundantSemicolons();
421 
422  /** Simplify function calls - constant return value
423  * @return true if something is modified
424  * false if nothing is done.
425  */
426  bool simplifyFunctionReturn();
427 
428  /** Struct initialization */
429  void simplifyStructInit();
430 
431  /** Struct simplification
432  * "struct S { } s;" => "struct S { }; S s;"
433  */
434 
435  void simplifyStructDecl();
436 
437  /**
438  * Remove redundant parentheses:
439  * - "((x))" => "(x)"
440  * - "(function())" => "function()"
441  * - "(delete x)" => "delete x"
442  * - "(delete [] x)" => "delete [] x"
443  * @return true if modifications to token-list are done.
444  * false if no modifications are done.
445  */
446  bool simplifyRedundantParentheses();
447 
448  void simplifyCharAt();
449 
450  /** Simplify references */
451  void simplifyReference();
452 
453  /**
454  * Simplify functions like "void f(x) int x; {"
455  * into "void f(int x) {"
456  */
457  void simplifyFunctionParameters();
458 
459  /**
460  * Simplify templates
461  */
462  void simplifyTemplates();
463 
464  void simplifyDoublePlusAndDoubleMinus();
465 
466  void simplifyRedundantConsecutiveBraces();
467 
468  void simplifyArrayAccessSyntax();
469 
470  void simplifyParameterVoid();
471 
472  void fillTypeSizes();
473 
474  void combineOperators();
475 
476  void combineStrings();
477 
478  void concatenateDoubleSharp();
479 
480  void simplifyFileAndLineMacro();
481 
482  void simplifyNull();
483 
484  void concatenateNegativeNumberAndAnyPositive();
485 
486  void simplifyExternC();
487 
488  void simplifyRoundCurlyParentheses();
489 
490  void simplifyDebugNew();
491 
492  void simplifySQL();
493 
494  bool hasEnumsWithTypedef();
495 
496  void simplifyDefaultAndDeleteInsideClass();
497 
498  void findComplicatedSyntaxErrorsInTemplates();
499 
500  /**
501  * Simplify e.g. 'atol("0")' into '0'
502  * @return true if simplifcations performed and false otherwise.
503  */
504  bool simplifyMathFunctions();
505 
506  /**
507  * Simplify e.g. 'sin(0)' into '0'
508  */
509  void simplifyMathExpressions();
510 
511  /**
512  * Modify strings in the token list by replacing hex and oct
513  * values. E.g. "\x61" -> "a" and "\000" -> "\0"
514  * @param source The string to be modified, e.g. "\x61"
515  * @return Modified string, e.g. "a"
516  */
517  static std::string simplifyString(const std::string &source);
518 
519  /**
520  * Change "int const x;" into "const int x;"
521  */
522  void simplifyConst();
523 
524  /**
525  * simplify "while (0)"
526  */
527  void simplifyWhile0();
528 
529  /**
530  * Simplify while(func() && errno==EINTR)
531  */
532  void simplifyErrNoInWhile();
533 
534  /**
535  * Simplify while(func(f))
536  */
537  void simplifyFuncInWhile();
538 
539  /**
540  * Replace enum with constant value
541  */
542  void simplifyEnum();
543 
544  /**
545  * Remove "std::" before some function names
546  */
547  void simplifyStd();
548 
549  /** Simplify pointer to standard type (C only) */
550  void simplifyPointerToStandardType();
551 
552  /** Simplify function pointers */
553  void simplifyFunctionPointers();
554 
555  /**
556  * Remove exception specifications.
557  */
558  void removeExceptionSpecifications();
559 
560 
561  /**
562  * Send error message to error logger about internal bug.
563  * @param tok the token that this bug concerns.
564  */
565  void cppcheckError(const Token *tok) const;
566 
567  /**
568  * Setup links for tokens so that one can call Token::link().
569  */
570  void createLinks();
571 
572  /**
573  * Setup links between < and >.
574  */
575  void createLinks2();
576 
577  /** Syntax error */
578  void syntaxError(const Token *tok) const;
579 
580  /** Syntax error. Example: invalid number of ')' */
581  void syntaxError(const Token *tok, char c) const;
582 
583  /** Report that there is an unhandled "class x y {" code */
584  void unhandled_macro_class_x_y(const Token *tok) const;
585 
586  /**
587  * assert that tokens are ok - used during debugging for example
588  * to catch problems in simplifyTokenList.
589  */
590  void validate() const;
591 
592  /**
593  * Remove __declspec()
594  */
595  void simplifyDeclspec();
596 
597  /**
598  * Remove calling convention
599  */
600  void simplifyCallingConvention();
601 
602  /**
603  * Remove __attribute__ ((?))
604  */
605  void simplifyAttribute();
606 
607  /**
608  * Remove keywords "volatile", "inline", "register", and "restrict"
609  */
610  void simplifyKeyword();
611 
612  /**
613  * Remove __asm
614  */
615  void simplifyAsm();
616 
617  /**
618  * Simplify bitfields - the field width is removed as we don't use it.
619  */
620  void simplifyBitfields();
621 
622  /**
623  * Remove __builtin_expect(...), likely(...), and unlikely(...)
624  */
625  void simplifyBuiltinExpect();
626 
627  /**
628  * Remove unnecessary member qualification
629  */
630  void removeUnnecessaryQualification();
631 
632  /**
633  * unnecessary member qualification error
634  */
635  void unnecessaryQualificationError(const Token *tok, const std::string &qualification) const;
636 
637  /**
638  * Add std:: in front of std classes, when using namespace std; was given
639  */
640  void simplifyNamespaceStd();
641 
642  /**
643  * Remove Microsoft MFC 'DECLARE_MESSAGE_MAP()'
644  */
645  void simplifyMicrosoftMFC();
646 
647  /**
648  * Convert Microsoft memory functions
649  * CopyMemory(dst, src, len) -> memcpy(dst, src, len)
650  * FillMemory(dst, len, val) -> memset(dst, val, len)
651  * MoveMemory(dst, src, len) -> memmove(dst, src, len)
652  * ZeroMemory(dst, len) -> memset(dst, 0, len)
653  */
654  void simplifyMicrosoftMemoryFunctions();
655 
656  /**
657  * Convert Microsoft string functions
658  * _tcscpy -> strcpy
659  */
660  void simplifyMicrosoftStringFunctions();
661 
662  /**
663  * Remove Borland code
664  */
665  void simplifyBorland();
666 
667  /**
668  * Remove Qt signals and slots
669  */
670  void simplifyQtSignalsSlots();
671 
672  /**
673  * Collapse operator name tokens into single token
674  * operator = => operator=
675  */
676  void simplifyOperatorName();
677 
678  /**
679  * check for duplicate enum definition
680  */
681  bool duplicateDefinition(Token **tokPtr, const Token *name) const;
682 
683  /**
684  * report error message
685  */
686  void reportError(const Token* tok, const Severity::SeverityType severity, const std::string& id, const std::string& msg, bool inconclusive = false) const;
687  void reportError(const std::list<const Token*>& callstack, Severity::SeverityType severity, const std::string& id, const std::string& msg, bool inconclusive = false) const;
688 
689  /**
690  * duplicate enum definition error
691  */
692  void duplicateEnumError(const Token *tok1, const Token *tok2, const std::string & type) const;
693 
694  bool duplicateTypedef(Token **tokPtr, const Token *name, const Token *typeDef, bool undefinedStruct) const;
695  void duplicateTypedefError(const Token *tok1, const Token *tok2, const std::string & type) const;
696 
697  /**
698  * Report error - duplicate declarations
699  */
700  void duplicateDeclarationError(const Token *tok1, const Token *tok2, const std::string &type) const;
701 
702  void unsupportedTypedef(const Token *tok) const;
703 
704  /** Was there templates in the code? */
705  bool codeWithTemplates() const {
706  return _codeWithTemplates;
707  }
708 
709  void setSettings(const Settings *settings) {
710  _settings = settings;
711  list.setSettings(settings);
712  }
713 
715  return _symbolDatabase;
716  }
717  void createSymbolDatabase();
718  void deleteSymbolDatabase();
719 
720  void printDebugOutput() const;
721 
722  void dump(std::ostream &out) const;
723 
724  Token *deleteInvalidTypedef(Token *typeDef);
725 
726  /**
727  * Get variable count.
728  * @return number of variables
729  */
730  unsigned int varIdCount() const {
731  return _varId;
732  }
733 
734  /**
735  * Simplify e.g. 'return(strncat(temp,"a",1));' into
736  * strncat(temp,"a",1); return temp;
737  */
738  void simplifyReturnStrncat();
739 
740  /**
741  * Output list of unknown types.
742  */
743  void printUnknownTypes() const;
744 
745 
746  /**
747  * Token list: stores all tokens.
748  */
750  // Implement tokens() as a wrapper for convinience when using the TokenList
751  const Token* tokens() const {
752  return list.front();
753  }
754 
755  /**
756  * Copy tokens.
757  * @param dest destination token where copied tokens will be inserted after
758  * @param first first token to copy
759  * @param last last token to copy
760  * @param one_line true=>copy all tokens to the same line as dest. false=>copy all tokens to dest while keeping the 'line breaks'
761  * @return new location of last token copied
762  */
763  static Token *copyTokens(Token *dest, const Token *first, const Token *last, bool one_line = true);
764 
765  /**
766  * Helper function to check wether number is zero (0 or 0.0 or 0E+0) or not?
767  * @param s --> a string to check
768  * @return true in case is is zero and false otherwise.
769  */
770  static bool isZeroNumber(const std::string &s);
771 
772  /**
773  * Helper function to check wether number is one (1 or 0.1E+1 or 1E+0) or not?
774  * @param s --> a string to check
775  * @return true in case is is one and false otherwise.
776  */
777  static bool isOneNumber(const std::string &s);
778 
779  /**
780  * Helper function to check wether number is one (2 or 0.2E+1 or 2E+0) or not?
781  * @param s --> a string to check
782  * @return true in case is is two and false otherwise.
783  */
784  static bool isTwoNumber(const std::string &s);
785 
786  /**
787  * Helper function to check for start of function execution scope.
788  * Do not use this in checks. Use the symbol database.
789  * @param tok --> pointer to end parentheses of parameter list
790  * @return pointer to start brace of function scope or nullptr if not start.
791  */
792  static const Token * startOfExecutableScope(const Token * tok);
793 
794 private:
795  /** Disable copy constructor, no implementation */
796  Tokenizer(const Tokenizer &);
797 
798  /** Disable assignment operator, no implementation */
799  Tokenizer &operator=(const Tokenizer &);
800 
801  static Token * startOfFunction(Token * tok);
803  return const_cast<Token*>(startOfExecutableScope(const_cast<const Token *>(tok)));
804  }
805 
806  /** Set pod types */
807  void setPodTypes();
808 
809  /** settings */
811 
812  /** errorlogger */
814 
815  /** Symbol database that all checks etc can use */
817 
818  /** E.g. "A" for code where "#ifdef A" is true. This is used to
819  print additional information in error situations. */
820  std::string _configuration;
821 
822  /** sizeof information for known types */
823  std::map<std::string, unsigned int> _typeSize;
824 
825  /** variable count */
826  unsigned int _varId;
827 
828  /**
829  * was there any templates? templates that are "unused" are
830  * removed from the token list
831  */
833 
834  /**
835  * TimerResults
836  */
838 #ifdef MAXTIME
839  /** Tokenizer maxtime */
840  std::time_t maxtime;
841 #endif
842 };
843 
844 /// @}
845 
846 //---------------------------------------------------------------------------
847 #endif // tokenizeH