GG

Lexer.h

Go to the documentation of this file.
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_