GG
|
00001 // -*- C++ -*- 00002 /* GG is a GUI for SDL and OpenGL. 00003 Copyright (C) 2003-2008 T. Zachary Laine 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Lesser General Public License 00007 as published by the Free Software Foundation; either version 2.1 00008 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public 00016 License along with this library; if not, write to the Free 00017 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 00018 02111-1307 USA 00019 00020 If you do not wish to comply with the terms of the LGPL please 00021 contact the author as other terms are available for a fee. 00022 00023 Zach Laine 00024 whatwasthataddress@gmail.com */ 00025 00028 #ifndef _GG_Lexer_h_ 00029 #define _GG_Lexer_h_ 00030 00031 #include <GG/Export.h> 00032 #include <GG/Token.h> 00033 #include <GG/adobe/name.hpp> 00034 #include <GG/adobe/istream.hpp> 00035 #include <GG/adobe/implementation/token.hpp> 00036 00037 #include <boost/spirit/include/lex_lexertl.hpp> 00038 00039 00040 namespace GG { 00041 00042 typedef std::string::const_iterator text_iterator; 00043 00044 typedef position_tracking_token< 00045 text_iterator, 00046 boost::mpl::vector< 00047 adobe::name_t, 00048 std::string, 00049 double, 00050 bool 00051 > 00052 > token_type; 00053 00054 typedef boost::spirit::lex::lexertl::actor_lexer<token_type> spirit_lexer_base_type; 00055 00056 namespace detail { 00057 struct named_eq_op : adobe::name_t {}; 00058 struct named_rel_op : adobe::name_t {}; 00059 struct named_mul_op : adobe::name_t {}; 00060 } 00061 00062 struct GG_API lexer : 00063 boost::spirit::lex::lexer<spirit_lexer_base_type> 00064 { 00065 lexer(const adobe::name_t* first_keyword, 00066 const adobe::name_t* last_keyword); 00067 00068 boost::spirit::lex::token_def<bool> keyword_true_false; 00069 boost::spirit::lex::token_def<boost::spirit::lex::omit> keyword_empty; 00070 boost::spirit::lex::token_def<adobe::name_t> identifier; 00071 boost::spirit::lex::token_def<std::string> lead_comment; 00072 boost::spirit::lex::token_def<std::string> trail_comment; 00073 boost::spirit::lex::token_def<std::string> quoted_string; 00074 boost::spirit::lex::token_def<double> number; 00075 boost::spirit::lex::token_def<detail::named_eq_op> eq_op; 00076 boost::spirit::lex::token_def<detail::named_rel_op> rel_op; 00077 boost::spirit::lex::token_def<detail::named_mul_op> mul_op; 00078 boost::spirit::lex::token_def<boost::spirit::lex::omit> define; 00079 boost::spirit::lex::token_def<boost::spirit::lex::omit> or_; 00080 boost::spirit::lex::token_def<boost::spirit::lex::omit> and_; 00081 std::map<adobe::name_t, boost::spirit::lex::token_def<adobe::name_t> > keywords; 00082 }; 00083 00084 typedef lexer::iterator_type token_iterator; 00085 00086 typedef lexer::lexer_def lexer_def; 00087 00088 typedef boost::spirit::qi::in_state_skipper<lexer_def> skipper_type; 00089 00090 } 00091 00092 00093 // This code creates a new Spirit.Qi parser that does approximately what the 00094 // Adobe lexer's next_position() function does. 00095 00096 namespace GG { namespace detail { 00097 BOOST_SPIRIT_TERMINAL(next_pos); 00098 } } 00099 00100 namespace boost { namespace spirit { 00101 template <> 00102 struct use_terminal<qi::domain, GG::detail::tag::next_pos> : 00103 mpl::true_ 00104 {}; 00105 } } 00106 00107 namespace GG { namespace detail { 00108 struct next_pos_parser : 00109 boost::spirit::qi::primitive_parser<next_pos_parser> 00110 { 00111 template <typename Context, typename Iter> 00112 struct attribute 00113 { typedef adobe::line_position_t type; }; 00114 00115 template <typename Iter, typename Context, typename Skipper, typename Attribute> 00116 bool parse(Iter& first, Iter const& last, Context&, Skipper const& skipper, Attribute& attr) const 00117 { 00118 boost::spirit::qi::skip_over(first, last, skipper); 00119 attr = adobe::line_position_t(first->filename(), first->line_number()); 00120 // Note that the +1's below are there to provide the user with 00121 // 1-based column numbers. This is Adobe's convention. The Adobe 00122 // convention is also that line numbers are 0-based. Go figure. 00123 attr.line_start_m = std::distance(token_type::s_begin, first->line_start()) + 1; 00124 attr.position_m = std::distance(token_type::s_begin, first->matched_range().first) + 1; 00125 return true; 00126 } 00127 00128 template <typename Context> 00129 boost::spirit::info what(Context&) const 00130 { return boost::spirit::info("next_pos"); } 00131 }; 00132 } } 00133 00134 namespace boost { namespace spirit { namespace qi { 00135 template <typename Modifiers> 00136 struct make_primitive<GG::detail::tag::next_pos, Modifiers> 00137 { 00138 typedef GG::detail::next_pos_parser result_type; 00139 result_type operator()(unused_type, unused_type) const 00140 { return result_type(); } 00141 }; 00142 } } } 00143 00144 00145 // These template specializations are required by Spirit.Lex to automatically 00146 // convert an iterator pair to an adobe::name_t in detail::lexer. 00147 00148 namespace boost { namespace spirit { namespace traits 00149 { 00150 // These template specializations are required by Spirit.Lex to automatically 00151 // convert an iterator pair to an adobe::name_t in the lexer below. 00152 00153 template <typename Iter> 00154 struct assign_to_attribute_from_iterators<adobe::name_t, Iter> 00155 { 00156 static void call(const Iter& first, const Iter& last, adobe::name_t& attr) 00157 { attr = adobe::name_t(std::string(first, last).c_str()); } 00158 }; 00159 00160 // HACK! This is only necessary because of a bug in Spirit in Boost 00161 // versions <= 1.45. 00162 template <> 00163 struct GG_API assign_to_attribute_from_iterators<bool, GG::text_iterator, void> 00164 { 00165 static void call(const GG::text_iterator& first, const GG::text_iterator& last, bool& attr) 00166 { attr = *first == 't' ? true : false; } 00167 }; 00168 00169 template <typename Iter> 00170 struct assign_to_attribute_from_iterators<GG::detail::named_eq_op, Iter> 00171 { 00172 static void call(const Iter& first, const Iter& last, adobe::name_t& attr) 00173 { attr = *first == '=' ? adobe::equal_k : adobe::not_equal_k; } 00174 }; 00175 00176 template <typename Iter> 00177 struct assign_to_attribute_from_iterators<GG::detail::named_rel_op, Iter> 00178 { 00179 static void call(const Iter& first, const Iter& last, adobe::name_t& attr) 00180 { 00181 std::ptrdiff_t dist = std::distance(first, last); 00182 attr = 00183 *first == '<' ? 00184 (dist == 1 ? adobe::less_k : adobe::less_equal_k) : 00185 (dist == 1 ? adobe::greater_k : adobe::greater_equal_k); 00186 } 00187 }; 00188 00189 template <typename Iter> 00190 struct assign_to_attribute_from_iterators<GG::detail::named_mul_op, Iter> 00191 { 00192 static void call(const Iter& first, const Iter& last, adobe::name_t& attr) 00193 { 00194 attr = 00195 *first == '*' ? 00196 adobe::multiply_k : 00197 (*first == '/' ? adobe::divide_k : adobe::modulus_k); 00198 } 00199 }; 00200 00201 } } } 00202 00203 #endif // _GG_Lexer_h_