GG: Lexer.h Source File

GG

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

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