OpenWalnut  1.4.0
WStructuredTextParser.h
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #ifndef WSTRUCTUREDTEXTPARSER_H
26 #define WSTRUCTUREDTEXTPARSER_H
27 
28 #include <algorithm>
29 #include <iostream>
30 #include <map>
31 #include <ostream>
32 #include <string>
33 #include <vector>
34 
35 #ifndef Q_MOC_RUN
36 #include <boost/config/warning_disable.hpp>
37 #endif
38 #ifndef Q_MOC_RUN
39 #include <boost/spirit/include/qi.hpp>
40 #endif
41 #ifndef Q_MOC_RUN
42 #include <boost/spirit/include/phoenix_core.hpp>
43 #endif
44 #ifndef Q_MOC_RUN
45 #include <boost/spirit/include/phoenix_operator.hpp>
46 #endif
47 #ifndef Q_MOC_RUN
48 #include <boost/spirit/include/phoenix_fusion.hpp>
49 #endif
50 #ifndef Q_MOC_RUN
51 #include <boost/spirit/include/phoenix_stl.hpp>
52 #endif
53 #ifndef Q_MOC_RUN
54 #include <boost/spirit/include/phoenix_object.hpp>
55 #endif
56 #ifndef Q_MOC_RUN
57 #include <boost/fusion/include/adapt_struct.hpp>
58 #endif
59 #ifndef Q_MOC_RUN
60 #include <boost/variant/recursive_variant.hpp>
61 #endif
62 #ifndef Q_MOC_RUN
63 #include <boost/fusion/include/io.hpp>
64 #endif
65 #ifndef Q_MOC_RUN
66 #include <boost/filesystem/path.hpp>
67 #endif
68 
69 #include "WStringUtils.h"
70 #include "exceptions/WTypeMismatch.h"
71 #include "exceptions/WNotFound.h"
72 
73 /**
74  * This namespace contains the WStructuredTextParser data types and the parser. It builds up the abstract syntax tree (AST)
75  * for the given input which later can be traversed.
76  */
77 namespace WStructuredTextParser
78 {
79  //! we use these quite often, so define some short alias for them:
80  namespace qi = boost::spirit::qi;
81 
82  //! we use these quite often, so define some short alias for them:
83  namespace fusion = boost::fusion;
84 
85  //! we use these quite often, so define some short alias for them:
86  namespace ascii = boost::spirit::ascii;
87 
88  //! we use these quite often, so define some short alias for them:
89  namespace phoenix = boost::phoenix;
90 
91  //! we use these quite often, so define some short alias for them:
92  namespace spirit = boost::spirit;
93 
94  /**
95  * The type used for keys
96  */
97  typedef std::string KeyType;
98 
99  /**
100  * The type used for values
101  */
102  typedef std::string ValueType;
103 
104  /**
105  * The type used for comments
106  */
107  typedef std::string CommentType;
108 
109  /**
110  * Forward declare the object type.
111  */
112  struct ObjectType;
113 
114  /**
115  * KeyValueType - a tuple containing name and value
116  */
118  {
119  /**
120  * Name string.
121  */
122  std::string m_name;
123  /**
124  * Value string.
125  */
126  std::string m_value;
127  };
128 
129  /**
130  * A node inside the AST is either another object or a key-value pair.
131  */
132  typedef
133  boost::variant<
134  boost::recursive_wrapper< ObjectType >,
135  KeyValueType,
136  CommentType
137  >
139 
140  /**
141  * An object is always a name and contains several further nodes
142  */
143  struct ObjectType
144  {
145  /**
146  * Name of the object
147  */
148  std::string m_name;
149 
150  /**
151  * Object's members
152  */
153  std::vector< MemberType > m_nodes;
154  };
155 
156  /**
157  * An object representing all objects and comments on file level.
158  */
159  typedef std::vector< MemberType > FileType;
160 }
161 
162 
163 // Doxygen has problems with the following
164 // \cond Suppress_Doxygen
165 /**
166  * Tell boost::fusion about our types.
167  */
168 BOOST_FUSION_ADAPT_STRUCT(
170  ( std::string, m_name )
171  ( std::vector< WStructuredTextParser::MemberType >, m_nodes )
172  )
173 
174 /**
175  * Tell boost::fusion about our types.
176  */
177 BOOST_FUSION_ADAPT_STRUCT(
178  WStructuredTextParser::KeyValueType,
179  ( std::string, m_name )
180  ( std::string, m_value )
181  )
182 // \endcond
183 
184 namespace WStructuredTextParser
185 {
186  /**
187  * The grammar describing the structured format. It uses the boost::spirit features to parse the input. There are several rules to comply to
188  * successfully parse a file:
189  * <ul>
190  * <li>Key: identifier, needs to be a-z,A-Z,0-9,_
191  * <li>Object: defined as key + { ... }
192  * <li> ";" is optional after objects
193  * <li>Key-Value Pair: is a member of an object and is defines as key="value".
194  * <li>Comments begin with //
195  * </ul>
196  * For more details please see the test fixture file in core/common/test/fixtures/WStrutcuredTextParser_test.txt.
197  *
198  * \tparam Iterator the iterator, used to get the input stream
199  */
200  template <typename Iterator>
201  struct Grammar: qi::grammar<Iterator, FileType(), ascii::space_type >
202  {
203  /**
204  * Constructor and grammar description. It contains the EBNF (Extended Backus Naur Form) of the format we can parse.
205  *
206  * \param error Will contain error message if any occurs during functions execution
207  */
208  explicit Grammar( std::ostream& error ): Grammar::base_type( file, "WStructuredTextParser::Grammar" ) // NOLINT - non-const ref
209  {
210  // a key begins with a letter
211  key %= qi::char_( "a-zA-Z_" ) >> *qi::char_( "a-zA-Z_0-9" );
212  // a value is a quoted string. Multi-line strings possible
213  value %= '"' >> *( ~qi::char_( "\"" ) | qi::char_( " " ) ) >> '"';
214 
215  // a pair is: key = value
216  kvpair %= key >> '=' >> value >> ';';
217  // a comment is // + arbitrary symbols
218  comment %= qi::lexeme[ qi::char_( "/" ) >> qi::char_( "/" ) >> *qi::char_( "a-zA-Z_0-9!\"#$%&'()*,:;<>?@\\^`{|}~/ .@=[]ยง!+-" ) ];
219  // a object is a name, and a set of nested objects or key-value pairs
220  object %= ( key | value ) >> '{' >> *( object | kvpair | comment ) >> '}' >> *qi::char_( ";" );
221  // a file is basically an object without name.
222  file %= *( object | kvpair | comment );
223 
224  // provide names for these objects for better readability of parse errors
225  object.name( "object" );
226  kvpair.name( "key-value pair" );
227  key.name( "key" );
228  value.name( "value" );
229  file.name( "file" );
230  comment.name( "comment" );
231 
232  // provide error handlers
233  // XXX: can someone tell me how to get them work? According to the boost::spirit doc, this is everything needed but it doesn't work.
234  qi::on_error< qi::fail >( object, error << phoenix::val( "Error: " ) << qi::_4 );
235  qi::on_error< qi::fail >( kvpair, error << phoenix::val( "Error: " ) << qi::_4 );
236  qi::on_error< qi::fail >( key, error << phoenix::val( "Error: " ) << qi::_4 );
237  qi::on_error< qi::fail >( value, error << phoenix::val( "Error: " ) << qi::_4 );
238  qi::on_error< qi::fail >( comment, error << phoenix::val( "Error: " ) << qi::_4 );
239  qi::on_error< qi::fail >( file, error << phoenix::val( "Error: " ) << qi::_4 );
240  }
241 
242  // Rules we use
243 
244  /**
245  * Rule for objects. Attribute is ObjectType and is the start rule of the grammar. See constructor for exact definition.
246  */
247  qi::rule< Iterator, ObjectType(), ascii::space_type > object;
248 
249  /**
250  * Rule for files. Basically the same as an object but without name
251  */
252  qi::rule< Iterator, FileType(), ascii::space_type > file;
253 
254  /**
255  * Rule for comments. Ignored.
256  */
257  qi::rule< Iterator, CommentType(), ascii::space_type > comment;
258 
259  /**
260  * Key-value pair rule. See constructor for exact definition.
261  */
262  qi::rule< Iterator, KeyValueType(), ascii::space_type > kvpair;
263 
264  /**
265  * Key rule. See constructor for exact definition.
266  */
267  qi::rule< Iterator, KeyType() > key;
268 
269  /**
270  * Value rule. See constructor for exact definition.
271  */
272  qi::rule< Iterator, ValueType() > value;
273  };
274 
275  /**
276  * This simplifies working with a tree in a \ref WStructuredTextParser::FileType instance. It provides easy query and check methods. It does not
277  * provide any semantic options. So check validity of the contents and structure of the tree is the job of the using class/derived class. As
278  * the tree does not know anything about the semantics of your structure, it is also untyped. For every key you query, you need to specify
279  * the type.
280  *
281  * This tree uses the types in the WStructuredTextParser namespace. To avoid unnecessary copy operations, this class is not recursive
282  * itself. When querying, you always need to specify the full path. This class can be seen as accessor to the
283  * \ref WStructuredTextParser::ObjectType tree.
284  *
285  * \note The syntax of the parsed files is defined by the parser itself. See WStructuredTextParser::Grammar for details.
286  * \note This also stores the comments of the parsed file. This allows them to be written again if OW loads a file, modifies it and re-writes
287  * it.
288  */
290  {
291  friend class WStructuredTextParserTest;
292  public:
293  /**
294  * This char is used as separator for identifying values in the tree. NEVER change this value.
295  */
296  static const std::string Separator;
297 
298  /**
299  * Construct the instance given the original parsing structure.
300  *
301  * \param file the parsing result structure (the root node).
302  */
303  explicit StructuredValueTree( const FileType& file );
304 
305  /**
306  * Construct the instance given a text as string.
307  *
308  * \param toParse the text to parse
309  */
310  explicit StructuredValueTree( const std::string& toParse );
311 
312  /**
313  * Construct the instance given a path to a file to load.
314  *
315  * \param file the path to a file to load.
316  */
317  explicit StructuredValueTree( const boost::filesystem::path& file );
318 
319  /**
320  * Creates an empty tree. It will contain no information at all.
321  */
323 
324  /**
325  * Cleanup.
326  */
327  virtual ~StructuredValueTree();
328 
329  /**
330  * Checks whether the given value or object exists. If you want to know only if a value with the given name exists, set valuesOnly to
331  * true.
332  *
333  * \param key path to the value
334  * \param valuesOnly if true, it checks only if a value with the name exists. If false, also objects with this name cause this function
335  * to return true.
336  *
337  * \return true if existing.
338  */
339  bool exists( std::string key, bool valuesOnly = false ) const;
340 
341  /**
342  * It is possible that there are multiple values matching a key. This method counts them.
343  *
344  * \param key path to the values to count
345  * \param valuesOnly if true, it only counts values matching the given name.
346  *
347  * \return the number of found values.
348  */
349  size_t count( std::string key, bool valuesOnly = false ) const;
350 
351  /**
352  * Queries the value with the given name. If it is not found, the default value will be returned.
353  *
354  * \param key path to the value. Paths to whole objects are invalid.
355  * \param defaultValue the default if no value was found
356  * \tparam T the return type. This method tries to cast to this type. If it fails, an exception is thrown. Type std::string is always valid.
357  *
358  * \throw WTypeMismatch if the value cannot be cast to the specified target type
359  *
360  * \return the value
361  *
362  * \note this does not return a reference as the default value might be returned. It returns a copy of the value.
363  */
364  template< typename T >
365  T getValue( std::string key, const T& defaultValue ) const;
366 
367  /**
368  * Queries the list of values matching the given path. If it is not found, the default value will be returned.
369  *
370  * \param key path to the value. Paths to whole objects are invalid.
371  * \param defaults the defaults if no value was found
372  * \tparam T the return type. This method tries to cast to this type. If it fails, an exception is thrown. Type std::string is always valid.
373  *
374  * \throw WTypeMismatch if the value cannot be cast to the specified target type
375  *
376  * \return the value
377  *
378  * \note this does not return a reference as the default value might be returned. It returns a copy of the value.
379  */
380  template< typename T >
381  std::vector< T > getValues( std::string key, const std::vector< T >& defaults ) const;
382 
383  /**
384  * Queries the list of values matching the given path. If it is not found, an empty results vector is returned.
385  *
386  * \param key path to the value. Paths to whole objects are invalid.
387  * \tparam T the return type. This method tries to cast to this type. If it fails, an exception is thrown. Type std::string is always valid.
388  *
389  * \throw WTypeMismatch if the value cannot be cast to the specified target type
390  *
391  * \return the value vector. Might be empty if no elements where found.
392  *
393  * \note this does not return a reference as the default value might be returned. It returns a copy of the value.
394  */
395  template< typename T >
396  std::vector< T > getValues( std::string key ) const;
397 
398  /**
399  * Queries the value with the given name. If it is not found, an exception is thrown. If multiple entries with this path exist, the first
400  * one is returned. Use \ref getValues in this case. Query the count of a key:value pair using \ref count
401  *
402  * \param key path to the value. Paths to whole objects are invalid.
403  * \tparam T the return type. This method tries to cast to this type. If it fails, an exception is thrown. Type std::string is always valid.
404  * \throw WTypeMismatch if the value cannot be cast to the specified target type
405  * \throw WNotFound if the key:value pair does not exist
406  *
407  * \return the value as copy to avoid any const_cast which would allow modification.
408  */
409  template< typename T >
410  T operator[]( std::string key ) const;
411 
412  /**
413  * Gets a subtree. The ValueTree returned contains the node you have searched. It only contains the first match. If all matches are
414  * needed, use \ref getSubTrees instead. If the key is not valid/nothing matches the key, an empty value tree is returned. If they key
415  * matches a key-value pair, nothing is returned. This means, this method is only useful for objects.
416  *
417  * \param key key to search.
418  *
419  * \return the structured value tree.
420  */
421  StructuredValueTree getSubTree( std::string key ) const;
422 
423  /**
424  * Gets all matching subtrees. The subtrees returned contains the node you have searched. If multiple objects match the key, a list of
425  * subtrees is returned. If nothing matches, the returned list is empty. If they key
426  * matches a key-value pair, nothing is returned. This means, this method is only useful for objects.
427  *
428  * \param key key to search.
429  *
430  * \return the structured value trees.
431  */
432  std::vector< StructuredValueTree > getSubTrees( std::string key ) const;
433 
434  protected:
435  private:
436  /**
437  * The named values.
438  */
439  FileType m_file;
440 
441  /**
442  * Recursively fills a result vector using a given path iterator. It checks whether the current element matches the current key. If yes,
443  * it traverses or adds the value to the result vector. This uses depth-first search and allows multiple matches for one key.
444  *
445  * \param current current element to check and recursively traverse
446  * \param keyIter the current path element
447  * \param keyEnd the end iter. Just used to stop iteration if the key as not further elements
448  * \param resultObjects all matching instances of type \ref WStructuredTextParser::ObjectType
449  * \param resultValues all matching instances of type \ref WStructuredTextParser::KeyValueType
450  */
451  void traverse( MemberType current, std::vector< std::string >::const_iterator keyIter,
452  std::vector< std::string >::const_iterator keyEnd,
453  std::vector< ObjectType >& resultObjects,
454  std::vector< KeyValueType >& resultValues ) const;
455 
456  /**
457  * Recursively fills a result vector using a given path iterator. It checks whether the current element matches the current key. If yes,
458  * it traverses or adds the value to the result vector. This uses depth-first search and allows multiple matches for one key.
459  *
460  * \param current current element to check and recursively traverse
461  * \param key the path
462  * \param resultObjects all matching instances of type \ref WStructuredTextParser::ObjectType
463  * \param resultValues all matching instances of type \ref WStructuredTextParser::KeyValueType
464  */
465  void traverse( FileType current, std::string key,
466  std::vector< ObjectType >& resultObjects,
467  std::vector< KeyValueType >& resultValues ) const;
468  };
469 
470  /**
471  * Parse the given input and return the syntax tree. Throws an exception WParseError on error.
472  *
473  * \param input the input to parse.
474  *
475  * \return the syntax tree in plain format. You should use WStructuredValueTree to use this.
476  *
477  * \throw WParseError on parse error
478  */
479  FileType parseFromString( std::string input );
480 
481  /**
482  * Parse the given input and return the syntax tree. Throws an exception WParseError on error.
483  *
484  * \param path the file to parse
485  *
486  * \return the syntax tree in plain format. You should use WStructuredValueTree to use this.
487  *
488  * \throw WParseError on parse error
489  * \throw WFileNotFOund in case the specified file could not be opened
490  */
491  FileType parseFromFile( boost::filesystem::path path );
492 
493  template< typename T >
494  T StructuredValueTree::getValue( std::string key, const T& defaultValue ) const
495  {
496  // NOTE: getValues ensures that always something is returned (the default value). So the returned vector has a valid begin iterator
497  return *getValues< T >( key, std::vector< T >( 1, defaultValue ) ).begin();
498  }
499 
500  template< typename T >
501  std::vector< T > StructuredValueTree::getValues( std::string key, const std::vector< T >& defaults ) const
502  {
503  std::vector< T > r = getValues< T >( key );
504  if( r.size() )
505  {
506  return r;
507  }
508  else
509  {
510  return defaults;
511  }
512  }
513 
514  template< typename T >
515  T StructuredValueTree::operator[]( std::string key ) const
516  {
517  std::vector< T > r = getValues< T >( key );
518  if( r.size() )
519  {
520  return *r.begin();
521  }
522  else
523  {
524  throw WNotFound( "The key \"" + key + "\" was not found." );
525  }
526  }
527 
528  /**
529  * Visitor to identify whether the given variant of type \ref WStructuredTextParser::MemberType is a object or key-value pair.
530  */
531  class IsLeafVisitor: public boost::static_visitor< bool >
532  {
533  public:
534  /**
535  * Returns always true as it is only called for key-value pairs.
536  *
537  * \return always true since it identified an key-value pair
538  */
539  bool operator()( const KeyValueType& /* element */ ) const
540  {
541  return true;
542  }
543 
544  /**
545  * Returns always false as it is only called for objects.
546  *
547  * \tparam T the type. Should be \ref WStructuredTextParser::ObjectType or \ref WStructuredTextParser::CommentType
548  * \return always false since it identified an Object/comment
549  */
550  template< typename T >
551  bool operator()( const T& /* element */ ) const
552  {
553  return false;
554  }
555  };
556 
557  /**
558  * Visitor to identify whether the given variant of type \ref WStructuredTextParser::MemberType is a comment.
559  */
560  class IsCommentVisitor: public boost::static_visitor< bool >
561  {
562  public:
563  /**
564  * Returns always true as it is only called for comments.
565  *
566  * \return always true
567  */
568  bool operator()( const CommentType& /* element */ ) const
569  {
570  return true;
571  }
572 
573  /**
574  * Returns always false as it is only called for objects and key-value pairs.
575  *
576  * \tparam T the type. Should be \ref WStructuredTextParser::ObjectType or \ref WStructuredTextParser::KeyValueType
577  * \return always false since it identified an Object/KeyValueType
578  */
579  template< typename T >
580  bool operator()( const T& /* element */ ) const
581  {
582  return false;
583  }
584  };
585 
586  /**
587  * Visitor to query the m_name member of \ref WStructuredTextParser::ObjectType and \ref WStructuredTextParser::KeyValueType.
588  */
589  class NameQueryVisitor: public boost::static_visitor< std::string >
590  {
591  public:
592  /**
593  * Comments have no name.
594  *
595  * \return empty string.
596  */
597  std::string operator()( const CommentType& /* element */ ) const
598  {
599  return "";
600  }
601 
602  /**
603  * Returns the m_name member of the specified object or key-valuev pair.
604  *
605  * \param element Specified object.
606  *
607  * \tparam T one of the types of the \ref WStructuredTextParser::MemberType variant
608  * \return always true since it identified an key-value pair
609  */
610  template< typename T >
611  std::string operator()( const T& element ) const
612  {
613  return element.m_name;
614  }
615  };
616 
617  template< typename T >
618  std::vector< T > StructuredValueTree::getValues( std::string key ) const
619  {
620  // traverse the tree
621  std::vector< ObjectType > rObj;
622  std::vector< KeyValueType > rKV;
623 
624  // traverse
625  traverse( m_file, key, rObj, rKV );
626 
627  // copy to result vector and cast
628  std::vector< T > r;
629  for( std::vector< KeyValueType >::const_iterator i = rKV.begin(); i != rKV.end(); ++i )
630  {
631  try
632  {
633  r.push_back( string_utils::fromString< T >( ( *i ).m_value ) );
634  }
635  catch( ... )
636  {
637  // convert the standard exception (if cannot convert) to a WTypeMismnatch.
638  throw WTypeMismatch( "Cannot convert element \"" + key + "\" to desired type." );
639  }
640  }
641 
642  // done
643  return r;
644  }
645 }
646 
647 #endif // WSTRUCTUREDTEXTPARSER_H
648 
Indicates invalid type of something.
Definition: WTypeMismatch.h:36
qi::rule< Iterator, ValueType() > value
Value rule.
Indicates invalid value which could not be found.
Definition: WNotFound.h:35
size_t count(std::string key, bool valuesOnly=false) const
It is possible that there are multiple values matching a key.
std::vector< T > getValues(std::string key, const std::vector< T > &defaults) const
Queries the list of values matching the given path.
StructuredValueTree getSubTree(std::string key) const
Gets a subtree.
bool exists(std::string key, bool valuesOnly=false) const
Checks whether the given value or object exists.
FileType m_file
The named values.
std::string operator()(const T &element) const
Returns the m_name member of the specified object or key-valuev pair.
T operator[](std::string key) const
Queries the value with the given name.
StructuredValueTree()
Creates an empty tree.
STL namespace.
std::string KeyType
we use these quite often, so define some short alias for them:
Visitor to identify whether the given variant of type WStructuredTextParser::MemberType is a object o...
bool operator()(const CommentType &) const
Returns always true as it is only called for comments.
std::string ValueType
The type used for values.
namespace WStructuredTextParser { /** The grammar describing the structured format.
qi::rule< Iterator, KeyValueType(), ascii::space_type > kvpair
Key-value pair rule.
This namespace contains the WStructuredTextParser data types and the parser.
void traverse(MemberType current, std::vector< std::string >::const_iterator keyIter, std::vector< std::string >::const_iterator keyEnd, std::vector< ObjectType > &resultObjects, std::vector< KeyValueType > &resultValues) const
Recursively fills a result vector using a given path iterator.
qi::rule< Iterator, ObjectType(), ascii::space_type > object
Rule for objects.
std::string CommentType
The type used for comments.
std::vector< MemberType > m_nodes
Object's members.
std::vector< MemberType > FileType
An object representing all objects and comments on file level.
static const std::string Separator
This char is used as separator for identifying values in the tree.
qi::rule< Iterator, FileType(), ascii::space_type > file
Rule for files.
Grammar(std::ostream &error)
Constructor and grammar description.
bool operator()(const T &) const
Returns always false as it is only called for objects.
KeyValueType - a tuple containing name and value.
An object is always a name and contains several further nodes.
std::string operator()(const CommentType &) const
Comments have no name.
Visitor to query the m_name member of WStructuredTextParser::ObjectType and WStructuredTextParser::Ke...
std::vector< StructuredValueTree > getSubTrees(std::string key) const
Gets all matching subtrees.
boost::variant< boost::recursive_wrapper< ObjectType >, KeyValueType, CommentType > MemberType
A node inside the AST is either another object or a key-value pair.
This simplifies working with a tree in a WStructuredTextParser::FileType instance.
virtual ~StructuredValueTree()
Cleanup.
bool operator()(const T &) const
Returns always false as it is only called for objects and key-value pairs.
Visitor to identify whether the given variant of type WStructuredTextParser::MemberType is a comment...
T getValue(std::string key, const T &defaultValue) const
Queries the value with the given name.
Test parsing and query functionality.
bool operator()(const KeyValueType &) const
Returns always true as it is only called for key-value pairs.
std::string m_name
Name of the object.
qi::rule< Iterator, KeyType() > key
Key rule.
qi::rule< Iterator, CommentType(), ascii::space_type > comment
Rule for comments.