custom_token_attribute.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // Copyright (c) 2001-2010 Hartmut Kaiser
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. // The purpose of this example is to demonstrate how custom, user defined types
  6. // can be easily integrated with the lexer as token value types. Moreover, the
  7. // custom token values are properly exposed to the parser as well, allowing to
  8. // retrieve the custom values using the built in parser attribute propagation
  9. // rules.
  10. #include <boost/spirit/include/lex_lexertl.hpp>
  11. #include <boost/spirit/include/qi.hpp>
  12. namespace lex = boost::spirit::lex;
  13. namespace qi = boost::spirit::qi;
  14. namespace mpl = boost::mpl;
  15. ///////////////////////////////////////////////////////////////////////////////
  16. // This is just a simple custom rational data structure holding two ints to be
  17. // interpreted as a rational number
  18. struct rational
  19. {
  20. rational(int n = 0, int d = 0)
  21. : nominator_(n), denominator_(d)
  22. {}
  23. int nominator_;
  24. int denominator_;
  25. };
  26. ///////////////////////////////////////////////////////////////////////////////
  27. // A rational is represented as "{n,d}", where 'n' and 'd' are the nominator
  28. // and denominator of the number. We use Spirit.Qi to do the low level parsing
  29. // of the input sequence as matched by the lexer. Certainly, any other
  30. // conversion could be used instead.
  31. //
  32. // The lexer uses the template assign_to_attribute_from_iterators<> to convert
  33. // the matched input sequence (pair of iterators) to the token value type as
  34. // specified while defining the lex::token_def<>.
  35. //
  36. // Our specialization of assign_to_attribute_from_iterators<> for the rational
  37. // data type defined above has to be placed into the
  38. // namespace boost::spirit::traits, otherwise it won't be found by the library.
  39. namespace boost { namespace spirit { namespace traits
  40. {
  41. template <typename Iterator>
  42. struct assign_to_attribute_from_iterators<rational, Iterator>
  43. {
  44. static void
  45. call(Iterator const& first, Iterator const& last, rational& attr)
  46. {
  47. int x, y;
  48. Iterator b = first;
  49. qi::parse(b, last,
  50. '{' >> qi::int_ >> ',' >> qi::int_ >> '}', x, y);
  51. attr = rational(x, y);
  52. }
  53. };
  54. }}}
  55. ///////////////////////////////////////////////////////////////////////////////
  56. // a lexer recognizing a single token type: rational
  57. template <typename Lexer>
  58. struct lex_rational : lex::lexer<Lexer>
  59. {
  60. lex_rational()
  61. {
  62. this->self.add_pattern("INT", "[1-9][0-9]*");
  63. rt = "\\{{INT},{INT}\\}";
  64. this->self.add(rt);
  65. }
  66. lex::token_def<rational> rt;
  67. };
  68. int main()
  69. {
  70. // the token type needs to know the iterator type of the underlying
  71. // input and the set of used token value types
  72. typedef lex::lexertl::token<std::string::iterator,
  73. mpl::vector<rational> > token_type;
  74. // use actor_lexer<> here if your token definitions have semantic
  75. // actions
  76. typedef lex::lexertl::lexer<token_type> lexer_type;
  77. // this is the iterator exposed by the lexer, we use this for parsing
  78. typedef lexer_type::iterator_type iterator_type;
  79. // create a lexer instance
  80. std::string input("{3,4}");
  81. std::string::iterator s = input.begin();
  82. lex_rational<lexer_type> lex;
  83. iterator_type b = lex.begin(s, input.end());
  84. // use the embedded token_def as a parser, it exposes its token value type
  85. // as its parser attribute type
  86. rational r;
  87. if (!qi::parse(b, lex.end(), lex.rt, r))
  88. {
  89. std::cerr << "Parsing failed!" << std::endl;
  90. return -1;
  91. }
  92. std::cout << "Parsing succeeded: {"
  93. << r.nominator_ << ", " << r.denominator_ << "}" << std::endl;
  94. return 0;
  95. }