GG
Lexer.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 /* GG is a GUI for SDL and OpenGL.
3  Copyright (C) 2003-2008 T. Zachary Laine
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public License
7  as published by the Free Software Foundation; either version 2.1
8  of the License, or (at your option) any later version.
9 
10  This library 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 GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free
17  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18  02111-1307 USA
19 
20  If you do not wish to comply with the terms of the LGPL please
21  contact the author as other terms are available for a fee.
22 
23  Zach Laine
24  whatwasthataddress@gmail.com */
25 
28 #ifndef _GG_Lexer_h_
29 #define _GG_Lexer_h_
30 
31 #include <GG/LexerFwd.h>
32 #include <GG/ReportParseError.h>
33 
34 #include <GG/adobe/istream.hpp>
35 #include <GG/adobe/implementation/token.hpp>
36 
37 
38 namespace GG {
39 
40 namespace detail {
41  struct named_eq_op : adobe::name_t {};
42  struct named_rel_op : adobe::name_t {};
43  struct named_mul_op : adobe::name_t {};
44 }
45 
46 struct GG_API lexer :
47  boost::spirit::lex::lexer<spirit_lexer_base_type>
48 {
49  lexer(const adobe::name_t* first_keyword,
50  const adobe::name_t* last_keyword);
51 
52  boost::spirit::lex::token_def<bool> keyword_true_false;
53  boost::spirit::lex::token_def<boost::spirit::lex::omit> keyword_empty;
54  boost::spirit::lex::token_def<adobe::name_t> identifier;
55  boost::spirit::lex::token_def<std::string> lead_comment;
56  boost::spirit::lex::token_def<std::string> trail_comment;
57  boost::spirit::lex::token_def<std::string> quoted_string;
58  boost::spirit::lex::token_def<double> number;
59  boost::spirit::lex::token_def<detail::named_eq_op> eq_op;
60  boost::spirit::lex::token_def<detail::named_rel_op> rel_op;
61  boost::spirit::lex::token_def<detail::named_mul_op> mul_op;
62  boost::spirit::lex::token_def<boost::spirit::lex::omit> define;
63  boost::spirit::lex::token_def<boost::spirit::lex::omit> or_;
64  boost::spirit::lex::token_def<boost::spirit::lex::omit> and_;
65  std::map<adobe::name_t, boost::spirit::lex::token_def<adobe::name_t> > keywords;
66 };
67 
68 typedef lexer::iterator_type token_iterator;
69 
70 typedef lexer::lexer_def lexer_def;
71 
72 typedef boost::spirit::qi::in_state_skipper<lexer_def> skipper_type;
73 
74 extern const boost::phoenix::function<report_error_<token_type> > report_error;
75 
76 }
77 
78 
79 // This code creates a new Spirit.Qi parser that does approximately what the
80 // Adobe lexer's next_position() function does.
81 
82 namespace GG { namespace detail {
83  BOOST_SPIRIT_TERMINAL(next_pos);
84 } }
85 
86 namespace boost { namespace spirit {
87  template <>
88  struct use_terminal<qi::domain, GG::detail::tag::next_pos> :
89  mpl::true_
90  {};
91 } }
92 
93 namespace GG { namespace detail {
94  struct next_pos_parser :
95  boost::spirit::qi::primitive_parser<next_pos_parser>
96  {
97  template <typename Context, typename Iter>
98  struct attribute
99  { typedef adobe::line_position_t type; };
100 
101  template <typename Iter, typename Context, typename Skipper, typename Attribute>
102  bool parse(Iter& first, Iter const& last, Context&, Skipper const& skipper, Attribute& attr) const
103  {
104  boost::spirit::qi::skip_over(first, last, skipper);
105  attr = adobe::line_position_t(detail::s_filename, boost::spirit::get_line(first->matched().begin()) - 1);
106  // Note that the +1's below are there to provide the user with
107  // 1-based column numbers. This is Adobe's convention. The Adobe
108  // convention is also that line numbers are 0-based. Go figure.
109  attr.line_start_m =
110  std::distance(detail::s_begin,
111  boost::spirit::get_line_start(detail::s_begin, first->matched().begin())) + 2;
112  attr.position_m =
113  std::distance(detail::s_begin, first->matched().begin()) + 1;
114  return true;
115  }
116 
117  template <typename Context>
118  boost::spirit::info what(Context&) const
119  { return boost::spirit::info("next_pos"); }
120  };
121 } }
122 
123 namespace boost { namespace spirit { namespace qi {
124  template <typename Modifiers>
125  struct make_primitive<GG::detail::tag::next_pos, Modifiers>
126  {
127  typedef GG::detail::next_pos_parser result_type;
128  result_type operator()(unused_type, unused_type) const
129  { return result_type(); }
130  };
131 } } }
132 
133 
134 // These template specializations are required by Spirit.Lex to automatically
135 // convert an iterator pair to an adobe::name_t in detail::lexer.
136 
137 namespace boost { namespace spirit { namespace traits
138 {
139  // These template specializations are required by Spirit.Lex to automatically
140  // convert an iterator pair to an adobe::name_t in the lexer below.
141 
142  template <typename Iter>
143  struct assign_to_attribute_from_iterators<adobe::name_t, Iter>
144  {
145  static void call(const Iter& first, const Iter& last, adobe::name_t& attr)
146  { attr = adobe::name_t(std::string(first, last).c_str()); }
147  };
148 
149  // HACK! This is only necessary because of a bug in Spirit in Boost
150  // versions <= 1.45.
151  template <>
152  struct GG_API assign_to_attribute_from_iterators<bool, GG::text_iterator, void>
153  {
154  static void call(const GG::text_iterator& first, const GG::text_iterator& last, bool& attr)
155  { attr = *first == 't' ? true : false; }
156  };
157 
158  template <typename Iter>
159  struct assign_to_attribute_from_iterators<GG::detail::named_eq_op, Iter>
160  {
161  static void call(const Iter& first, const Iter& last, adobe::name_t& attr)
162  { attr = *first == '=' ? adobe::equal_k : adobe::not_equal_k; }
163  };
164 
165  template <typename Iter>
166  struct assign_to_attribute_from_iterators<GG::detail::named_rel_op, Iter>
167  {
168  static void call(const Iter& first, const Iter& last, adobe::name_t& attr)
169  {
170  std::ptrdiff_t dist = std::distance(first, last);
171  attr =
172  *first == '<' ?
173  (dist == 1 ? adobe::less_k : adobe::less_equal_k) :
174  (dist == 1 ? adobe::greater_k : adobe::greater_equal_k);
175  }
176  };
177 
178  template <typename Iter>
179  struct assign_to_attribute_from_iterators<GG::detail::named_mul_op, Iter>
180  {
181  static void call(const Iter& first, const Iter& last, adobe::name_t& attr)
182  {
183  attr =
184  *first == '*' ?
185  adobe::multiply_k :
186  (*first == '/' ? adobe::divide_k : adobe::modulus_k);
187  }
188  };
189 
190 } } }
191 
192 #endif