diff options
Diffstat (limited to 'src/boost/libs/spirit/example/qi')
169 files changed, 22460 insertions, 0 deletions
diff --git a/src/boost/libs/spirit/example/qi/Jamfile b/src/boost/libs/spirit/example/qi/Jamfile new file mode 100644 index 00000000..a071c0d2 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/Jamfile @@ -0,0 +1,48 @@ +#============================================================================== +# Copyright (c) 2001-2007 Joel de Guzman +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#============================================================================== +project spirit-qi-example + : requirements + <c++-template-depth>300 + : + : + ; + +exe actions_ : actions.cpp ; +exe sum : sum.cpp ; +exe complex_number : complex_number.cpp ; +exe employee : employee.cpp ; +exe roman : roman.cpp ; +exe reference : reference.cpp ; +exe mini_xml1 : mini_xml1.cpp ; +exe mini_xml2 : mini_xml2.cpp ; +exe mini_xml3 : mini_xml3.cpp ; +exe num_list1 : num_list1.cpp ; +exe num_list2 : num_list2.cpp ; +exe num_list3 : num_list3.cpp ; +exe num_list4 : num_list4.cpp ; +exe reorder_struct : reorder_struct.cpp ; +exe parse_date : parse_date.cpp ; +exe expect : expect.cpp ; + +exe key_value_sequence : key_value_sequence.cpp ; +exe key_value_sequence_ordered : key_value_sequence_ordered.cpp ; +exe key_value_sequence_empty_value : key_value_sequence_empty_value.cpp ; + +exe iter_pos_parser : iter_pos_parser.cpp ; +exe boost_array : boost_array.cpp ; +exe display_attribute_type : display_attribute_type.cpp ; +exe adapt_template_struct : adapt_template_struct.cpp ; + +exe unescaped_string : unescaped_string.cpp ; + +exe calc_utree_naive : calc_utree_naive.cpp ; +exe calc_utree_ast : calc_utree_ast.cpp ; +exe calc_utree : calc_utree.cpp ; + +exe nabialek : nabialek.cpp ; +exe typeof : typeof.cpp ; + diff --git a/src/boost/libs/spirit/example/qi/actions.cpp b/src/boost/libs/spirit/example/qi/actions.cpp new file mode 100644 index 00000000..c5379703 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/actions.cpp @@ -0,0 +1,108 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/lambda/lambda.hpp> +#include <boost/bind.hpp> + +#include <iostream> + +// Presented are various ways to attach semantic actions +// * Using plain function pointer +// * Using simple function object +// * Using boost.bind with a plain function +// * Using boost.bind with a member function +// * Using boost.lambda + +//[tutorial_semantic_action_functions +namespace client +{ + namespace qi = boost::spirit::qi; + + // A plain function + void print(int const& i) + { + std::cout << i << std::endl; + } + + // A member function + struct writer + { + void print(int const& i) const + { + std::cout << i << std::endl; + } + }; + + // A function object + struct print_action + { + void operator()(int const& i, qi::unused_type, qi::unused_type) const + { + std::cout << i << std::endl; + } + }; +} +//] + +int main() +{ + using boost::spirit::qi::int_; + using boost::spirit::qi::parse; + using client::print; + using client::writer; + using client::print_action; + + { // example using plain function + + char const *first = "{42}", *last = first + std::strlen(first); + //[tutorial_attach_actions1 + parse(first, last, '{' >> int_[&print] >> '}'); + //] + } + + { // example using simple function object + + char const *first = "{43}", *last = first + std::strlen(first); + //[tutorial_attach_actions2 + parse(first, last, '{' >> int_[print_action()] >> '}'); + //] + } + + { // example using boost.bind with a plain function + + char const *first = "{44}", *last = first + std::strlen(first); + //[tutorial_attach_actions3 + parse(first, last, '{' >> int_[boost::bind(&print, _1)] >> '}'); + //] + } + + { // example using boost.bind with a member function + + char const *first = "{44}", *last = first + std::strlen(first); + //[tutorial_attach_actions4 + writer w; + parse(first, last, '{' >> int_[boost::bind(&writer::print, &w, _1)] >> '}'); + //] + } + + { // example using boost.lambda + + namespace lambda = boost::lambda; + char const *first = "{45}", *last = first + std::strlen(first); + using lambda::_1; + //[tutorial_attach_actions5 + parse(first, last, '{' >> int_[std::cout << _1 << '\n'] >> '}'); + //] + } + + return 0; +} + + + + diff --git a/src/boost/libs/spirit/example/qi/adapt_template_struct.cpp b/src/boost/libs/spirit/example/qi/adapt_template_struct.cpp new file mode 100644 index 00000000..360707d1 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/adapt_template_struct.cpp @@ -0,0 +1,92 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This example demonstrates a trick allowing to adapt a template data +// structure as a Fusion sequence in order to use is for direct attribute +// propagation. For more information see +// http://boost-spirit.com/home/2010/02/08/how-to-adapt-templates-as-a-fusion-sequence + +#include <boost/spirit/include/qi.hpp> + +namespace qi = boost::spirit::qi; +namespace fusion = boost::fusion; + +namespace client +{ + template <typename A, typename B> + struct data + { + A a; + B b; + }; + + template <typename Iterator, typename A, typename B> + struct data_grammar : qi::grammar<Iterator, data<A, B>()> + { + data_grammar() : data_grammar::base_type(start) + { + start = real_start; + real_start = qi::auto_ >> ',' >> qi::auto_; + } + + qi::rule<Iterator, data<A, B>()> start; + qi::rule<Iterator, fusion::vector<A&, B&>()> real_start; + }; +} + +namespace boost { namespace spirit { namespace traits +{ + template <typename A, typename B> + struct transform_attribute<client::data<A, B>, fusion::vector<A&, B&>, qi::domain> + { + typedef fusion::vector<A&, B&> type; + + static type pre(client::data<A, B>& val) { return type(val.a, val.b); } + static void post(client::data<A, B>&, fusion::vector<A&, B&> const&) {} + static void fail(client::data<A, B>&) {} + }; +}}} + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA parser for Spirit utilizing an adapted template ...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me two comma separated integers:\n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + client::data_grammar<std::string::const_iterator, long, int> g; // Our grammar + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + client::data<long, int> d; + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + bool r = phrase_parse(iter, end, g, qi::space, d); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "got: " << d.a << "," << d.b << std::endl; + std::cout << "\n-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/boost_array.cpp b/src/boost/libs/spirit/example/qi/boost_array.cpp new file mode 100644 index 00000000..66485b97 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/boost_array.cpp @@ -0,0 +1,119 @@ +// Copyright (c) 2009 Erik Bryan +// Copyright (c) 2007-2010 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file licence_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <string> +#include <vector> + +#include <boost/array.hpp> + +#include <boost/spirit/include/qi.hpp> + +namespace qi = boost::spirit::qi; +namespace ascii = boost::spirit::ascii; + +/////////////////////////////////////////////////////////////////////////////// +// create a wrapper holding the boost::array and a current insertion point +namespace client +{ + namespace detail + { + template <typename T> + struct adapt_array; + + template <typename T, std::size_t N> + struct adapt_array<boost::array<T, N> > + { + typedef boost::array<T, N> array_type; + + adapt_array(array_type& arr) + : arr_(arr), current_(0) {} + + // expose a push_back function compatible with std containers + bool push_back(typename array_type::value_type const& val) + { + // if the array is full, we need to bail out + // returning false will fail the parse + if (current_ >= N) + return false; + + arr_[current_++] = val; + return true; + } + + array_type& arr_; + std::size_t current_; + }; + } + + namespace result_of + { + template <typename T> + struct adapt_array; + + template <typename T, std::size_t N> + struct adapt_array<boost::array<T, N> > + { + typedef detail::adapt_array<boost::array<T, N> > type; + }; + } + + template <typename T, std::size_t N> + inline detail::adapt_array<boost::array<T, N> > + adapt_array(boost::array<T, N>& arr) + { + return detail::adapt_array<boost::array<T, N> >(arr); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// specialize Spirit's container specific customization points for our adaptor +namespace boost { namespace spirit { namespace traits +{ + template <typename T, std::size_t N> + struct is_container<client::detail::adapt_array<boost::array<T, N> > > + : boost::mpl::true_ + {}; + + template <typename T, std::size_t N> + struct container_value<client::detail::adapt_array<boost::array<T, N> > > + { + typedef T type; // value type of container + }; + + template <typename T, std::size_t N> + struct push_back_container< + client::detail::adapt_array<boost::array<T, N> >, T> + { + static bool call(client::detail::adapt_array<boost::array<T, N> >& c + , T const& val) + { + return c.push_back(val); + } + }; +}}} + +int main() +{ + typedef std::string::const_iterator iterator_type; + typedef boost::array<int, 2> array_type; + typedef client::result_of::adapt_array<array_type>::type adapted_type; + + array_type arr; + + std::string str = "1 2"; + iterator_type iter = str.begin(); + iterator_type end = str.end(); + + qi::rule<iterator_type, adapted_type(), ascii::space_type> r = *qi::int_; + + adapted_type attr = client::adapt_array(arr); + bool result = qi::phrase_parse(iter, end, r, ascii::space, attr); + + if (result) + std::cout << "Parsed: " << arr[0] << ", " << arr[1] << std::endl; + + return 0; +} diff --git a/src/boost/libs/spirit/example/qi/calc_utree.cpp b/src/boost/libs/spirit/example/qi/calc_utree.cpp new file mode 100644 index 00000000..00293df3 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/calc_utree.cpp @@ -0,0 +1,166 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Plain calculator example demonstrating the grammar. The parser is a +// syntax checker only and does not do any semantic evaluation. +// +// [ JDG May 10, 2002 ] spirit1 +// [ JDG March 4, 2007 ] spirit2 +// [ HK November 30, 2010 ] spirit2/utree +// +/////////////////////////////////////////////////////////////////////////////// + +// #define BOOST_SPIRIT_DEBUG + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/support_utree.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/spirit/include/phoenix_function.hpp> + +#include <iostream> +#include <string> + +#if BOOST_PHOENIX_VERSION == 0x2000 +namespace boost { namespace phoenix +{ + // There's a bug in the Phoenix V2 type deduction mechanism that prevents + // correct return type deduction for the math operations below. Newer + // versions of Phoenix will be switching to BOOST_TYPEOF. In the meantime, + // we will use the specializations helping with return type deduction + // below: + template <> + struct result_of_plus<spirit::utree&, spirit::utree&> + { + typedef spirit::utree type; + }; + + template <> + struct result_of_minus<spirit::utree&, spirit::utree&> + { + typedef spirit::utree type; + }; + + template <> + struct result_of_multiplies<spirit::utree&, spirit::utree&> + { + typedef spirit::utree type; + }; + + template <> + struct result_of_divides<spirit::utree&, spirit::utree&> + { + typedef spirit::utree type; + }; + + template <> + struct result_of_negate<spirit::utree&> + { + typedef spirit::utree type; + }; +}} +#endif + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + namespace spirit = boost::spirit; + + /////////////////////////////////////////////////////////////////////////////// + // Our calculator grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct calculator : qi::grammar<Iterator, ascii::space_type, spirit::utree()> + { + calculator() : calculator::base_type(expression) + { + using qi::uint_; + using qi::_val; + using qi::_1; + + expression = + term [_val = _1] + >> *( ('+' >> term [_val = _val + _1]) + | ('-' >> term [_val = _val - _1]) + ) + ; + + term = + factor [_val = _1] + >> *( ('*' >> factor [_val = _val * _1]) + | ('/' >> factor [_val = _val / _1]) + ) + ; + + factor = + uint_ [_val = _1] + | '(' >> expression [_val = _1] >> ')' + | ('-' >> factor [_val = -_1]) + | ('+' >> factor [_val = _1]) + ; + + BOOST_SPIRIT_DEBUG_NODE(expression); + BOOST_SPIRIT_DEBUG_NODE(term); + BOOST_SPIRIT_DEBUG_NODE(factor); + } + + qi::rule<Iterator, ascii::space_type, spirit::utree()> expression, term, factor; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Expression parser...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type an expression...or [q or Q] to quit\n\n"; + + using boost::spirit::ascii::space; + using boost::spirit::utree; + typedef std::string::const_iterator iterator_type; + typedef client::calculator<iterator_type> calculator; + + calculator calc; // Our grammar + + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + utree ut; + bool r = phrase_parse(iter, end, calc, space, ut); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded: " << ut << "\n"; + std::cout << "-------------------------\n"; + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \": " << rest << "\"\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/calc_utree_ast.cpp b/src/boost/libs/spirit/example/qi/calc_utree_ast.cpp new file mode 100644 index 00000000..3465ba08 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/calc_utree_ast.cpp @@ -0,0 +1,164 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Plain calculator example demonstrating the grammar. The parser is a +// syntax checker only and does not do any semantic evaluation. +// +// [ JDG May 10, 2002 ] spirit1 +// [ JDG March 4, 2007 ] spirit2 +// [ HK November 30, 2010 ] spirit2/utree +// +/////////////////////////////////////////////////////////////////////////////// + +// #define BOOST_SPIRIT_DEBUG + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/support_utree.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/spirit/include/phoenix_function.hpp> + +#include <iostream> +#include <string> + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + namespace spirit = boost::spirit; + + struct expr + { + template <typename T1, typename T2 = void> + struct result { typedef void type; }; + + expr(char op) : op(op) {} + + void operator()(spirit::utree& expr, spirit::utree const& rhs) const + { + spirit::utree lhs; + lhs.swap(expr); + expr.push_back(spirit::utf8_symbol_range_type(&op, &op+1)); + expr.push_back(lhs); + expr.push_back(rhs); + } + + char const op; + }; + boost::phoenix::function<expr> const plus = expr('+'); + boost::phoenix::function<expr> const minus = expr('-'); + boost::phoenix::function<expr> const times = expr('*'); + boost::phoenix::function<expr> const divide = expr('/'); + + struct negate_expr + { + template <typename T1, typename T2 = void> + struct result { typedef void type; }; + + void operator()(spirit::utree& expr, spirit::utree const& rhs) const + { + char const op = '-'; + expr.clear(); + expr.push_back(spirit::utf8_symbol_range_type(&op, &op+1)); + expr.push_back(rhs); + } + }; + boost::phoenix::function<negate_expr> neg; + + /////////////////////////////////////////////////////////////////////////////// + // Our calculator grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct calculator : qi::grammar<Iterator, ascii::space_type, spirit::utree()> + { + calculator() : calculator::base_type(expression) + { + using qi::uint_; + using qi::_val; + using qi::_1; + + expression = + term [_val = _1] + >> *( ('+' >> term [plus(_val, _1)]) + | ('-' >> term [minus(_val, _1)]) + ) + ; + + term = + factor [_val = _1] + >> *( ('*' >> factor [times(_val, _1)]) + | ('/' >> factor [divide(_val, _1)]) + ) + ; + + factor = + uint_ [_val = _1] + | '(' >> expression [_val = _1] >> ')' + | ('-' >> factor [neg(_val, _1)]) + | ('+' >> factor [_val = _1]) + ; + + BOOST_SPIRIT_DEBUG_NODE(expression); + BOOST_SPIRIT_DEBUG_NODE(term); + BOOST_SPIRIT_DEBUG_NODE(factor); + } + + qi::rule<Iterator, ascii::space_type, spirit::utree()> expression, term, factor; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Expression parser...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type an expression...or [q or Q] to quit\n\n"; + + using boost::spirit::ascii::space; + using boost::spirit::utree; + typedef std::string::const_iterator iterator_type; + typedef client::calculator<iterator_type> calculator; + + calculator calc; // Our grammar + + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + utree ut; + bool r = phrase_parse(iter, end, calc, space, ut); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded: " << ut << "\n"; + std::cout << "-------------------------\n"; + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \": " << rest << "\"\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/calc_utree_naive.cpp b/src/boost/libs/spirit/example/qi/calc_utree_naive.cpp new file mode 100644 index 00000000..c6ac3ddb --- /dev/null +++ b/src/boost/libs/spirit/example/qi/calc_utree_naive.cpp @@ -0,0 +1,134 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Plain calculator example demonstrating the grammar. The parser is a +// syntax checker only and does not do any semantic evaluation. +// +// [ JDG May 10, 2002 ] spirit1 +// [ JDG March 4, 2007 ] spirit2 +// [ HK November 30, 2010 ] spirit2/utree +// +/////////////////////////////////////////////////////////////////////////////// + +// This rather naive example demonstrates that you can pass an instance of a +// utree as the attribute for almost any grammar. As the result the utree will +// be filled with the parse tree as generated during the parsing. This is most +// of the time not what's desired, but is usually a good first step in order to +// prepare your grammar to generate a customized AST. See the calc_utree_ast +// example for a modified version of this grammar filling the attribute with a +// AST (abstract syntax tree) representing the math expression as matched from +// the input. + +// #define BOOST_SPIRIT_DEBUG + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/support_utree.hpp> + +#include <iostream> +#include <string> + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + namespace spirit = boost::spirit; + + /////////////////////////////////////////////////////////////////////////////// + // Our calculator grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct calculator : qi::grammar<Iterator, ascii::space_type, spirit::utree()> + { + calculator() : calculator::base_type(expression) + { + using qi::uint_; + using qi::char_; + + expression = + term + >> *( (char_('+') >> term) + | (char_('-') >> term) + ) + ; + + term = + factor + >> *( (char_('*') >> factor) + | (char_('/') >> factor) + ) + ; + + factor = + uint_ + | '(' >> expression >> ')' + | (char_('-') >> factor) + | (char_('+') >> factor) + ; + + BOOST_SPIRIT_DEBUG_NODE(expression); + BOOST_SPIRIT_DEBUG_NODE(term); + BOOST_SPIRIT_DEBUG_NODE(factor); + } + + qi::rule<Iterator, ascii::space_type, spirit::utree()> expression; + qi::rule<Iterator, ascii::space_type, spirit::utree::list_type()> term; + qi::rule<Iterator, ascii::space_type, spirit::utree::list_type()> factor; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Expression parser...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type an expression...or [q or Q] to quit\n\n"; + + using boost::spirit::ascii::space; + using boost::spirit::utree; + typedef std::string::const_iterator iterator_type; + typedef client::calculator<iterator_type> calculator; + + calculator calc; // Our grammar + + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + utree ut; + bool r = phrase_parse(iter, end, calc, space, ut); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded: " << ut << "\n"; + std::cout << "-------------------------\n"; + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \": " << rest << "\"\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/Jamfile b/src/boost/libs/spirit/example/qi/compiler_tutorial/Jamfile new file mode 100644 index 00000000..bda2fad4 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/Jamfile @@ -0,0 +1,132 @@ +#============================================================================== +# Copyright (c) 2001-2011 Joel de Guzman +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#============================================================================== +project spirit-qi-compiler_tutorial + : requirements + <c++-template-depth>300 + : + ; + +import modules ; + +exe calc1 : calc1.cpp ; +exe calc2 : calc2.cpp ; +exe calc3 : calc3.cpp ; +exe calc4 : calc4.cpp ; +exe calc5 : calc5.cpp ; +exe calc6 : calc6.cpp ; + +exe calc7 : + calc7/vm.cpp + calc7/compiler.cpp + calc7/expression.cpp + calc7/statement.cpp + calc7/main.cpp +; + +exe calc8 : + calc8/vm.cpp + calc8/compiler.cpp + calc8/expression.cpp + calc8/statement.cpp + calc8/main.cpp +; + +exe mini_c : + mini_c/vm.cpp + mini_c/compiler.cpp + mini_c/expression.cpp + mini_c/statement.cpp + mini_c/function.cpp + mini_c/main.cpp +; + +exe conjure1 : + conjure1/vm.cpp + conjure1/compiler.cpp + conjure1/expression.cpp + conjure1/statement.cpp + conjure1/function.cpp + conjure1/main.cpp +; + +exe conjure2 : + conjure2/compiler.cpp + conjure2/expression.cpp + conjure2/function.cpp + conjure2/lexer.cpp + conjure2/main.cpp + conjure2/statement.cpp + conjure2/vm.cpp +; + +#============================================================================== +# conjure3 and above require LLVM. Make sure you provide the +# LLVM_PATH in your bjam invocation. E.g.: +# +# bjam -sLLVM_PATH=C:/dev/llvm conjure3 +# +#============================================================================== + +if [ modules.peek : LLVM_PATH ] +{ + LLVM_PATH = [ modules.peek : LLVM_PATH ] ; +} + +if $(LLVM_PATH) +{ + path-constant LLVM_LIB_DEBUG_PATH : $(LLVM_PATH)/lib/Debug ; + path-constant LLVM_LIB_RELEASE_PATH : $(LLVM_PATH)/lib/Release ; + + llvm_linker_flags = + "advapi32.lib" + "shell32.lib" + ; + + llvm_debug_libs = [ glob $(LLVM_LIB_DEBUG_PATH)/LLVM*.lib ] ; + llvm_release_libs = [ glob $(LLVM_LIB_RELEASE_PATH)/LLVM*.lib ] ; + + rule build_exe_1 ( target-name : sources + : requirements * ) + { + local llvm_lib ; + if <variant>debug in $(requirements) + { + llvm_lib = $(llvm_debug_libs) ; + } + else + { + llvm_lib = $(llvm_release_libs) ; + } + + exe $(target-name) + : $(sources) + $(llvm_lib) + : $(requirements) + <toolset>msvc + <include>$(LLVM_PATH)/include + <linkflags>$(llvm_linker_flags) + ; + } + + rule build_exe ( target-name : sources + ) + { + build_exe_1 $(target-name) : $(sources) : <variant>debug ; + build_exe_1 $(target-name) : $(sources) : <variant>release ; + } + + build_exe conjure3 : + conjure3/compiler.cpp + conjure3/expression.cpp + conjure3/function.cpp + conjure3/lexer.cpp + conjure3/main.cpp + conjure3/statement.cpp + conjure3/vm.cpp + ; +} + + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc1.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc1.cpp new file mode 100644 index 00000000..d070172f --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc1.cpp @@ -0,0 +1,118 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Plain calculator example demonstrating the grammar. The parser is a +// syntax checker only and does not do any semantic evaluation. +// +// [ JDG May 10, 2002 ] spirit1 +// [ JDG March 4, 2007 ] spirit2 +// [ JDG February 21, 2011 ] spirit2.5 +// +/////////////////////////////////////////////////////////////////////////////// + +// Spirit v2.5 allows you to suppress automatic generation +// of predefined terminals to speed up complation. With +// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are +// responsible in creating instances of the terminals that +// you need (e.g. see qi::uint_type uint_ below). +#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <iostream> +#include <string> + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // Our calculator grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct calculator : qi::grammar<Iterator, ascii::space_type> + { + calculator() : calculator::base_type(expression) + { + qi::uint_type uint_; + + expression = + term + >> *( ('+' >> term) + | ('-' >> term) + ) + ; + + term = + factor + >> *( ('*' >> factor) + | ('/' >> factor) + ) + ; + + factor = + uint_ + | '(' >> expression >> ')' + | ('-' >> factor) + | ('+' >> factor) + ; + } + + qi::rule<Iterator, ascii::space_type> expression, term, factor; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Expression parser...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type an expression...or [q or Q] to quit\n\n"; + + typedef std::string::const_iterator iterator_type; + typedef client::calculator<iterator_type> calculator; + + boost::spirit::ascii::space_type space; // Our skipper + calculator calc; // Our grammar + + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + bool r = phrase_parse(iter, end, calc, space); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "-------------------------\n"; + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \" " << rest << "\"\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc2.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc2.cpp new file mode 100644 index 00000000..92e03f49 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc2.cpp @@ -0,0 +1,131 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A Calculator example demonstrating the grammar and semantic actions +// using plain functions. The parser prints code suitable for a stack +// based virtual machine. +// +// [ JDG May 10, 2002 ] spirit1 +// [ JDG March 4, 2007 ] spirit2 +// [ JDG February 21, 2011 ] spirit2.5 +// +/////////////////////////////////////////////////////////////////////////////// + +// Spirit v2.5 allows you to suppress automatic generation +// of predefined terminals to speed up complation. With +// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are +// responsible in creating instances of the terminals that +// you need (e.g. see qi::uint_type uint_ below). +#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> + +#include <iostream> +#include <string> + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // Semantic actions + ////////////////////////////////////////////////////////1/////////////////////// + namespace + { + void do_int(int n) { std::cout << "push " << n << std::endl; } + void do_add() { std::cout << "add\n"; } + void do_subt() { std::cout << "subtract\n"; } + void do_mult() { std::cout << "mult\n"; } + void do_div() { std::cout << "divide\n"; } + void do_neg() { std::cout << "negate\n"; } + } + + /////////////////////////////////////////////////////////////////////////////// + // Our calculator grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct calculator : qi::grammar<Iterator, ascii::space_type> + { + calculator() : calculator::base_type(expression) + { + qi::uint_type uint_; + + expression = + term + >> *( ('+' >> term [&do_add]) + | ('-' >> term [&do_subt]) + ) + ; + + term = + factor + >> *( ('*' >> factor [&do_mult]) + | ('/' >> factor [&do_div]) + ) + ; + + factor = + uint_ [&do_int] + | '(' >> expression >> ')' + | ('-' >> factor [&do_neg]) + | ('+' >> factor) + ; + } + + qi::rule<Iterator, ascii::space_type> expression, term, factor; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Expression parser...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type an expression...or [q or Q] to quit\n\n"; + + typedef std::string::const_iterator iterator_type; + typedef client::calculator<iterator_type> calculator; + + boost::spirit::ascii::space_type space; // Our skipper + calculator calc; // Our grammar + + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + bool r = phrase_parse(iter, end, calc, space); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "-------------------------\n"; + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \" " << rest << "\"\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc3.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc3.cpp new file mode 100644 index 00000000..4f214e30 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc3.cpp @@ -0,0 +1,124 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A calculator example demonstrating the grammar and semantic actions +// using phoenix to do the actual expression evaluation. The parser is +// essentially an "interpreter" that evaluates expressions on the fly. +// +// [ JDG June 29, 2002 ] spirit1 +// [ JDG March 5, 2007 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +// Spirit v2.5 allows you to suppress automatic generation +// of predefined terminals to speed up complation. With +// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are +// responsible in creating instances of the terminals that +// you need (e.g. see qi::uint_type uint_ below). +#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> + +#include <iostream> +#include <string> + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////// + // Our calculator grammar + /////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct calculator : qi::grammar<Iterator, int(), ascii::space_type> + { + calculator() : calculator::base_type(expression) + { + qi::_val_type _val; + qi::_1_type _1; + qi::uint_type uint_; + + expression = + term [_val = _1] + >> *( ('+' >> term [_val += _1]) + | ('-' >> term [_val -= _1]) + ) + ; + + term = + factor [_val = _1] + >> *( ('*' >> factor [_val *= _1]) + | ('/' >> factor [_val /= _1]) + ) + ; + + factor = + uint_ [_val = _1] + | '(' >> expression [_val = _1] >> ')' + | ('-' >> factor [_val = -_1]) + | ('+' >> factor [_val = _1]) + ; + } + + qi::rule<Iterator, int(), ascii::space_type> expression, term, factor; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Expression parser...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type an expression...or [q or Q] to quit\n\n"; + + typedef std::string::const_iterator iterator_type; + typedef client::calculator<iterator_type> calculator; + + boost::spirit::ascii::space_type space; // Our skipper + calculator calc; // Our grammar + + std::string str; + int result; + while (std::getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + bool r = phrase_parse(iter, end, calc, space, result); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "result = " << result << std::endl; + std::cout << "-------------------------\n"; + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \" " << rest << "\"\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc4.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc4.cpp new file mode 100644 index 00000000..645926f7 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc4.cpp @@ -0,0 +1,285 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A Calculator example demonstrating generation of AST. The AST, +// once created, is traversed, 1) To print its contents and +// 2) To evaluate the result. +// +// [ JDG April 28, 2008 ] For BoostCon 2008 +// [ JDG February 18, 2011 ] Pure attributes. No semantic actions. +// +/////////////////////////////////////////////////////////////////////////////// + +// Spirit v2.5 allows you to suppress automatic generation +// of predefined terminals to speed up complation. With +// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are +// responsible in creating instances of the terminals that +// you need (e.g. see qi::uint_type uint_ below). +#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS + +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/variant/recursive_variant.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/foreach.hpp> + +#include <iostream> +#include <string> + +namespace client { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + // The AST + /////////////////////////////////////////////////////////////////////////// + struct nil {}; + struct signed_; + struct program; + + typedef boost::variant< + nil + , unsigned int + , boost::recursive_wrapper<signed_> + , boost::recursive_wrapper<program> + > + operand; + + struct signed_ + { + char sign; + operand operand_; + }; + + struct operation + { + char operator_; + operand operand_; + }; + + struct program + { + operand first; + std::list<operation> rest; + }; +}} + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::signed_, + (char, sign) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::operation, + (char, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::program, + (client::ast::operand, first) + (std::list<client::ast::operation>, rest) +) + +namespace client { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + // The AST Printer + /////////////////////////////////////////////////////////////////////////// + struct printer + { + typedef void result_type; + + void operator()(nil) const {} + void operator()(unsigned int n) const { std::cout << n; } + + void operator()(operation const& x) const + { + boost::apply_visitor(*this, x.operand_); + switch (x.operator_) + { + case '+': std::cout << " add"; break; + case '-': std::cout << " subt"; break; + case '*': std::cout << " mult"; break; + case '/': std::cout << " div"; break; + } + } + + void operator()(signed_ const& x) const + { + boost::apply_visitor(*this, x.operand_); + switch (x.sign) + { + case '-': std::cout << " neg"; break; + case '+': std::cout << " pos"; break; + } + } + + void operator()(program const& x) const + { + boost::apply_visitor(*this, x.first); + BOOST_FOREACH(operation const& oper, x.rest) + { + std::cout << ' '; + (*this)(oper); + } + } + }; + + /////////////////////////////////////////////////////////////////////////// + // The AST evaluator + /////////////////////////////////////////////////////////////////////////// + struct eval + { + typedef int result_type; + + int operator()(nil) const { BOOST_ASSERT(0); return 0; } + int operator()(unsigned int n) const { return n; } + + int operator()(operation const& x, int lhs) const + { + int rhs = boost::apply_visitor(*this, x.operand_); + switch (x.operator_) + { + case '+': return lhs + rhs; + case '-': return lhs - rhs; + case '*': return lhs * rhs; + case '/': return lhs / rhs; + } + BOOST_ASSERT(0); + return 0; + } + + int operator()(signed_ const& x) const + { + int rhs = boost::apply_visitor(*this, x.operand_); + switch (x.sign) + { + case '-': return -rhs; + case '+': return +rhs; + } + BOOST_ASSERT(0); + return 0; + } + + int operator()(program const& x) const + { + int state = boost::apply_visitor(*this, x.first); + BOOST_FOREACH(operation const& oper, x.rest) + { + state = (*this)(oper, state); + } + return state; + } + }; +}} + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // The calculator grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct calculator : qi::grammar<Iterator, ast::program(), ascii::space_type> + { + calculator() : calculator::base_type(expression) + { + qi::uint_type uint_; + qi::char_type char_; + + expression = + term + >> *( (char_('+') >> term) + | (char_('-') >> term) + ) + ; + + term = + factor + >> *( (char_('*') >> factor) + | (char_('/') >> factor) + ) + ; + + factor = + uint_ + | '(' >> expression >> ')' + | (char_('-') >> factor) + | (char_('+') >> factor) + ; + } + + qi::rule<Iterator, ast::program(), ascii::space_type> expression; + qi::rule<Iterator, ast::program(), ascii::space_type> term; + qi::rule<Iterator, ast::operand(), ascii::space_type> factor; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Expression parser...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type an expression...or [q or Q] to quit\n\n"; + + typedef std::string::const_iterator iterator_type; + typedef client::calculator<iterator_type> calculator; + typedef client::ast::program ast_program; + typedef client::ast::printer ast_print; + typedef client::ast::eval ast_eval; + + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + calculator calc; // Our grammar + ast_program program; // Our program (AST) + ast_print print; // Prints the program + ast_eval eval; // Evaluates the program + + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + boost::spirit::ascii::space_type space; + bool r = phrase_parse(iter, end, calc, space, program); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + print(program); + std::cout << "\nResult: " << eval(program) << std::endl; + std::cout << "-------------------------\n"; + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \" " << rest << "\"\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc5.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc5.cpp new file mode 100644 index 00000000..8aa71342 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc5.cpp @@ -0,0 +1,339 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Same as Calc4, this time, we'll incorporate debugging support, +// plus error handling and reporting. +// +// [ JDG April 28, 2008 ] For BoostCon 2008 +// [ JDG February 18, 2011 ] Pure attributes. No semantic actions. +// +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Spirit v2.5 allows you to suppress automatic generation +// of predefined terminals to speed up complation. With +// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are +// responsible in creating instances of the terminals that +// you need (e.g. see qi::uint_type uint_ below). +#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Define this to enable debugging +#define BOOST_SPIRIT_QI_DEBUG + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment this if you want to enable debugging +//#define BOOST_SPIRIT_QI_DEBUG +/////////////////////////////////////////////////////////////////////////////// + +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/variant/recursive_variant.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/spirit/include/phoenix_function.hpp> +#include <boost/foreach.hpp> + +#include <iostream> +#include <string> + +namespace client { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + // The AST + /////////////////////////////////////////////////////////////////////////// + struct nil {}; + struct signed_; + struct program; + + typedef boost::variant< + nil + , unsigned int + , boost::recursive_wrapper<signed_> + , boost::recursive_wrapper<program> + > + operand; + + struct signed_ + { + char sign; + operand operand_; + }; + + struct operation + { + char operator_; + operand operand_; + }; + + struct program + { + operand first; + std::list<operation> rest; + }; + + // print function for debugging + inline std::ostream& operator<<(std::ostream& out, nil) { out << "nil"; return out; } +}} + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::signed_, + (char, sign) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::operation, + (char, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::program, + (client::ast::operand, first) + (std::list<client::ast::operation>, rest) +) + +namespace client { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + // The AST Printer + /////////////////////////////////////////////////////////////////////////// + struct printer + { + typedef void result_type; + + void operator()(nil) const {} + void operator()(unsigned int n) const { std::cout << n; } + + void operator()(operation const& x) const + { + boost::apply_visitor(*this, x.operand_); + switch (x.operator_) + { + case '+': std::cout << " add"; break; + case '-': std::cout << " subt"; break; + case '*': std::cout << " mult"; break; + case '/': std::cout << " div"; break; + } + } + + void operator()(signed_ const& x) const + { + boost::apply_visitor(*this, x.operand_); + switch (x.sign) + { + case '-': std::cout << " neg"; break; + case '+': std::cout << " pos"; break; + } + } + + void operator()(program const& x) const + { + boost::apply_visitor(*this, x.first); + BOOST_FOREACH(operation const& oper, x.rest) + { + std::cout << ' '; + (*this)(oper); + } + } + }; + + /////////////////////////////////////////////////////////////////////////// + // The AST evaluator + /////////////////////////////////////////////////////////////////////////// + struct eval + { + typedef int result_type; + + int operator()(nil) const { BOOST_ASSERT(0); return 0; } + int operator()(unsigned int n) const { return n; } + + int operator()(operation const& x, int lhs) const + { + int rhs = boost::apply_visitor(*this, x.operand_); + switch (x.operator_) + { + case '+': return lhs + rhs; + case '-': return lhs - rhs; + case '*': return lhs * rhs; + case '/': return lhs / rhs; + } + BOOST_ASSERT(0); + return 0; + } + + int operator()(signed_ const& x) const + { + int rhs = boost::apply_visitor(*this, x.operand_); + switch (x.sign) + { + case '-': return -rhs; + case '+': return +rhs; + } + BOOST_ASSERT(0); + return 0; + } + + int operator()(program const& x) const + { + int state = boost::apply_visitor(*this, x.first); + BOOST_FOREACH(operation const& oper, x.rest) + { + state = (*this)(oper, state); + } + return state; + } + }; +}} + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + using boost::phoenix::function; + + /////////////////////////////////////////////////////////////////////////////// + // Our error handler + /////////////////////////////////////////////////////////////////////////////// + struct error_handler_ + { + template <typename, typename, typename> + struct result { typedef void type; }; + + template <typename Iterator> + void operator()( + qi::info const& what + , Iterator err_pos, Iterator last) const + { + std::cout + << "Error! Expecting " + << what // what failed? + << " here: \"" + << std::string(err_pos, last) // iterators to error-pos, end + << "\"" + << std::endl + ; + } + }; + + function<error_handler_> const error_handler = error_handler_(); + + /////////////////////////////////////////////////////////////////////////////// + // Our calculator grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct calculator : qi::grammar<Iterator, ast::program(), ascii::space_type> + { + calculator() : calculator::base_type(expression) + { + qi::char_type char_; + qi::uint_type uint_; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + using qi::on_error; + using qi::fail; + + expression = + term + >> *( (char_('+') > term) + | (char_('-') > term) + ) + ; + + term = + factor + >> *( (char_('*') > factor) + | (char_('/') > factor) + ) + ; + + factor = + uint_ + | '(' > expression > ')' + | (char_('-') > factor) + | (char_('+') > factor) + ; + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODE(expression); + BOOST_SPIRIT_DEBUG_NODE(term); + BOOST_SPIRIT_DEBUG_NODE(factor); + + // Error handling + on_error<fail>(expression, error_handler(_4, _3, _2)); + } + + qi::rule<Iterator, ast::program(), ascii::space_type> expression; + qi::rule<Iterator, ast::program(), ascii::space_type> term; + qi::rule<Iterator, ast::operand(), ascii::space_type> factor; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Expression parser...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type an expression...or [q or Q] to quit\n\n"; + + typedef std::string::const_iterator iterator_type; + typedef client::calculator<iterator_type> calculator; + typedef client::ast::program ast_program; + typedef client::ast::printer ast_print; + typedef client::ast::eval ast_eval; + + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + calculator calc; // Our grammar + ast_program program; // Our program (AST) + ast_print print; // Prints the program + ast_eval eval; // Evaluates the program + + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + boost::spirit::ascii::space_type space; + bool r = phrase_parse(iter, end, calc, space, program); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + print(program); + std::cout << "\nResult: " << eval(program) << std::endl; + std::cout << "-------------------------\n"; + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc6.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc6.cpp new file mode 100644 index 00000000..af362f3d --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc6.cpp @@ -0,0 +1,373 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Yet another calculator example! This time, we will compile to a simple +// virtual machine. This is actually one of the very first Spirit example +// circa 2000. Now, it's ported to Spirit2. +// +// [ JDG Sometime 2000 ] pre-boost +// [ JDG September 18, 2002 ] spirit1 +// [ JDG April 8, 2007 ] spirit2 +// [ JDG February 18, 2011 ] Pure attributes. No semantic actions. +// +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Spirit v2.5 allows you to suppress automatic generation +// of predefined terminals to speed up complation. With +// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are +// responsible in creating instances of the terminals that +// you need (e.g. see qi::uint_type uint_ below). +#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Define this to enable debugging +//#define BOOST_SPIRIT_QI_DEBUG + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment this if you want to enable debugging +//#define BOOST_SPIRIT_QI_DEBUG +/////////////////////////////////////////////////////////////////////////////// + +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/variant/recursive_variant.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/spirit/include/phoenix_function.hpp> +#include <boost/foreach.hpp> + +#include <iostream> +#include <string> + +namespace client { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + // The AST + /////////////////////////////////////////////////////////////////////////// + struct nil {}; + struct signed_; + struct expression; + + typedef boost::variant< + nil + , unsigned int + , boost::recursive_wrapper<signed_> + , boost::recursive_wrapper<expression> + > + operand; + + struct signed_ + { + char sign; + operand operand_; + }; + + struct operation + { + char operator_; + operand operand_; + }; + + struct expression + { + operand first; + std::list<operation> rest; + }; + + // print function for debugging + inline std::ostream& operator<<(std::ostream& out, nil) { out << "nil"; return out; } +}} + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::signed_, + (char, sign) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::operation, + (char, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::expression, + (client::ast::operand, first) + (std::list<client::ast::operation>, rest) +) + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // The Virtual Machine + /////////////////////////////////////////////////////////////////////////// + enum byte_code + { + op_neg, // negate the top stack entry + op_add, // add top two stack entries + op_sub, // subtract top two stack entries + op_mul, // multiply top two stack entries + op_div, // divide top two stack entries + op_int, // push constant integer into the stack + }; + + class vmachine + { + public: + + vmachine(unsigned stackSize = 4096) + : stack(stackSize) + , stack_ptr(stack.begin()) + { + } + + int top() const { return stack_ptr[-1]; }; + void execute(std::vector<int> const& code); + + private: + + std::vector<int> stack; + std::vector<int>::iterator stack_ptr; + }; + + void vmachine::execute(std::vector<int> const& code) + { + std::vector<int>::const_iterator pc = code.begin(); + stack_ptr = stack.begin(); + + while (pc != code.end()) + { + switch (*pc++) + { + case op_neg: + stack_ptr[-1] = -stack_ptr[-1]; + break; + + case op_add: + --stack_ptr; + stack_ptr[-1] += stack_ptr[0]; + break; + + case op_sub: + --stack_ptr; + stack_ptr[-1] -= stack_ptr[0]; + break; + + case op_mul: + --stack_ptr; + stack_ptr[-1] *= stack_ptr[0]; + break; + + case op_div: + --stack_ptr; + stack_ptr[-1] /= stack_ptr[0]; + break; + + case op_int: + *stack_ptr++ = *pc++; + break; + } + } + } + + /////////////////////////////////////////////////////////////////////////// + // The Compiler + /////////////////////////////////////////////////////////////////////////// + struct compiler + { + typedef void result_type; + + std::vector<int>& code; + compiler(std::vector<int>& code) + : code(code) {} + + void operator()(ast::nil) const { BOOST_ASSERT(0); } + void operator()(unsigned int n) const + { + code.push_back(op_int); + code.push_back(n); + } + + void operator()(ast::operation const& x) const + { + boost::apply_visitor(*this, x.operand_); + switch (x.operator_) + { + case '+': code.push_back(op_add); break; + case '-': code.push_back(op_sub); break; + case '*': code.push_back(op_mul); break; + case '/': code.push_back(op_div); break; + default: BOOST_ASSERT(0); break; + } + } + + void operator()(ast::signed_ const& x) const + { + boost::apply_visitor(*this, x.operand_); + switch (x.sign) + { + case '-': code.push_back(op_neg); break; + case '+': break; + default: BOOST_ASSERT(0); break; + } + } + + void operator()(ast::expression const& x) const + { + boost::apply_visitor(*this, x.first); + BOOST_FOREACH(ast::operation const& oper, x.rest) + { + (*this)(oper); + } + } + }; + + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + using boost::phoenix::function; + + /////////////////////////////////////////////////////////////////////////////// + // The error handler + /////////////////////////////////////////////////////////////////////////////// + struct error_handler_ + { + template <typename, typename, typename> + struct result { typedef void type; }; + + template <typename Iterator> + void operator()( + qi::info const& what + , Iterator err_pos, Iterator last) const + { + std::cout + << "Error! Expecting " + << what // what failed? + << " here: \"" + << std::string(err_pos, last) // iterators to error-pos, end + << "\"" + << std::endl + ; + } + }; + + function<error_handler_> const error_handler = error_handler_(); + + /////////////////////////////////////////////////////////////////////////////// + // The calculator grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct calculator : qi::grammar<Iterator, ast::expression(), ascii::space_type> + { + calculator() : calculator::base_type(expression) + { + qi::char_type char_; + qi::uint_type uint_; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + using qi::on_error; + using qi::fail; + + expression = + term + >> *( (char_('+') > term) + | (char_('-') > term) + ) + ; + + term = + factor + >> *( (char_('*') > factor) + | (char_('/') > factor) + ) + ; + + factor = + uint_ + | '(' > expression > ')' + | (char_('-') > factor) + | (char_('+') > factor) + ; + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (expression)(term)(factor)); + + // Error handling + on_error<fail>(expression, error_handler(_4, _3, _2)); + } + + qi::rule<Iterator, ast::expression(), ascii::space_type> expression; + qi::rule<Iterator, ast::expression(), ascii::space_type> term; + qi::rule<Iterator, ast::operand(), ascii::space_type> factor; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Expression parser...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type an expression...or [q or Q] to quit\n\n"; + + typedef std::string::const_iterator iterator_type; + typedef client::calculator<iterator_type> calculator; + typedef client::ast::expression ast_expression; + typedef client::compiler compiler; + + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + client::vmachine mach; // Our virtual machine + std::vector<int> code; // Our VM code + calculator calc; // Our grammar + ast_expression expression; // Our program (AST) + compiler compile(code); // Compiles the program + + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + boost::spirit::ascii::space_type space; + bool r = phrase_parse(iter, end, calc, space, expression); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + compile(expression); + mach.execute(code); + std::cout << "\nResult: " << mach.top() << std::endl; + std::cout << "-------------------------\n"; + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/annotation.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/annotation.hpp new file mode 100644 index 00000000..37365283 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/annotation.hpp @@ -0,0 +1,78 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC7_ANNOTATION_HPP) +#define BOOST_SPIRIT_CALC7_ANNOTATION_HPP + +#include <map> +#include <boost/variant/apply_visitor.hpp> +#include <boost/type_traits/is_base_of.hpp> +#include <boost/mpl/bool.hpp> +#include "ast.hpp" + +namespace client +{ + /////////////////////////////////////////////////////////////////////////////// + // The annotation handler links the AST to a map of iterator positions + // for the purpose of subsequent semantic error handling when the + // program is being compiled. + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct annotation + { + template <typename, typename> + struct result { typedef void type; }; + + std::vector<Iterator>& iters; + annotation(std::vector<Iterator>& iters) + : iters(iters) {} + + struct set_id + { + typedef void result_type; + + int id; + set_id(int id) : id(id) {} + + template <typename T> + void operator()(T& x) const + { + this->dispatch(x, boost::is_base_of<ast::tagged, T>()); + } + + // This will catch all nodes except those inheriting from ast::tagged + template <typename T> + void dispatch(T& x, boost::mpl::false_) const + { + // (no-op) no need for tags + } + + // This will catch all nodes inheriting from ast::tagged + template <typename T> + void dispatch(T& x, boost::mpl::true_) const + { + x.id = id; + } + }; + + void operator()(ast::operand& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + boost::apply_visitor(set_id(id), ast); + } + + void operator()(ast::assignment& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.lhs.id = id; + } + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/ast.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/ast.hpp new file mode 100644 index 00000000..82fba496 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/ast.hpp @@ -0,0 +1,117 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC7_AST_HPP) +#define BOOST_SPIRIT_CALC7_AST_HPP + +#include <boost/config/warning_disable.hpp> +#include <boost/variant/recursive_variant.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/fusion/include/io.hpp> +#include <list> + +namespace client { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + // The AST + /////////////////////////////////////////////////////////////////////////// + struct tagged + { + int id; // Used to annotate the AST with the iterator position. + // This id is used as a key to a map<int, Iterator> + // (not really part of the AST.) + }; + + struct nil {}; + struct signed_; + struct expression; + + struct variable : tagged + { + variable(std::string const& name = "") : name(name) {} + std::string name; + }; + + typedef boost::variant< + nil + , unsigned int + , variable + , boost::recursive_wrapper<signed_> + , boost::recursive_wrapper<expression> + > + operand; + + struct signed_ + { + char sign; + operand operand_; + }; + + struct operation + { + char operator_; + operand operand_; + }; + + struct expression + { + operand first; + std::list<operation> rest; + }; + + struct assignment + { + variable lhs; + expression rhs; + }; + + struct variable_declaration + { + assignment assign; + }; + + typedef boost::variant< + variable_declaration + , assignment> + statement; + + typedef std::list<statement> statement_list; + + // print functions for debugging + inline std::ostream& operator<<(std::ostream& out, nil) { out << "nil"; return out; } + inline std::ostream& operator<<(std::ostream& out, variable const& var) { out << var.name; return out; } +}} + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::signed_, + (char, sign) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::operation, + (char, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::expression, + (client::ast::operand, first) + (std::list<client::ast::operation>, rest) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::variable_declaration, + (client::ast::assignment, assign) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::assignment, + (client::ast::variable, lhs) + (client::ast::expression, rhs) +) + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.cpp new file mode 100644 index 00000000..8aa23017 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.cpp @@ -0,0 +1,222 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "compiler.hpp" +#include "vm.hpp" +#include <boost/foreach.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/assert.hpp> + +namespace client { namespace code_gen +{ + void program::op(int a) + { + code.push_back(a); + } + + void program::op(int a, int b) + { + code.push_back(a); + code.push_back(b); + } + + void program::op(int a, int b, int c) + { + code.push_back(a); + code.push_back(b); + code.push_back(c); + } + + int const* program::find_var(std::string const& name) const + { + std::map<std::string, int>::const_iterator i = variables.find(name); + if (i == variables.end()) + return 0; + return &i->second; + } + + void program::add_var(std::string const& name) + { + std::size_t n = variables.size(); + variables[name] = n; + } + + void program::print_variables(std::vector<int> const& stack) const + { + typedef std::pair<std::string, int> pair; + BOOST_FOREACH(pair const& p, variables) + { + std::cout << " " << p.first << ": " << stack[p.second] << std::endl; + } + } + + void program::print_assembler() const + { + std::vector<int>::const_iterator pc = code.begin(); + + std::vector<std::string> locals(variables.size()); + typedef std::pair<std::string, int> pair; + BOOST_FOREACH(pair const& p, variables) + { + locals[p.second] = p.first; + std::cout << "local " + << p.first << ", @" << p.second << std::endl; + } + + while (pc != code.end()) + { + switch (*pc++) + { + case op_neg: + std::cout << "op_neg" << std::endl; + break; + + case op_add: + std::cout << "op_add" << std::endl; + break; + + case op_sub: + std::cout << "op_sub" << std::endl; + break; + + case op_mul: + std::cout << "op_mul" << std::endl; + break; + + case op_div: + std::cout << "op_div" << std::endl; + break; + + case op_load: + std::cout << "op_load " << locals[*pc++] << std::endl; + break; + + case op_store: + std::cout << "op_store " << locals[*pc++] << std::endl; + break; + + case op_int: + std::cout << "op_int " << *pc++ << std::endl; + break; + + case op_stk_adj: + std::cout << "op_stk_adj " << *pc++ << std::endl; + break; + } + } + } + + bool compiler::operator()(unsigned int x) const + { + program.op(op_int, x); + return true; + } + + bool compiler::operator()(ast::variable const& x) const + { + int const* p = program.find_var(x.name); + if (p == 0) + { + std::cout << x.id << std::endl; + error_handler(x.id, "Undeclared variable: " + x.name); + return false; + } + program.op(op_load, *p); + return true; + } + + bool compiler::operator()(ast::operation const& x) const + { + if (!boost::apply_visitor(*this, x.operand_)) + return false; + switch (x.operator_) + { + case '+': program.op(op_add); break; + case '-': program.op(op_sub); break; + case '*': program.op(op_mul); break; + case '/': program.op(op_div); break; + default: BOOST_ASSERT(0); return false; + } + return true; + } + + bool compiler::operator()(ast::signed_ const& x) const + { + if (!boost::apply_visitor(*this, x.operand_)) + return false; + switch (x.sign) + { + case '-': program.op(op_neg); break; + case '+': break; + default: BOOST_ASSERT(0); return false; + } + return true; + } + + bool compiler::operator()(ast::expression const& x) const + { + if (!boost::apply_visitor(*this, x.first)) + return false; + BOOST_FOREACH(ast::operation const& oper, x.rest) + { + if (!(*this)(oper)) + return false; + } + return true; + } + + bool compiler::operator()(ast::assignment const& x) const + { + if (!(*this)(x.rhs)) + return false; + int const* p = program.find_var(x.lhs.name); + if (p == 0) + { + std::cout << x.lhs.id << std::endl; + error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name); + return false; + } + program.op(op_store, *p); + return true; + } + + bool compiler::operator()(ast::variable_declaration const& x) const + { + int const* p = program.find_var(x.assign.lhs.name); + if (p != 0) + { + std::cout << x.assign.lhs.id << std::endl; + error_handler(x.assign.lhs.id, "Duplicate variable: " + x.assign.lhs.name); + return false; + } + bool r = (*this)(x.assign.rhs); + if (r) // don't add the variable if the RHS fails + { + program.add_var(x.assign.lhs.name); + program.op(op_store, *program.find_var(x.assign.lhs.name)); + } + return r; + } + + bool compiler::operator()(ast::statement_list const& x) const + { + program.clear(); + + // op_stk_adj 0 for now. we'll know how many variables we'll have later + program.op(op_stk_adj, 0); + BOOST_FOREACH(ast::statement const& s, x) + { + if (!boost::apply_visitor(*this, s)) + { + program.clear(); + return false; + } + } + program[1] = program.nvars(); // now store the actual number of variables + return true; + } +}} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.hpp new file mode 100644 index 00000000..179a315a --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/compiler.hpp @@ -0,0 +1,85 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC7_COMPILER_HPP) +#define BOOST_SPIRIT_CALC7_COMPILER_HPP + +#include "ast.hpp" +#include "error_handler.hpp" +#include <vector> +#include <map> +#include <boost/function.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_function.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> + +namespace client { namespace code_gen +{ + /////////////////////////////////////////////////////////////////////////// + // The Program + /////////////////////////////////////////////////////////////////////////// + struct program + { + void op(int a); + void op(int a, int b); + void op(int a, int b, int c); + + int& operator[](std::size_t i) { return code[i]; } + int const& operator[](std::size_t i) const { return code[i]; } + void clear() { code.clear(); variables.clear(); } + std::vector<int> const& operator()() const { return code; } + + int nvars() const { return variables.size(); } + int const* find_var(std::string const& name) const; + void add_var(std::string const& name); + + void print_variables(std::vector<int> const& stack) const; + void print_assembler() const; + + private: + + std::map<std::string, int> variables; + std::vector<int> code; + }; + + /////////////////////////////////////////////////////////////////////////// + // The Compiler + /////////////////////////////////////////////////////////////////////////// + struct compiler + { + typedef bool result_type; + + template <typename ErrorHandler> + compiler(client::code_gen::program& program, ErrorHandler& error_handler_) + : program(program) + { + using namespace boost::phoenix::arg_names; + namespace phx = boost::phoenix; + using boost::phoenix::function; + + error_handler = function<ErrorHandler>(error_handler_)( + "Error! ", _2, phx::cref(error_handler_.iters)[_1]); + } + + bool operator()(ast::nil) const { BOOST_ASSERT(0); return false; } + bool operator()(unsigned int x) const; + bool operator()(ast::variable const& x) const; + bool operator()(ast::operation const& x) const; + bool operator()(ast::signed_ const& x) const; + bool operator()(ast::expression const& x) const; + bool operator()(ast::assignment const& x) const; + bool operator()(ast::variable_declaration const& x) const; + bool operator()(ast::statement_list const& x) const; + + client::code_gen::program& program; + + boost::function< + void(int tag, std::string const& what)> + error_handler; + }; +}} + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/error_handler.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/error_handler.hpp new file mode 100644 index 00000000..867e9ee7 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/error_handler.hpp @@ -0,0 +1,93 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC7_ERROR_HANDLER_HPP) +#define BOOST_SPIRIT_CALC7_ERROR_HANDLER_HPP + +#include <iostream> +#include <string> +#include <vector> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////////// + // The error handler + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct error_handler + { + template <typename, typename, typename> + struct result { typedef void type; }; + + error_handler(Iterator first, Iterator last) + : first(first), last(last) {} + + template <typename Message, typename What> + void operator()( + Message const& message, + What const& what, + Iterator err_pos) const + { + int line; + Iterator line_start = get_pos(err_pos, line); + if (err_pos != last) + { + std::cout << message << what << " line " << line << ':' << std::endl; + std::cout << get_line(line_start) << std::endl; + for (; line_start != err_pos; ++line_start) + std::cout << ' '; + std::cout << '^' << std::endl; + } + else + { + std::cout << "Unexpected end of file. "; + std::cout << message << what << " line " << line << std::endl; + } + } + + Iterator get_pos(Iterator err_pos, int& line) const + { + line = 1; + Iterator i = first; + Iterator line_start = first; + while (i != err_pos) + { + bool eol = false; + if (i != err_pos && *i == '\r') // CR + { + eol = true; + line_start = ++i; + } + if (i != err_pos && *i == '\n') // LF + { + eol = true; + line_start = ++i; + } + if (eol) + ++line; + else + ++i; + } + return line_start; + } + + std::string get_line(Iterator err_pos) const + { + Iterator i = err_pos; + // position i to the next EOL + while (i != last && (*i != '\r' && *i != '\n')) + ++i; + return std::string(err_pos, i); + } + + Iterator first; + Iterator last; + std::vector<Iterator> iters; + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/expression.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/expression.cpp new file mode 100644 index 00000000..32f44adc --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/expression.cpp @@ -0,0 +1,14 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "expression_def.hpp" + +typedef std::string::const_iterator iterator_type; +template struct client::parser::expression<iterator_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/expression.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/expression.hpp new file mode 100644 index 00000000..916e26e7 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/expression.hpp @@ -0,0 +1,53 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC7_EXPRESSION_HPP) +#define BOOST_SPIRIT_CALC7_EXPRESSION_HPP + +/////////////////////////////////////////////////////////////////////////////// +// Spirit v2.5 allows you to suppress automatic generation +// of predefined terminals to speed up complation. With +// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are +// responsible in creating instances of the terminals that +// you need (e.g. see qi::uint_type uint_ below). +#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment this if you want to enable debugging +// #define BOOST_SPIRIT_QI_DEBUG +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/spirit/include/qi.hpp> +#include "ast.hpp" +#include "error_handler.hpp" +#include <vector> + +namespace client { namespace parser +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // The expression grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct expression : qi::grammar<Iterator, ast::expression(), ascii::space_type> + { + expression(error_handler<Iterator>& error_handler); + + qi::rule<Iterator, ast::expression(), ascii::space_type> expr; + qi::rule<Iterator, ast::expression(), ascii::space_type> additive_expr; + qi::rule<Iterator, ast::expression(), ascii::space_type> multiplicative_expr; + qi::rule<Iterator, ast::operand(), ascii::space_type> unary_expr; + qi::rule<Iterator, ast::operand(), ascii::space_type> primary_expr; + qi::rule<Iterator, std::string(), ascii::space_type> identifier; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/expression_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/expression_def.hpp new file mode 100644 index 00000000..2770677c --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/expression_def.hpp @@ -0,0 +1,94 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "expression.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" +#include <boost/spirit/include/phoenix_function.hpp> + +namespace client { namespace parser +{ + template <typename Iterator> + expression<Iterator>::expression(error_handler<Iterator>& error_handler) + : expression::base_type(expr) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::char_type char_; + qi::uint_type uint_; + qi::_val_type _val; + qi::raw_type raw; + qi::lexeme_type lexeme; + qi::alpha_type alpha; + qi::alnum_type alnum; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef function<client::error_handler<Iterator> > error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + expr = + additive_expr.alias() + ; + + additive_expr = + multiplicative_expr + >> *( (char_('+') > multiplicative_expr) + | (char_('-') > multiplicative_expr) + ) + ; + + multiplicative_expr = + unary_expr + >> *( (char_('*') > unary_expr) + | (char_('/') > unary_expr) + ) + ; + + unary_expr = + primary_expr + | (char_('-') > primary_expr) + | (char_('+') > primary_expr) + ; + + primary_expr = + uint_ + | identifier + | '(' > expr > ')' + ; + + identifier = + raw[lexeme[(alpha | '_') >> *(alnum | '_')]] + ; + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (expr) + (additive_expr) + (multiplicative_expr) + (unary_expr) + (primary_expr) + (identifier) + ); + + // Error handling: on error in expr, call error_handler. + on_error<fail>(expr, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + // Annotation: on success in primary_expr, call annotation. + on_success(primary_expr, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/main.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/main.cpp new file mode 100644 index 00000000..4e139eb2 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/main.cpp @@ -0,0 +1,101 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Now we'll introduce variables and assignment. This time, we'll also +// be renaming some of the rules -- a strategy for a grander scheme +// to come ;-) +// +// This version also shows off grammar modularization. Here you will +// see how expressions and statements are built as modular grammars. +// +// [ JDG April 9, 2007 ] spirit2 +// [ JDG February 18, 2011 ] Pure attributes. No semantic actions. +// +/////////////////////////////////////////////////////////////////////////////// + +#include "statement.hpp" +#include "vm.hpp" +#include "compiler.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Statement parser...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type some statements... "; + std::cout << "An empty line ends input, compiles, runs and prints results\n\n"; + std::cout << "Example:\n\n"; + std::cout << " var a = 123;\n"; + std::cout << " var b = 456;\n"; + std::cout << " var c = a + b * 2;\n\n"; + std::cout << "-------------------------\n"; + + std::string str; + std::string source; + while (std::getline(std::cin, str)) + { + if (str.empty()) + break; + source += str + '\n'; + } + + typedef std::string::const_iterator iterator_type; + iterator_type iter = source.begin(); + iterator_type end = source.end(); + + client::vmachine vm; // Our virtual machine + client::code_gen::program program; // Our VM program + client::ast::statement_list ast; // Our AST + + client::error_handler<iterator_type> + error_handler(iter, end); // Our error handler + client::parser::statement<iterator_type> + parser(error_handler); // Our parser + client::code_gen::compiler + compile(program, error_handler); // Our compiler + + boost::spirit::ascii::space_type space; + bool success = phrase_parse(iter, end, parser, space, ast); + + std::cout << "-------------------------\n"; + + if (success && iter == end) + { + if (compile(ast)) + { + std::cout << "Success\n"; + std::cout << "-------------------------\n"; + vm.execute(program()); + + std::cout << "-------------------------\n"; + std::cout << "Assembler----------------\n\n"; + program.print_assembler(); + + std::cout << "-------------------------\n"; + std::cout << "Results------------------\n\n"; + program.print_variables(vm.get_stack()); + } + else + { + std::cout << "Compile failure\n"; + } + } + else + { + std::cout << "Parse failure\n"; + } + + std::cout << "-------------------------\n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/statement.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/statement.cpp new file mode 100644 index 00000000..54bc9ac3 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/statement.cpp @@ -0,0 +1,14 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "statement_def.hpp" + +typedef std::string::const_iterator iterator_type; +template struct client::parser::statement<iterator_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/statement.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/statement.hpp new file mode 100644 index 00000000..12baf38f --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/statement.hpp @@ -0,0 +1,32 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC7_STATEMENT_HPP) +#define BOOST_SPIRIT_CALC7_STATEMENT_HPP + +#include "expression.hpp" + +namespace client { namespace parser +{ + /////////////////////////////////////////////////////////////////////////////// + // The statement grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct statement : qi::grammar<Iterator, ast::statement_list(), ascii::space_type> + { + statement(error_handler<Iterator>& error_handler); + + expression<Iterator> expr; + qi::rule<Iterator, ast::statement_list(), ascii::space_type> statement_list; + qi::rule<Iterator, ast::variable_declaration(), ascii::space_type> variable_declaration; + qi::rule<Iterator, ast::assignment(), ascii::space_type> assignment; + qi::rule<Iterator, std::string(), ascii::space_type> identifier; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/statement_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/statement_def.hpp new file mode 100644 index 00000000..408a2368 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/statement_def.hpp @@ -0,0 +1,75 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "statement.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" + +namespace client { namespace parser +{ + template <typename Iterator> + statement<Iterator>::statement(error_handler<Iterator>& error_handler) + : statement::base_type(statement_list), expr(error_handler) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::_val_type _val; + qi::raw_type raw; + qi::lexeme_type lexeme; + qi::alpha_type alpha; + qi::alnum_type alnum; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef function<client::error_handler<Iterator> > error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + statement_list = + +(variable_declaration | assignment) + ; + + identifier = + raw[lexeme[(alpha | '_') >> *(alnum | '_')]] + ; + + variable_declaration = + lexeme["var" >> !(alnum | '_')] // make sure we have whole words + > assignment + ; + + assignment = + identifier + > '=' + > expr + > ';' + ; + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (statement_list) + (identifier) + (variable_declaration) + (assignment) + ); + + // Error handling: on error in statement_list, call error_handler. + on_error<fail>(statement_list, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + // Annotation: on success in assignment, call annotation. + on_success(assignment, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/vm.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/vm.cpp new file mode 100644 index 00000000..c481f2b7 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/vm.cpp @@ -0,0 +1,66 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "vm.hpp" + +namespace client +{ + void vmachine::execute(std::vector<int> const& code) + { + std::vector<int>::const_iterator pc = code.begin(); + std::vector<int>::iterator locals = stack.begin(); + stack_ptr = stack.begin(); + + while (pc != code.end()) + { + switch (*pc++) + { + case op_neg: + stack_ptr[-1] = -stack_ptr[-1]; + break; + + case op_add: + --stack_ptr; + stack_ptr[-1] += stack_ptr[0]; + break; + + case op_sub: + --stack_ptr; + stack_ptr[-1] -= stack_ptr[0]; + break; + + case op_mul: + --stack_ptr; + stack_ptr[-1] *= stack_ptr[0]; + break; + + case op_div: + --stack_ptr; + stack_ptr[-1] /= stack_ptr[0]; + break; + + case op_load: + *stack_ptr++ = locals[*pc++]; + break; + + case op_store: + --stack_ptr; + locals[*pc++] = stack_ptr[0]; + break; + + case op_int: + *stack_ptr++ = *pc++; + break; + + case op_stk_adj: + stack_ptr = stack.begin() + *pc++; + break; + } + } + } +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/vm.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/vm.hpp new file mode 100644 index 00000000..853aa9c7 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc7/vm.hpp @@ -0,0 +1,52 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC7_VM_HPP) +#define BOOST_SPIRIT_CALC7_VM_HPP + +#include <vector> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // The Virtual Machine + /////////////////////////////////////////////////////////////////////////// + enum byte_code + { + op_neg, // negate the top stack entry + op_add, // add top two stack entries + op_sub, // subtract top two stack entries + op_mul, // multiply top two stack entries + op_div, // divide top two stack entries + + op_load, // load a variable + op_store, // store a variable + op_int, // push constant integer into the stack + op_stk_adj // adjust the stack for local variables + }; + + class vmachine + { + public: + + vmachine(unsigned stackSize = 4096) + : stack(stackSize) + , stack_ptr(stack.begin()) + { + } + + void execute(std::vector<int> const& code); + std::vector<int> const& get_stack() const { return stack; }; + + private: + + std::vector<int> stack; + std::vector<int>::iterator stack_ptr; + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/annotation.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/annotation.hpp new file mode 100644 index 00000000..8cd00973 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/annotation.hpp @@ -0,0 +1,78 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC8_ANNOTATION_HPP) +#define BOOST_SPIRIT_CALC8_ANNOTATION_HPP + +#include <map> +#include <boost/variant/apply_visitor.hpp> +#include <boost/type_traits/is_base_of.hpp> +#include <boost/mpl/bool.hpp> +#include "ast.hpp" + +namespace client +{ + /////////////////////////////////////////////////////////////////////////////// + // The annotation handler links the AST to a map of iterator positions + // for the purpose of subsequent semantic error handling when the + // program is being compiled. + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct annotation + { + template <typename, typename> + struct result { typedef void type; }; + + std::vector<Iterator>& iters; + annotation(std::vector<Iterator>& iters) + : iters(iters) {} + + struct set_id + { + typedef void result_type; + + int id; + set_id(int id) : id(id) {} + + template <typename T> + void operator()(T& x) const + { + this->dispatch(x, boost::is_base_of<ast::tagged, T>()); + } + + // This will catch all nodes except those inheriting from ast::tagged + template <typename T> + void dispatch(T& x, boost::mpl::false_) const + { + // (no-op) no need for tags + } + + // This will catch all nodes inheriting from ast::tagged + template <typename T> + void dispatch(T& x, boost::mpl::true_) const + { + x.id = id; + } + }; + + void operator()(ast::operand& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + boost::apply_visitor(set_id(id), ast); + } + + void operator()(ast::assignment& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.lhs.id = id; + } + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/ast.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/ast.hpp new file mode 100644 index 00000000..3e6e2d79 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/ast.hpp @@ -0,0 +1,172 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC8_AST_HPP) +#define BOOST_SPIRIT_CALC8_AST_HPP + +#include <boost/config/warning_disable.hpp> +#include <boost/variant/recursive_variant.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/fusion/include/io.hpp> +#include <boost/optional.hpp> +#include <list> + +namespace client { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + // The AST + /////////////////////////////////////////////////////////////////////////// + struct tagged + { + int id; // Used to annotate the AST with the iterator position. + // This id is used as a key to a map<int, Iterator> + // (not really part of the AST.) + }; + + struct nil {}; + struct unary; + struct expression; + + struct variable : tagged + { + variable(std::string const& name = "") : name(name) {} + std::string name; + }; + + typedef boost::variant< + nil + , bool + , unsigned int + , variable + , boost::recursive_wrapper<unary> + , boost::recursive_wrapper<expression> + > + operand; + + enum optoken + { + op_plus, + op_minus, + op_times, + op_divide, + op_positive, + op_negative, + op_not, + op_equal, + op_not_equal, + op_less, + op_less_equal, + op_greater, + op_greater_equal, + op_and, + op_or + }; + + struct unary + { + optoken operator_; + operand operand_; + }; + + struct operation + { + optoken operator_; + operand operand_; + }; + + struct expression + { + operand first; + std::list<operation> rest; + }; + + struct assignment + { + variable lhs; + expression rhs; + }; + + struct variable_declaration + { + assignment assign; + }; + + struct if_statement; + struct while_statement; + struct statement_list; + + typedef boost::variant< + variable_declaration + , assignment + , boost::recursive_wrapper<if_statement> + , boost::recursive_wrapper<while_statement> + , boost::recursive_wrapper<statement_list> + > + statement; + + struct statement_list : std::list<statement> {}; + + struct if_statement + { + expression condition; + statement then; + boost::optional<statement> else_; + }; + + struct while_statement + { + expression condition; + statement body; + }; + + // print functions for debugging + inline std::ostream& operator<<(std::ostream& out, nil) { out << "nil"; return out; } + inline std::ostream& operator<<(std::ostream& out, variable const& var) { out << var.name; return out; } +}} + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::unary, + (client::ast::optoken, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::operation, + (client::ast::optoken, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::expression, + (client::ast::operand, first) + (std::list<client::ast::operation>, rest) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::variable_declaration, + (client::ast::assignment, assign) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::assignment, + (client::ast::variable, lhs) + (client::ast::expression, rhs) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::if_statement, + (client::ast::expression, condition) + (client::ast::statement, then) + (boost::optional<client::ast::statement>, else_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::while_statement, + (client::ast::expression, condition) + (client::ast::statement, body) +) + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/compiler.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/compiler.cpp new file mode 100644 index 00000000..2d8b3eb1 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/compiler.cpp @@ -0,0 +1,382 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "compiler.hpp" +#include "vm.hpp" +#include <boost/foreach.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/assert.hpp> +#include <boost/lexical_cast.hpp> +#include <set> + +namespace client { namespace code_gen +{ + void program::op(int a) + { + code.push_back(a); + } + + void program::op(int a, int b) + { + code.push_back(a); + code.push_back(b); + } + + void program::op(int a, int b, int c) + { + code.push_back(a); + code.push_back(b); + code.push_back(c); + } + + int const* program::find_var(std::string const& name) const + { + std::map<std::string, int>::const_iterator i = variables.find(name); + if (i == variables.end()) + return 0; + return &i->second; + } + + void program::add_var(std::string const& name) + { + std::size_t n = variables.size(); + variables[name] = n; + } + + void program::print_variables(std::vector<int> const& stack) const + { + typedef std::pair<std::string, int> pair; + BOOST_FOREACH(pair const& p, variables) + { + std::cout << " " << p.first << ": " << stack[p.second] << std::endl; + } + } + + void program::print_assembler() const + { + std::vector<int>::const_iterator pc = code.begin(); + + std::vector<std::string> locals(variables.size()); + typedef std::pair<std::string, int> pair; + BOOST_FOREACH(pair const& p, variables) + { + locals[p.second] = p.first; + std::cout << " local " + << p.first << ", @" << p.second << std::endl; + } + + std::map<std::size_t, std::string> lines; + std::set<std::size_t> jumps; + + while (pc != code.end()) + { + std::string line; + std::size_t address = pc - code.begin(); + + switch (*pc++) + { + case op_neg: + line += " op_neg"; + break; + + case op_not: + line += " op_not"; + break; + + case op_add: + line += " op_add"; + break; + + case op_sub: + line += " op_sub"; + break; + + case op_mul: + line += " op_mul"; + break; + + case op_div: + line += " op_div"; + break; + + case op_eq: + line += " op_eq"; + break; + + case op_neq: + line += " op_neq"; + break; + + case op_lt: + line += " op_lt"; + break; + + case op_lte: + line += " op_lte"; + break; + + case op_gt: + line += " op_gt"; + break; + + case op_gte: + line += " op_gte"; + break; + + case op_and: + line += " op_and"; + break; + + case op_or: + line += " op_or"; + break; + + case op_load: + line += " op_load "; + line += locals[*pc++]; + break; + + case op_store: + line += " op_store "; + line += locals[*pc++]; + break; + + case op_int: + line += " op_int "; + line += boost::lexical_cast<std::string>(*pc++); + break; + + case op_true: + line += " op_true"; + break; + + case op_false: + line += " op_false"; + break; + + case op_jump: + { + line += " op_jump "; + std::size_t pos = (pc - code.begin()) + *pc++; + if (pos == code.size()) + line += "end"; + else + line += boost::lexical_cast<std::string>(pos); + jumps.insert(pos); + } + break; + + case op_jump_if: + { + line += " op_jump_if "; + std::size_t pos = (pc - code.begin()) + *pc++; + if (pos == code.size()) + line += "end"; + else + line += boost::lexical_cast<std::string>(pos); + jumps.insert(pos); + } + break; + + case op_stk_adj: + line += " op_stk_adj "; + line += boost::lexical_cast<std::string>(*pc++); + break; + } + lines[address] = line; + } + + std::cout << "start:" << std::endl; + typedef std::pair<std::size_t, std::string> line_info; + BOOST_FOREACH(line_info const& l, lines) + { + std::size_t pos = l.first; + if (jumps.find(pos) != jumps.end()) + std::cout << pos << ':' << std::endl; + std::cout << l.second << std::endl; + } + + std::cout << "end:" << std::endl; + } + + bool compiler::operator()(unsigned int x) const + { + program.op(op_int, x); + return true; + } + + bool compiler::operator()(bool x) const + { + program.op(x ? op_true : op_false); + return true; + } + + bool compiler::operator()(ast::variable const& x) const + { + int const* p = program.find_var(x.name); + if (p == 0) + { + std::cout << x.id << std::endl; + error_handler(x.id, "Undeclared variable: " + x.name); + return false; + } + program.op(op_load, *p); + return true; + } + + bool compiler::operator()(ast::operation const& x) const + { + if (!boost::apply_visitor(*this, x.operand_)) + return false; + switch (x.operator_) + { + case ast::op_plus: program.op(op_add); break; + case ast::op_minus: program.op(op_sub); break; + case ast::op_times: program.op(op_mul); break; + case ast::op_divide: program.op(op_div); break; + + case ast::op_equal: program.op(op_eq); break; + case ast::op_not_equal: program.op(op_neq); break; + case ast::op_less: program.op(op_lt); break; + case ast::op_less_equal: program.op(op_lte); break; + case ast::op_greater: program.op(op_gt); break; + case ast::op_greater_equal: program.op(op_gte); break; + + case ast::op_and: program.op(op_and); break; + case ast::op_or: program.op(op_or); break; + default: BOOST_ASSERT(0); return false; + } + return true; + } + + bool compiler::operator()(ast::unary const& x) const + { + if (!boost::apply_visitor(*this, x.operand_)) + return false; + switch (x.operator_) + { + case ast::op_negative: program.op(op_neg); break; + case ast::op_not: program.op(op_not); break; + case ast::op_positive: break; + default: BOOST_ASSERT(0); return false; + } + return true; + } + + bool compiler::operator()(ast::expression const& x) const + { + if (!boost::apply_visitor(*this, x.first)) + return false; + BOOST_FOREACH(ast::operation const& oper, x.rest) + { + if (!(*this)(oper)) + return false; + } + return true; + } + + bool compiler::operator()(ast::assignment const& x) const + { + if (!(*this)(x.rhs)) + return false; + int const* p = program.find_var(x.lhs.name); + if (p == 0) + { + std::cout << x.lhs.id << std::endl; + error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name); + return false; + } + program.op(op_store, *p); + return true; + } + + bool compiler::operator()(ast::variable_declaration const& x) const + { + int const* p = program.find_var(x.assign.lhs.name); + if (p != 0) + { + std::cout << x.assign.lhs.id << std::endl; + error_handler(x.assign.lhs.id, "Duplicate variable: " + x.assign.lhs.name); + return false; + } + bool r = (*this)(x.assign.rhs); + if (r) // don't add the variable if the RHS fails + { + program.add_var(x.assign.lhs.name); + program.op(op_store, *program.find_var(x.assign.lhs.name)); + } + return r; + } + + bool compiler::operator()(ast::statement const& x) const + { + return boost::apply_visitor(*this, x); + } + + bool compiler::operator()(ast::statement_list const& x) const + { + BOOST_FOREACH(ast::statement const& s, x) + { + if (!(*this)(s)) + return false; + } + return true; + } + + bool compiler::operator()(ast::if_statement const& x) const + { + if (!(*this)(x.condition)) + return false; + program.op(op_jump_if, 0); // we shall fill this (0) in later + std::size_t skip = program.size()-1; // mark its position + if (!(*this)(x.then)) + return false; + program[skip] = program.size()-skip; // now we know where to jump to (after the if branch) + + if (x.else_) // We got an alse + { + program[skip] += 2; // adjust for the "else" jump + program.op(op_jump, 0); // we shall fill this (0) in later + std::size_t exit = program.size()-1; // mark its position + if (!(*this)(*x.else_)) + return false; + program[exit] = program.size()-exit; // now we know where to jump to (after the else branch) + } + + return true; + } + + bool compiler::operator()(ast::while_statement const& x) const + { + std::size_t loop = program.size(); // mark our position + if (!(*this)(x.condition)) + return false; + program.op(op_jump_if, 0); // we shall fill this (0) in later + std::size_t exit = program.size()-1; // mark its position + if (!(*this)(x.body)) + return false; + program.op(op_jump, + int(loop-1) - int(program.size())); // loop back + program[exit] = program.size()-exit; // now we know where to jump to (to exit the loop) + return true; + } + + bool compiler::start(ast::statement_list const& x) const + { + program.clear(); + // op_stk_adj 0 for now. we'll know how many variables we'll have later + program.op(op_stk_adj, 0); + + if (!(*this)(x)) + { + program.clear(); + return false; + } + program[1] = program.nvars(); // now store the actual number of variables + return true; + } +}} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/compiler.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/compiler.hpp new file mode 100644 index 00000000..915a87d0 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/compiler.hpp @@ -0,0 +1,92 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC8_COMPILER_HPP) +#define BOOST_SPIRIT_CALC8_COMPILER_HPP + +#include "ast.hpp" +#include "error_handler.hpp" +#include <vector> +#include <map> +#include <boost/function.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_function.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> + +namespace client { namespace code_gen +{ + /////////////////////////////////////////////////////////////////////////// + // The Program + /////////////////////////////////////////////////////////////////////////// + struct program + { + void op(int a); + void op(int a, int b); + void op(int a, int b, int c); + + int& operator[](std::size_t i) { return code[i]; } + int const& operator[](std::size_t i) const { return code[i]; } + void clear() { code.clear(); variables.clear(); } + std::size_t size() const { return code.size(); } + std::vector<int> const& operator()() const { return code; } + + int nvars() const { return variables.size(); } + int const* find_var(std::string const& name) const; + void add_var(std::string const& name); + + void print_variables(std::vector<int> const& stack) const; + void print_assembler() const; + + private: + + std::map<std::string, int> variables; + std::vector<int> code; + }; + + /////////////////////////////////////////////////////////////////////////// + // The Compiler + /////////////////////////////////////////////////////////////////////////// + struct compiler + { + typedef bool result_type; + + template <typename ErrorHandler> + compiler(client::code_gen::program& program, ErrorHandler& error_handler_) + : program(program) + { + using namespace boost::phoenix::arg_names; + namespace phx = boost::phoenix; + using boost::phoenix::function; + + error_handler = function<ErrorHandler>(error_handler_)( + "Error! ", _2, phx::cref(error_handler_.iters)[_1]); + } + + bool operator()(ast::nil) const { BOOST_ASSERT(0); return false; } + bool operator()(unsigned int x) const; + bool operator()(bool x) const; + bool operator()(ast::variable const& x) const; + bool operator()(ast::operation const& x) const; + bool operator()(ast::unary const& x) const; + bool operator()(ast::expression const& x) const; + bool operator()(ast::assignment const& x) const; + bool operator()(ast::variable_declaration const& x) const; + bool operator()(ast::statement_list const& x) const; + bool operator()(ast::statement const& x) const; + bool operator()(ast::if_statement const& x) const; + bool operator()(ast::while_statement const& x) const; + + bool start(ast::statement_list const& x) const; + + client::code_gen::program& program; + + boost::function< + void(int tag, std::string const& what)> + error_handler; + }; +}} + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/error_handler.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/error_handler.hpp new file mode 100644 index 00000000..0cc42ca9 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/error_handler.hpp @@ -0,0 +1,93 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC8_ERROR_HANDLER_HPP) +#define BOOST_SPIRIT_CALC8_ERROR_HANDLER_HPP + +#include <iostream> +#include <string> +#include <vector> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////////// + // The error handler + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct error_handler + { + template <typename, typename, typename> + struct result { typedef void type; }; + + error_handler(Iterator first, Iterator last) + : first(first), last(last) {} + + template <typename Message, typename What> + void operator()( + Message const& message, + What const& what, + Iterator err_pos) const + { + int line; + Iterator line_start = get_pos(err_pos, line); + if (err_pos != last) + { + std::cout << message << what << " line " << line << ':' << std::endl; + std::cout << get_line(line_start) << std::endl; + for (; line_start != err_pos; ++line_start) + std::cout << ' '; + std::cout << '^' << std::endl; + } + else + { + std::cout << "Unexpected end of file. "; + std::cout << message << what << " line " << line << std::endl; + } + } + + Iterator get_pos(Iterator err_pos, int& line) const + { + line = 1; + Iterator i = first; + Iterator line_start = first; + while (i != err_pos) + { + bool eol = false; + if (i != err_pos && *i == '\r') // CR + { + eol = true; + line_start = ++i; + } + if (i != err_pos && *i == '\n') // LF + { + eol = true; + line_start = ++i; + } + if (eol) + ++line; + else + ++i; + } + return line_start; + } + + std::string get_line(Iterator err_pos) const + { + Iterator i = err_pos; + // position i to the next EOL + while (i != last && (*i != '\r' && *i != '\n')) + ++i; + return std::string(err_pos, i); + } + + Iterator first; + Iterator last; + std::vector<Iterator> iters; + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/expression.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/expression.cpp new file mode 100644 index 00000000..32f44adc --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/expression.cpp @@ -0,0 +1,14 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "expression_def.hpp" + +typedef std::string::const_iterator iterator_type; +template struct client::parser::expression<iterator_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/expression.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/expression.hpp new file mode 100644 index 00000000..e5770bb1 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/expression.hpp @@ -0,0 +1,68 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC8_EXPRESSION_HPP) +#define BOOST_SPIRIT_CALC8_EXPRESSION_HPP + +/////////////////////////////////////////////////////////////////////////////// +// Spirit v2.5 allows you to suppress automatic generation +// of predefined terminals to speed up complation. With +// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are +// responsible in creating instances of the terminals that +// you need (e.g. see qi::uint_type uint_ below). +#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment this if you want to enable debugging +// #define BOOST_SPIRIT_QI_DEBUG +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/spirit/include/qi.hpp> +#include "ast.hpp" +#include "error_handler.hpp" +#include <vector> + +namespace client { namespace parser +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // The expression grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct expression : qi::grammar<Iterator, ast::expression(), ascii::space_type> + { + expression(error_handler<Iterator>& error_handler); + + qi::rule<Iterator, ast::expression(), ascii::space_type> + expr, equality_expr, relational_expr, + logical_expr, additive_expr, multiplicative_expr + ; + + qi::rule<Iterator, ast::operand(), ascii::space_type> + unary_expr, primary_expr + ; + + qi::rule<Iterator, std::string(), ascii::space_type> + identifier + ; + + qi::symbols<char, ast::optoken> + equality_op, relational_op, logical_op, + additive_op, multiplicative_op, unary_op + ; + + qi::symbols<char> + keywords + ; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/expression_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/expression_def.hpp new file mode 100644 index 00000000..608992c3 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/expression_def.hpp @@ -0,0 +1,159 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "expression.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" +#include <boost/spirit/include/phoenix_function.hpp> + +namespace client { namespace parser +{ + template <typename Iterator> + expression<Iterator>::expression(error_handler<Iterator>& error_handler) + : expression::base_type(expr) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::char_type char_; + qi::uint_type uint_; + qi::_val_type _val; + qi::raw_type raw; + qi::lexeme_type lexeme; + qi::alpha_type alpha; + qi::alnum_type alnum; + qi::bool_type bool_; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef function<client::error_handler<Iterator> > error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + /////////////////////////////////////////////////////////////////////// + // Tokens + logical_op.add + ("&&", ast::op_and) + ("||", ast::op_or) + ; + + equality_op.add + ("==", ast::op_equal) + ("!=", ast::op_not_equal) + ; + + relational_op.add + ("<", ast::op_less) + ("<=", ast::op_less_equal) + (">", ast::op_greater) + (">=", ast::op_greater_equal) + ; + + additive_op.add + ("+", ast::op_plus) + ("-", ast::op_minus) + ; + + multiplicative_op.add + ("*", ast::op_times) + ("/", ast::op_divide) + ; + + unary_op.add + ("+", ast::op_positive) + ("-", ast::op_negative) + ("!", ast::op_not) + ; + + keywords.add + ("var") + ("true") + ("false") + ("if") + ("else") + ("while") + ; + + /////////////////////////////////////////////////////////////////////// + // Main expression grammar + expr = + logical_expr.alias() + ; + + logical_expr = + equality_expr + >> *(logical_op > equality_expr) + ; + + equality_expr = + relational_expr + >> *(equality_op > relational_expr) + ; + + relational_expr = + additive_expr + >> *(relational_op > additive_expr) + ; + + additive_expr = + multiplicative_expr + >> *(additive_op > multiplicative_expr) + ; + + multiplicative_expr = + unary_expr + >> *(multiplicative_op > unary_expr) + ; + + unary_expr = + primary_expr + | (unary_op > primary_expr) + ; + + primary_expr = + uint_ + | identifier + | bool_ + | '(' > expr > ')' + ; + + identifier = + !keywords + >> raw[lexeme[(alpha | '_') >> *(alnum | '_')]] + ; + + /////////////////////////////////////////////////////////////////////// + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (expr) + (equality_expr) + (relational_expr) + (logical_expr) + (additive_expr) + (multiplicative_expr) + (unary_expr) + (primary_expr) + (identifier) + ); + + /////////////////////////////////////////////////////////////////////// + // Error handling: on error in expr, call error_handler. + on_error<fail>(expr, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + /////////////////////////////////////////////////////////////////////// + // Annotation: on success in primary_expr, call annotation. + on_success(primary_expr, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/main.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/main.cpp new file mode 100644 index 00000000..9c3b7346 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/main.cpp @@ -0,0 +1,97 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Now we'll introduce boolean expressions and control structures. +// Is it obvious now what we are up to? ;-) +// +// [ JDG April 9, 2007 ] spirit2 +// [ JDG February 18, 2011 ] Pure attributes. No semantic actions. +// +/////////////////////////////////////////////////////////////////////////////// + +#include "statement.hpp" +#include "vm.hpp" +#include "compiler.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Statement parser...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type some statements... "; + std::cout << "An empty line ends input, compiles, runs and prints results\n\n"; + std::cout << "Example:\n\n"; + std::cout << " var a = 123;\n"; + std::cout << " var b = 456;\n"; + std::cout << " var c = a + b * 2;\n\n"; + std::cout << "-------------------------\n"; + + std::string str; + std::string source; + while (std::getline(std::cin, str)) + { + if (str.empty()) + break; + source += str + '\n'; + } + + typedef std::string::const_iterator iterator_type; + iterator_type iter = source.begin(); + iterator_type end = source.end(); + + client::vmachine vm; // Our virtual machine + client::code_gen::program program; // Our VM program + client::ast::statement_list ast; // Our AST + + client::error_handler<iterator_type> + error_handler(iter, end); // Our error handler + client::parser::statement<iterator_type> + parser(error_handler); // Our parser + client::code_gen::compiler + compile(program, error_handler); // Our compiler + + boost::spirit::ascii::space_type space; + bool success = phrase_parse(iter, end, parser, space, ast); + + std::cout << "-------------------------\n"; + + if (success && iter == end) + { + if (compile.start(ast)) + { + std::cout << "Success\n"; + std::cout << "-------------------------\n"; + vm.execute(program()); + + std::cout << "-------------------------\n"; + std::cout << "Assembler----------------\n\n"; + program.print_assembler(); + + std::cout << "-------------------------\n"; + std::cout << "Results------------------\n\n"; + program.print_variables(vm.stack); + } + else + { + std::cout << "Compile failure\n"; + } + } + else + { + std::cout << "Parse failure\n"; + } + + std::cout << "-------------------------\n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/statement.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/statement.cpp new file mode 100644 index 00000000..54bc9ac3 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/statement.cpp @@ -0,0 +1,14 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "statement_def.hpp" + +typedef std::string::const_iterator iterator_type; +template struct client::parser::statement<iterator_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/statement.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/statement.hpp new file mode 100644 index 00000000..8b6c6b77 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/statement.hpp @@ -0,0 +1,37 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC8_STATEMENT_HPP) +#define BOOST_SPIRIT_CALC8_STATEMENT_HPP + +#include "expression.hpp" + +namespace client { namespace parser +{ + /////////////////////////////////////////////////////////////////////////////// + // The statement grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct statement : qi::grammar<Iterator, ast::statement_list(), ascii::space_type> + { + statement(error_handler<Iterator>& error_handler); + + expression<Iterator> expr; + qi::rule<Iterator, ast::statement_list(), ascii::space_type> + statement_list, compound_statement; + + qi::rule<Iterator, ast::statement(), ascii::space_type> statement_; + qi::rule<Iterator, ast::variable_declaration(), ascii::space_type> variable_declaration; + qi::rule<Iterator, ast::assignment(), ascii::space_type> assignment; + qi::rule<Iterator, ast::if_statement(), ascii::space_type> if_statement; + qi::rule<Iterator, ast::while_statement(), ascii::space_type> while_statement; + qi::rule<Iterator, std::string(), ascii::space_type> identifier; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/statement_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/statement_def.hpp new file mode 100644 index 00000000..d007ac06 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/statement_def.hpp @@ -0,0 +1,111 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "statement.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" + +namespace client { namespace parser +{ + template <typename Iterator> + statement<Iterator>::statement(error_handler<Iterator>& error_handler) + : statement::base_type(statement_list), expr(error_handler) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::_val_type _val; + qi::raw_type raw; + qi::lexeme_type lexeme; + qi::alpha_type alpha; + qi::alnum_type alnum; + qi::lit_type lit; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef function<client::error_handler<Iterator> > error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + statement_list = + +statement_ + ; + + statement_ = + variable_declaration + | assignment + | compound_statement + | if_statement + | while_statement + ; + + identifier = + !expr.keywords + >> raw[lexeme[(alpha | '_') >> *(alnum | '_')]] + ; + + variable_declaration = + lexeme["var" >> !(alnum | '_')] // make sure we have whole words + > &identifier // expect an identifier + > assignment + ; + + assignment = + identifier + > '=' + > expr + > ';' + ; + + if_statement = + lit("if") + > '(' + > expr + > ')' + > statement_ + > + -( + lexeme["else" >> !(alnum | '_')] // make sure we have whole words + > statement_ + ) + ; + + while_statement = + lit("while") + > '(' + > expr + > ')' + > statement_ + ; + + compound_statement = + '{' >> -statement_list >> '}' + ; + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (statement_list) + (identifier) + (variable_declaration) + (assignment) + ); + + // Error handling: on error in statement_list, call error_handler. + on_error<fail>(statement_list, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + // Annotation: on success in assignment, call annotation. + on_success(assignment, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/vm.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/vm.cpp new file mode 100644 index 00000000..70589fa1 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/vm.cpp @@ -0,0 +1,163 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "vm.hpp" +#include <boost/assert.hpp> + +#if defined(_MSC_VER) +# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' + // (performance warning) +#endif + +namespace client +{ + int vmachine::execute( + std::vector<int> const& code + , std::vector<int>::const_iterator pc + , std::vector<int>::iterator frame_ptr + ) + { + std::vector<int>::iterator stack_ptr = frame_ptr; + + while (pc != code.end()) + { + BOOST_ASSERT(pc != code.end()); + + switch (*pc++) + { + case op_neg: + stack_ptr[-1] = -stack_ptr[-1]; + break; + + case op_not: + stack_ptr[-1] = !bool(stack_ptr[-1]); + break; + + case op_add: + --stack_ptr; + stack_ptr[-1] += stack_ptr[0]; + break; + + case op_sub: + --stack_ptr; + stack_ptr[-1] -= stack_ptr[0]; + break; + + case op_mul: + --stack_ptr; + stack_ptr[-1] *= stack_ptr[0]; + break; + + case op_div: + --stack_ptr; + stack_ptr[-1] /= stack_ptr[0]; + break; + + case op_eq: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] == stack_ptr[0]); + break; + + case op_neq: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] != stack_ptr[0]); + break; + + case op_lt: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] < stack_ptr[0]); + break; + + case op_lte: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] <= stack_ptr[0]); + break; + + case op_gt: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] > stack_ptr[0]); + break; + + case op_gte: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] >= stack_ptr[0]); + break; + + case op_and: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1]) && bool(stack_ptr[0]); + break; + + case op_or: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1]) || bool(stack_ptr[0]); + break; + + case op_load: + *stack_ptr++ = frame_ptr[*pc++]; + break; + + case op_store: + --stack_ptr; + frame_ptr[*pc++] = stack_ptr[0]; + break; + + case op_int: + *stack_ptr++ = *pc++; + break; + + case op_true: + *stack_ptr++ = true; + break; + + case op_false: + *stack_ptr++ = false; + break; + + case op_jump: + pc += *pc; + break; + + case op_jump_if: + if (!bool(stack_ptr[-1])) + pc += *pc; + else + ++pc; + --stack_ptr; + break; + + case op_stk_adj: + stack_ptr = stack.begin() + *pc++; + break; + + case op_call: + { + int nargs = *pc++; + int jump = *pc++; + + // a function call is a recursive call to execute + int r = execute( + code + , code.begin() + jump + , stack_ptr - nargs + ); + + // cleanup after return from function + stack_ptr[-nargs] = r; // get return value + stack_ptr -= (nargs - 1); // the stack will now contain + // the return value + } + break; + + case op_return: + return stack_ptr[-1]; + } + } + return -1; + } +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/vm.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/vm.hpp new file mode 100644 index 00000000..bab387f7 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/calc8/vm.hpp @@ -0,0 +1,77 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CALC8_VM_HPP) +#define BOOST_SPIRIT_CALC8_VM_HPP + +#include <vector> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // The Virtual Machine + /////////////////////////////////////////////////////////////////////////// + enum byte_code + { + op_neg, // negate the top stack entry + op_add, // add top two stack entries + op_sub, // subtract top two stack entries + op_mul, // multiply top two stack entries + op_div, // divide top two stack entries + + op_not, // boolean negate the top stack entry + op_eq, // compare the top two stack entries for == + op_neq, // compare the top two stack entries for != + op_lt, // compare the top two stack entries for < + op_lte, // compare the top two stack entries for <= + op_gt, // compare the top two stack entries for > + op_gte, // compare the top two stack entries for >= + + op_and, // logical and top two stack entries + op_or, // logical or top two stack entries + + op_load, // load a variable + op_store, // store a variable + + op_int, // push constant integer into the stack + op_true, // push constant 0 into the stack + op_false, // push constant 1 into the stack + + op_jump_if, // jump to a relative position in the code if top stack + // evaluates to false + op_jump, // jump to a relative position in the code + + op_stk_adj, // adjust the stack (for args and locals) + op_call, // function call + op_return // return from function + }; + + class vmachine + { + public: + + vmachine(unsigned stackSize = 4096) + : stack(stackSize) + { + } + + int execute( + std::vector<int> const& code // the program code + , std::vector<int>::const_iterator pc // program counter + , std::vector<int>::iterator frame_ptr // start of arguments and locals + ); + + int execute(std::vector<int> const& code) + { + return execute(code, code.begin(), stack.begin()); + }; + + std::vector<int> stack; + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/annotation.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/annotation.hpp new file mode 100644 index 00000000..2361a7f4 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/annotation.hpp @@ -0,0 +1,95 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_ANNOTATION_HPP) +#define BOOST_SPIRIT_CONJURE_ANNOTATION_HPP + +#include <map> +#include <boost/variant/apply_visitor.hpp> +#include <boost/type_traits/is_base_of.hpp> +#include <boost/mpl/bool.hpp> +#include "ast.hpp" + +namespace client +{ + /////////////////////////////////////////////////////////////////////////////// + // The annotation handler links the AST to a map of iterator positions + // for the purpose of subsequent semantic error handling when the + // program is being compiled. + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct annotation + { + template <typename, typename> + struct result { typedef void type; }; + + std::vector<Iterator>& iters; + annotation(std::vector<Iterator>& iters) + : iters(iters) {} + + struct set_id + { + typedef void result_type; + + int id; + set_id(int id) : id(id) {} + + void operator()(ast::function_call& x) const + { + x.function_name.id = id; + } + + void operator()(ast::identifier& x) const + { + x.id = id; + } + + template <typename T> + void operator()(T& x) const + { + // no-op + } + }; + + void operator()(ast::operand& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + boost::apply_visitor(set_id(id), ast); + } + + void operator()(ast::variable_declaration& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.lhs.id = id; + } + + void operator()(ast::assignment& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.lhs.id = id; + } + + void operator()(ast::return_statement& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.id = id; + } + + void operator()(ast::identifier& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.id = id; + } + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/ast.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/ast.hpp new file mode 100644 index 00000000..e5022472 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/ast.hpp @@ -0,0 +1,275 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_AST_HPP) +#define BOOST_SPIRIT_CONJURE_AST_HPP + +#include <boost/config/warning_disable.hpp> +#include <boost/variant/recursive_variant.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/fusion/include/io.hpp> +#include <boost/optional.hpp> +#include <list> + +namespace client { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + // The AST + /////////////////////////////////////////////////////////////////////////// + struct tagged + { + int id; // Used to annotate the AST with the iterator position. + // This id is used as a key to a map<int, Iterator> + // (not really part of the AST.) + }; + + struct nil {}; + struct unary; + struct function_call; + struct expression; + + struct identifier : tagged + { + identifier(std::string const& name = "") : name(name) {} + std::string name; + }; + + typedef boost::variant< + nil + , bool + , unsigned int + , identifier + , boost::recursive_wrapper<unary> + , boost::recursive_wrapper<function_call> + , boost::recursive_wrapper<expression> + > + operand; + + enum optoken + { + // precedence 1 + op_comma, + + // precedence 2 + op_assign, + op_plus_assign, + op_minus_assign, + op_times_assign, + op_divide_assign, + op_mod_assign, + op_bit_and_assign, + op_bit_xor_assign, + op_bitor_assign, + op_shift_left_assign, + op_shift_right_assign, + + // precedence 3 + op_logical_or, + + // precedence 4 + op_logical_and, + + // precedence 5 + op_bit_or, + + // precedence 6 + op_bit_xor, + + // precedence 7 + op_bit_and, + + // precedence 8 + op_equal, + op_not_equal, + + // precedence 9 + op_less, + op_less_equal, + op_greater, + op_greater_equal, + + // precedence 10 + op_shift_left, + op_shift_right, + + // precedence 11 + op_plus, + op_minus, + + // precedence 12 + op_times, + op_divide, + op_mod, + + // precedence 13 + op_positive, + op_negative, + op_pre_incr, + op_pre_decr, + op_compl, + op_not, + + // precedence 14 + op_post_incr, + op_post_decr, + }; + + struct unary + { + optoken operator_; + operand operand_; + }; + + struct operation + { + optoken operator_; + operand operand_; + }; + + struct function_call + { + identifier function_name; + std::list<expression> args; + }; + + struct expression + { + operand first; + std::list<operation> rest; + }; + + struct assignment + { + identifier lhs; + expression rhs; + }; + + struct variable_declaration + { + identifier lhs; + boost::optional<expression> rhs; + }; + + struct if_statement; + struct while_statement; + struct statement_list; + struct return_statement; + + typedef boost::variant< + variable_declaration + , assignment + , boost::recursive_wrapper<if_statement> + , boost::recursive_wrapper<while_statement> + , boost::recursive_wrapper<return_statement> + , boost::recursive_wrapper<statement_list> + > + statement; + + struct statement_list : std::list<statement> {}; + + struct if_statement + { + expression condition; + statement then; + boost::optional<statement> else_; + }; + + struct while_statement + { + expression condition; + statement body; + }; + + struct return_statement : tagged + { + boost::optional<expression> expr; + }; + + struct function + { + std::string return_type; + identifier function_name; + std::list<identifier> args; + statement_list body; + }; + + typedef std::list<function> function_list; + + // print functions for debugging + inline std::ostream& operator<<(std::ostream& out, nil) + { + out << "nil"; return out; + } + + inline std::ostream& operator<<(std::ostream& out, identifier const& id) + { + out << id.name; return out; + } +}} + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::unary, + (client::ast::optoken, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::operation, + (client::ast::optoken, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::function_call, + (client::ast::identifier, function_name) + (std::list<client::ast::expression>, args) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::expression, + (client::ast::operand, first) + (std::list<client::ast::operation>, rest) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::variable_declaration, + (client::ast::identifier, lhs) + (boost::optional<client::ast::expression>, rhs) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::assignment, + (client::ast::identifier, lhs) + (client::ast::expression, rhs) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::if_statement, + (client::ast::expression, condition) + (client::ast::statement, then) + (boost::optional<client::ast::statement>, else_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::while_statement, + (client::ast::expression, condition) + (client::ast::statement, body) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::return_statement, + (boost::optional<client::ast::expression>, expr) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::function, + (std::string, return_type) + (client::ast::identifier, function_name) + (std::list<client::ast::identifier>, args) + (client::ast::statement_list, body) +) + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/compiler.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/compiler.cpp new file mode 100644 index 00000000..22a036d4 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/compiler.cpp @@ -0,0 +1,628 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "compiler.hpp" +#include "vm.hpp" +#include <boost/foreach.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/assert.hpp> +#include <boost/lexical_cast.hpp> +#include <set> + +namespace client { namespace code_gen +{ + void function::op(int a) + { + code.push_back(a); + size_ += 1; + } + + void function::op(int a, int b) + { + code.push_back(a); + code.push_back(b); + size_ += 2; + } + + void function::op(int a, int b, int c) + { + code.push_back(a); + code.push_back(b); + code.push_back(c); + size_ += 3; + } + + int const* function::find_var(std::string const& name) const + { + std::map<std::string, int>::const_iterator i = variables.find(name); + if (i == variables.end()) + return 0; + return &i->second; + } + + void function::add_var(std::string const& name) + { + std::size_t n = variables.size(); + variables[name] = n; + } + + void function::link_to(std::string const& name, std::size_t address) + { + function_calls[address] = name; + } + + void function::print_assembler() const + { + std::vector<int>::const_iterator pc = code.begin() + address; + + std::vector<std::string> locals(variables.size()); + typedef std::pair<std::string, int> pair; + BOOST_FOREACH(pair const& p, variables) + { + locals[p.second] = p.first; + std::cout << " local " + << p.first << ", @" << p.second << std::endl; + } + + std::map<std::size_t, std::string> lines; + std::set<std::size_t> jumps; + + while (pc != (code.begin() + address + size_)) + { + std::string line; + std::size_t address = pc - code.begin(); + + switch (*pc++) + { + case op_neg: + line += " op_neg"; + break; + + case op_not: + line += " op_not"; + break; + + case op_add: + line += " op_add"; + break; + + case op_sub: + line += " op_sub"; + break; + + case op_mul: + line += " op_mul"; + break; + + case op_div: + line += " op_div"; + break; + + case op_eq: + line += " op_eq"; + break; + + case op_neq: + line += " op_neq"; + break; + + case op_lt: + line += " op_lt"; + break; + + case op_lte: + line += " op_lte"; + break; + + case op_gt: + line += " op_gt"; + break; + + case op_gte: + line += " op_gte"; + break; + + case op_and: + line += " op_and"; + break; + + case op_or: + line += " op_or"; + break; + + case op_load: + line += " op_load "; + line += locals[*pc++]; + break; + + case op_store: + line += " op_store "; + line += locals[*pc++]; + break; + + case op_int: + line += " op_int "; + line += boost::lexical_cast<std::string>(*pc++); + break; + + case op_true: + line += " op_true"; + break; + + case op_false: + line += " op_false"; + break; + + case op_jump: + { + line += " op_jump "; + std::size_t pos = (pc - code.begin()) + *pc++; + if (pos == code.size()) + line += "end"; + else + line += boost::lexical_cast<std::string>(pos); + jumps.insert(pos); + } + break; + + case op_jump_if: + { + line += " op_jump_if "; + std::size_t pos = (pc - code.begin()) + *pc++; + if (pos == code.size()) + line += "end"; + else + line += boost::lexical_cast<std::string>(pos); + jumps.insert(pos); + } + break; + + case op_call: + { + line += " op_call "; + int nargs = *pc++; + std::size_t jump = *pc++; + line += boost::lexical_cast<std::string>(nargs) + ", "; + BOOST_ASSERT(function_calls.find(jump) != function_calls.end()); + line += function_calls.find(jump)->second; + } + break; + + case op_stk_adj: + line += " op_stk_adj "; + line += boost::lexical_cast<std::string>(*pc++); + break; + + + case op_return: + line += " op_return"; + break; + } + lines[address] = line; + } + + std::cout << "start:" << std::endl; + typedef std::pair<std::size_t, std::string> line_info; + BOOST_FOREACH(line_info const& l, lines) + { + std::size_t pos = l.first; + if (jumps.find(pos) != jumps.end()) + std::cout << pos << ':' << std::endl; + std::cout << l.second << std::endl; + } + + std::cout << "end:" << std::endl << std::endl; + } + + bool compiler::operator()(unsigned int x) + { + BOOST_ASSERT(current != 0); + current->op(op_int, x); + return true; + } + + bool compiler::operator()(bool x) + { + BOOST_ASSERT(current != 0); + current->op(x ? op_true : op_false); + return true; + } + + bool compiler::operator()(ast::identifier const& x) + { + BOOST_ASSERT(current != 0); + int const* p = current->find_var(x.name); + if (p == 0) + { + error_handler(x.id, "Undeclared variable: " + x.name); + return false; + } + current->op(op_load, *p); + return true; + } + + bool compiler::operator()(ast::optoken const& x) + { + BOOST_ASSERT(current != 0); + switch (x) + { + case ast::op_plus: current->op(op_add); break; + case ast::op_minus: current->op(op_sub); break; + case ast::op_times: current->op(op_mul); break; + case ast::op_divide: current->op(op_div); break; + + case ast::op_equal: current->op(op_eq); break; + case ast::op_not_equal: current->op(op_neq); break; + case ast::op_less: current->op(op_lt); break; + case ast::op_less_equal: current->op(op_lte); break; + case ast::op_greater: current->op(op_gt); break; + case ast::op_greater_equal: current->op(op_gte); break; + + case ast::op_logical_or: current->op(op_or); break; + case ast::op_logical_and: current->op(op_and); break; + default: BOOST_ASSERT(0); return false; + } + return true; + } + + bool compiler::operator()(ast::unary const& x) + { + BOOST_ASSERT(current != 0); + if (!boost::apply_visitor(*this, x.operand_)) + return false; + switch (x.operator_) + { + case ast::op_negative: current->op(op_neg); break; + case ast::op_not: current->op(op_not); break; + case ast::op_positive: break; + default: BOOST_ASSERT(0); return false; + } + return true; + } + + bool compiler::operator()(ast::function_call const& x) + { + BOOST_ASSERT(current != 0); + + if (functions.find(x.function_name.name) == functions.end()) + { + error_handler(x.function_name.id, "Function not found: " + x.function_name.name); + return false; + } + + boost::shared_ptr<code_gen::function> p = functions[x.function_name.name]; + + if (p->nargs() != x.args.size()) + { + error_handler(x.function_name.id, "Wrong number of arguments: " + x.function_name.name); + return false; + } + + BOOST_FOREACH(ast::expression const& expr, x.args) + { + if (!(*this)(expr)) + return false; + } + + current->op( + op_call, + p->nargs(), + p->get_address()); + current->link_to(x.function_name.name, p->get_address()); + + return true; + } + + namespace + { + int precedence[] = { + // precedence 1 + 1, // op_comma + + // precedence 2 + 2, // op_assign + 2, // op_plus_assign + 2, // op_minus_assign + 2, // op_times_assign + 2, // op_divide_assign + 2, // op_mod_assign + 2, // op_bit_and_assign + 2, // op_bit_xor_assign + 2, // op_bitor_assign + 2, // op_shift_left_assign + 2, // op_shift_right_assign + + // precedence 3 + 3, // op_logical_or + + // precedence 4 + 4, // op_logical_and + + // precedence 5 + 5, // op_bit_or + + // precedence 6 + 6, // op_bit_xor + + // precedence 7 + 7, // op_bit_and + + // precedence 8 + 8, // op_equal + 8, // op_not_equal + + // precedence 9 + 9, // op_less + 9, // op_less_equal + 9, // op_greater + 9, // op_greater_equal + + // precedence 10 + 10, // op_shift_left + 10, // op_shift_right + + // precedence 11 + 11, // op_plus + 11, // op_minus + + // precedence 12 + 12, // op_times + 12, // op_divide + 12, // op_mod + + // precedence 13 + 13, // op_positive + 13, // op_negative + 13, // op_pre_incr + 13, // op_pre_decr + 13, // op_compl + 13, // op_not + + // precedence 14 + 14, // op_post_incr + 14 // op_post_decr + }; + } + + // The Shunting-yard algorithm + bool compiler::compile_expression( + int min_precedence, + std::list<ast::operation>::const_iterator& rbegin, + std::list<ast::operation>::const_iterator rend) + { + while ((rbegin != rend) && (precedence[rbegin->operator_] >= min_precedence)) + { + ast::optoken op = rbegin->operator_; + if (!boost::apply_visitor(*this, rbegin->operand_)) + return false; + ++rbegin; + + while ((rbegin != rend) && (precedence[rbegin->operator_] > precedence[op])) + { + ast::optoken next_op = rbegin->operator_; + compile_expression(precedence[next_op], rbegin, rend); + } + (*this)(op); + } + return true; + } + + bool compiler::operator()(ast::expression const& x) + { + BOOST_ASSERT(current != 0); + if (!boost::apply_visitor(*this, x.first)) + return false; + std::list<ast::operation>::const_iterator rbegin = x.rest.begin(); + if (!compile_expression(0, rbegin, x.rest.end())) + return false; + return true; + } + + bool compiler::operator()(ast::assignment const& x) + { + BOOST_ASSERT(current != 0); + if (!(*this)(x.rhs)) + return false; + int const* p = current->find_var(x.lhs.name); + if (p == 0) + { + error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name); + return false; + } + current->op(op_store, *p); + return true; + } + + bool compiler::operator()(ast::variable_declaration const& x) + { + BOOST_ASSERT(current != 0); + int const* p = current->find_var(x.lhs.name); + if (p != 0) + { + error_handler(x.lhs.id, "Duplicate variable: " + x.lhs.name); + return false; + } + if (x.rhs) // if there's an RHS initializer + { + bool r = (*this)(*x.rhs); + if (r) // don't add the variable if the RHS fails + { + current->add_var(x.lhs.name); + current->op(op_store, *current->find_var(x.lhs.name)); + } + return r; + } + else + { + current->add_var(x.lhs.name); + } + return true; + } + + bool compiler::operator()(ast::statement const& x) + { + BOOST_ASSERT(current != 0); + return boost::apply_visitor(*this, x); + } + + bool compiler::operator()(ast::statement_list const& x) + { + BOOST_ASSERT(current != 0); + BOOST_FOREACH(ast::statement const& s, x) + { + if (!(*this)(s)) + return false; + } + return true; + } + + bool compiler::operator()(ast::if_statement const& x) + { + BOOST_ASSERT(current != 0); + if (!(*this)(x.condition)) + return false; + current->op(op_jump_if, 0); // we shall fill this (0) in later + std::size_t skip = current->size()-1; // mark its position + if (!(*this)(x.then)) + return false; + (*current)[skip] = current->size()-skip; // now we know where to jump to (after the if branch) + + if (x.else_) // We got an alse + { + (*current)[skip] += 2; // adjust for the "else" jump + current->op(op_jump, 0); // we shall fill this (0) in later + std::size_t exit = current->size()-1; // mark its position + if (!(*this)(*x.else_)) + return false; + (*current)[exit] = current->size()-exit;// now we know where to jump to (after the else branch) + } + + return true; + } + + bool compiler::operator()(ast::while_statement const& x) + { + BOOST_ASSERT(current != 0); + std::size_t loop = current->size(); // mark our position + if (!(*this)(x.condition)) + return false; + current->op(op_jump_if, 0); // we shall fill this (0) in later + std::size_t exit = current->size()-1; // mark its position + if (!(*this)(x.body)) + return false; + current->op(op_jump, + int(loop-1) - int(current->size())); // loop back + (*current)[exit] = current->size()-exit; // now we know where to jump to (to exit the loop) + return true; + } + + bool compiler::operator()(ast::return_statement const& x) + { + if (void_return) + { + if (x.expr) + { + error_handler(x.id, "'void' function returning a value: "); + return false; + } + } + else + { + if (!x.expr) + { + error_handler(x.id, current_function_name + " function must return a value: "); + return false; + } + } + + if (x.expr) + { + if (!(*this)(*x.expr)) + return false; + } + current->op(op_return); + return true; + } + + bool compiler::operator()(ast::function const& x) + { + void_return = x.return_type == "void"; + if (functions.find(x.function_name.name) != functions.end()) + { + error_handler(x.function_name.id, "Duplicate function: " + x.function_name.name); + return false; + } + boost::shared_ptr<code_gen::function>& p = functions[x.function_name.name]; + p.reset(new code_gen::function(code, x.args.size())); + current = p.get(); + current_function_name = x.function_name.name; + + // op_stk_adj 0 for now. we'll know how many variables + // we'll have later and add them + current->op(op_stk_adj, 0); + BOOST_FOREACH(ast::identifier const& arg, x.args) + { + current->add_var(arg.name); + } + + if (!(*this)(x.body)) + return false; + (*current)[1] = current->nvars(); // now store the actual number of variables + // this includes the arguments + return true; + } + + bool compiler::operator()(ast::function_list const& x) + { + // Jump to the main function + code.push_back(op_jump); + code.push_back(0); // we will fill this in later when we finish compiling + // and we know where the main function is + + BOOST_FOREACH(ast::function const& f, x) + { + if (!(*this)(f)) + { + code.clear(); + return false; + } + } + // find the main function + boost::shared_ptr<code_gen::function> p = + find_function("main"); + + if (!p) // main function not found + { + std::cerr << "Error: main function not defined" << std::endl; + return false; + } + code[1] = p->get_address()-1; // jump to this (main function) address + + return true; + } + + void compiler::print_assembler() const + { + typedef std::pair<std::string, boost::shared_ptr<code_gen::function> > pair; + BOOST_FOREACH(pair const& p, functions) + { + std::cout << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" << std::endl; + std::cout << p.second->get_address() << ": function " << p.first << std::endl; + p.second->print_assembler(); + } + } + + boost::shared_ptr<code_gen::function> + compiler::find_function(std::string const& name) const + { + function_table::const_iterator i = functions.find(name); + if (i == functions.end()) + return boost::shared_ptr<code_gen::function>(); + else + return i->second; + } +}} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/compiler.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/compiler.hpp new file mode 100644 index 00000000..461f7a7c --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/compiler.hpp @@ -0,0 +1,123 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_COMPILER_HPP) +#define BOOST_SPIRIT_CONJURE_COMPILER_HPP + +#include "ast.hpp" +#include "error_handler.hpp" +#include <vector> +#include <map> +#include <boost/function.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_function.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> + +namespace client { namespace code_gen +{ + /////////////////////////////////////////////////////////////////////////// + // The Function + /////////////////////////////////////////////////////////////////////////// + struct function + { + function(std::vector<int>& code, int nargs) + : code(code), address(code.size()), size_(0), nargs_(nargs) {} + + void op(int a); + void op(int a, int b); + void op(int a, int b, int c); + + int& operator[](std::size_t i) { return code[address+i]; } + int const& operator[](std::size_t i) const { return code[address+i]; } + std::size_t size() const { return size_; } + std::size_t get_address() const { return address; } + + int nargs() const { return nargs_; } + int nvars() const { return variables.size(); } + int const* find_var(std::string const& name) const; + void add_var(std::string const& name); + void link_to(std::string const& name, std::size_t address); + + void print_assembler() const; + + private: + + std::map<std::string, int> variables; + std::map<std::size_t, std::string> function_calls; + std::vector<int>& code; + std::size_t address; + std::size_t size_; + std::size_t nargs_; + }; + + /////////////////////////////////////////////////////////////////////////// + // The Compiler + /////////////////////////////////////////////////////////////////////////// + struct compiler + { + typedef bool result_type; + + template <typename ErrorHandler> + compiler(ErrorHandler& error_handler_) + : current(0) + { + using namespace boost::phoenix::arg_names; + namespace phx = boost::phoenix; + using boost::phoenix::function; + + error_handler = function<ErrorHandler>(error_handler_)( + "Error! ", _2, phx::cref(error_handler_.iters)[_1]); + } + + bool operator()(ast::nil) { BOOST_ASSERT(0); return false; } + bool operator()(unsigned int x); + bool operator()(bool x); + bool operator()(ast::identifier const& x); + bool operator()(ast::optoken const& x); + bool operator()(ast::unary const& x); + bool operator()(ast::function_call const& x); + bool operator()(ast::expression const& x); + bool operator()(ast::assignment const& x); + bool operator()(ast::variable_declaration const& x); + bool operator()(ast::statement_list const& x); + bool operator()(ast::statement const& x); + bool operator()(ast::if_statement const& x); + bool operator()(ast::while_statement const& x); + bool operator()(ast::return_statement const& x); + bool operator()(ast::function const& x); + bool operator()(ast::function_list const& x); + + void print_assembler() const; + + boost::shared_ptr<code_gen::function> + find_function(std::string const& name) const; + + std::vector<int>& get_code() { return code; } + std::vector<int> const& get_code() const { return code; } + + private: + + bool compile_expression( + int min_precedence, + std::list<ast::operation>::const_iterator& rbegin, + std::list<ast::operation>::const_iterator rend); + + typedef std::map<std::string, boost::shared_ptr<code_gen::function> > function_table; + + std::vector<int> code; + code_gen::function* current; + std::string current_function_name; + function_table functions; + bool void_return; + + boost::function< + void(int tag, std::string const& what)> + error_handler; + }; +}} + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/error_handler.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/error_handler.hpp new file mode 100644 index 00000000..2c1aa44e --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/error_handler.hpp @@ -0,0 +1,93 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_ERROR_HANDLER_HPP) +#define BOOST_SPIRIT_CONJURE_ERROR_HANDLER_HPP + +#include <iostream> +#include <string> +#include <vector> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////////// + // The error handler + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct error_handler + { + template <typename, typename, typename> + struct result { typedef void type; }; + + error_handler(Iterator first, Iterator last) + : first(first), last(last) {} + + template <typename Message, typename What> + void operator()( + Message const& message, + What const& what, + Iterator err_pos) const + { + int line; + Iterator line_start = get_pos(err_pos, line); + if (err_pos != last) + { + std::cout << message << what << " line " << line << ':' << std::endl; + std::cout << get_line(line_start) << std::endl; + for (; line_start != err_pos; ++line_start) + std::cout << ' '; + std::cout << '^' << std::endl; + } + else + { + std::cout << "Unexpected end of file. "; + std::cout << message << what << " line " << line << std::endl; + } + } + + Iterator get_pos(Iterator err_pos, int& line) const + { + line = 1; + Iterator i = first; + Iterator line_start = first; + while (i != err_pos) + { + bool eol = false; + if (i != err_pos && *i == '\r') // CR + { + eol = true; + line_start = ++i; + } + if (i != err_pos && *i == '\n') // LF + { + eol = true; + line_start = ++i; + } + if (eol) + ++line; + else + ++i; + } + return line_start; + } + + std::string get_line(Iterator err_pos) const + { + Iterator i = err_pos; + // position i to the next EOL + while (i != last && (*i != '\r' && *i != '\n')) + ++i; + return std::string(err_pos, i); + } + + Iterator first; + Iterator last; + std::vector<Iterator> iters; + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/expression.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/expression.cpp new file mode 100644 index 00000000..32f44adc --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/expression.cpp @@ -0,0 +1,14 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "expression_def.hpp" + +typedef std::string::const_iterator iterator_type; +template struct client::parser::expression<iterator_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/expression.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/expression.hpp new file mode 100644 index 00000000..985b972c --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/expression.hpp @@ -0,0 +1,75 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_EXPRESSION_HPP) +#define BOOST_SPIRIT_CONJURE_EXPRESSION_HPP + +/////////////////////////////////////////////////////////////////////////////// +// Spirit v2.5 allows you to suppress automatic generation +// of predefined terminals to speed up complation. With +// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are +// responsible in creating instances of the terminals that +// you need (e.g. see qi::uint_type uint_ below). +#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment this if you want to enable debugging +// #define BOOST_SPIRIT_QI_DEBUG +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/spirit/include/qi.hpp> +#include "ast.hpp" +#include "error_handler.hpp" +#include "skipper.hpp" +#include <vector> + +namespace client { namespace parser +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // The expression grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct expression : qi::grammar<Iterator, ast::expression(), skipper<Iterator> > + { + expression(error_handler<Iterator>& error_handler); + + qi::rule<Iterator, ast::expression(), skipper<Iterator> > + expr + ; + + qi::rule<Iterator, ast::operand(), skipper<Iterator> > + unary_expr, primary_expr + ; + + qi::rule<Iterator, ast::function_call(), skipper<Iterator> > + function_call + ; + + qi::rule<Iterator, std::list<ast::expression>(), skipper<Iterator> > + argument_list + ; + + qi::rule<Iterator, std::string(), skipper<Iterator> > + identifier + ; + + qi::symbols<char, ast::optoken> + unary_op, binary_op + ; + + qi::symbols<char> + keywords + ; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/expression_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/expression_def.hpp new file mode 100644 index 00000000..21ccc9bd --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/expression_def.hpp @@ -0,0 +1,131 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "expression.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" +#include <boost/spirit/include/phoenix_function.hpp> + +namespace client { namespace parser +{ + template <typename Iterator> + expression<Iterator>::expression(error_handler<Iterator>& error_handler) + : expression::base_type(expr) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::char_type char_; + qi::uint_type uint_; + qi::_val_type _val; + qi::raw_type raw; + qi::lexeme_type lexeme; + qi::alpha_type alpha; + qi::alnum_type alnum; + qi::bool_type bool_; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef function<client::error_handler<Iterator> > error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + /////////////////////////////////////////////////////////////////////// + // Tokens + binary_op.add + ("||", ast::op_logical_or) + ("&&", ast::op_logical_and) + ("==", ast::op_equal) + ("!=", ast::op_not_equal) + ("<", ast::op_less) + ("<=", ast::op_less_equal) + (">", ast::op_greater) + (">=", ast::op_greater_equal) + ("+", ast::op_plus) + ("-", ast::op_minus) + ("*", ast::op_times) + ("/", ast::op_divide) + ; + + unary_op.add + ("+", ast::op_positive) + ("-", ast::op_negative) + ("!", ast::op_not) + ; + + keywords.add + ("true") + ("false") + ("if") + ("else") + ("while") + ("int") + ("void") + ("return") + ; + + /////////////////////////////////////////////////////////////////////// + // Main expression grammar + expr = + unary_expr + >> *(binary_op > unary_expr) + ; + + unary_expr = + primary_expr + | (unary_op > unary_expr) + ; + + primary_expr = + uint_ + | function_call + | identifier + | bool_ + | '(' > expr > ')' + ; + + function_call = + (identifier >> '(') + > argument_list + > ')' + ; + + argument_list = -(expr % ','); + + identifier = + !lexeme[keywords >> !(alnum | '_')] + >> raw[lexeme[(alpha | '_') >> *(alnum | '_')]] + ; + + /////////////////////////////////////////////////////////////////////// + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (expr) + (unary_expr) + (primary_expr) + (function_call) + (argument_list) + (identifier) + ); + + /////////////////////////////////////////////////////////////////////// + // Error handling: on error in expr, call error_handler. + on_error<fail>(expr, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + /////////////////////////////////////////////////////////////////////// + // Annotation: on success in primary_expr, call annotation. + on_success(primary_expr, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/function.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/function.cpp new file mode 100644 index 00000000..ababd4ad --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/function.cpp @@ -0,0 +1,14 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "function_def.hpp" + +typedef std::string::const_iterator iterator_type; +template struct client::parser::function<iterator_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/function.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/function.hpp new file mode 100644 index 00000000..9eddd66c --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/function.hpp @@ -0,0 +1,32 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_FUNCTION_HPP) +#define BOOST_SPIRIT_CONJURE_FUNCTION_HPP + +#include "statement.hpp" + +namespace client { namespace parser +{ + /////////////////////////////////////////////////////////////////////////////// + // The function grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct function : qi::grammar<Iterator, ast::function(), skipper<Iterator> > + { + function(error_handler<Iterator>& error_handler); + + statement<Iterator> body; + qi::rule<Iterator, std::string(), skipper<Iterator> > name; + qi::rule<Iterator, ast::identifier(), skipper<Iterator> > identifier; + qi::rule<Iterator, std::list<ast::identifier>(), skipper<Iterator> > argument_list; + qi::rule<Iterator, ast::function(), skipper<Iterator> > start; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/function_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/function_def.hpp new file mode 100644 index 00000000..bd2c7d02 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/function_def.hpp @@ -0,0 +1,71 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "function.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" + +namespace client { namespace parser +{ + template <typename Iterator> + function<Iterator>::function(error_handler<Iterator>& error_handler) + : function::base_type(start), body(error_handler) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::_val_type _val; + qi::raw_type raw; + qi::lexeme_type lexeme; + qi::alpha_type alpha; + qi::alnum_type alnum; + qi::string_type string; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef function<client::error_handler<Iterator> > error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + name = + !body.expr.keywords + >> raw[lexeme[(alpha | '_') >> *(alnum | '_')]] + ; + + identifier = name; + argument_list = -(identifier % ','); + + start = + lexeme[(string("void") | string("int")) + >> !(alnum | '_')] // make sure we have whole words + > identifier + > '(' > argument_list > ')' + > '{' > body > '}' + ; + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (identifier) + (argument_list) + (start) + ); + + // Error handling: on error in start, call error_handler. + on_error<fail>(start, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + // Annotation: on success in start, call annotation. + on_success(identifier, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/main.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/main.cpp new file mode 100644 index 00000000..8b2a8007 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/main.cpp @@ -0,0 +1,121 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Not a calculator anymore, right? :-) +// +// [ JDG April 10, 2007 ] spirit2 +// [ JDG February 18, 2011 ] Pure attributes. No semantic actions. +// +/////////////////////////////////////////////////////////////////////////////// + +#include "function.hpp" +#include "skipper.hpp" +#include "vm.hpp" +#include "compiler.hpp" +#include <boost/lexical_cast.hpp> +#include <fstream> + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main(int argc, char **argv) +{ + char const* filename; + if (argc > 1) + { + filename = argv[1]; + } + else + { + std::cerr << "Error: No input file provided." << std::endl; + return 1; + } + + std::ifstream in(filename, std::ios_base::in); + + if (!in) + { + std::cerr << "Error: Could not open input file: " + << filename << std::endl; + return 1; + } + + std::string source_code; // We will read the contents here. + in.unsetf(std::ios::skipws); // No white space skipping! + std::copy( + std::istream_iterator<char>(in), + std::istream_iterator<char>(), + std::back_inserter(source_code)); + + typedef std::string::const_iterator iterator_type; + iterator_type iter = source_code.begin(); + iterator_type end = source_code.end(); + + client::vmachine vm; // Our virtual machine + client::ast::function_list ast; // Our AST + + client::error_handler<iterator_type> + error_handler(iter, end); // Our error handler + client::parser::function<iterator_type> + function(error_handler); // Our parser + client::parser::skipper<iterator_type> + skipper; // Our skipper + client::code_gen::compiler + compiler(error_handler); // Our compiler + + + bool success = phrase_parse(iter, end, +function, skipper, ast); + + std::cout << "-------------------------\n"; + + if (success && iter == end) + { + if (compiler(ast)) + { + boost::shared_ptr<client::code_gen::function> + p = compiler.find_function("main"); + if (!p) + return 1; + + int nargs = argc-2; + if (p->nargs() != nargs) + { + std::cerr << "Error: main function requires " << p->nargs() << " arguments." << std::endl; + std::cerr << nargs << " supplied." << std::endl; + return 1; + } + + std::cout << "Success\n"; + std::cout << "-------------------------\n"; + std::cout << "Assembler----------------\n\n"; + compiler.print_assembler(); + + // Push the arguments into our stack + for (int i = 0; i < nargs; ++i) + vm.get_stack()[i] = boost::lexical_cast<int>(argv[i+2]); + + // Call the interpreter + int r = vm.execute(compiler.get_code()); + + std::cout << "-------------------------\n"; + std::cout << "Result: " << r << std::endl; + std::cout << "-------------------------\n\n"; + } + else + { + std::cout << "Compile failure\n"; + } + } + else + { + std::cout << "Parse failure\n"; + } + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/skipper.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/skipper.hpp new file mode 100644 index 00000000..bb1acc21 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/skipper.hpp @@ -0,0 +1,40 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_SKIPPER_HPP) +#define BOOST_SPIRIT_CONJURE_SKIPPER_HPP + +#include <boost/spirit/include/qi.hpp> + +namespace client { namespace parser +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // The skipper grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct skipper : qi::grammar<Iterator> + { + skipper() : skipper::base_type(start) + { + qi::char_type char_; + ascii::space_type space; + + start = + space // tab/space/cr/lf + | "/*" >> *(char_ - "*/") >> "*/" // C-style comments + ; + } + + qi::rule<Iterator> start; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/statement.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/statement.cpp new file mode 100644 index 00000000..54bc9ac3 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/statement.cpp @@ -0,0 +1,14 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "statement_def.hpp" + +typedef std::string::const_iterator iterator_type; +template struct client::parser::statement<iterator_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/statement.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/statement.hpp new file mode 100644 index 00000000..72485cbf --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/statement.hpp @@ -0,0 +1,38 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_STATEMENT_HPP) +#define BOOST_SPIRIT_CONJURE_STATEMENT_HPP + +#include "expression.hpp" + +namespace client { namespace parser +{ + /////////////////////////////////////////////////////////////////////////////// + // The statement grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct statement : qi::grammar<Iterator, ast::statement_list(), skipper<Iterator> > + { + statement(error_handler<Iterator>& error_handler); + + expression<Iterator> expr; + qi::rule<Iterator, ast::statement_list(), skipper<Iterator> > + statement_list, compound_statement; + + qi::rule<Iterator, ast::statement(), skipper<Iterator> > statement_; + qi::rule<Iterator, ast::variable_declaration(), skipper<Iterator> > variable_declaration; + qi::rule<Iterator, ast::assignment(), skipper<Iterator> > assignment; + qi::rule<Iterator, ast::if_statement(), skipper<Iterator> > if_statement; + qi::rule<Iterator, ast::while_statement(), skipper<Iterator> > while_statement; + qi::rule<Iterator, ast::return_statement(), skipper<Iterator> > return_statement; + qi::rule<Iterator, std::string(), skipper<Iterator> > identifier; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/statement_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/statement_def.hpp new file mode 100644 index 00000000..29e40942 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/statement_def.hpp @@ -0,0 +1,128 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "statement.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" + +namespace client { namespace parser +{ + template <typename Iterator> + statement<Iterator>::statement(error_handler<Iterator>& error_handler) + : statement::base_type(statement_list), expr(error_handler) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::_val_type _val; + qi::raw_type raw; + qi::lexeme_type lexeme; + qi::alpha_type alpha; + qi::alnum_type alnum; + qi::lit_type lit; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef function<client::error_handler<Iterator> > error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + statement_list = + +statement_ + ; + + statement_ = + variable_declaration + | assignment + | compound_statement + | if_statement + | while_statement + | return_statement + ; + + identifier = + !expr.keywords + >> raw[lexeme[(alpha | '_') >> *(alnum | '_')]] + ; + + variable_declaration = + lexeme["int" >> !(alnum | '_')] // make sure we have whole words + > identifier + > -('=' > expr) + > ';' + ; + + assignment = + identifier + > '=' + > expr + > ';' + ; + + if_statement = + lit("if") + > '(' + > expr + > ')' + > statement_ + > + -( + lexeme["else" >> !(alnum | '_')] // make sure we have whole words + > statement_ + ) + ; + + while_statement = + lit("while") + > '(' + > expr + > ')' + > statement_ + ; + + compound_statement = + '{' >> -statement_list >> '}' + ; + + return_statement = + lexeme["return" >> !(alnum | '_')] // make sure we have whole words + > -expr + > ';' + ; + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (statement_list) + (statement_) + (variable_declaration) + (assignment) + (if_statement) + (while_statement) + (compound_statement) + (return_statement) + ); + + // Error handling: on error in statement_list, call error_handler. + on_error<fail>(statement_list, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + // Annotation: on success in variable_declaration, + // assignment and return_statement, call annotation. + on_success(variable_declaration, + annotation_function(error_handler.iters)(_val, _1)); + on_success(assignment, + annotation_function(error_handler.iters)(_val, _1)); + on_success(return_statement, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/vm.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/vm.cpp new file mode 100644 index 00000000..8740bf9c --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/vm.cpp @@ -0,0 +1,159 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "vm.hpp" + +#if defined(_MSC_VER) +# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' + // (performance warning) +#endif + +namespace client +{ + int vmachine::execute( + std::vector<int> const& code + , std::vector<int>::const_iterator pc + , std::vector<int>::iterator frame_ptr + ) + { + std::vector<int>::iterator stack_ptr = frame_ptr; + + while (true) + { + switch (*pc++) + { + case op_neg: + stack_ptr[-1] = -stack_ptr[-1]; + break; + + case op_not: + stack_ptr[-1] = !bool(stack_ptr[-1]); + break; + + case op_add: + --stack_ptr; + stack_ptr[-1] += stack_ptr[0]; + break; + + case op_sub: + --stack_ptr; + stack_ptr[-1] -= stack_ptr[0]; + break; + + case op_mul: + --stack_ptr; + stack_ptr[-1] *= stack_ptr[0]; + break; + + case op_div: + --stack_ptr; + stack_ptr[-1] /= stack_ptr[0]; + break; + + case op_eq: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] == stack_ptr[0]); + break; + + case op_neq: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] != stack_ptr[0]); + break; + + case op_lt: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] < stack_ptr[0]); + break; + + case op_lte: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] <= stack_ptr[0]); + break; + + case op_gt: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] > stack_ptr[0]); + break; + + case op_gte: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] >= stack_ptr[0]); + break; + + case op_and: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1]) && bool(stack_ptr[0]); + break; + + case op_or: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1]) || bool(stack_ptr[0]); + break; + + case op_load: + *stack_ptr++ = frame_ptr[*pc++]; + break; + + case op_store: + --stack_ptr; + frame_ptr[*pc++] = stack_ptr[0]; + break; + + case op_int: + *stack_ptr++ = *pc++; + break; + + case op_true: + *stack_ptr++ = true; + break; + + case op_false: + *stack_ptr++ = false; + break; + + case op_jump: + pc += *pc; + break; + + case op_jump_if: + if (!bool(stack_ptr[-1])) + pc += *pc; + else + ++pc; + --stack_ptr; + break; + + case op_stk_adj: + stack_ptr += *pc++; + break; + + case op_call: + { + int nargs = *pc++; + int jump = *pc++; + + // a function call is a recursive call to execute + int r = execute( + code + , code.begin() + jump + , stack_ptr - nargs + ); + + // cleanup after return from function + stack_ptr[-nargs] = r; // get return value + stack_ptr -= (nargs - 1); // the stack will now contain + // the return value + } + break; + + case op_return: + return stack_ptr[-1]; + } + } + } +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/vm.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/vm.hpp new file mode 100644 index 00000000..0362eaf8 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure1/vm.hpp @@ -0,0 +1,82 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_VM_HPP) +#define BOOST_SPIRIT_CONJURE_VM_HPP + +#include <vector> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // The Virtual Machine + /////////////////////////////////////////////////////////////////////////// + enum byte_code + { + op_neg, // negate the top stack entry + op_add, // add top two stack entries + op_sub, // subtract top two stack entries + op_mul, // multiply top two stack entries + op_div, // divide top two stack entries + + op_not, // boolean negate the top stack entry + op_eq, // compare the top two stack entries for == + op_neq, // compare the top two stack entries for != + op_lt, // compare the top two stack entries for < + op_lte, // compare the top two stack entries for <= + op_gt, // compare the top two stack entries for > + op_gte, // compare the top two stack entries for >= + + op_and, // logical and top two stack entries + op_or, // logical or top two stack entries + + op_load, // load a variable + op_store, // store a variable + + op_int, // push constant integer into the stack + op_true, // push constant 0 into the stack + op_false, // push constant 1 into the stack + + op_jump_if, // jump to a relative position in the code if top stack + // evaluates to false + op_jump, // jump to a relative position in the code + + op_stk_adj, // adjust the stack (for args and locals) + op_call, // function call + op_return // return from function + }; + + class vmachine + { + public: + + vmachine(unsigned stackSize = 4096) + : stack(stackSize) + { + } + + int execute(std::vector<int> const& code) + { + return execute(code, code.begin(), stack.begin()); + } + + std::vector<int> const& get_stack() const { return stack; }; + std::vector<int>& get_stack() { return stack; }; + + private: + + int execute( + std::vector<int> const& code // the program code + , std::vector<int>::const_iterator pc // program counter + , std::vector<int>::iterator frame_ptr // start of arguments and locals + ); + + std::vector<int> stack; + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/annotation.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/annotation.hpp new file mode 100644 index 00000000..2361a7f4 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/annotation.hpp @@ -0,0 +1,95 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_ANNOTATION_HPP) +#define BOOST_SPIRIT_CONJURE_ANNOTATION_HPP + +#include <map> +#include <boost/variant/apply_visitor.hpp> +#include <boost/type_traits/is_base_of.hpp> +#include <boost/mpl/bool.hpp> +#include "ast.hpp" + +namespace client +{ + /////////////////////////////////////////////////////////////////////////////// + // The annotation handler links the AST to a map of iterator positions + // for the purpose of subsequent semantic error handling when the + // program is being compiled. + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct annotation + { + template <typename, typename> + struct result { typedef void type; }; + + std::vector<Iterator>& iters; + annotation(std::vector<Iterator>& iters) + : iters(iters) {} + + struct set_id + { + typedef void result_type; + + int id; + set_id(int id) : id(id) {} + + void operator()(ast::function_call& x) const + { + x.function_name.id = id; + } + + void operator()(ast::identifier& x) const + { + x.id = id; + } + + template <typename T> + void operator()(T& x) const + { + // no-op + } + }; + + void operator()(ast::operand& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + boost::apply_visitor(set_id(id), ast); + } + + void operator()(ast::variable_declaration& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.lhs.id = id; + } + + void operator()(ast::assignment& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.lhs.id = id; + } + + void operator()(ast::return_statement& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.id = id; + } + + void operator()(ast::identifier& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.id = id; + } + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/ast.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/ast.hpp new file mode 100644 index 00000000..d2f893b0 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/ast.hpp @@ -0,0 +1,209 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_AST_HPP) +#define BOOST_SPIRIT_CONJURE_AST_HPP + +#include <boost/config/warning_disable.hpp> +#include <boost/variant/recursive_variant.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/fusion/include/io.hpp> +#include <boost/optional.hpp> +#include <list> + +#include "ids.hpp" + +namespace client { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + // The AST + /////////////////////////////////////////////////////////////////////////// + struct tagged + { + int id; // Used to annotate the AST with the iterator position. + // This id is used as a key to a map<int, Iterator> + // (not really part of the AST.) + }; + + struct nil {}; + struct unary; + struct function_call; + struct expression; + + struct identifier : tagged + { + identifier(std::string const& name = "") : name(name) {} + std::string name; + }; + + typedef boost::variant< + nil + , bool + , unsigned int + , identifier + , boost::recursive_wrapper<unary> + , boost::recursive_wrapper<function_call> + , boost::recursive_wrapper<expression> + > + operand; + + struct unary + { + token_ids::type operator_; + operand operand_; + }; + + struct operation + { + token_ids::type operator_; + operand operand_; + }; + + struct function_call + { + identifier function_name; + std::list<expression> args; + }; + + struct expression + { + operand first; + std::list<operation> rest; + }; + + struct assignment + { + identifier lhs; + expression rhs; + }; + + struct variable_declaration + { + identifier lhs; + boost::optional<expression> rhs; + }; + + struct if_statement; + struct while_statement; + struct statement_list; + struct return_statement; + + typedef boost::variant< + variable_declaration + , assignment + , boost::recursive_wrapper<if_statement> + , boost::recursive_wrapper<while_statement> + , boost::recursive_wrapper<return_statement> + , boost::recursive_wrapper<statement_list> + > + statement; + + struct statement_list : std::list<statement> {}; + + struct if_statement + { + expression condition; + statement then; + boost::optional<statement> else_; + }; + + struct while_statement + { + expression condition; + statement body; + }; + + struct return_statement : tagged + { + boost::optional<expression> expr; + }; + + struct function + { + std::string return_type; + identifier function_name; + std::list<identifier> args; + statement_list body; + }; + + typedef std::list<function> function_list; + + // print functions for debugging + inline std::ostream& operator<<(std::ostream& out, nil) + { + out << "nil"; return out; + } + + inline std::ostream& operator<<(std::ostream& out, identifier const& id) + { + out << id.name; return out; + } +}} + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::unary, + (client::token_ids::type, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::operation, + (client::token_ids::type, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::function_call, + (client::ast::identifier, function_name) + (std::list<client::ast::expression>, args) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::expression, + (client::ast::operand, first) + (std::list<client::ast::operation>, rest) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::variable_declaration, + (client::ast::identifier, lhs) + (boost::optional<client::ast::expression>, rhs) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::assignment, + (client::ast::identifier, lhs) + (client::ast::expression, rhs) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::if_statement, + (client::ast::expression, condition) + (client::ast::statement, then) + (boost::optional<client::ast::statement>, else_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::while_statement, + (client::ast::expression, condition) + (client::ast::statement, body) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::return_statement, + (boost::optional<client::ast::expression>, expr) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::function, + (std::string, return_type) + (client::ast::identifier, function_name) + (std::list<client::ast::identifier>, args) + (client::ast::statement_list, body) +) + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/compiler.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/compiler.cpp new file mode 100644 index 00000000..87459b35 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/compiler.cpp @@ -0,0 +1,622 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "config.hpp" +#include "compiler.hpp" +#include "vm.hpp" +#include <boost/foreach.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/assert.hpp> +#include <boost/lexical_cast.hpp> +#include <set> + +namespace client { namespace code_gen +{ + void function::op(int a) + { + code.push_back(a); + size_ += 1; + } + + void function::op(int a, int b) + { + code.push_back(a); + code.push_back(b); + size_ += 2; + } + + void function::op(int a, int b, int c) + { + code.push_back(a); + code.push_back(b); + code.push_back(c); + size_ += 3; + } + + int const* function::find_var(std::string const& name) const + { + std::map<std::string, int>::const_iterator i = variables.find(name); + if (i == variables.end()) + return 0; + return &i->second; + } + + void function::add_var(std::string const& name) + { + std::size_t n = variables.size(); + variables[name] = n; + } + + void function::link_to(std::string const& name, std::size_t address) + { + function_calls[address] = name; + } + + void function::print_assembler() const + { + std::vector<int>::const_iterator pc = code.begin() + address; + + std::vector<std::string> locals(variables.size()); + typedef std::pair<std::string, int> pair; + BOOST_FOREACH(pair const& p, variables) + { + locals[p.second] = p.first; + std::cout << " local " + << p.first << ", @" << p.second << std::endl; + } + + std::map<std::size_t, std::string> lines; + std::set<std::size_t> jumps; + + while (pc != (code.begin() + address + size_)) + { + std::string line; + std::size_t address = pc - code.begin(); + + switch (*pc++) + { + case op_neg: + line += " op_neg"; + break; + + case op_not: + line += " op_not"; + break; + + case op_add: + line += " op_add"; + break; + + case op_sub: + line += " op_sub"; + break; + + case op_mul: + line += " op_mul"; + break; + + case op_div: + line += " op_div"; + break; + + case op_eq: + line += " op_eq"; + break; + + case op_neq: + line += " op_neq"; + break; + + case op_lt: + line += " op_lt"; + break; + + case op_lte: + line += " op_lte"; + break; + + case op_gt: + line += " op_gt"; + break; + + case op_gte: + line += " op_gte"; + break; + + case op_and: + line += " op_and"; + break; + + case op_or: + line += " op_or"; + break; + + case op_load: + line += " op_load "; + line += locals[*pc++]; + break; + + case op_store: + line += " op_store "; + line += locals[*pc++]; + break; + + case op_int: + line += " op_int "; + line += boost::lexical_cast<std::string>(*pc++); + break; + + case op_true: + line += " op_true"; + break; + + case op_false: + line += " op_false"; + break; + + case op_jump: + { + line += " op_jump "; + std::size_t pos = (pc - code.begin()) + *pc++; + if (pos == code.size()) + line += "end"; + else + line += boost::lexical_cast<std::string>(pos); + jumps.insert(pos); + } + break; + + case op_jump_if: + { + line += " op_jump_if "; + std::size_t pos = (pc - code.begin()) + *pc++; + if (pos == code.size()) + line += "end"; + else + line += boost::lexical_cast<std::string>(pos); + jumps.insert(pos); + } + break; + + case op_call: + { + line += " op_call "; + int nargs = *pc++; + std::size_t jump = *pc++; + line += boost::lexical_cast<std::string>(nargs) + ", "; + BOOST_ASSERT(function_calls.find(jump) != function_calls.end()); + line += function_calls.find(jump)->second; + } + break; + + case op_stk_adj: + line += " op_stk_adj "; + line += boost::lexical_cast<std::string>(*pc++); + break; + + + case op_return: + line += " op_return"; + break; + } + lines[address] = line; + } + + std::cout << "start:" << std::endl; + typedef std::pair<std::size_t, std::string> line_info; + BOOST_FOREACH(line_info const& l, lines) + { + std::size_t pos = l.first; + if (jumps.find(pos) != jumps.end()) + std::cout << pos << ':' << std::endl; + std::cout << l.second << std::endl; + } + + std::cout << "end:" << std::endl << std::endl; + } + + bool compiler::operator()(unsigned int x) + { + BOOST_ASSERT(current != 0); + current->op(op_int, x); + return true; + } + + bool compiler::operator()(bool x) + { + BOOST_ASSERT(current != 0); + current->op(x ? op_true : op_false); + return true; + } + + bool compiler::operator()(ast::identifier const& x) + { + BOOST_ASSERT(current != 0); + int const* p = current->find_var(x.name); + if (p == 0) + { + error_handler(x.id, "Undeclared variable: " + x.name); + return false; + } + current->op(op_load, *p); + return true; + } + + bool compiler::operator()(token_ids::type const& x) + { + BOOST_ASSERT(current != 0); + switch (x) + { + case token_ids::plus: current->op(op_add); break; + case token_ids::minus: current->op(op_sub); break; + case token_ids::times: current->op(op_mul); break; + case token_ids::divide: current->op(op_div); break; + + case token_ids::equal: current->op(op_eq); break; + case token_ids::not_equal: current->op(op_neq); break; + case token_ids::less: current->op(op_lt); break; + case token_ids::less_equal: current->op(op_lte); break; + case token_ids::greater: current->op(op_gt); break; + case token_ids::greater_equal: current->op(op_gte); break; + + case token_ids::logical_or: current->op(op_or); break; + case token_ids::logical_and: current->op(op_and); break; + default: BOOST_ASSERT(0); return false; + } + return true; + } + + bool compiler::operator()(ast::unary const& x) + { + BOOST_ASSERT(current != 0); + if (!boost::apply_visitor(*this, x.operand_)) + return false; + switch (x.operator_) + { + case token_ids::minus: current->op(op_neg); break; + case token_ids::not_: current->op(op_not); break; + case token_ids::plus: break; + default: BOOST_ASSERT(0); return false; + } + return true; + } + + bool compiler::operator()(ast::function_call const& x) + { + BOOST_ASSERT(current != 0); + + if (functions.find(x.function_name.name) == functions.end()) + { + error_handler(x.function_name.id, "Function not found: " + x.function_name.name); + return false; + } + + boost::shared_ptr<code_gen::function> p = functions[x.function_name.name]; + + if (p->nargs() != x.args.size()) + { + error_handler(x.function_name.id, "Wrong number of arguments: " + x.function_name.name); + return false; + } + + BOOST_FOREACH(ast::expression const& expr, x.args) + { + if (!(*this)(expr)) + return false; + } + + current->op( + op_call, + p->nargs(), + p->get_address()); + current->link_to(x.function_name.name, p->get_address()); + + return true; + } + + namespace + { + int precedence[] = { + // precedence 1 + 1, // op_comma + + // precedence 2 + 2, // op_assign + 2, // op_plus_assign + 2, // op_minus_assign + 2, // op_times_assign + 2, // op_divide_assign + 2, // op_mod_assign + 2, // op_bit_and_assign + 2, // op_bit_xor_assign + 2, // op_bitor_assign + 2, // op_shift_left_assign + 2, // op_shift_right_assign + + // precedence 3 + 3, // op_logical_or + + // precedence 4 + 4, // op_logical_and + + // precedence 5 + 5, // op_bit_or + + // precedence 6 + 6, // op_bit_xor + + // precedence 7 + 7, // op_bit_and + + // precedence 8 + 8, // op_equal + 8, // op_not_equal + + // precedence 9 + 9, // op_less + 9, // op_less_equal + 9, // op_greater + 9, // op_greater_equal + + // precedence 10 + 10, // op_shift_left + 10, // op_shift_right + + // precedence 11 + 11, // op_plus + 11, // op_minus + + // precedence 12 + 12, // op_times + 12, // op_divide + 12 // op_mod + }; + } + + inline int precedence_of(token_ids::type op) + { + return precedence[op & 0xFF]; + } + + // The Shunting-yard algorithm + bool compiler::compile_expression( + int min_precedence, + std::list<ast::operation>::const_iterator& rbegin, + std::list<ast::operation>::const_iterator rend) + { + while ((rbegin != rend) && (precedence_of(rbegin->operator_) >= min_precedence)) + { + token_ids::type op = rbegin->operator_; + if (!boost::apply_visitor(*this, rbegin->operand_)) + return false; + ++rbegin; + + while ((rbegin != rend) && (precedence_of(rbegin->operator_) > precedence_of(op))) + { + token_ids::type next_op = rbegin->operator_; + compile_expression(precedence_of(next_op), rbegin, rend); + } + (*this)(op); + } + return true; + } + + bool compiler::operator()(ast::expression const& x) + { + BOOST_ASSERT(current != 0); + if (!boost::apply_visitor(*this, x.first)) + return false; + std::list<ast::operation>::const_iterator rbegin = x.rest.begin(); + if (!compile_expression(0, rbegin, x.rest.end())) + return false; + return true; + } + + bool compiler::operator()(ast::assignment const& x) + { + BOOST_ASSERT(current != 0); + if (!(*this)(x.rhs)) + return false; + int const* p = current->find_var(x.lhs.name); + if (p == 0) + { + error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name); + return false; + } + current->op(op_store, *p); + return true; + } + + bool compiler::operator()(ast::variable_declaration const& x) + { + BOOST_ASSERT(current != 0); + int const* p = current->find_var(x.lhs.name); + if (p != 0) + { + error_handler(x.lhs.id, "Duplicate variable: " + x.lhs.name); + return false; + } + if (x.rhs) // if there's an RHS initializer + { + bool r = (*this)(*x.rhs); + if (r) // don't add the variable if the RHS fails + { + current->add_var(x.lhs.name); + current->op(op_store, *current->find_var(x.lhs.name)); + } + return r; + } + else + { + current->add_var(x.lhs.name); + } + return true; + } + + bool compiler::operator()(ast::statement const& x) + { + BOOST_ASSERT(current != 0); + return boost::apply_visitor(*this, x); + } + + bool compiler::operator()(ast::statement_list const& x) + { + BOOST_ASSERT(current != 0); + BOOST_FOREACH(ast::statement const& s, x) + { + if (!(*this)(s)) + return false; + } + return true; + } + + bool compiler::operator()(ast::if_statement const& x) + { + BOOST_ASSERT(current != 0); + if (!(*this)(x.condition)) + return false; + current->op(op_jump_if, 0); // we shall fill this (0) in later + std::size_t skip = current->size()-1; // mark its position + if (!(*this)(x.then)) + return false; + (*current)[skip] = current->size()-skip; // now we know where to jump to (after the if branch) + + if (x.else_) // We got an alse + { + (*current)[skip] += 2; // adjust for the "else" jump + current->op(op_jump, 0); // we shall fill this (0) in later + std::size_t exit = current->size()-1; // mark its position + if (!(*this)(*x.else_)) + return false; + (*current)[exit] = current->size()-exit;// now we know where to jump to (after the else branch) + } + + return true; + } + + bool compiler::operator()(ast::while_statement const& x) + { + BOOST_ASSERT(current != 0); + std::size_t loop = current->size(); // mark our position + if (!(*this)(x.condition)) + return false; + current->op(op_jump_if, 0); // we shall fill this (0) in later + std::size_t exit = current->size()-1; // mark its position + if (!(*this)(x.body)) + return false; + current->op(op_jump, + int(loop-1) - int(current->size())); // loop back + (*current)[exit] = current->size()-exit; // now we know where to jump to (to exit the loop) + return true; + } + + bool compiler::operator()(ast::return_statement const& x) + { + if (void_return) + { + if (x.expr) + { + error_handler(x.id, "'void' function returning a value: "); + return false; + } + } + else + { + if (!x.expr) + { + error_handler(x.id, current_function_name + " function must return a value: "); + return false; + } + } + + if (x.expr) + { + if (!(*this)(*x.expr)) + return false; + } + current->op(op_return); + return true; + } + + bool compiler::operator()(ast::function const& x) + { + void_return = x.return_type == "void"; + if (functions.find(x.function_name.name) != functions.end()) + { + error_handler(x.function_name.id, "Duplicate function: " + x.function_name.name); + return false; + } + boost::shared_ptr<code_gen::function>& p = functions[x.function_name.name]; + p.reset(new code_gen::function(code, x.args.size())); + current = p.get(); + current_function_name = x.function_name.name; + + // op_stk_adj 0 for now. we'll know how many variables + // we'll have later and add them + current->op(op_stk_adj, 0); + BOOST_FOREACH(ast::identifier const& arg, x.args) + { + current->add_var(arg.name); + } + + if (!(*this)(x.body)) + return false; + (*current)[1] = current->nvars(); // now store the actual number of variables + // this includes the arguments + return true; + } + + bool compiler::operator()(ast::function_list const& x) + { + // Jump to the main function + code.push_back(op_jump); + code.push_back(0); // we will fill this in later when we finish compiling + // and we know where the main function is + + BOOST_FOREACH(ast::function const& f, x) + { + if (!(*this)(f)) + { + code.clear(); + return false; + } + } + // find the main function + boost::shared_ptr<code_gen::function> p = + find_function("main"); + + if (!p) // main function not found + { + std::cerr << "Error: main function not defined" << std::endl; + return false; + } + code[1] = p->get_address()-1; // jump to this (main function) address + + return true; + } + + void compiler::print_assembler() const + { + typedef std::pair<std::string, boost::shared_ptr<code_gen::function> > pair; + BOOST_FOREACH(pair const& p, functions) + { + std::cout << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" << std::endl; + std::cout << p.second->get_address() << ": function " << p.first << std::endl; + p.second->print_assembler(); + } + } + + boost::shared_ptr<code_gen::function> + compiler::find_function(std::string const& name) const + { + function_table::const_iterator i = functions.find(name); + if (i == functions.end()) + return boost::shared_ptr<code_gen::function>(); + else + return i->second; + } +}} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/compiler.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/compiler.hpp new file mode 100644 index 00000000..b49c0ac4 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/compiler.hpp @@ -0,0 +1,123 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_COMPILER_HPP) +#define BOOST_SPIRIT_CONJURE_COMPILER_HPP + +#include "ast.hpp" +#include "error_handler.hpp" +#include <vector> +#include <map> +#include <boost/function.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_function.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> + +namespace client { namespace code_gen +{ + /////////////////////////////////////////////////////////////////////////// + // The Function + /////////////////////////////////////////////////////////////////////////// + struct function + { + function(std::vector<int>& code, int nargs) + : code(code), address(code.size()), size_(0), nargs_(nargs) {} + + void op(int a); + void op(int a, int b); + void op(int a, int b, int c); + + int& operator[](std::size_t i) { return code[address+i]; } + int const& operator[](std::size_t i) const { return code[address+i]; } + std::size_t size() const { return size_; } + std::size_t get_address() const { return address; } + + int nargs() const { return nargs_; } + int nvars() const { return variables.size(); } + int const* find_var(std::string const& name) const; + void add_var(std::string const& name); + void link_to(std::string const& name, std::size_t address); + + void print_assembler() const; + + private: + + std::map<std::string, int> variables; + std::map<std::size_t, std::string> function_calls; + std::vector<int>& code; + std::size_t address; + std::size_t size_; + std::size_t nargs_; + }; + + /////////////////////////////////////////////////////////////////////////// + // The Compiler + /////////////////////////////////////////////////////////////////////////// + struct compiler + { + typedef bool result_type; + + template <typename ErrorHandler> + compiler(ErrorHandler& error_handler_) + : current(0) + { + using namespace boost::phoenix::arg_names; + namespace phx = boost::phoenix; + using boost::phoenix::function; + + error_handler = function<ErrorHandler>(error_handler_)( + "Error! ", _2, phx::cref(error_handler_.iters)[_1]); + } + + bool operator()(ast::nil) { BOOST_ASSERT(0); return false; } + bool operator()(unsigned int x); + bool operator()(bool x); + bool operator()(ast::identifier const& x); + bool operator()(token_ids::type const& x); + bool operator()(ast::unary const& x); + bool operator()(ast::function_call const& x); + bool operator()(ast::expression const& x); + bool operator()(ast::assignment const& x); + bool operator()(ast::variable_declaration const& x); + bool operator()(ast::statement_list const& x); + bool operator()(ast::statement const& x); + bool operator()(ast::if_statement const& x); + bool operator()(ast::while_statement const& x); + bool operator()(ast::return_statement const& x); + bool operator()(ast::function const& x); + bool operator()(ast::function_list const& x); + + void print_assembler() const; + + boost::shared_ptr<code_gen::function> + find_function(std::string const& name) const; + + std::vector<int>& get_code() { return code; } + std::vector<int> const& get_code() const { return code; } + + private: + + bool compile_expression( + int min_precedence, + std::list<ast::operation>::const_iterator& rbegin, + std::list<ast::operation>::const_iterator rend); + + typedef std::map<std::string, boost::shared_ptr<code_gen::function> > function_table; + + std::vector<int> code; + code_gen::function* current; + std::string current_function_name; + function_table functions; + bool void_return; + + boost::function< + void(int tag, std::string const& what)> + error_handler; + }; +}} + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/config.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/config.hpp new file mode 100644 index 00000000..70af0db0 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/config.hpp @@ -0,0 +1,51 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_LEXER_CONFIG_HPP) +#define BOOST_SPIRIT_CONJURE_LEXER_CONFIG_HPP + +/////////////////////////////////////////////////////////////////////////////// +// The conjure lexer example can be built in 3 different variations: +// +// - With a lexer using runtime generated DFA tables +// - With a lexer using pre-generated (static) DFA tables +// - With a lexer using a pre-generated custom switch based state machine +// +// Use one of the following preprocessor constants to define, which of those +// will be built: + +/////////////////////////////////////////////////////////////////////////////// +// Use the lexer based on runtime generated DFA tables +// #define CONJURE_LEXER_DYNAMIC_TABLES 1 + +/////////////////////////////////////////////////////////////////////////////// +// Use the lexer based on pre-generated static DFA tables +// #define CONJURE_LEXER_STATIC_TABLES 1 + +/////////////////////////////////////////////////////////////////////////////// +// Use the lexer based on runtime generated DFA tables +// #define CONJURE_LEXER_STATIC_SWITCH 1 + +/////////////////////////////////////////////////////////////////////////////// +// The default is to use the dynamic table driven lexer +#if CONJURE_LEXER_DYNAMIC_TABLES == 0 && \ + CONJURE_LEXER_STATIC_TABLES == 0 && \ + CONJURE_LEXER_STATIC_SWITCH == 0 + +#define CONJURE_LEXER_DYNAMIC_TABLES 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Make sure we have only one lexer type selected +#if (CONJURE_LEXER_DYNAMIC_TABLES != 0 && CONJURE_LEXER_STATIC_TABLES != 0) || \ + (CONJURE_LEXER_DYNAMIC_TABLES != 0 && CONJURE_LEXER_STATIC_SWITCH != 0) || \ + (CONJURE_LEXER_STATIC_TABLES != 0 && CONJURE_LEXER_STATIC_SWITCH != 0) + +#error "Configuration problem: please select exactly one type of lexer to build" +#endif + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/conjure_static_lexer.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/conjure_static_lexer.hpp new file mode 100644 index 00000000..d626840b --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/conjure_static_lexer.hpp @@ -0,0 +1,483 @@ +// Copyright (c) 2008-2009 Ben Hanson +// Copyright (c) 2008-2011 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file licence_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Auto-generated by boost::lexer, do not edit + +#if !defined(BOOST_SPIRIT_LEXER_NEXT_TOKEN_CONJURE_STATIC_JUL_25_2011_07_03_08) +#define BOOST_SPIRIT_LEXER_NEXT_TOKEN_CONJURE_STATIC_JUL_25_2011_07_03_08 + +#include <boost/spirit/home/support/detail/lexer/char_traits.hpp> + +//////////////////////////////////////////////////////////////////////////////// +// the generated table of state names and the tokenizer have to be +// defined in the boost::spirit::lex::lexertl::static_ namespace +namespace boost { namespace spirit { namespace lex { namespace lexertl { namespace static_ { + +//////////////////////////////////////////////////////////////////////////////// +// this table defines the names of the lexer states +char const* const lexer_state_names_conjure_static[1] = +{ + "INITIAL" +}; + +//////////////////////////////////////////////////////////////////////////////// +// this variable defines the number of lexer states +std::size_t const lexer_state_count_conjure_static = 1; + +//////////////////////////////////////////////////////////////////////////////// +// this function returns the next matched token +template<typename Iterator> +std::size_t next_token_conjure_static (std::size_t& /*start_state_*/, bool& /*bol_*/, + Iterator &start_token_, Iterator const& end_, std::size_t& unique_id_) +{ + enum {end_state_index, id_index, unique_id_index, state_index, bol_index, + eol_index, dead_state_index, dfa_offset}; + + static std::size_t const npos = static_cast<std::size_t>(~0); + static std::size_t const lookup_[256] = { + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 7, 7, 41, 41, 7, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 7, 8, 41, 41, 41, 41, 9, 41, + 10, 11, 12, 13, 14, 15, 41, 16, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 41, 19, 20, 21, 22, 41, + 41, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 41, 41, 41, 41, 18, + 41, 23, 18, 18, 24, 25, 26, 18, + 27, 28, 18, 18, 29, 18, 30, 31, + 18, 18, 32, 33, 34, 35, 36, 37, + 18, 18, 18, 38, 39, 40, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41 }; + static std::size_t const dfa_alphabet_ = 42; + static std::size_t const dfa_[2604] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 27, 13, 11, 20, 21, 18, 16, + 24, 17, 19, 2, 26, 25, 14, 12, + 15, 26, 26, 7, 4, 26, 6, 26, + 26, 26, 9, 26, 3, 26, 5, 8, + 22, 10, 23, 0, 1, 35, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 28, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 1, 32, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 29, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 0, 0, + 0, 0, 1, 32, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 26, + 26, 30, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0, 1, 32, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 26, 32, 26, + 26, 26, 31, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 33, 26, 26, 26, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 1, 32, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 26, + 26, 26, 26, 34, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 0, 0, + 0, 0, 1, 32, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 35, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 36, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 37, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 61, 26, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 38, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 262177, 20, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 39, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 131091, 12, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 40, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 131093, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 41, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 393241, 16, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 393242, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 131099, 18, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 131100, + 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 42, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 40, 21, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 41, 22, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 123, 23, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 125, + 24, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 44, 25, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 59, 27, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 32, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 34, + 30, 0, 0, 0, 0, 27, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 32, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 43, 26, 26, 0, 0, + 0, 0, 1, 32, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 44, + 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0, 1, 32, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 26, 26, 26, + 45, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 46, 26, 26, 26, 0, 0, 0, 0, + 1, 65538, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 0, 0, + 0, 0, 1, 32, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 47, 26, 26, 26, 26, + 0, 0, 0, 0, 1, 32, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 26, 26, 26, + 48, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 49, 26, 26, 26, 0, 0, 0, 0, + 1, 131084, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 131085, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 131089, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 131090, + 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 131092, 13, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 131094, 15, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 42, 42, 42, 42, 42, + 50, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 51, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 1, 32, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 43, 26, 26, 26, 26, 0, 0, + 0, 0, 1, 32, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 52, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0, 1, 65537, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 53, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 1, 32, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 26, + 26, 26, 26, 26, 26, 54, 26, 26, + 26, 26, 26, 26, 26, 26, 0, 0, + 0, 0, 1, 32, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 55, 26, 26, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 56, 56, 56, 56, 56, + 50, 56, 56, 56, 57, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 1, 36, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 1, 65536, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 0, 0, + 0, 0, 1, 65539, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0, 1, 32, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 58, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 59, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 56, + 56, 56, 56, 56, 60, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 1, 33, 29, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 65540, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 61, 26, 26, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 56, + 56, 56, 56, 56, 60, 56, 56, 56, + 57, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 1, 65541, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0 }; + + if (start_token_ == end_) + { + unique_id_ = npos; + return 0; + } + + std::size_t const* ptr_ = dfa_ + dfa_alphabet_; + Iterator curr_ = start_token_; + bool end_state_ = *ptr_ != 0; + std::size_t id_ = *(ptr_ + id_index); + std::size_t uid_ = *(ptr_ + unique_id_index); + Iterator end_token_ = start_token_; + + while (curr_ != end_) + { + std::size_t const state_ = + ptr_[lookup_[static_cast<unsigned char>(*curr_++)]]; + + if (state_ == 0) break; + + ptr_ = &dfa_[state_ * dfa_alphabet_]; + + if (*ptr_) + { + end_state_ = true; + id_ = *(ptr_ + id_index); + uid_ = *(ptr_ + unique_id_index); + end_token_ = curr_; + } + } + + if (end_state_) + { + // return longest match + start_token_ = end_token_; + } + else + { + id_ = npos; + uid_ = npos; + } + + unique_id_ = uid_; + return id_; +} + +//////////////////////////////////////////////////////////////////////////////// +// this defines a generic accessors for the information above +struct lexer_conjure_static +{ + // version number and feature-set of compatible static lexer engine + enum + { + static_version = 65536, + supports_bol = false, + supports_eol = false + }; + + // return the number of lexer states + static std::size_t state_count() + { + return lexer_state_count_conjure_static; + } + + // return the name of the lexer state as given by 'idx' + static char const* state_name(std::size_t idx) + { + return lexer_state_names_conjure_static[idx]; + } + + // return the next matched token + template<typename Iterator> + static std::size_t next(std::size_t &start_state_, bool& bol_ + , Iterator &start_token_, Iterator const& end_, std::size_t& unique_id_) + { + return next_token_conjure_static(start_state_, bol_, start_token_, end_, unique_id_); + } +}; + +}}}}} // namespace boost::spirit::lex::lexertl::static_ + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/conjure_static_lexer_generate.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/conjure_static_lexer_generate.cpp new file mode 100644 index 00000000..1ba8fac0 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/conjure_static_lexer_generate.cpp @@ -0,0 +1,43 @@ +// Copyright (c) 2001-2011 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This small utility program generates the 2 static lexers, the static table +// driven and the static switch based lexer. + +#include <fstream> +#include <iostream> + +#include "lexer_def.hpp" +#include <boost/spirit/include/lex_generate_static_lexertl.hpp> + +int main() +{ + typedef std::string::const_iterator base_iterator_type; + typedef client::lexer::conjure_tokens<base_iterator_type> lexer_type; + + lexer_type lexer; + + // first generate the static switch based lexer + std::ofstream out_static("conjure_static_switch_lexer.hpp"); + + bool result = boost::spirit::lex::lexertl::generate_static_switch( + lexer, out_static, "conjure_static_switch"); + if (!result) { + std::cerr << "Failed to generate static switch based lexer\n"; + return -1; + } + + // now generate the static table based lexer + std::ofstream out("conjure_static_lexer.hpp"); + result = boost::spirit::lex::lexertl::generate_static( + lexer, out, "conjure_static"); + if (!result) { + std::cerr << "Failed to generate static table based lexer\n"; + return -1; + } + + return 0; +} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/conjure_static_switch_lexer.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/conjure_static_switch_lexer.hpp new file mode 100644 index 00000000..3b23016b --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/conjure_static_switch_lexer.hpp @@ -0,0 +1,873 @@ +// Copyright (c) 2008-2009 Ben Hanson +// Copyright (c) 2008-2011 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file licence_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Auto-generated by boost::lexer, do not edit + +#if !defined(BOOST_SPIRIT_LEXER_NEXT_TOKEN_CONJURE_STATIC_SWITCH_JUL_25_2011_07_03_08) +#define BOOST_SPIRIT_LEXER_NEXT_TOKEN_CONJURE_STATIC_SWITCH_JUL_25_2011_07_03_08 + +#include <boost/spirit/home/support/detail/lexer/char_traits.hpp> + +//////////////////////////////////////////////////////////////////////////////// +// the generated table of state names and the tokenizer have to be +// defined in the boost::spirit::lex::lexertl::static_ namespace +namespace boost { namespace spirit { namespace lex { namespace lexertl { namespace static_ { + +//////////////////////////////////////////////////////////////////////////////// +// this table defines the names of the lexer states +char const* const lexer_state_names_conjure_static_switch[1] = +{ + "INITIAL" +}; + +//////////////////////////////////////////////////////////////////////////////// +// this variable defines the number of lexer states +std::size_t const lexer_state_count_conjure_static_switch = 1; + +//////////////////////////////////////////////////////////////////////////////// +// this function returns the next matched token +template<typename Iterator> +std::size_t next_token_conjure_static_switch (std::size_t& /*start_state_*/, bool& /*bol_*/, + Iterator &start_token_, Iterator const& end_, std::size_t& unique_id_) +{ + static std::size_t const npos = static_cast<std::size_t>(~0); + + if (start_token_ == end_) + { + unique_id_ = npos; + return 0; + } + + Iterator curr_ = start_token_; + bool end_state_ = false; + std::size_t id_ = npos; + std::size_t uid_ = npos; + Iterator end_token_ = start_token_; + + char ch_ = 0; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9')) goto state0_1; + + if (ch_ == 't') goto state0_2; + + if (ch_ == 'f') goto state0_3; + + if (ch_ == 'v') goto state0_4; + + if (ch_ == 'i') goto state0_5; + + if (ch_ == 'e') goto state0_6; + + if (ch_ == 'w') goto state0_7; + + if (ch_ == 'r') goto state0_8; + + if (ch_ == '|') goto state0_9; + + if (ch_ == '&') goto state0_10; + + if (ch_ == '=') goto state0_11; + + if (ch_ == '!') goto state0_12; + + if (ch_ == '<') goto state0_13; + + if (ch_ == '>') goto state0_14; + + if (ch_ == '+') goto state0_15; + + if (ch_ == '-') goto state0_16; + + if (ch_ == '*') goto state0_17; + + if (ch_ == '/') goto state0_18; + + if (ch_ == '(') goto state0_19; + + if (ch_ == ')') goto state0_20; + + if (ch_ == '{') goto state0_21; + + if (ch_ == '}') goto state0_22; + + if (ch_ == ',') goto state0_23; + + if (ch_ == ';') goto state0_24; + + if ((ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'd') || (ch_ >= 'g' && ch_ <= 'h') || (ch_ >= 'j' && ch_ <= 'q') || ch_ == 's' || ch_ == 'u' || (ch_ >= 'x' && ch_ <= 'z')) goto state0_25; + + if ((ch_ >= '\t' && ch_ <= '\n') || ch_ == '\r' || ch_ == ' ') goto state0_26; + goto end; + +state0_1: + end_state_ = true; + id_ = 35; + uid_ = 0; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9')) goto state0_1; + goto end; + +state0_2: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'q') || (ch_ >= 's' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'r') goto state0_27; + goto end; + +state0_3: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'b' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'a') goto state0_28; + goto end; + +state0_4: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'n') || (ch_ >= 'p' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'o') goto state0_29; + goto end; + +state0_5: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'e') || (ch_ >= 'g' && ch_ <= 'm') || (ch_ >= 'o' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'n') goto state0_30; + + if (ch_ == 'f') goto state0_31; + goto end; + +state0_6: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'k') || (ch_ >= 'm' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'l') goto state0_32; + goto end; + +state0_7: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'g') || (ch_ >= 'i' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'h') goto state0_33; + goto end; + +state0_8: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'd') || (ch_ >= 'f' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'e') goto state0_34; + goto end; + +state0_9: + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '|') goto state0_35; + goto end; + +state0_10: + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '&') goto state0_36; + goto end; + +state0_11: + end_state_ = true; + id_ = 61; + uid_ = 26; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '=') goto state0_37; + goto end; + +state0_12: + end_state_ = true; + id_ = 262177; + uid_ = 20; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '=') goto state0_38; + goto end; + +state0_13: + end_state_ = true; + id_ = 131091; + uid_ = 12; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '=') goto state0_39; + goto end; + +state0_14: + end_state_ = true; + id_ = 131093; + uid_ = 14; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '=') goto state0_40; + goto end; + +state0_15: + end_state_ = true; + id_ = 393241; + uid_ = 16; + end_token_ = curr_; + goto end; + +state0_16: + end_state_ = true; + id_ = 393242; + uid_ = 17; + end_token_ = curr_; + goto end; + +state0_17: + end_state_ = true; + id_ = 131099; + uid_ = 18; + end_token_ = curr_; + goto end; + +state0_18: + end_state_ = true; + id_ = 131100; + uid_ = 19; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '*') goto state0_41; + goto end; + +state0_19: + end_state_ = true; + id_ = 40; + uid_ = 21; + end_token_ = curr_; + goto end; + +state0_20: + end_state_ = true; + id_ = 41; + uid_ = 22; + end_token_ = curr_; + goto end; + +state0_21: + end_state_ = true; + id_ = 123; + uid_ = 23; + end_token_ = curr_; + goto end; + +state0_22: + end_state_ = true; + id_ = 125; + uid_ = 24; + end_token_ = curr_; + goto end; + +state0_23: + end_state_ = true; + id_ = 44; + uid_ = 25; + end_token_ = curr_; + goto end; + +state0_24: + end_state_ = true; + id_ = 59; + uid_ = 27; + end_token_ = curr_; + goto end; + +state0_25: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_26: + end_state_ = true; + id_ = 34; + uid_ = 30; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '\t' && ch_ <= '\n') || ch_ == '\r' || ch_ == ' ') goto state0_26; + goto end; + +state0_27: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 't') || (ch_ >= 'v' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'u') goto state0_42; + goto end; + +state0_28: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'k') || (ch_ >= 'm' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'l') goto state0_43; + goto end; + +state0_29: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'h') || (ch_ >= 'j' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'i') goto state0_44; + goto end; + +state0_30: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 's') || (ch_ >= 'u' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 't') goto state0_45; + goto end; + +state0_31: + end_state_ = true; + id_ = 65538; + uid_ = 4; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_32: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'r') || (ch_ >= 't' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 's') goto state0_46; + goto end; + +state0_33: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'h') || (ch_ >= 'j' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'i') goto state0_47; + goto end; + +state0_34: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 's') || (ch_ >= 'u' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 't') goto state0_48; + goto end; + +state0_35: + end_state_ = true; + id_ = 131084; + uid_ = 8; + end_token_ = curr_; + goto end; + +state0_36: + end_state_ = true; + id_ = 131085; + uid_ = 9; + end_token_ = curr_; + goto end; + +state0_37: + end_state_ = true; + id_ = 131089; + uid_ = 10; + end_token_ = curr_; + goto end; + +state0_38: + end_state_ = true; + id_ = 131090; + uid_ = 11; + end_token_ = curr_; + goto end; + +state0_39: + end_state_ = true; + id_ = 131092; + uid_ = 13; + end_token_ = curr_; + goto end; + +state0_40: + end_state_ = true; + id_ = 131094; + uid_ = 15; + end_token_ = curr_; + goto end; + +state0_41: + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ != '*') goto state0_41; + + if (ch_ == '*') goto state0_49; + goto end; + +state0_42: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'd') || (ch_ >= 'f' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'e') goto state0_50; + goto end; + +state0_43: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'r') || (ch_ >= 't' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 's') goto state0_42; + goto end; + +state0_44: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'c') || (ch_ >= 'e' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'd') goto state0_51; + goto end; + +state0_45: + end_state_ = true; + id_ = 65537; + uid_ = 3; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_46: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'd') || (ch_ >= 'f' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'e') goto state0_52; + goto end; + +state0_47: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'k') || (ch_ >= 'm' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'l') goto state0_53; + goto end; + +state0_48: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 't') || (ch_ >= 'v' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'u') goto state0_54; + goto end; + +state0_49: + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '*') goto state0_49; + + if (ch_ != '*' && ch_ != '/') goto state0_55; + + if (ch_ == '/') goto state0_56; + goto end; + +state0_50: + end_state_ = true; + id_ = 36; + uid_ = 1; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_51: + end_state_ = true; + id_ = 65536; + uid_ = 2; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_52: + end_state_ = true; + id_ = 65539; + uid_ = 5; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_53: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'd') || (ch_ >= 'f' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'e') goto state0_57; + goto end; + +state0_54: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'q') || (ch_ >= 's' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'r') goto state0_58; + goto end; + +state0_55: + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ != '*') goto state0_55; + + if (ch_ == '*') goto state0_59; + goto end; + +state0_56: + end_state_ = true; + id_ = 33; + uid_ = 29; + end_token_ = curr_; + goto end; + +state0_57: + end_state_ = true; + id_ = 65540; + uid_ = 6; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_58: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'm') || (ch_ >= 'o' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'n') goto state0_60; + goto end; + +state0_59: + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ != '*' && ch_ != '/') goto state0_55; + + if (ch_ == '/') goto state0_56; + + if (ch_ == '*') goto state0_59; + goto end; + +state0_60: + end_state_ = true; + id_ = 65541; + uid_ = 7; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + +end: + if (end_state_) + { + // return longest match + start_token_ = end_token_; + } + else + { + id_ = npos; + uid_ = npos; + } + + unique_id_ = uid_; + return id_; +} + +//////////////////////////////////////////////////////////////////////////////// +// this defines a generic accessors for the information above +struct lexer_conjure_static_switch +{ + // version number and feature-set of compatible static lexer engine + enum + { + static_version = 65536, + supports_bol = false, + supports_eol = false + }; + + // return the number of lexer states + static std::size_t state_count() + { + return lexer_state_count_conjure_static_switch; + } + + // return the name of the lexer state as given by 'idx' + static char const* state_name(std::size_t idx) + { + return lexer_state_names_conjure_static_switch[idx]; + } + + // return the next matched token + template<typename Iterator> + static std::size_t next(std::size_t &start_state_, bool& bol_ + , Iterator &start_token_, Iterator const& end_, std::size_t& unique_id_) + { + return next_token_conjure_static_switch(start_state_, bol_, start_token_, end_, unique_id_); + } +}; + +}}}}} // namespace boost::spirit::lex::lexertl::static_ + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/error_handler.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/error_handler.hpp new file mode 100644 index 00000000..2b1ee5b2 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/error_handler.hpp @@ -0,0 +1,105 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_ERROR_HANDLER_HPP) +#define BOOST_SPIRIT_CONJURE_ERROR_HANDLER_HPP + +#include <iostream> +#include <string> +#include <vector> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////////// + // The error handler + /////////////////////////////////////////////////////////////////////////////// + template <typename BaseIterator, typename Iterator> + struct error_handler + { + template <typename, typename, typename> + struct result { typedef void type; }; + + error_handler(BaseIterator first, BaseIterator last) + : first(first), last(last) {} + + template <typename Message, typename What> + void operator()( + Message const& message, + What const& what, + Iterator err_pos) const + { + // retrieve underlying iterator from current token, err_pos points + // to the last validly matched token, so we use its end iterator + // as the error position + BaseIterator err_pos_base = err_pos->matched().end(); + std::cout << message << what << std::endl; + if (err_pos_base != BaseIterator()) + dump_error_line(err_pos_base); + } + + void dump_error_line(BaseIterator err_pos_base) const + { + int line; + BaseIterator line_start = get_pos(err_pos_base, line); + if (err_pos_base != last) + { + std::cout << " line " << line << ':' << std::endl; + std::cout << get_line(line_start) << std::endl; + for (; line_start != err_pos_base; ++line_start) + std::cout << ' '; + std::cout << '^' << std::endl; + } + else + { + std::cout << "Unexpected end of file.\n"; + } + + } + + BaseIterator get_pos(BaseIterator err_pos, int& line) const + { + line = 1; + BaseIterator i = first; + BaseIterator line_start = first; + while (i != err_pos) + { + bool eol = false; + if (i != err_pos && *i == '\r') // CR + { + eol = true; + line_start = ++i; + } + if (i != err_pos && *i == '\n') // LF + { + eol = true; + line_start = ++i; + } + if (eol) + ++line; + else + ++i; + } + return line_start; + } + + std::string get_line(BaseIterator err_pos) const + { + BaseIterator i = err_pos; + // position i to the next EOL + while (i != last && (*i != '\r' && *i != '\n')) + ++i; + return std::string(err_pos, i); + } + + BaseIterator first; + BaseIterator last; + std::vector<Iterator> iters; + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/expression.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/expression.cpp new file mode 100644 index 00000000..5b51ce36 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/expression.cpp @@ -0,0 +1,20 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "config.hpp" +#include "lexer.hpp" +#include "expression_def.hpp" + +typedef std::string::const_iterator base_iterator_type; +typedef client::lexer::conjure_tokens<base_iterator_type> lexer_type; +typedef lexer_type::iterator_type iterator_type; + +template struct client::parser::expression<iterator_type, lexer_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/expression.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/expression.hpp new file mode 100644 index 00000000..a5d431ef --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/expression.hpp @@ -0,0 +1,58 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_EXPRESSION_HPP) +#define BOOST_SPIRIT_CONJURE_EXPRESSION_HPP + +/////////////////////////////////////////////////////////////////////////////// +// Spirit v2.5 allows you to suppress automatic generation +// of predefined terminals to speed up complation. With +// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are +// responsible in creating instances of the terminals that +// you need (e.g. see qi::uint_type uint_ below). +#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment this if you want to enable debugging +// #define BOOST_SPIRIT_QI_DEBUG +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/spirit/include/qi.hpp> +#include "ast.hpp" +#include "error_handler.hpp" +#include <vector> + +namespace client { namespace parser +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // The expression grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator, typename Lexer> + struct expression : qi::grammar<Iterator, ast::expression()> + { + typedef error_handler<typename Lexer::base_iterator_type, Iterator> + error_handler_type; + + expression(error_handler_type& error_handler, Lexer const& l); + + Lexer const& lexer; + + qi::rule<Iterator, ast::expression()> expr; + qi::rule<Iterator, ast::operand()> unary_expr, primary_expr; + qi::rule<Iterator, ast::function_call()> function_call; + qi::rule<Iterator, std::list<ast::expression>()> argument_list; + qi::rule<Iterator, std::string()> identifier; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/expression_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/expression_def.hpp new file mode 100644 index 00000000..795051eb --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/expression_def.hpp @@ -0,0 +1,94 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "expression.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" +#include <boost/spirit/include/phoenix_function.hpp> +#include <boost/spirit/include/lex_plain_token.hpp> + +namespace client { namespace parser +{ + template <typename Iterator, typename Lexer> + expression<Iterator, Lexer>::expression( + error_handler<typename Lexer::base_iterator_type, Iterator>& error_handler + , Lexer const& l) + : expression::base_type(expr), lexer(l) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::_val_type _val; + qi::tokenid_mask_type tokenid_mask; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef client::error_handler<typename Lexer::base_iterator_type, Iterator> + error_handler_type; + typedef function<error_handler_type> error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + /////////////////////////////////////////////////////////////////////// + // Main expression grammar + expr = + unary_expr + >> *(tokenid_mask(token_ids::op_binary) > unary_expr) + ; + + unary_expr = + primary_expr + | (tokenid_mask(token_ids::op_unary) > unary_expr) + ; + + primary_expr = + lexer.lit_uint + | function_call + | identifier + | lexer.true_or_false + | '(' > expr > ')' + ; + + function_call = + (identifier >> '(') + > argument_list + > ')' + ; + + argument_list = -(expr % ','); + + identifier = lexer.identifier; + + /////////////////////////////////////////////////////////////////////// + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (expr) + (unary_expr) + (primary_expr) + (function_call) + (argument_list) + (identifier) + ); + + /////////////////////////////////////////////////////////////////////// + // Error handling: on error in expr, call error_handler. + on_error<fail>(expr, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + /////////////////////////////////////////////////////////////////////// + // Annotation: on success in primary_expr, call annotation. + on_success(primary_expr, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/function.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/function.cpp new file mode 100644 index 00000000..98c8169b --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/function.cpp @@ -0,0 +1,20 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "config.hpp" +#include "lexer.hpp" +#include "function_def.hpp" + +typedef std::string::const_iterator base_iterator_type; +typedef client::lexer::conjure_tokens<base_iterator_type> lexer_type; +typedef lexer_type::iterator_type iterator_type; + +template struct client::parser::function<iterator_type, lexer_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/function.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/function.hpp new file mode 100644 index 00000000..fc5263f1 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/function.hpp @@ -0,0 +1,36 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_FUNCTION_HPP) +#define BOOST_SPIRIT_CONJURE_FUNCTION_HPP + +#include "statement.hpp" + +namespace client { namespace parser +{ + /////////////////////////////////////////////////////////////////////////////// + // The function grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator, typename Lexer> + struct function : qi::grammar<Iterator, ast::function()> + { + typedef error_handler<typename Lexer::base_iterator_type, Iterator> + error_handler_type; + + function(error_handler_type& error_handler, Lexer const& l); + + statement<Iterator, Lexer> body; + + qi::rule<Iterator, ast::identifier()> identifier; + qi::rule<Iterator, std::list<ast::identifier>()> argument_list; + qi::rule<Iterator, ast::function()> start; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/function_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/function_def.hpp new file mode 100644 index 00000000..72bab856 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/function_def.hpp @@ -0,0 +1,64 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "function.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" + +namespace client { namespace parser +{ + template <typename Iterator, typename Lexer> + function<Iterator, Lexer>::function( + error_handler<typename Lexer::base_iterator_type, Iterator>& error_handler + , Lexer const& l) + : function::base_type(start), body(error_handler, l) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::_val_type _val; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef client::error_handler<typename Lexer::base_iterator_type, Iterator> + error_handler_type; + typedef function<error_handler_type> error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + identifier = body.expr.identifier; + argument_list = -(identifier % ','); + + start = (l.token("void") | l.token("int")) + > identifier + > '(' > argument_list > ')' + > '{' > body > '}' + ; + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (identifier) + (argument_list) + (start) + ); + + // Error handling: on error in start, call error_handler. + on_error<fail>(start, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + // Annotation: on success in start, call annotation. + on_success(identifier, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/ids.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/ids.hpp new file mode 100644 index 00000000..9446074c --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/ids.hpp @@ -0,0 +1,154 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_IDS_HPP) +#define BOOST_SPIRIT_CONJURE_IDS_HPP + +namespace client +{ + struct op_type + { + enum type + { + binary = 0x20000, + unary = 0x40000, + assign = 0x80000 + }; + }; + + struct op + { + enum type + { + // binary + comma, + assign, + plus_assign, + minus_assign, + times_assign, + divide_assign, + mod_assign, + bit_and_assign, + bit_xor_assign, + bit_or_assign, + shift_left_assign, + shift_right_assign, + logical_or, + logical_and, + bit_or, + bit_xor, + bit_and, + equal, + not_equal, + less, + less_equal, + greater, + greater_equal, + shift_left, + shift_right, + plus, + minus, + times, + divide, + mod, + + // unary + plus_plus, + minus_minus, + compl_, + not_, + }; + }; + + template <int type, int op> + struct make_op + { + static int const value = type + op; + }; + + template <op::type op> + struct unary_op : make_op<op_type::unary, op> {}; + + template <op::type op> + struct binary_op + : make_op<op_type::binary, op> {}; + + template <op::type op> + struct assign_op + : make_op<op_type::assign, op> {}; + + template <op::type op> + struct binary_or_unary_op + : make_op<op_type::unary | op_type::binary, op> {}; + + struct token_ids + { + enum type + { + // pseudo tags + invalid = -1, + op_binary = op_type::binary, + op_unary = op_type::unary, + op_assign = op_type::assign, + + // binary / unary operators with common tokens + // '+' and '-' can be binary or unary + // (the lexer cannot distinguish which) + plus = binary_or_unary_op<op::plus>::value, + minus = binary_or_unary_op<op::minus>::value, + + // binary operators + comma = binary_op<op::comma>::value, + assign = assign_op<op::assign>::value, + plus_assign = assign_op<op::plus_assign>::value, + minus_assign = assign_op<op::minus_assign>::value, + times_assign = assign_op<op::times_assign>::value, + divide_assign = assign_op<op::divide_assign>::value, + mod_assign = assign_op<op::mod_assign>::value, + bit_and_assign = assign_op<op::bit_and_assign>::value, + bit_xor_assign = assign_op<op::bit_xor_assign>::value, + bit_or_assign = assign_op<op::bit_or_assign>::value, + shift_left_assign = assign_op<op::shift_left_assign>::value, + shift_right_assign = assign_op<op::shift_right_assign>::value, + logical_or = binary_op<op::logical_or>::value, + logical_and = binary_op<op::logical_and>::value, + bit_or = binary_op<op::bit_or>::value, + bit_xor = binary_op<op::bit_xor>::value, + bit_and = binary_op<op::bit_and>::value, + equal = binary_op<op::equal>::value, + not_equal = binary_op<op::not_equal>::value, + less = binary_op<op::less>::value, + less_equal = binary_op<op::less_equal>::value, + greater = binary_op<op::greater>::value, + greater_equal = binary_op<op::greater_equal>::value, + shift_left = binary_op<op::shift_left>::value, + shift_right = binary_op<op::shift_right>::value, + times = binary_op<op::times>::value, + divide = binary_op<op::divide>::value, + mod = binary_op<op::mod>::value, + + // unary operators with overlaps + // '++' and '--' can be prefix or postfix + // (the lexer cannot distinguish which) + plus_plus = unary_op<op::plus_plus>::value, + minus_minus = unary_op<op::minus_minus>::value, + + // unary operators + compl_ = unary_op<op::compl_>::value, + not_ = unary_op<op::not_>::value, + + // misc tags + identifier = op::not_ + 1, + comment, + whitespace, + lit_uint, + true_or_false + }; + }; +} + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/lexer.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/lexer.cpp new file mode 100644 index 00000000..7ce7ec0c --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/lexer.cpp @@ -0,0 +1,17 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "config.hpp" +#include "lexer_def.hpp" + +typedef std::string::const_iterator base_iterator_type; +template client::lexer::conjure_tokens<base_iterator_type>::conjure_tokens(); +template bool client::lexer::conjure_tokens<base_iterator_type>::add_keyword( + std::string const&); diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/lexer.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/lexer.hpp new file mode 100644 index 00000000..c4945779 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/lexer.hpp @@ -0,0 +1,128 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_LEXER_HPP) +#define BOOST_SPIRIT_CONJURE_LEXER_HPP + +#include <boost/spirit/include/lex_lexertl.hpp> +#include <boost/spirit/include/lex_lexertl_position_token.hpp> + +#include "config.hpp" +#include "ids.hpp" + +#if CONJURE_LEXER_STATIC_TABLES != 0 +#include <boost/spirit/include/lex_static_lexertl.hpp> +#include "conjure_static_lexer.hpp" +#elif CONJURE_LEXER_STATIC_SWITCH != 0 +#include <boost/spirit/include/lex_static_lexertl.hpp> +#include "conjure_static_switch_lexer.hpp" +#endif +#include <boost/assert.hpp> + +namespace client { namespace lexer +{ + namespace lex = boost::spirit::lex; + + /////////////////////////////////////////////////////////////////////////// + namespace detail + { + namespace lex = boost::spirit::lex; + + template <typename BaseIterator> + struct get_lexer_type + { + // Our token needs to be able to carry several token values: + // std::string, unsigned int, and bool + typedef boost::mpl::vector<std::string, unsigned int, bool> + token_value_types; + + // Using the position_token class as the token type to be returned + // from the lexer iterators allows to retain positional information + // as every token instance stores an iterator pair pointing to the + // matched input sequence. + typedef lex::lexertl::position_token< + BaseIterator, token_value_types, boost::mpl::false_ + > token_type; + +#if CONJURE_LEXER_DYNAMIC_TABLES != 0 + // use the lexer based on runtime generated DFA tables + typedef lex::lexertl::actor_lexer<token_type> type; +#elif CONJURE_LEXER_STATIC_TABLES != 0 + // use the lexer based on pre-generated static DFA tables + typedef lex::lexertl::static_actor_lexer< + token_type + , boost::spirit::lex::lexertl::static_::lexer_conjure_static + > type; +#elif CONJURE_LEXER_STATIC_SWITCH != 0 + // use the lexer based on pre-generated static code + typedef lex::lexertl::static_actor_lexer< + token_type + , boost::spirit::lex::lexertl::static_::lexer_conjure_static_switch + > type; +#else +#error "Configuration problem: please select exactly one type of lexer to build" +#endif + }; + } + + /////////////////////////////////////////////////////////////////////////// + template <typename BaseIterator> + struct conjure_tokens + : lex::lexer<typename detail::get_lexer_type<BaseIterator>::type> + { + private: + // get the type of any qi::raw_token(...) and qi::token(...) constructs + typedef typename boost::spirit::result_of::terminal< + boost::spirit::tag::raw_token(token_ids::type) + >::type raw_token_spec; + + typedef typename boost::spirit::result_of::terminal< + boost::spirit::tag::token(token_ids::type) + >::type token_spec; + + typedef std::map<std::string, token_ids::type> keyword_map_type; + + protected: + // add a keyword to the mapping table + bool add_keyword(std::string const& keyword); + + public: + typedef BaseIterator base_iterator_type; + + conjure_tokens(); + + // extract a raw_token(id) for the given registered keyword + raw_token_spec operator()(std::string const& kwd) const + { + namespace qi = boost::spirit::qi; + qi::raw_token_type raw_token; + + typename keyword_map_type::const_iterator it = keywords_.find(kwd); + BOOST_ASSERT(it != keywords_.end()); + return raw_token((it != keywords_.end()) ? (*it).second : token_ids::invalid); + } + + // extract a token(id) for the given registered keyword + token_spec token(std::string const& kwd) const + { + namespace qi = boost::spirit::qi; + qi::token_type token; + + typename keyword_map_type::const_iterator it = keywords_.find(kwd); + BOOST_ASSERT(it != keywords_.end()); + return token((it != keywords_.end()) ? (*it).second : token_ids::invalid); + } + + lex::token_def<std::string> identifier; + lex::token_def<unsigned int> lit_uint; + lex::token_def<bool> true_or_false; + keyword_map_type keywords_; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/lexer_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/lexer_def.hpp new file mode 100644 index 00000000..cab990f7 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/lexer_def.hpp @@ -0,0 +1,74 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#include "lexer.hpp" + +namespace client { namespace lexer +{ + template <typename BaseIterator> + conjure_tokens<BaseIterator>::conjure_tokens() + : identifier("[a-zA-Z_][a-zA-Z_0-9]*", token_ids::identifier) + , lit_uint("[0-9]+", token_ids::lit_uint) + , true_or_false("true|false", token_ids::true_or_false) + { + lex::_pass_type _pass; + + this->self = lit_uint | true_or_false; + + add_keyword("void"); + add_keyword("int"); + add_keyword("if"); + add_keyword("else"); + add_keyword("while"); + add_keyword("return"); + + this->self.add + ("\\|\\|", token_ids::logical_or) + ("&&", token_ids::logical_and) + ("==", token_ids::equal) + ("!=", token_ids::not_equal) + ("<", token_ids::less) + ("<=", token_ids::less_equal) + (">", token_ids::greater) + (">=", token_ids::greater_equal) + ("\\+", token_ids::plus) + ("\\-", token_ids::minus) + ("\\*", token_ids::times) + ("\\/", token_ids::divide) + ("!", token_ids::not_) + ; + + this->self += lex::char_('(') | ')' | '{' | '}' | ',' | '=' | ';'; + + this->self += + identifier + | lex::string("\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\/", token_ids::comment) + [ + lex::_pass = lex::pass_flags::pass_ignore + ] + | lex::string("[ \t\n\r]+", token_ids::whitespace) + [ + lex::_pass = lex::pass_flags::pass_ignore + ] + ; + } + + template <typename BaseIterator> + bool conjure_tokens<BaseIterator>::add_keyword(std::string const& keyword) + { + // add the token to the lexer + token_ids::type id = token_ids::type(this->get_next_id()); + this->self.add(keyword, id); + + // store the mapping for later retrieval + std::pair<typename keyword_map_type::iterator, bool> p = + keywords_.insert(typename keyword_map_type::value_type(keyword, id)); + + return p.second; + } +}} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/main.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/main.cpp new file mode 100644 index 00000000..3e4e83c9 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/main.cpp @@ -0,0 +1,131 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Not a calculator anymore, right? :-) +// +// [ JDG April 10, 2007 ] spirit2 +// [ JDG February 18, 2011 ] Pure attributes. No semantic actions. +// [ HK June 3, 2011 ] Adding lexer +// +/////////////////////////////////////////////////////////////////////////////// + +#include "config.hpp" +#include "function.hpp" +#include "vm.hpp" +#include "compiler.hpp" +#include "lexer.hpp" +#include <boost/lexical_cast.hpp> +#include <fstream> + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main(int argc, char **argv) +{ + char const* filename; + if (argc > 1) + { + filename = argv[1]; + } + else + { + std::cerr << "Error: No input file provided." << std::endl; + return 1; + } + + std::ifstream in(filename, std::ios_base::in); + + if (!in) + { + std::cerr << "Error: Could not open input file: " + << filename << std::endl; + return 1; + } + + std::string source_code; // We will read the contents here. + in.unsetf(std::ios::skipws); // No white space skipping! + std::copy( + std::istream_iterator<char>(in), + std::istream_iterator<char>(), + std::back_inserter(source_code)); + + typedef std::string::const_iterator base_iterator_type; + typedef client::lexer::conjure_tokens<base_iterator_type> lexer_type; + typedef lexer_type::iterator_type iterator_type; + + lexer_type lexer; // Our lexer + + base_iterator_type first = source_code.begin(); + base_iterator_type last = source_code.end(); + + iterator_type iter = lexer.begin(first, last); + iterator_type end = lexer.end(); + + client::vmachine vm; // Our virtual machine + client::ast::function_list ast; // Our AST + + client::error_handler<base_iterator_type, iterator_type> + error_handler(first, last); // Our error handler + client::parser::function<iterator_type, lexer_type> + function(error_handler, lexer); // Our parser + client::code_gen::compiler + compiler(error_handler); // Our compiler + + // note: we don't need a skipper + bool success = parse(iter, end, +function, ast); + + std::cout << "-------------------------\n"; + + if (success && iter == end) + { + if (compiler(ast)) + { + boost::shared_ptr<client::code_gen::function> + p = compiler.find_function("main"); + if (!p) + return 1; + + int nargs = argc-2; + if (p->nargs() != nargs) + { + std::cerr << "Error: main function requires " << p->nargs() << " arguments." << std::endl; + std::cerr << nargs << " supplied." << std::endl; + return 1; + } + + std::cout << "Success\n"; + std::cout << "-------------------------\n"; + std::cout << "Assembler----------------\n\n"; + compiler.print_assembler(); + + // Push the arguments into our stack + for (int i = 0; i < nargs; ++i) + vm.get_stack()[i] = boost::lexical_cast<int>(argv[i+2]); + + // Call the interpreter + int r = vm.execute(compiler.get_code()); + + std::cout << "-------------------------\n"; + std::cout << "Result: " << r << std::endl; + std::cout << "-------------------------\n\n"; + } + else + { + std::cout << "Compile failure\n"; + } + } + else + { + error_handler.dump_error_line(first); + std::cout << "Parse failure\n"; + } + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/statement.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/statement.cpp new file mode 100644 index 00000000..ca85a61c --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/statement.cpp @@ -0,0 +1,20 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "config.hpp" +#include "lexer.hpp" +#include "statement_def.hpp" + +typedef std::string::const_iterator base_iterator_type; +typedef client::lexer::conjure_tokens<base_iterator_type> lexer_type; +typedef lexer_type::iterator_type iterator_type; + +template struct client::parser::statement<iterator_type, lexer_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/statement.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/statement.hpp new file mode 100644 index 00000000..208ca247 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/statement.hpp @@ -0,0 +1,42 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_STATEMENT_HPP) +#define BOOST_SPIRIT_CONJURE_STATEMENT_HPP + +#include "expression.hpp" + +namespace client { namespace parser +{ + /////////////////////////////////////////////////////////////////////////////// + // The statement grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator, typename Lexer> + struct statement : qi::grammar<Iterator, ast::statement_list()> + { + typedef error_handler<typename Lexer::base_iterator_type, Iterator> + error_handler_type; + + statement(error_handler_type& error_handler, Lexer const& l); + + expression<Iterator, Lexer> expr; + + qi::rule<Iterator, ast::statement_list()> + statement_list, compound_statement; + + qi::rule<Iterator, ast::statement()> statement_; + qi::rule<Iterator, ast::variable_declaration()> variable_declaration; + qi::rule<Iterator, ast::assignment()> assignment; + qi::rule<Iterator, ast::if_statement()> if_statement; + qi::rule<Iterator, ast::while_statement()> while_statement; + qi::rule<Iterator, ast::return_statement()> return_statement; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/statement_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/statement_def.hpp new file mode 100644 index 00000000..ab937085 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/statement_def.hpp @@ -0,0 +1,123 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "statement.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" + +namespace client { namespace parser +{ + template <typename Iterator, typename Lexer> + statement<Iterator, Lexer>::statement( + error_handler<typename Lexer::base_iterator_type, Iterator>& error_handler + , Lexer const& l) + : statement::base_type(statement_list), expr(error_handler, l) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::_val_type _val; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef client::error_handler<typename Lexer::base_iterator_type, Iterator> + error_handler_type; + typedef function<error_handler_type> error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + statement_list = + +statement_ + ; + + statement_ = + variable_declaration + | assignment + | compound_statement + | if_statement + | while_statement + | return_statement + ; + + variable_declaration = + l("int") + > expr.identifier + > -('=' > expr) + > ';' + ; + + assignment = + expr.identifier + > '=' + > expr + > ';' + ; + + if_statement = + l("if") + > '(' + > expr + > ')' + > statement_ + > + -( + l("else") + > statement_ + ) + ; + + while_statement = + l("while") + > '(' + > expr + > ')' + > statement_ + ; + + compound_statement = + '{' >> -statement_list >> '}' + ; + + return_statement = + l("return") + > -expr + > ';' + ; + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (statement_list) + (statement_) + (variable_declaration) + (assignment) + (if_statement) + (while_statement) + (compound_statement) + (return_statement) + ); + + // Error handling: on error in statement_list, call error_handler. + on_error<fail>(statement_list, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + // Annotation: on success in variable_declaration, + // assignment and return_statement, call annotation. + on_success(variable_declaration, + annotation_function(error_handler.iters)(_val, _1)); + on_success(assignment, + annotation_function(error_handler.iters)(_val, _1)); + on_success(return_statement, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/vm.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/vm.cpp new file mode 100644 index 00000000..af68f523 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/vm.cpp @@ -0,0 +1,160 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "config.hpp" +#include "vm.hpp" + +#if defined(_MSC_VER) +# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' + // (performance warning) +#endif + +namespace client +{ + int vmachine::execute( + std::vector<int> const& code + , std::vector<int>::const_iterator pc + , std::vector<int>::iterator frame_ptr + ) + { + std::vector<int>::iterator stack_ptr = frame_ptr; + + while (true) + { + switch (*pc++) + { + case op_neg: + stack_ptr[-1] = -stack_ptr[-1]; + break; + + case op_not: + stack_ptr[-1] = !bool(stack_ptr[-1]); + break; + + case op_add: + --stack_ptr; + stack_ptr[-1] += stack_ptr[0]; + break; + + case op_sub: + --stack_ptr; + stack_ptr[-1] -= stack_ptr[0]; + break; + + case op_mul: + --stack_ptr; + stack_ptr[-1] *= stack_ptr[0]; + break; + + case op_div: + --stack_ptr; + stack_ptr[-1] /= stack_ptr[0]; + break; + + case op_eq: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] == stack_ptr[0]); + break; + + case op_neq: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] != stack_ptr[0]); + break; + + case op_lt: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] < stack_ptr[0]); + break; + + case op_lte: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] <= stack_ptr[0]); + break; + + case op_gt: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] > stack_ptr[0]); + break; + + case op_gte: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] >= stack_ptr[0]); + break; + + case op_and: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1]) && bool(stack_ptr[0]); + break; + + case op_or: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1]) || bool(stack_ptr[0]); + break; + + case op_load: + *stack_ptr++ = frame_ptr[*pc++]; + break; + + case op_store: + --stack_ptr; + frame_ptr[*pc++] = stack_ptr[0]; + break; + + case op_int: + *stack_ptr++ = *pc++; + break; + + case op_true: + *stack_ptr++ = true; + break; + + case op_false: + *stack_ptr++ = false; + break; + + case op_jump: + pc += *pc; + break; + + case op_jump_if: + if (!bool(stack_ptr[-1])) + pc += *pc; + else + ++pc; + --stack_ptr; + break; + + case op_stk_adj: + stack_ptr += *pc++; + break; + + case op_call: + { + int nargs = *pc++; + int jump = *pc++; + + // a function call is a recursive call to execute + int r = execute( + code + , code.begin() + jump + , stack_ptr - nargs + ); + + // cleanup after return from function + stack_ptr[-nargs] = r; // get return value + stack_ptr -= (nargs - 1); // the stack will now contain + // the return value + } + break; + + case op_return: + return stack_ptr[-1]; + } + } + } +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/vm.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/vm.hpp new file mode 100644 index 00000000..0362eaf8 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/vm.hpp @@ -0,0 +1,82 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_VM_HPP) +#define BOOST_SPIRIT_CONJURE_VM_HPP + +#include <vector> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // The Virtual Machine + /////////////////////////////////////////////////////////////////////////// + enum byte_code + { + op_neg, // negate the top stack entry + op_add, // add top two stack entries + op_sub, // subtract top two stack entries + op_mul, // multiply top two stack entries + op_div, // divide top two stack entries + + op_not, // boolean negate the top stack entry + op_eq, // compare the top two stack entries for == + op_neq, // compare the top two stack entries for != + op_lt, // compare the top two stack entries for < + op_lte, // compare the top two stack entries for <= + op_gt, // compare the top two stack entries for > + op_gte, // compare the top two stack entries for >= + + op_and, // logical and top two stack entries + op_or, // logical or top two stack entries + + op_load, // load a variable + op_store, // store a variable + + op_int, // push constant integer into the stack + op_true, // push constant 0 into the stack + op_false, // push constant 1 into the stack + + op_jump_if, // jump to a relative position in the code if top stack + // evaluates to false + op_jump, // jump to a relative position in the code + + op_stk_adj, // adjust the stack (for args and locals) + op_call, // function call + op_return // return from function + }; + + class vmachine + { + public: + + vmachine(unsigned stackSize = 4096) + : stack(stackSize) + { + } + + int execute(std::vector<int> const& code) + { + return execute(code, code.begin(), stack.begin()); + } + + std::vector<int> const& get_stack() const { return stack; }; + std::vector<int>& get_stack() { return stack; }; + + private: + + int execute( + std::vector<int> const& code // the program code + , std::vector<int>::const_iterator pc // program counter + , std::vector<int>::iterator frame_ptr // start of arguments and locals + ); + + std::vector<int> stack; + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/annotation.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/annotation.hpp new file mode 100644 index 00000000..3b876431 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/annotation.hpp @@ -0,0 +1,141 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_ANNOTATION_HPP) +#define BOOST_SPIRIT_CONJURE_ANNOTATION_HPP + +#include <map> +#include <boost/variant/apply_visitor.hpp> +#include <boost/type_traits/is_base_of.hpp> +#include <boost/mpl/bool.hpp> +#include "ast.hpp" + +namespace client +{ + /////////////////////////////////////////////////////////////////////////////// + // The annotation handler links the AST to a map of iterator positions + // for the purpose of subsequent semantic error handling when the + // program is being compiled. + /////////////////////////////////////////////////////////////////////////////// + struct set_annotation_id + { + typedef void result_type; + + int id; + set_annotation_id(int id) : id(id) {} + + void operator()(ast::function_call& x) const + { + x.function_name.id = id; + } + + template <typename T> + void dispatch(T& x, boost::mpl::true_) const + { + x.id = id; + } + + template <typename T> + void dispatch(T& x, boost::mpl::false_) const + { + // no-op + } + + template <typename T> + void operator()(T& x) const + { + typename boost::is_base_of<ast::tagged, T> is_tagged; + dispatch(x, is_tagged); + } + }; + + struct get_annotation_id + { + typedef int result_type; + + int operator()(ast::function_call& x) const + { + return x.function_name.id; + } + + template <typename T> + int dispatch(T& x, boost::mpl::true_) const + { + return x.id; + } + + template <typename T> + int dispatch(T& x, boost::mpl::false_) const + { + return -1; + } + + template <typename T> + int operator()(T& x) const + { + typename boost::is_base_of<ast::tagged, T> is_tagged; + return dispatch(x, is_tagged); + } + }; + + template <typename Iterator> + struct annotation + { + template <typename, typename> + struct result { typedef void type; }; + + std::vector<Iterator>& iters; + annotation(std::vector<Iterator>& iters) + : iters(iters) {} + + void operator()(ast::operand& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + boost::apply_visitor(set_annotation_id(id), ast); + ast.id = id; + } + + void operator()(ast::primary_expr& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + boost::apply_visitor(set_annotation_id(id), ast); + ast.id = id; + } + + void operator()(ast::variable_declaration& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.lhs.id = id; + } + + void operator()(ast::assignment& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.lhs.id = id; + } + + void operator()(ast::return_statement& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.id = id; + } + + void operator()(ast::identifier& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.id = id; + } + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/ast.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/ast.hpp new file mode 100644 index 00000000..a77cb0ed --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/ast.hpp @@ -0,0 +1,240 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_AST_HPP) +#define BOOST_SPIRIT_CONJURE_AST_HPP + +#include <boost/config/warning_disable.hpp> +#include <boost/variant/recursive_variant.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/fusion/include/io.hpp> +#include <boost/spirit/include/support_extended_variant.hpp> +#include <boost/spirit/include/support_attributes.hpp> +#include <boost/optional.hpp> +#include <list> + +#include "ids.hpp" + +namespace client { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + // The AST + /////////////////////////////////////////////////////////////////////////// + struct tagged + { + int id; // Used to annotate the AST with the iterator position. + // This id is used as a key to a map<int, Iterator> + // (not really part of the AST.) + }; + + struct nil {}; + struct unary_expr; + struct function_call; + struct expression; + + struct identifier : tagged + { + identifier(std::string const& name = "") : name(name) {} + std::string name; + }; + + struct primary_expr : + tagged, + boost::spirit::extended_variant< + nil + , bool + , unsigned int + , identifier + , boost::recursive_wrapper<expression> + > + { + primary_expr() : base_type() {} + primary_expr(bool val) : base_type(val) {} + primary_expr(unsigned int val) : base_type(val) {} + primary_expr(identifier const& val) : base_type(val) {} + primary_expr(expression const& val) : base_type(val) {} + primary_expr(primary_expr const& rhs) + : base_type(rhs.get()) {} + }; + + struct operand : + tagged, + boost::spirit::extended_variant< + nil + , primary_expr + , boost::recursive_wrapper<unary_expr> + , boost::recursive_wrapper<function_call> + > + { + operand() : base_type() {} + operand(primary_expr const& val) : base_type(val) {} + operand(unary_expr const& val) : base_type(val) {} + operand(function_call const& val) : base_type(val) {} + operand(operand const& rhs) + : base_type(rhs.get()) {} + }; + + struct unary_expr : tagged + { + token_ids::type operator_; + operand operand_; + }; + + struct operation + { + token_ids::type operator_; + operand operand_; + }; + + struct function_call + { + identifier function_name; + std::list<expression> args; + }; + + struct expression + { + operand first; + std::list<operation> rest; + }; + + struct assignment + { + identifier lhs; + token_ids::type operator_; + expression rhs; + }; + + struct variable_declaration + { + identifier lhs; + boost::optional<expression> rhs; + }; + + struct if_statement; + struct while_statement; + struct statement_list; + struct return_statement; + + typedef boost::variant< + nil + , variable_declaration + , assignment + , boost::recursive_wrapper<if_statement> + , boost::recursive_wrapper<while_statement> + , boost::recursive_wrapper<return_statement> + , boost::recursive_wrapper<statement_list> + , boost::recursive_wrapper<expression> + > + statement; + + struct statement_list : std::list<statement> {}; + + struct if_statement + { + expression condition; + statement then; + boost::optional<statement> else_; + }; + + struct while_statement + { + expression condition; + statement body; + }; + + struct return_statement : tagged + { + boost::optional<expression> expr; + }; + + struct function + { + std::string return_type; + identifier function_name; + std::list<identifier> args; + boost::optional<statement_list> body; + }; + + typedef std::list<function> function_list; + + // print functions for debugging + inline std::ostream& operator<<(std::ostream& out, nil) + { + out << "nil"; return out; + } + + inline std::ostream& operator<<(std::ostream& out, identifier const& id) + { + out << id.name; return out; + } +}} + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::unary_expr, + (client::token_ids::type, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::operation, + (client::token_ids::type, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::function_call, + (client::ast::identifier, function_name) + (std::list<client::ast::expression>, args) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::expression, + (client::ast::operand, first) + (std::list<client::ast::operation>, rest) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::variable_declaration, + (client::ast::identifier, lhs) + (boost::optional<client::ast::expression>, rhs) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::assignment, + (client::ast::identifier, lhs) + (client::token_ids::type, operator_) + (client::ast::expression, rhs) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::if_statement, + (client::ast::expression, condition) + (client::ast::statement, then) + (boost::optional<client::ast::statement>, else_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::while_statement, + (client::ast::expression, condition) + (client::ast::statement, body) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::return_statement, + (boost::optional<client::ast::expression>, expr) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::function, + (std::string, return_type) + (client::ast::identifier, function_name) + (std::list<client::ast::identifier>, args) + (boost::optional<client::ast::statement_list>, body) +) + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.cpp new file mode 100644 index 00000000..e36ad770 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.cpp @@ -0,0 +1,1141 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "config.hpp" +#include "compiler.hpp" +#include "annotation.hpp" +#include "vm.hpp" + +#include <boost/foreach.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/range/adaptor/transformed.hpp> +#include <boost/assert.hpp> +#include <set> + +namespace client { namespace code_gen +{ + value::value() + : v(0), + is_lvalue_(false), + builder(0) + {} + + value::value( + llvm::Value* v, + bool is_lvalue_, + llvm::IRBuilder<>* builder) + : v(v), + is_lvalue_(is_lvalue_), + builder(builder) + {} + + value::value(value const& rhs) + : v(rhs.v), + is_lvalue_(rhs.is_lvalue_), + builder(rhs.builder) + {} + + bool value::is_lvalue() const + { + return is_lvalue_; + } + + bool value::is_valid() const + { + return v != 0; + } + + value::operator bool() const + { + return v != 0; + } + + void value::name(char const* id) + { + v->setName(id); + } + + void value::name(std::string const& id) + { + v->setName(id); + } + + value::operator llvm::Value*() const + { + if (is_lvalue_) + { + BOOST_ASSERT(builder != 0); + return builder->CreateLoad(v, v->getName()); + } + return v; + } + + value& value::operator=(value const& rhs) + { + v = rhs.v; + is_lvalue_ = rhs.is_lvalue_; + builder = rhs.builder; + return *this; + } + + value& value::assign(value const& rhs) + { + BOOST_ASSERT(is_lvalue()); + BOOST_ASSERT(builder != 0); + builder->CreateStore(rhs, v); + return *this; + } + + value operator-(value a) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateNeg(a, "neg_tmp"), + false, a.builder + ); + } + + value operator!(value a) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateNot(a, "not_tmp"), + false, a.builder + ); + } + + value operator+(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateAdd(a, b, "add_tmp"), + false, a.builder + ); + } + + value operator-(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateSub(a, b, "sub_tmp"), + false, a.builder + ); + } + + value operator*(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateMul(a, b, "mul_tmp"), + false, a.builder + ); + } + + value operator/(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateSDiv(a, b, "div_tmp"), + false, a.builder + ); + } + + value operator%(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateSRem(a, b, "mod_tmp"), + false, a.builder + ); + } + + value operator&(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateAnd(a, b, "and_tmp"), + false, a.builder + ); + } + + value operator|(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateOr(a, b, "or_tmp"), + false, a.builder + ); + } + + value operator^(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateXor(a, b, "xor_tmp"), + false, a.builder + ); + } + + value operator<<(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateShl(a, b, "shl_tmp"), + false, a.builder + ); + } + + value operator>>(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateLShr(a, b, "shr_tmp"), + false, a.builder + ); + } + + value operator==(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateICmpEQ(a, b, "eq_tmp"), + false, a.builder + ); + } + + value operator!=(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateICmpNE(a, b, "ne_tmp"), + false, a.builder + ); + } + + value operator<(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateICmpSLT(a, b, "slt_tmp"), + false, a.builder + ); + } + + value operator<=(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateICmpSLE(a, b, "sle_tmp"), + false, a.builder + ); + } + + value operator>(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateICmpSGT(a, b, "sgt_tmp"), + false, a.builder + ); + } + + value operator>=(value a, value b) + { + BOOST_ASSERT(a.builder != 0); + return value( + a.builder->CreateICmpSGE(a, b, "sge_tmp"), + false, a.builder + ); + } + + struct function::to_value + { + typedef value result_type; + llvm_compiler* c; + + to_value(llvm_compiler* c = 0) : c(c) {} + + value operator()(llvm::Value& v) const + { + return c->val(&v); + } + }; + + bool basic_block::has_terminator() const + { + return b->getTerminator() != 0; + } + + bool basic_block::is_valid() const + { + return b != 0; + } + + function::operator llvm::Function*() const + { + return f; + } + + std::size_t function::arg_size() const + { + return f->arg_size(); + } + + void function::add(basic_block const& b) + { + f->getBasicBlockList().push_back(b); + } + + void function::erase_from_parent() + { + f->eraseFromParent(); + } + + basic_block function::last_block() + { + return &f->getBasicBlockList().back(); + } + + bool function::empty() const + { + return f->empty(); + } + + std::string function::name() const + { + return f->getName(); + } + + function::arg_range function::args() const + { + BOOST_ASSERT(c != 0); + arg_val_iterator first(f->arg_begin(), to_value()); + arg_val_iterator last(f->arg_end(), to_value()); + return arg_range(first, last); + } + + bool function::is_valid() const + { + return f != 0; + } + + void function::verify() const + { + llvm::verifyFunction(*f); + } + + value llvm_compiler::val(unsigned int x) + { + return value( + llvm::ConstantInt::get(context(), llvm::APInt(int_size, x)), + false, &llvm_builder); + } + + value llvm_compiler::val(int x) + { + return value( + llvm::ConstantInt::get(context(), llvm::APInt(int_size, x)), + false, &llvm_builder); + } + + value llvm_compiler::val(bool x) + { + return value( + llvm::ConstantInt::get(context(), llvm::APInt(1, x)), + false, &llvm_builder); + } + + value llvm_compiler::val(llvm::Value* v) + { + return value(v, false, &llvm_builder); + } + + namespace + { + // Create an alloca instruction in the entry block of + // the function. This is used for mutable variables etc. + llvm::AllocaInst* + make_entry_block_alloca( + llvm::Function* f, + char const* name, + llvm::LLVMContext& context) + { + llvm::IRBuilder<> builder( + &f->getEntryBlock(), + f->getEntryBlock().begin()); + + return builder.CreateAlloca( + llvm::Type::getIntNTy(context, int_size), 0, name); + } + } + + value llvm_compiler::var(char const* name) + { + llvm::Function* f = llvm_builder.GetInsertBlock()->getParent(); + llvm::IRBuilder<> builder( + &f->getEntryBlock(), + f->getEntryBlock().begin()); + + llvm::AllocaInst* alloca = builder.CreateAlloca( + llvm::Type::getIntNTy(context(), int_size), 0, name); + + return value(alloca, true, &llvm_builder); + } + + struct value::to_llvm_value + { + typedef llvm::Value* result_type; + llvm::Value* operator()(value const& x) const + { + return x; + } + }; + + template <typename C> + llvm::Value* llvm_compiler::call_impl( + function callee, + C const& args_) + { + // Sigh. LLVM requires CreateCall arguments to be random access. + // It would have been better if it can accept forward iterators. + // I guess it needs the arguments to be in contiguous memory. + // So, we have to put the args into a temporary std::vector. + std::vector<llvm::Value*> args( + args_.begin(), args_.end()); + + // Check the args for null values. We can't have null values. + // Return 0 if we find one to flag error. + BOOST_FOREACH(llvm::Value* arg, args) + { + if (arg == 0) + return 0; + } + + return llvm_builder.CreateCall( + callee, args.begin(), args.end(), "call_tmp"); + } + + template <typename Container> + value llvm_compiler::call( + function callee, + Container const& args) + { + llvm::Value* call = call_impl( + callee, + args | boost::adaptors::transformed(value::to_llvm_value())); + + if (call == 0) + return val(); + return value(call, false, &llvm_builder); + } + + function llvm_compiler::get_function(char const* name) + { + return function(vm.module()->getFunction(name), this); + } + + function llvm_compiler::get_current_function() + { + // get the current function + return function(llvm_builder.GetInsertBlock()->getParent(), this); + } + + function llvm_compiler::declare_function( + bool void_return + , std::string const& name + , std::size_t nargs) + { + llvm::Type const* int_type = + llvm::Type::getIntNTy(context(), int_size); + llvm::Type const* void_type = llvm::Type::getVoidTy(context()); + + std::vector<llvm::Type const*> ints(nargs, int_type); + llvm::Type const* return_type = void_return ? void_type : int_type; + + llvm::FunctionType* function_type = + llvm::FunctionType::get(void_return ? void_type : int_type, ints, false); + + return function(llvm::Function::Create( + function_type, llvm::Function::ExternalLinkage, + name, vm.module()), this); + } + + basic_block llvm_compiler::make_basic_block( + char const* name + , function parent + , basic_block before) + { + return llvm::BasicBlock::Create(context(), name, parent, before); + } + + value llvm_compiler::var(std::string const& name) + { + return var(name.c_str()); + } + + function llvm_compiler::get_function(std::string const& name) + { + return get_function(name.c_str()); + } + + basic_block llvm_compiler::get_insert_block() + { + return llvm_builder.GetInsertBlock(); + } + + void llvm_compiler::set_insert_point(basic_block b) + { + llvm_builder.SetInsertPoint(b); + } + + void llvm_compiler::conditional_branch( + value cond, basic_block true_br, basic_block false_br) + { + llvm_builder.CreateCondBr(cond, true_br, false_br); + } + + void llvm_compiler::branch(basic_block b) + { + llvm_builder.CreateBr(b); + } + + void llvm_compiler::return_() + { + llvm_builder.CreateRetVoid(); + } + + void llvm_compiler::return_(value v) + { + llvm_builder.CreateRet(v); + } + + void llvm_compiler::optimize_function(function f) + { + // Optimize the function. + fpm.run(*f); + } + + void llvm_compiler::init_fpm() + { + // Set up the optimizer pipeline. Start with registering info about how the + // target lays out data structures. + fpm.add(new llvm::TargetData(*vm.execution_engine()->getTargetData())); + // Provide basic AliasAnalysis support for GVN. + fpm.add(llvm::createBasicAliasAnalysisPass()); + // Promote allocas to registers. + fpm.add(llvm::createPromoteMemoryToRegisterPass()); + // Do simple "peephole" optimizations and bit-twiddling optzns. + fpm.add(llvm::createInstructionCombiningPass()); + // Reassociate expressions. + fpm.add(llvm::createReassociatePass()); + // Eliminate Common SubExpressions. + fpm.add(llvm::createGVNPass()); + // Simplify the control flow graph (deleting unreachable blocks, etc). + fpm.add(llvm::createCFGSimplificationPass()); + + fpm.doInitialization(); + } + + value compiler::operator()(unsigned int x) + { + return val(x); + } + + value compiler::operator()(bool x) + { + return val(x); + } + + value compiler::operator()(ast::primary_expr const& x) + { + return boost::apply_visitor(*this, x.get()); + } + + value compiler::operator()(ast::identifier const& x) + { + // Look this variable up in the function. + if (locals.find(x.name) == locals.end()) + { + error_handler(x.id, "Undeclared variable: " + x.name); + return val(); + } + return locals[x.name]; + } + + value compiler::operator()(ast::unary_expr const& x) + { + value operand = boost::apply_visitor(*this, x.operand_); + if (!operand.is_valid()) + return val(); + + switch (x.operator_) + { + case token_ids::compl_: return operand ^ val(-1); + case token_ids::minus: return -operand; + case token_ids::not_: return !operand; + case token_ids::plus: return operand; + case token_ids::plus_plus: + { + if (!operand.is_lvalue()) + { + error_handler(x.id, "++ needs an var"); + return val(); + } + + value r = operand + val(1); + operand.assign(r); + return operand; + } + case token_ids::minus_minus: + { + if (!operand.is_lvalue()) + { + error_handler(x.id, "-- needs an var"); + return val(); + } + + value r = operand - val(1); + operand.assign(r); + return operand; + } + default: + BOOST_ASSERT(0); + return val(); + } + } + + namespace + { + struct compile_args + { + compiler& c; + compile_args(compiler& c) : c(c) {} + + typedef value result_type; + value operator()(ast::expression const& expr) const + { + return c(expr); + } + }; + } + + value compiler::operator()(ast::function_call const& x) + { + function callee = get_function(x.function_name.name); + if (!callee.is_valid()) + { + error_handler(x.function_name.id, + "Function not found: " + x.function_name.name); + return val(); + } + + if (callee.arg_size() != x.args.size()) + { + error_handler(x.function_name.id, + "Wrong number of arguments: " + x.function_name.name); + return val(); + } + + return call(callee, + x.args | boost::adaptors::transformed(compile_args(*this))); + } + + namespace + { + int precedence[] = { + // precedence 1 + 1, // op_comma + + // precedence 2 + 2, // op_assign + 2, // op_plus_assign + 2, // op_minus_assign + 2, // op_times_assign + 2, // op_divide_assign + 2, // op_mod_assign + 2, // op_bit_and_assign + 2, // op_bit_xor_assign + 2, // op_bitor_assign + 2, // op_shift_left_assign + 2, // op_shift_right_assign + + // precedence 3 + 3, // op_logical_or + + // precedence 4 + 4, // op_logical_and + + // precedence 5 + 5, // op_bit_or + + // precedence 6 + 6, // op_bit_xor + + // precedence 7 + 7, // op_bit_and + + // precedence 8 + 8, // op_equal + 8, // op_not_equal + + // precedence 9 + 9, // op_less + 9, // op_less_equal + 9, // op_greater + 9, // op_greater_equal + + // precedence 10 + 10, // op_shift_left + 10, // op_shift_right + + // precedence 11 + 11, // op_plus + 11, // op_minus + + // precedence 12 + 12, // op_times + 12, // op_divide + 12 // op_mod + }; + } + + inline int precedence_of(token_ids::type op) + { + return precedence[op & 0xFF]; + } + + value compiler::compile_binary_expression( + value lhs, value rhs, token_ids::type op) + { + switch (op) + { + case token_ids::plus: return lhs + rhs; + case token_ids::minus: return lhs - rhs; + case token_ids::times: return lhs * rhs; + case token_ids::divide: return lhs / rhs; + case token_ids::mod: return lhs % rhs; + + case token_ids::logical_or: + case token_ids::bit_or: return lhs | rhs; + + case token_ids::logical_and: + case token_ids::bit_and: return lhs & rhs; + + case token_ids::bit_xor: return lhs ^ rhs; + case token_ids::shift_left: return lhs << rhs; + case token_ids::shift_right: return lhs >> rhs; + + case token_ids::equal: return lhs == rhs; + case token_ids::not_equal: return lhs != rhs; + case token_ids::less: return lhs < rhs; + case token_ids::less_equal: return lhs <= rhs; + case token_ids::greater: return lhs > rhs; + case token_ids::greater_equal: return lhs >= rhs; + + default: BOOST_ASSERT(0); return val(); + } + } + + // The Shunting-yard algorithm + value compiler::compile_expression( + int min_precedence, + value lhs, + std::list<ast::operation>::const_iterator& rest_begin, + std::list<ast::operation>::const_iterator rest_end) + { + while ((rest_begin != rest_end) && + (precedence_of(rest_begin->operator_) >= min_precedence)) + { + token_ids::type op = rest_begin->operator_; + value rhs = boost::apply_visitor(*this, rest_begin->operand_); + if (!rhs.is_valid()) + return val(); + ++rest_begin; + + while ((rest_begin != rest_end) && + (precedence_of(rest_begin->operator_) > precedence_of(op))) + { + token_ids::type next_op = rest_begin->operator_; + rhs = compile_expression( + precedence_of(next_op), rhs, rest_begin, rest_end); + } + + lhs = compile_binary_expression(lhs, rhs, op); + } + return lhs; + } + + value compiler::operator()(ast::expression const& x) + { + value lhs = boost::apply_visitor(*this, x.first); + if (!lhs.is_valid()) + return val(); + std::list<ast::operation>::const_iterator rest_begin = x.rest.begin(); + return compile_expression(0, lhs, rest_begin, x.rest.end()); + } + + value compiler::operator()(ast::assignment const& x) + { + if (locals.find(x.lhs.name) == locals.end()) + { + error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name); + return val(); + } + + value lhs = locals[x.lhs.name]; + value rhs = (*this)(x.rhs); + if (!rhs.is_valid()) + return val(); + + if (x.operator_ == token_ids::assign) + { + lhs.assign(rhs); + return lhs; + } + + value result; + switch (x.operator_) + { + case token_ids::plus_assign: result = lhs + rhs; break; + case token_ids::minus_assign: result = lhs - rhs; break; + case token_ids::times_assign: result = lhs * rhs; break; + case token_ids::divide_assign: result = lhs / rhs; break; + case token_ids::mod_assign: result = lhs % rhs; break; + case token_ids::bit_and_assign: result = lhs & rhs; break; + case token_ids::bit_xor_assign: result = lhs ^ rhs; break; + case token_ids::bit_or_assign: result = lhs | rhs; break; + case token_ids::shift_left_assign: result = lhs << rhs; break; + case token_ids::shift_right_assign: result = lhs >> rhs; break; + default: BOOST_ASSERT(0); return val(); + } + + lhs.assign(result); + return lhs; + } + + bool compiler::operator()(ast::variable_declaration const& x) + { + if (locals.find(x.lhs.name) != locals.end()) + { + error_handler(x.lhs.id, "Duplicate variable: " + x.lhs.name); + return false; + } + + value init; + std::string const& name = x.lhs.name; + + if (x.rhs) // if there's an RHS initializer + { + init = (*this)(*x.rhs); + if (!init.is_valid()) // don't add the variable if the RHS fails + return false; + } + + value var_ = var(name.c_str()); + if (init.is_valid()) + var_.assign(init); + + // Remember this binding. + locals[name] = var_; + return true; + } + + struct compiler::statement_compiler : compiler + { + typedef bool result_type; + }; + + compiler::statement_compiler& compiler::as_statement() + { + return *static_cast<statement_compiler*>(this); + } + + bool compiler::operator()(ast::statement const& x) + { + if (boost::get<ast::nil>(&x) != 0) // empty statement + return true; + return boost::apply_visitor(as_statement(), x); + } + + bool compiler::operator()(ast::statement_list const& x) + { + BOOST_FOREACH(ast::statement const& s, x) + { + if (!(*this)(s)) + return false; + } + return true; + } + + bool compiler::operator()(ast::if_statement const& x) + { + value condition = (*this)(x.condition); + if (!condition.is_valid()) + return false; + + function f = get_current_function(); + + // Create blocks for the then and else cases. Insert the 'then' block at the + // end of the function. + basic_block then_block = make_basic_block("if.then", f); + basic_block else_block; + basic_block exit_block; + + if (x.else_) + { + else_block = make_basic_block("if.else"); + conditional_branch(condition, then_block, else_block); + } + else + { + exit_block = make_basic_block("if.end"); + conditional_branch(condition, then_block, exit_block); + } + + // Emit then value. + set_insert_point(then_block); + if (!(*this)(x.then)) + return false; + if (!then_block.has_terminator()) + { + if (!exit_block.is_valid()) + exit_block = make_basic_block("if.end"); + branch(exit_block); + } + // Codegen of 'then' can change the current block, update then_block + then_block = get_insert_block(); + + if (x.else_) + { + // Emit else block. + f.add(else_block); + set_insert_point(else_block); + if (!(*this)(*x.else_)) + return false; + if (!else_block.has_terminator()) + { + if (!exit_block.is_valid()) + exit_block = make_basic_block("if.end"); + branch(exit_block); + } + // Codegen of 'else' can change the current block, update else_block + else_block = get_insert_block(); + } + + if (exit_block.is_valid()) + { + // Emit exit block + f.add(exit_block); + set_insert_point(exit_block); + } + return true; + } + + bool compiler::operator()(ast::while_statement const& x) + { + function f = get_current_function(); + + basic_block cond_block = make_basic_block("while.cond", f); + basic_block body_block = make_basic_block("while.body"); + basic_block exit_block = make_basic_block("while.end"); + + branch(cond_block); + set_insert_point(cond_block); + value condition = (*this)(x.condition); + if (!condition.is_valid()) + return false; + conditional_branch(condition, body_block, exit_block); + f.add(body_block); + set_insert_point(body_block); + + if (!(*this)(x.body)) + return false; + + if (!body_block.has_terminator()) + branch(cond_block); // loop back + + // Emit exit block + f.add(exit_block); + set_insert_point(exit_block); + + return true; + } + + bool compiler::operator()(ast::return_statement const& x) + { + if (void_return) + { + if (x.expr) + { + error_handler( + x.id, "'void' function returning a value: "); + return false; + } + } + else + { + if (!x.expr) + { + error_handler( + x.id, current_function_name + + " function must return a value: "); + return false; + } + } + + if (x.expr) + { + value return_val = (*this)(*x.expr); + if (!return_val.is_valid()) + return false; + return_var.assign(return_val); + } + + branch(return_block); + return true; + } + + function compiler::function_decl(ast::function const& x) + { + void_return = x.return_type == "void"; + current_function_name = x.function_name.name; + + function f = + declare_function( + void_return + , current_function_name + , x.args.size()); + + // If function conflicted, the function already exixts. If it has a + // body, don't allow redefinition or reextern. + if (f.name() != current_function_name) + { + // Delete the one we just made and get the existing one. + f.erase_from_parent(); + f = get_function(current_function_name); + + // If function already has a body, reject this. + if (!f.empty()) + { + error_handler( + x.function_name.id, + "Duplicate function: " + x.function_name.name); + return function(); + } + + // If function took a different number of args, reject. + if (f.arg_size() != x.args.size()) + { + error_handler( + x.function_name.id, + "Redefinition of function with different # args: " + + x.function_name.name); + return function(); + } + + // Set names for all arguments. + function::arg_range rng = f.args(); + function::arg_range::const_iterator iter = rng.begin(); + BOOST_FOREACH(ast::identifier const& arg, x.args) + { + iter->name(arg.name); + ++iter; + } + } + return f; + } + + void compiler::function_allocas(ast::function const& x, function f) + { + // Create variables for each argument and register the + // argument in the symbol table so that references to it will succeed. + function::arg_range rng = f.args(); + function::arg_range::const_iterator iter = rng.begin(); + BOOST_FOREACH(ast::identifier const& arg, x.args) + { + // Create an arg_ for this variable. + value arg_ = var(arg.name); + + // Store the initial value into the arg_. + arg_.assign(*iter); + + // Add arguments to variable symbol table. + locals[arg.name] = arg_; + ++iter; + } + + if (!void_return) + { + // Create an alloca for the return value + return_var = var("return.val"); + } + } + + bool compiler::operator()(ast::function const& x) + { + /////////////////////////////////////////////////////////////////////// + // the signature: + function f = function_decl(x); + if (!f.is_valid()) + return false; + + /////////////////////////////////////////////////////////////////////// + // the body: + if (x.body) // compile the body if this is not a prototype + { + // Create a new basic block to start insertion into. + basic_block block = make_basic_block("entry", f); + set_insert_point(block); + + function_allocas(x, f); + return_block = make_basic_block("return"); + + if (!(*this)(*x.body)) + { + // Error reading body, remove function. + f.erase_from_parent(); + return false; + } + + basic_block last_block = f.last_block(); + + // If the last block is unterminated, connect it to return_block + if (!last_block.has_terminator()) + { + set_insert_point(last_block); + branch(return_block); + } + + f.add(return_block); + set_insert_point(return_block); + + if (void_return) + return_(); + else + return_(return_var); + + // Validate the generated code, checking for consistency. + f.verify(); + + // Optimize the function. + optimize_function(f); + } + + return true; + } + + bool compiler::operator()(ast::function_list const& x) + { + BOOST_FOREACH(ast::function const& f, x) + { + locals.clear(); // clear the variables + if (!(*this)(f)) + return false; + } + return true; + } +}} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.hpp new file mode 100644 index 00000000..ccca3644 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.hpp @@ -0,0 +1,311 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_COMPILER_HPP) +#define BOOST_SPIRIT_CONJURE_COMPILER_HPP + +#include "ast.hpp" +#include "error_handler.hpp" +#include "vm.hpp" +#include <map> + +#include <boost/function.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_function.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/iterator/transform_iterator.hpp> + +#include <llvm/DerivedTypes.h> +#include <llvm/Constants.h> +#include <llvm/LLVMContext.h> +#include <llvm/Module.h> +#include <llvm/PassManager.h> +#include <llvm/Analysis/Verifier.h> +#include <llvm/Analysis/Passes.h> +#include <llvm/Transforms/Scalar.h> +#include <llvm/Support/IRBuilder.h> + +namespace client { namespace code_gen +{ + unsigned const int_size = 32; + struct compiler; + struct llvm_compiler; + + /////////////////////////////////////////////////////////////////////////// + // The Value (light abstraction of an LLVM::Value) + /////////////////////////////////////////////////////////////////////////// + struct value + { + value(); + value(value const& rhs); + + value& operator=(value const& rhs); + bool is_lvalue() const; + bool is_valid() const; + operator bool() const; + + value& assign(value const& rhs); + + void name(char const* id); + void name(std::string const& id); + + friend value operator-(value a); + friend value operator!(value a); + friend value operator+(value a, value b); + friend value operator-(value a, value b); + friend value operator*(value a, value b); + friend value operator/(value a, value b); + friend value operator%(value a, value b); + + friend value operator&(value a, value b); + friend value operator|(value a, value b); + friend value operator^(value a, value b); + friend value operator<<(value a, value b); + friend value operator>>(value a, value b); + + friend value operator==(value a, value b); + friend value operator!=(value a, value b); + friend value operator<(value a, value b); + friend value operator<=(value a, value b); + friend value operator>(value a, value b); + friend value operator>=(value a, value b); + + private: + + struct to_llvm_value; + friend struct to_llvm_value; + friend struct llvm_compiler; + + value( + llvm::Value* v, + bool is_lvalue_, + llvm::IRBuilder<>* builder); + + llvm::LLVMContext& context() const + { return llvm::getGlobalContext(); } + + operator llvm::Value*() const; + + llvm::Value* v; + bool is_lvalue_; + llvm::IRBuilder<>* builder; + }; + + /////////////////////////////////////////////////////////////////////////// + // The Basic Block (light abstraction of an LLVM::BasicBlock) + /////////////////////////////////////////////////////////////////////////// + struct function; + + struct basic_block + { + basic_block() + : b(0) {} + + bool has_terminator() const; + bool is_valid() const; + + private: + + basic_block(llvm::BasicBlock* b) + : b(b) {} + + operator llvm::BasicBlock*() const + { return b; } + + friend struct llvm_compiler; + friend struct function; + llvm::BasicBlock* b; + }; + + /////////////////////////////////////////////////////////////////////////// + // The Function (light abstraction of an LLVM::Function) + /////////////////////////////////////////////////////////////////////////// + struct llvm_compiler; + + struct function + { + private: + + struct to_value; + typedef llvm::Function::arg_iterator arg_iterator; + typedef boost::transform_iterator< + to_value, arg_iterator> + arg_val_iterator; + + public: + + typedef boost::iterator_range<arg_val_iterator> arg_range; + + function() + : f(0), c(c) {} + + std::string name() const; + + std::size_t arg_size() const; + arg_range args() const; + + void add(basic_block const& b); + void erase_from_parent(); + basic_block last_block(); + bool empty() const; + + bool is_valid() const; + void verify() const; + + private: + + function(llvm::Function* f, llvm_compiler* c) + : f(f), c(c) {} + + operator llvm::Function*() const; + + friend struct llvm_compiler; + llvm::Function* f; + llvm_compiler* c; + }; + + /////////////////////////////////////////////////////////////////////////// + // The LLVM Compiler. Lower level compiler (does not deal with ASTs) + /////////////////////////////////////////////////////////////////////////// + struct llvm_compiler + { + llvm_compiler(vmachine& vm) + : llvm_builder(context()) + , vm(vm) + , fpm(vm.module()) + { init_fpm(); } + + value val() { return value(); } + value val(unsigned int x); + value val(int x); + value val(bool x); + + value var(char const* name); + value var(std::string const& name); + + template <typename Container> + value call(function callee, Container const& args); + + function get_function(char const* name); + function get_function(std::string const& name); + function get_current_function(); + + function declare_function( + bool void_return + , std::string const& name + , std::size_t nargs); + + basic_block make_basic_block( + char const* name + , function parent = function() + , basic_block before = basic_block()); + + basic_block get_insert_block(); + void set_insert_point(basic_block b); + + void conditional_branch( + value cond, basic_block true_br, basic_block false_br); + void branch(basic_block b); + + void return_(); + void return_(value v); + + void optimize_function(function f); + + protected: + + llvm::LLVMContext& context() const + { return llvm::getGlobalContext(); } + + llvm::IRBuilder<>& builder() + { return llvm_builder; } + + private: + + friend struct function::to_value; + + value val(llvm::Value* v); + + template <typename C> + llvm::Value* call_impl( + function callee, + C const& args); + + void init_fpm(); + llvm::IRBuilder<> llvm_builder; + vmachine& vm; + llvm::FunctionPassManager fpm; + }; + + /////////////////////////////////////////////////////////////////////////// + // The main compiler. Generates code from our AST. + /////////////////////////////////////////////////////////////////////////// + struct compiler : llvm_compiler + { + typedef value result_type; + + template <typename ErrorHandler> + compiler(vmachine& vm, ErrorHandler& error_handler_) + : llvm_compiler(vm) + { + using namespace boost::phoenix::arg_names; + namespace phx = boost::phoenix; + using boost::phoenix::function; + + error_handler = function<ErrorHandler>(error_handler_)( + "Error! ", _2, phx::cref(error_handler_.iters)[_1]); + } + + value operator()(ast::nil) { BOOST_ASSERT(0); return val(); } + value operator()(unsigned int x); + value operator()(bool x); + value operator()(ast::primary_expr const& x); + value operator()(ast::identifier const& x); + value operator()(ast::unary_expr const& x); + value operator()(ast::function_call const& x); + value operator()(ast::expression const& x); + value operator()(ast::assignment const& x); + + bool operator()(ast::variable_declaration const& x); + bool operator()(ast::statement_list const& x); + bool operator()(ast::statement const& x); + bool operator()(ast::if_statement const& x); + bool operator()(ast::while_statement const& x); + bool operator()(ast::return_statement const& x); + bool operator()(ast::function const& x); + bool operator()(ast::function_list const& x); + + private: + + value compile_binary_expression( + value lhs, value rhs, token_ids::type op); + + value compile_expression( + int min_precedence, + value lhs, + std::list<ast::operation>::const_iterator& rest_begin, + std::list<ast::operation>::const_iterator rest_end); + + struct statement_compiler; + statement_compiler& as_statement(); + + function function_decl(ast::function const& x); + void function_allocas(ast::function const& x, function function); + + boost::function< + void(int tag, std::string const& what)> + error_handler; + + bool void_return; + std::string current_function_name; + std::map<std::string, value> locals; + basic_block return_block; + value return_var; + }; +}} + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/config.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/config.hpp new file mode 100644 index 00000000..70af0db0 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/config.hpp @@ -0,0 +1,51 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_LEXER_CONFIG_HPP) +#define BOOST_SPIRIT_CONJURE_LEXER_CONFIG_HPP + +/////////////////////////////////////////////////////////////////////////////// +// The conjure lexer example can be built in 3 different variations: +// +// - With a lexer using runtime generated DFA tables +// - With a lexer using pre-generated (static) DFA tables +// - With a lexer using a pre-generated custom switch based state machine +// +// Use one of the following preprocessor constants to define, which of those +// will be built: + +/////////////////////////////////////////////////////////////////////////////// +// Use the lexer based on runtime generated DFA tables +// #define CONJURE_LEXER_DYNAMIC_TABLES 1 + +/////////////////////////////////////////////////////////////////////////////// +// Use the lexer based on pre-generated static DFA tables +// #define CONJURE_LEXER_STATIC_TABLES 1 + +/////////////////////////////////////////////////////////////////////////////// +// Use the lexer based on runtime generated DFA tables +// #define CONJURE_LEXER_STATIC_SWITCH 1 + +/////////////////////////////////////////////////////////////////////////////// +// The default is to use the dynamic table driven lexer +#if CONJURE_LEXER_DYNAMIC_TABLES == 0 && \ + CONJURE_LEXER_STATIC_TABLES == 0 && \ + CONJURE_LEXER_STATIC_SWITCH == 0 + +#define CONJURE_LEXER_DYNAMIC_TABLES 1 +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Make sure we have only one lexer type selected +#if (CONJURE_LEXER_DYNAMIC_TABLES != 0 && CONJURE_LEXER_STATIC_TABLES != 0) || \ + (CONJURE_LEXER_DYNAMIC_TABLES != 0 && CONJURE_LEXER_STATIC_SWITCH != 0) || \ + (CONJURE_LEXER_STATIC_TABLES != 0 && CONJURE_LEXER_STATIC_SWITCH != 0) + +#error "Configuration problem: please select exactly one type of lexer to build" +#endif + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/conjure_static_lexer.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/conjure_static_lexer.hpp new file mode 100644 index 00000000..651d34d6 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/conjure_static_lexer.hpp @@ -0,0 +1,483 @@ +// Copyright (c) 2008-2009 Ben Hanson +// Copyright (c) 2008-2011 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file licence_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Auto-generated by boost::lexer, do not edit + +#if !defined(BOOST_SPIRIT_LEXER_NEXT_TOKEN_CONJURE_STATIC_JUL_25_2011_07_25_53) +#define BOOST_SPIRIT_LEXER_NEXT_TOKEN_CONJURE_STATIC_JUL_25_2011_07_25_53 + +#include <boost/spirit/home/support/detail/lexer/char_traits.hpp> + +//////////////////////////////////////////////////////////////////////////////// +// the generated table of state names and the tokenizer have to be +// defined in the boost::spirit::lex::lexertl::static_ namespace +namespace boost { namespace spirit { namespace lex { namespace lexertl { namespace static_ { + +//////////////////////////////////////////////////////////////////////////////// +// this table defines the names of the lexer states +char const* const lexer_state_names_conjure_static[1] = +{ + "INITIAL" +}; + +//////////////////////////////////////////////////////////////////////////////// +// this variable defines the number of lexer states +std::size_t const lexer_state_count_conjure_static = 1; + +//////////////////////////////////////////////////////////////////////////////// +// this function returns the next matched token +template<typename Iterator> +std::size_t next_token_conjure_static (std::size_t& /*start_state_*/, bool& /*bol_*/, + Iterator &start_token_, Iterator const& end_, std::size_t& unique_id_) +{ + enum {end_state_index, id_index, unique_id_index, state_index, bol_index, + eol_index, dead_state_index, dfa_offset}; + + static std::size_t const npos = static_cast<std::size_t>(~0); + static std::size_t const lookup_[256] = { + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 7, 7, 41, 41, 7, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 7, 8, 41, 41, 41, 41, 9, 41, + 10, 11, 12, 13, 14, 15, 41, 16, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 41, 19, 20, 21, 22, 41, + 41, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 41, 41, 41, 41, 18, + 41, 23, 18, 18, 24, 25, 26, 18, + 27, 28, 18, 18, 29, 18, 30, 31, + 18, 18, 32, 33, 34, 35, 36, 37, + 18, 18, 18, 38, 39, 40, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41 }; + static std::size_t const dfa_alphabet_ = 42; + static std::size_t const dfa_[2604] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 27, 13, 11, 20, 21, 18, 16, + 24, 17, 19, 2, 26, 25, 14, 12, + 15, 26, 26, 7, 4, 26, 6, 26, + 26, 26, 9, 26, 3, 26, 5, 8, + 22, 10, 23, 0, 1, 35, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 28, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 1, 32, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 29, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 0, 0, + 0, 0, 1, 32, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 26, + 26, 30, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0, 1, 32, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 26, 32, 26, + 26, 26, 31, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 33, 26, 26, 26, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 1, 32, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 26, + 26, 26, 26, 34, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 0, 0, + 0, 0, 1, 32, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 35, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 36, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 37, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 61, 26, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 38, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 262177, 20, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 39, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 131091, 12, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 40, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 131093, + 14, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 41, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 393241, 16, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 393242, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 131099, 18, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 131100, + 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 42, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 40, 21, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 41, 22, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 123, 23, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 125, + 24, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 44, 25, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 59, 27, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 32, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 34, + 30, 0, 0, 0, 0, 27, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 32, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 43, 26, 26, 0, 0, + 0, 0, 1, 32, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 44, + 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0, 1, 32, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 26, 26, 26, + 45, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 46, 26, 26, 26, 0, 0, 0, 0, + 1, 65538, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 0, 0, + 0, 0, 1, 32, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 47, 26, 26, 26, 26, + 0, 0, 0, 0, 1, 32, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 26, 26, 26, + 48, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 49, 26, 26, 26, 0, 0, 0, 0, + 1, 131084, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 131085, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 131089, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 131090, + 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 131092, 13, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 131094, 15, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 42, 42, 42, 42, 42, + 50, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 51, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 1, 32, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 43, 26, 26, 26, 26, 0, 0, + 0, 0, 1, 32, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 52, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0, 1, 65537, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 53, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 1, 32, 28, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 26, + 26, 26, 26, 26, 26, 54, 26, 26, + 26, 26, 26, 26, 26, 26, 0, 0, + 0, 0, 1, 32, 28, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 55, 26, 26, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 56, 56, 56, 56, 56, + 50, 56, 56, 56, 57, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 1, 36, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 1, 65536, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 26, 26, 0, 0, 0, 0, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 0, 0, + 0, 0, 1, 65539, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0, 1, 32, 28, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 58, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 59, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 56, + 56, 56, 56, 56, 60, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 1, 33, 29, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 65540, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 26, 0, + 0, 0, 0, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 1, 32, + 28, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 26, + 26, 0, 0, 0, 0, 26, 26, 26, + 26, 26, 26, 26, 61, 26, 26, 26, + 26, 26, 26, 26, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 56, + 56, 56, 56, 56, 60, 56, 56, 56, + 57, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 1, 65541, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 26, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 0, 0, 0, 0 }; + + if (start_token_ == end_) + { + unique_id_ = npos; + return 0; + } + + std::size_t const* ptr_ = dfa_ + dfa_alphabet_; + Iterator curr_ = start_token_; + bool end_state_ = *ptr_ != 0; + std::size_t id_ = *(ptr_ + id_index); + std::size_t uid_ = *(ptr_ + unique_id_index); + Iterator end_token_ = start_token_; + + while (curr_ != end_) + { + std::size_t const state_ = + ptr_[lookup_[static_cast<unsigned char>(*curr_++)]]; + + if (state_ == 0) break; + + ptr_ = &dfa_[state_ * dfa_alphabet_]; + + if (*ptr_) + { + end_state_ = true; + id_ = *(ptr_ + id_index); + uid_ = *(ptr_ + unique_id_index); + end_token_ = curr_; + } + } + + if (end_state_) + { + // return longest match + start_token_ = end_token_; + } + else + { + id_ = npos; + uid_ = npos; + } + + unique_id_ = uid_; + return id_; +} + +//////////////////////////////////////////////////////////////////////////////// +// this defines a generic accessors for the information above +struct lexer_conjure_static +{ + // version number and feature-set of compatible static lexer engine + enum + { + static_version = 65536, + supports_bol = false, + supports_eol = false + }; + + // return the number of lexer states + static std::size_t state_count() + { + return lexer_state_count_conjure_static; + } + + // return the name of the lexer state as given by 'idx' + static char const* state_name(std::size_t idx) + { + return lexer_state_names_conjure_static[idx]; + } + + // return the next matched token + template<typename Iterator> + static std::size_t next(std::size_t &start_state_, bool& bol_ + , Iterator &start_token_, Iterator const& end_, std::size_t& unique_id_) + { + return next_token_conjure_static(start_state_, bol_, start_token_, end_, unique_id_); + } +}; + +}}}}} // namespace boost::spirit::lex::lexertl::static_ + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/conjure_static_lexer_generate.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/conjure_static_lexer_generate.cpp new file mode 100644 index 00000000..1ba8fac0 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/conjure_static_lexer_generate.cpp @@ -0,0 +1,43 @@ +// Copyright (c) 2001-2011 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This small utility program generates the 2 static lexers, the static table +// driven and the static switch based lexer. + +#include <fstream> +#include <iostream> + +#include "lexer_def.hpp" +#include <boost/spirit/include/lex_generate_static_lexertl.hpp> + +int main() +{ + typedef std::string::const_iterator base_iterator_type; + typedef client::lexer::conjure_tokens<base_iterator_type> lexer_type; + + lexer_type lexer; + + // first generate the static switch based lexer + std::ofstream out_static("conjure_static_switch_lexer.hpp"); + + bool result = boost::spirit::lex::lexertl::generate_static_switch( + lexer, out_static, "conjure_static_switch"); + if (!result) { + std::cerr << "Failed to generate static switch based lexer\n"; + return -1; + } + + // now generate the static table based lexer + std::ofstream out("conjure_static_lexer.hpp"); + result = boost::spirit::lex::lexertl::generate_static( + lexer, out, "conjure_static"); + if (!result) { + std::cerr << "Failed to generate static table based lexer\n"; + return -1; + } + + return 0; +} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/conjure_static_switch_lexer.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/conjure_static_switch_lexer.hpp new file mode 100644 index 00000000..0dcd1ac7 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/conjure_static_switch_lexer.hpp @@ -0,0 +1,873 @@ +// Copyright (c) 2008-2009 Ben Hanson +// Copyright (c) 2008-2011 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file licence_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Auto-generated by boost::lexer, do not edit + +#if !defined(BOOST_SPIRIT_LEXER_NEXT_TOKEN_CONJURE_STATIC_SWITCH_JUL_25_2011_07_25_53) +#define BOOST_SPIRIT_LEXER_NEXT_TOKEN_CONJURE_STATIC_SWITCH_JUL_25_2011_07_25_53 + +#include <boost/spirit/home/support/detail/lexer/char_traits.hpp> + +//////////////////////////////////////////////////////////////////////////////// +// the generated table of state names and the tokenizer have to be +// defined in the boost::spirit::lex::lexertl::static_ namespace +namespace boost { namespace spirit { namespace lex { namespace lexertl { namespace static_ { + +//////////////////////////////////////////////////////////////////////////////// +// this table defines the names of the lexer states +char const* const lexer_state_names_conjure_static_switch[1] = +{ + "INITIAL" +}; + +//////////////////////////////////////////////////////////////////////////////// +// this variable defines the number of lexer states +std::size_t const lexer_state_count_conjure_static_switch = 1; + +//////////////////////////////////////////////////////////////////////////////// +// this function returns the next matched token +template<typename Iterator> +std::size_t next_token_conjure_static_switch (std::size_t& /*start_state_*/, bool& /*bol_*/, + Iterator &start_token_, Iterator const& end_, std::size_t& unique_id_) +{ + static std::size_t const npos = static_cast<std::size_t>(~0); + + if (start_token_ == end_) + { + unique_id_ = npos; + return 0; + } + + Iterator curr_ = start_token_; + bool end_state_ = false; + std::size_t id_ = npos; + std::size_t uid_ = npos; + Iterator end_token_ = start_token_; + + char ch_ = 0; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9')) goto state0_1; + + if (ch_ == 't') goto state0_2; + + if (ch_ == 'f') goto state0_3; + + if (ch_ == 'v') goto state0_4; + + if (ch_ == 'i') goto state0_5; + + if (ch_ == 'e') goto state0_6; + + if (ch_ == 'w') goto state0_7; + + if (ch_ == 'r') goto state0_8; + + if (ch_ == '|') goto state0_9; + + if (ch_ == '&') goto state0_10; + + if (ch_ == '=') goto state0_11; + + if (ch_ == '!') goto state0_12; + + if (ch_ == '<') goto state0_13; + + if (ch_ == '>') goto state0_14; + + if (ch_ == '+') goto state0_15; + + if (ch_ == '-') goto state0_16; + + if (ch_ == '*') goto state0_17; + + if (ch_ == '/') goto state0_18; + + if (ch_ == '(') goto state0_19; + + if (ch_ == ')') goto state0_20; + + if (ch_ == '{') goto state0_21; + + if (ch_ == '}') goto state0_22; + + if (ch_ == ',') goto state0_23; + + if (ch_ == ';') goto state0_24; + + if ((ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'd') || (ch_ >= 'g' && ch_ <= 'h') || (ch_ >= 'j' && ch_ <= 'q') || ch_ == 's' || ch_ == 'u' || (ch_ >= 'x' && ch_ <= 'z')) goto state0_25; + + if ((ch_ >= '\t' && ch_ <= '\n') || ch_ == '\r' || ch_ == ' ') goto state0_26; + goto end; + +state0_1: + end_state_ = true; + id_ = 35; + uid_ = 0; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9')) goto state0_1; + goto end; + +state0_2: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'q') || (ch_ >= 's' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'r') goto state0_27; + goto end; + +state0_3: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'b' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'a') goto state0_28; + goto end; + +state0_4: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'n') || (ch_ >= 'p' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'o') goto state0_29; + goto end; + +state0_5: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'e') || (ch_ >= 'g' && ch_ <= 'm') || (ch_ >= 'o' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'n') goto state0_30; + + if (ch_ == 'f') goto state0_31; + goto end; + +state0_6: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'k') || (ch_ >= 'm' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'l') goto state0_32; + goto end; + +state0_7: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'g') || (ch_ >= 'i' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'h') goto state0_33; + goto end; + +state0_8: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'd') || (ch_ >= 'f' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'e') goto state0_34; + goto end; + +state0_9: + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '|') goto state0_35; + goto end; + +state0_10: + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '&') goto state0_36; + goto end; + +state0_11: + end_state_ = true; + id_ = 61; + uid_ = 26; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '=') goto state0_37; + goto end; + +state0_12: + end_state_ = true; + id_ = 262177; + uid_ = 20; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '=') goto state0_38; + goto end; + +state0_13: + end_state_ = true; + id_ = 131091; + uid_ = 12; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '=') goto state0_39; + goto end; + +state0_14: + end_state_ = true; + id_ = 131093; + uid_ = 14; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '=') goto state0_40; + goto end; + +state0_15: + end_state_ = true; + id_ = 393241; + uid_ = 16; + end_token_ = curr_; + goto end; + +state0_16: + end_state_ = true; + id_ = 393242; + uid_ = 17; + end_token_ = curr_; + goto end; + +state0_17: + end_state_ = true; + id_ = 131099; + uid_ = 18; + end_token_ = curr_; + goto end; + +state0_18: + end_state_ = true; + id_ = 131100; + uid_ = 19; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '*') goto state0_41; + goto end; + +state0_19: + end_state_ = true; + id_ = 40; + uid_ = 21; + end_token_ = curr_; + goto end; + +state0_20: + end_state_ = true; + id_ = 41; + uid_ = 22; + end_token_ = curr_; + goto end; + +state0_21: + end_state_ = true; + id_ = 123; + uid_ = 23; + end_token_ = curr_; + goto end; + +state0_22: + end_state_ = true; + id_ = 125; + uid_ = 24; + end_token_ = curr_; + goto end; + +state0_23: + end_state_ = true; + id_ = 44; + uid_ = 25; + end_token_ = curr_; + goto end; + +state0_24: + end_state_ = true; + id_ = 59; + uid_ = 27; + end_token_ = curr_; + goto end; + +state0_25: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_26: + end_state_ = true; + id_ = 34; + uid_ = 30; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '\t' && ch_ <= '\n') || ch_ == '\r' || ch_ == ' ') goto state0_26; + goto end; + +state0_27: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 't') || (ch_ >= 'v' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'u') goto state0_42; + goto end; + +state0_28: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'k') || (ch_ >= 'm' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'l') goto state0_43; + goto end; + +state0_29: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'h') || (ch_ >= 'j' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'i') goto state0_44; + goto end; + +state0_30: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 's') || (ch_ >= 'u' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 't') goto state0_45; + goto end; + +state0_31: + end_state_ = true; + id_ = 65538; + uid_ = 4; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_32: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'r') || (ch_ >= 't' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 's') goto state0_46; + goto end; + +state0_33: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'h') || (ch_ >= 'j' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'i') goto state0_47; + goto end; + +state0_34: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 's') || (ch_ >= 'u' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 't') goto state0_48; + goto end; + +state0_35: + end_state_ = true; + id_ = 131084; + uid_ = 8; + end_token_ = curr_; + goto end; + +state0_36: + end_state_ = true; + id_ = 131085; + uid_ = 9; + end_token_ = curr_; + goto end; + +state0_37: + end_state_ = true; + id_ = 131089; + uid_ = 10; + end_token_ = curr_; + goto end; + +state0_38: + end_state_ = true; + id_ = 131090; + uid_ = 11; + end_token_ = curr_; + goto end; + +state0_39: + end_state_ = true; + id_ = 131092; + uid_ = 13; + end_token_ = curr_; + goto end; + +state0_40: + end_state_ = true; + id_ = 131094; + uid_ = 15; + end_token_ = curr_; + goto end; + +state0_41: + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ != '*') goto state0_41; + + if (ch_ == '*') goto state0_49; + goto end; + +state0_42: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'd') || (ch_ >= 'f' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'e') goto state0_50; + goto end; + +state0_43: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'r') || (ch_ >= 't' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 's') goto state0_42; + goto end; + +state0_44: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'c') || (ch_ >= 'e' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'd') goto state0_51; + goto end; + +state0_45: + end_state_ = true; + id_ = 65537; + uid_ = 3; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_46: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'd') || (ch_ >= 'f' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'e') goto state0_52; + goto end; + +state0_47: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'k') || (ch_ >= 'm' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'l') goto state0_53; + goto end; + +state0_48: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 't') || (ch_ >= 'v' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'u') goto state0_54; + goto end; + +state0_49: + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ == '*') goto state0_49; + + if (ch_ != '*' && ch_ != '/') goto state0_55; + + if (ch_ == '/') goto state0_56; + goto end; + +state0_50: + end_state_ = true; + id_ = 36; + uid_ = 1; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_51: + end_state_ = true; + id_ = 65536; + uid_ = 2; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_52: + end_state_ = true; + id_ = 65539; + uid_ = 5; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_53: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'd') || (ch_ >= 'f' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'e') goto state0_57; + goto end; + +state0_54: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'q') || (ch_ >= 's' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'r') goto state0_58; + goto end; + +state0_55: + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ != '*') goto state0_55; + + if (ch_ == '*') goto state0_59; + goto end; + +state0_56: + end_state_ = true; + id_ = 33; + uid_ = 29; + end_token_ = curr_; + goto end; + +state0_57: + end_state_ = true; + id_ = 65540; + uid_ = 6; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + goto end; + +state0_58: + end_state_ = true; + id_ = 32; + uid_ = 28; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'm') || (ch_ >= 'o' && ch_ <= 'z')) goto state0_25; + + if (ch_ == 'n') goto state0_60; + goto end; + +state0_59: + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if (ch_ != '*' && ch_ != '/') goto state0_55; + + if (ch_ == '/') goto state0_56; + + if (ch_ == '*') goto state0_59; + goto end; + +state0_60: + end_state_ = true; + id_ = 65541; + uid_ = 7; + end_token_ = curr_; + + if (curr_ == end_) goto end; + ch_ = *curr_; + ++curr_; + + if ((ch_ >= '0' && ch_ <= '9') || (ch_ >= 'A' && ch_ <= 'Z') || ch_ == '_' || (ch_ >= 'a' && ch_ <= 'z')) goto state0_25; + +end: + if (end_state_) + { + // return longest match + start_token_ = end_token_; + } + else + { + id_ = npos; + uid_ = npos; + } + + unique_id_ = uid_; + return id_; +} + +//////////////////////////////////////////////////////////////////////////////// +// this defines a generic accessors for the information above +struct lexer_conjure_static_switch +{ + // version number and feature-set of compatible static lexer engine + enum + { + static_version = 65536, + supports_bol = false, + supports_eol = false + }; + + // return the number of lexer states + static std::size_t state_count() + { + return lexer_state_count_conjure_static_switch; + } + + // return the name of the lexer state as given by 'idx' + static char const* state_name(std::size_t idx) + { + return lexer_state_names_conjure_static_switch[idx]; + } + + // return the next matched token + template<typename Iterator> + static std::size_t next(std::size_t &start_state_, bool& bol_ + , Iterator &start_token_, Iterator const& end_, std::size_t& unique_id_) + { + return next_token_conjure_static_switch(start_state_, bol_, start_token_, end_, unique_id_); + } +}; + +}}}}} // namespace boost::spirit::lex::lexertl::static_ + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/error_handler.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/error_handler.hpp new file mode 100644 index 00000000..efda9a6a --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/error_handler.hpp @@ -0,0 +1,99 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_ERROR_HANDLER_HPP) +#define BOOST_SPIRIT_CONJURE_ERROR_HANDLER_HPP + +#include <iostream> +#include <string> +#include <vector> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////////// + // The error handler + /////////////////////////////////////////////////////////////////////////////// + template <typename BaseIterator, typename Iterator> + struct error_handler + { + template <typename, typename, typename> + struct result { typedef void type; }; + + error_handler(BaseIterator first, BaseIterator last) + : first(first), last(last) {} + + template <typename Message, typename What> + void operator()( + Message const& message, + What const& what, + Iterator err_pos) const + { + // retrieve underlying iterator from current token, err_pos points + // to the last validly matched token, so we use its end iterator + // as the error position + BaseIterator err_pos_base = err_pos->matched().end(); + + int line; + BaseIterator line_start = get_pos(err_pos_base, line); + if (err_pos_base != last) + { + std::cout << message << what << " line " << line << ':' << std::endl; + std::cout << get_line(line_start) << std::endl; + for (; line_start != err_pos_base; ++line_start) + std::cout << ' '; + std::cout << '^' << std::endl; + } + else + { + std::cout << "Unexpected end of file. "; + std::cout << message << what << " line " << line << std::endl; + } + } + + BaseIterator get_pos(BaseIterator err_pos, int& line) const + { + line = 1; + BaseIterator i = first; + BaseIterator line_start = first; + while (i != err_pos) + { + bool eol = false; + if (i != err_pos && *i == '\r') // CR + { + eol = true; + line_start = ++i; + } + if (i != err_pos && *i == '\n') // LF + { + eol = true; + line_start = ++i; + } + if (eol) + ++line; + else + ++i; + } + return line_start; + } + + std::string get_line(BaseIterator err_pos) const + { + BaseIterator i = err_pos; + // position i to the next EOL + while (i != last && (*i != '\r' && *i != '\n')) + ++i; + return std::string(err_pos, i); + } + + BaseIterator first; + BaseIterator last; + std::vector<Iterator> iters; + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/expression.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/expression.cpp new file mode 100644 index 00000000..5b51ce36 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/expression.cpp @@ -0,0 +1,20 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "config.hpp" +#include "lexer.hpp" +#include "expression_def.hpp" + +typedef std::string::const_iterator base_iterator_type; +typedef client::lexer::conjure_tokens<base_iterator_type> lexer_type; +typedef lexer_type::iterator_type iterator_type; + +template struct client::parser::expression<iterator_type, lexer_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/expression.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/expression.hpp new file mode 100644 index 00000000..eec9cd6a --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/expression.hpp @@ -0,0 +1,59 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_EXPRESSION_HPP) +#define BOOST_SPIRIT_CONJURE_EXPRESSION_HPP + +/////////////////////////////////////////////////////////////////////////////// +// Spirit v2.5 allows you to suppress automatic generation +// of predefined terminals to speed up complation. With +// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are +// responsible in creating instances of the terminals that +// you need (e.g. see qi::uint_type uint_ below). +#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment this if you want to enable debugging +// #define BOOST_SPIRIT_QI_DEBUG +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/spirit/include/qi.hpp> +#include "ast.hpp" +#include "error_handler.hpp" +#include <vector> + +namespace client { namespace parser +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // The expression grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator, typename Lexer> + struct expression : qi::grammar<Iterator, ast::expression()> + { + typedef error_handler<typename Lexer::base_iterator_type, Iterator> + error_handler_type; + + expression(error_handler_type& error_handler, Lexer const& l); + + Lexer const& lexer; + + qi::rule<Iterator, ast::expression()> expr; + qi::rule<Iterator, ast::operand()> unary_expr, postfix_expr; + qi::rule<Iterator, ast::function_call()> function_call; + qi::rule<Iterator, std::list<ast::expression>()> argument_list; + qi::rule<Iterator, std::string()> identifier; + qi::rule<Iterator, ast::primary_expr()> primary_expr; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/expression_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/expression_def.hpp new file mode 100644 index 00000000..2d21323a --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/expression_def.hpp @@ -0,0 +1,104 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "expression.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" +#include <boost/spirit/include/phoenix_function.hpp> +#include <boost/spirit/include/lex_plain_token.hpp> + +namespace client { namespace parser +{ + template <typename Iterator, typename Lexer> + expression<Iterator, Lexer>::expression( + error_handler<typename Lexer::base_iterator_type, Iterator>& error_handler + , Lexer const& l) + : expression::base_type(expr), lexer(l) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::_val_type _val; + qi::tokenid_mask_type tokenid_mask; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef client::error_handler<typename Lexer::base_iterator_type, Iterator> + error_handler_type; + typedef function<error_handler_type> error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + /////////////////////////////////////////////////////////////////////// + // Main expression grammar + expr = + unary_expr + >> *(tokenid_mask(token_ids::op_binary) > unary_expr) + ; + + unary_expr = + postfix_expr + | (tokenid_mask(token_ids::op_unary) > unary_expr) + ; + + postfix_expr = + function_call + | primary_expr + ; + + primary_expr = + lexer.lit_uint + | lexer.true_or_false + | identifier + | '(' > expr > ')' + ; + + function_call = + (identifier >> '(') + > argument_list + > ')' + ; + + argument_list = -(expr % ','); + + identifier = lexer.identifier; + + /////////////////////////////////////////////////////////////////////// + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (expr) + (unary_expr) + (postfix_expr) + (primary_expr) + (function_call) + (argument_list) + (identifier) + ); + + /////////////////////////////////////////////////////////////////////// + // Error handling: on error in expr, call error_handler. + on_error<fail>(expr, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + /////////////////////////////////////////////////////////////////////// + // Annotation: on success in unary_expr, postfix_expr, + // and primary_expr call annotation. + on_success(unary_expr, + annotation_function(error_handler.iters)(_val, _1)); + on_success(postfix_expr, + annotation_function(error_handler.iters)(_val, _1)); + on_success(primary_expr, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/function.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/function.cpp new file mode 100644 index 00000000..98c8169b --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/function.cpp @@ -0,0 +1,20 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "config.hpp" +#include "lexer.hpp" +#include "function_def.hpp" + +typedef std::string::const_iterator base_iterator_type; +typedef client::lexer::conjure_tokens<base_iterator_type> lexer_type; +typedef lexer_type::iterator_type iterator_type; + +template struct client::parser::function<iterator_type, lexer_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/function.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/function.hpp new file mode 100644 index 00000000..fc5263f1 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/function.hpp @@ -0,0 +1,36 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_FUNCTION_HPP) +#define BOOST_SPIRIT_CONJURE_FUNCTION_HPP + +#include "statement.hpp" + +namespace client { namespace parser +{ + /////////////////////////////////////////////////////////////////////////////// + // The function grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator, typename Lexer> + struct function : qi::grammar<Iterator, ast::function()> + { + typedef error_handler<typename Lexer::base_iterator_type, Iterator> + error_handler_type; + + function(error_handler_type& error_handler, Lexer const& l); + + statement<Iterator, Lexer> body; + + qi::rule<Iterator, ast::identifier()> identifier; + qi::rule<Iterator, std::list<ast::identifier>()> argument_list; + qi::rule<Iterator, ast::function()> start; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/function_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/function_def.hpp new file mode 100644 index 00000000..95846264 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/function_def.hpp @@ -0,0 +1,64 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "function.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" + +namespace client { namespace parser +{ + template <typename Iterator, typename Lexer> + function<Iterator, Lexer>::function( + error_handler<typename Lexer::base_iterator_type, Iterator>& error_handler + , Lexer const& l) + : function::base_type(start), body(error_handler, l) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::_val_type _val; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef client::error_handler<typename Lexer::base_iterator_type, Iterator> + error_handler_type; + typedef function<error_handler_type> error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + identifier = body.expr.identifier; + argument_list = -(identifier % ','); + + start = (l.token("void") | l.token("int")) + > identifier + > '(' > argument_list > ')' + > (';' | '{' > body > '}') + ; + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (identifier) + (argument_list) + (start) + ); + + // Error handling: on error in start, call error_handler. + on_error<fail>(start, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + // Annotation: on success in start, call annotation. + on_success(identifier, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/ids.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/ids.hpp new file mode 100644 index 00000000..c4d98acc --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/ids.hpp @@ -0,0 +1,160 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_IDS_HPP) +#define BOOST_SPIRIT_CONJURE_IDS_HPP + +namespace client +{ + struct op_type + { + enum type + { + binary = 0x20000, + unary = 0x40000, + postfix_unary = 0x80000, + assign = 0x100000 + }; + }; + + struct op + { + enum type + { + // binary + comma, + assign, + plus_assign, + minus_assign, + times_assign, + divide_assign, + mod_assign, + bit_and_assign, + bit_xor_assign, + bit_or_assign, + shift_left_assign, + shift_right_assign, + logical_or, + logical_and, + bit_or, + bit_xor, + bit_and, + equal, + not_equal, + less, + less_equal, + greater, + greater_equal, + shift_left, + shift_right, + plus, + minus, + times, + divide, + mod, + + // unary + plus_plus, + minus_minus, + compl_, + not_, + }; + }; + + template <int type, int op> + struct make_op + { + static int const value = type + op; + }; + + template <op::type op> + struct unary_op : make_op<op_type::unary, op> {}; + + template <op::type op> + struct binary_op + : make_op<op_type::binary, op> {}; + + template <op::type op> + struct assign_op + : make_op<op_type::assign, op> {}; + + template <op::type op> + struct binary_or_unary_op + : make_op<op_type::unary | op_type::binary, op> {}; + + struct token_ids + { + enum type + { + // pseudo tags + invalid = -1, + op_binary = op_type::binary, + op_unary = op_type::unary, + op_assign = op_type::assign, + + // binary / unary operators with common tokens + // '+' and '-' can be binary or unary + // (the lexer cannot distinguish which) + plus = binary_or_unary_op<op::plus>::value, + minus = binary_or_unary_op<op::minus>::value, + + // binary operators + comma = binary_op<op::comma>::value, + assign = assign_op<op::assign>::value, + plus_assign = assign_op<op::plus_assign>::value, + minus_assign = assign_op<op::minus_assign>::value, + times_assign = assign_op<op::times_assign>::value, + divide_assign = assign_op<op::divide_assign>::value, + mod_assign = assign_op<op::mod_assign>::value, + bit_and_assign = assign_op<op::bit_and_assign>::value, + bit_xor_assign = assign_op<op::bit_xor_assign>::value, + bit_or_assign = assign_op<op::bit_or_assign>::value, + shift_left_assign = assign_op<op::shift_left_assign>::value, + shift_right_assign = assign_op<op::shift_right_assign>::value, + logical_or = binary_op<op::logical_or>::value, + logical_and = binary_op<op::logical_and>::value, + bit_or = binary_op<op::bit_or>::value, + bit_xor = binary_op<op::bit_xor>::value, + bit_and = binary_op<op::bit_and>::value, + equal = binary_op<op::equal>::value, + not_equal = binary_op<op::not_equal>::value, + less = binary_op<op::less>::value, + less_equal = binary_op<op::less_equal>::value, + greater = binary_op<op::greater>::value, + greater_equal = binary_op<op::greater_equal>::value, + shift_left = binary_op<op::shift_left>::value, + shift_right = binary_op<op::shift_right>::value, + times = binary_op<op::times>::value, + divide = binary_op<op::divide>::value, + mod = binary_op<op::mod>::value, + + // unary operators with overlaps + // '++' and '--' can be prefix or postfix + // (the lexer cannot distinguish which) + plus_plus = make_op< + op_type::unary + | op_type::postfix_unary, op::plus_plus>::value, + + minus_minus = make_op< + op_type::unary + | op_type::postfix_unary, op::minus_minus>::value, + + // unary operators + compl_ = unary_op<op::compl_>::value, + not_ = unary_op<op::not_>::value, + + // misc tags + identifier = op::not_ + 1, + comment, + whitespace, + lit_uint, + true_or_false + }; + }; +} + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/lexer.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/lexer.cpp new file mode 100644 index 00000000..d7125fed --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/lexer.cpp @@ -0,0 +1,17 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "config.hpp" +#include "lexer_def.hpp" + +typedef std::string::const_iterator base_iterator_type; +template client::lexer::conjure_tokens<base_iterator_type>::conjure_tokens(); +template bool client::lexer::conjure_tokens<base_iterator_type>::add_( + std::string const&, int); diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/lexer.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/lexer.hpp new file mode 100644 index 00000000..9624fe2f --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/lexer.hpp @@ -0,0 +1,144 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_LEXER_HPP) +#define BOOST_SPIRIT_CONJURE_LEXER_HPP + +#include <boost/spirit/include/lex_lexertl.hpp> +#include <boost/spirit/include/lex_lexertl_position_token.hpp> + +#include "config.hpp" +#include "ids.hpp" + +#if CONJURE_LEXER_STATIC_TABLES != 0 +#include <boost/spirit/include/lex_static_lexertl.hpp> +#include "conjure_static_lexer.hpp" +#elif CONJURE_LEXER_STATIC_SWITCH != 0 +#include <boost/spirit/include/lex_static_lexertl.hpp> +#include "conjure_static_switch_lexer.hpp" +#endif +#include <boost/assert.hpp> + +namespace client { namespace lexer +{ + namespace lex = boost::spirit::lex; + + /////////////////////////////////////////////////////////////////////////// + namespace detail + { + namespace lex = boost::spirit::lex; + + template <typename BaseIterator> + struct get_lexer_type + { + // Our token needs to be able to carry several token values: + // std::string, unsigned int, and bool + typedef boost::mpl::vector<std::string, unsigned int, bool> + token_value_types; + + // Using the position_token class as the token type to be returned + // from the lexer iterators allows to retain positional information + // as every token instance stores an iterator pair pointing to the + // matched input sequence. + typedef lex::lexertl::position_token< + BaseIterator, token_value_types, boost::mpl::false_ + > token_type; + +#if CONJURE_LEXER_DYNAMIC_TABLES != 0 + // use the lexer based on runtime generated DFA tables + typedef lex::lexertl::actor_lexer<token_type> type; +#elif CONJURE_LEXER_STATIC_TABLES != 0 + // use the lexer based on pre-generated static DFA tables + typedef lex::lexertl::static_actor_lexer< + token_type + , boost::spirit::lex::lexertl::static_::lexer_conjure_static + > type; +#elif CONJURE_LEXER_STATIC_SWITCH != 0 + // use the lexer based on pre-generated static code + typedef lex::lexertl::static_actor_lexer< + token_type + , boost::spirit::lex::lexertl::static_::lexer_conjure_static_switch + > type; +#else +#error "Configuration problem: please select exactly one type of lexer to build" +#endif + }; + } + + /////////////////////////////////////////////////////////////////////////// + template <typename BaseIterator> + struct conjure_tokens + : lex::lexer<typename detail::get_lexer_type<BaseIterator>::type> + { + private: + // get the type of any qi::raw_token(...) and qi::token(...) constructs + typedef typename boost::spirit::result_of::terminal< + boost::spirit::tag::raw_token(token_ids::type) + >::type raw_token_spec; + + typedef typename boost::spirit::result_of::terminal< + boost::spirit::tag::token(token_ids::type) + >::type token_spec; + + typedef std::map<std::string, token_ids::type> keyword_map_type; + + protected: + // add a keyword to the mapping table + bool add_(std::string const& keyword, int id = token_ids::invalid); + + struct keyword_adder + { + conjure_tokens& l; + keyword_adder(conjure_tokens& l) : l(l) {} + keyword_adder& operator()( + std::string const& keyword, int id = token_ids::invalid) + { + l.add_(keyword, id); + return *this; + } + }; + + friend struct keyword_adder; + keyword_adder add; + + public: + typedef BaseIterator base_iterator_type; + + conjure_tokens(); + + // extract a raw_token(id) for the given registered keyword + raw_token_spec operator()(std::string const& kwd) const + { + namespace qi = boost::spirit::qi; + qi::raw_token_type raw_token; + + typename keyword_map_type::const_iterator it = keywords_.find(kwd); + BOOST_ASSERT(it != keywords_.end()); + return raw_token((it != keywords_.end()) ? (*it).second : token_ids::invalid); + } + + // extract a token(id) for the given registered keyword + token_spec token(std::string const& kwd) const + { + namespace qi = boost::spirit::qi; + qi::token_type token; + + typename keyword_map_type::const_iterator it = keywords_.find(kwd); + BOOST_ASSERT(it != keywords_.end()); + return token((it != keywords_.end()) ? (*it).second : token_ids::invalid); + } + + lex::token_def<std::string> identifier; + lex::token_def<unsigned int> lit_uint; + lex::token_def<bool> true_or_false; + keyword_map_type keywords_; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/lexer_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/lexer_def.hpp new file mode 100644 index 00000000..29239768 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/lexer_def.hpp @@ -0,0 +1,100 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#include "lexer.hpp" + +namespace client { namespace lexer +{ + template <typename BaseIterator> + conjure_tokens<BaseIterator>::conjure_tokens() + : identifier("[a-zA-Z_][a-zA-Z_0-9]*", token_ids::identifier) + , lit_uint("[0-9]+", token_ids::lit_uint) + , true_or_false("true|false", token_ids::true_or_false) + , add(*this) + { + lex::_pass_type _pass; + + this->self = lit_uint | true_or_false; + + this->add + ("void") + ("int") + ("if") + ("else") + ("while") + ("return") + ("=", token_ids::assign) + ("\\+=", token_ids::plus_assign) + ("\\-=", token_ids::minus_assign) + ("\\*=", token_ids::times_assign) + ("\\/=", token_ids::divide_assign) + ("%=", token_ids::mod_assign) + ("\\&=", token_ids::bit_and_assign) + ("\\^=", token_ids::bit_xor_assign) + ("\\|=", token_ids::bit_or_assign) + ("<<=", token_ids::shift_left_assign) + (">>=", token_ids::shift_right_assign) + ("\\|\\|", token_ids::logical_or) + ("&&", token_ids::logical_and) + ("\\|", token_ids::bit_or) + ("\\^", token_ids::bit_xor) + ("&", token_ids::bit_and) + ("<<", token_ids::shift_left) + (">>", token_ids::shift_right) + ("==", token_ids::equal) + ("!=", token_ids::not_equal) + ("<", token_ids::less) + ("<=", token_ids::less_equal) + (">", token_ids::greater) + (">=", token_ids::greater_equal) + ("\\+", token_ids::plus) + ("\\-", token_ids::minus) + ("\\*", token_ids::times) + ("\\/", token_ids::divide) + ("%", token_ids::mod) + ("\\+\\+", token_ids::plus_plus) + ("\\-\\-", token_ids::minus_minus) + ("~", token_ids::compl_) + ("!", token_ids::not_) + ; + + this->self += lex::char_('(') | ')' | '{' | '}' | ',' | ';'; + + this->self += + identifier + | lex::string("(\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\/)|(\\/\\/[^\r\n]*)", token_ids::comment) + [ + lex::_pass = lex::pass_flags::pass_ignore + ] + | lex::string("[ \t\n\r]+", token_ids::whitespace) + [ + lex::_pass = lex::pass_flags::pass_ignore + ] + ; + } + + template <typename BaseIterator> + bool conjure_tokens<BaseIterator>::add_( + std::string const& keyword, int id_) + { + // add the token to the lexer + token_ids::type id; + if (id_ == token_ids::invalid) + id = token_ids::type(this->get_next_id()); + else + id = token_ids::type(id_); + + this->self.add(keyword, id); + // store the mapping for later retrieval + std::pair<typename keyword_map_type::iterator, bool> p = + keywords_.insert(typename keyword_map_type::value_type(keyword, id)); + + return p.second; + } +}} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/main.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/main.cpp new file mode 100644 index 00000000..9788e56f --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/main.cpp @@ -0,0 +1,156 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Not a calculator anymore, right? :-) +// +// [ JDG April 10, 2007 ] spirit2 +// [ JDG February 18, 2011 ] Pure attributes. No semantic actions. +// [ HK June 3, 2011 ] Adding lexer +// [ JDG July 18, 2011 ] Switching to LLVM backend +// +/////////////////////////////////////////////////////////////////////////////// + +#include "config.hpp" +#include "function.hpp" +#include "vm.hpp" +#include "compiler.hpp" +#include "lexer.hpp" +#include <boost/lexical_cast.hpp> +#include <fstream> + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main(int argc, char **argv) +{ + char const* filename; + if (argc > 1) + { + filename = argv[1]; + } + else + { + std::cerr << "Error: No input file provided." << std::endl; + return 1; + } + + std::ifstream in(filename, std::ios_base::in); + + if (!in) + { + std::cerr << "Error: Could not open input file: " + << filename << std::endl; + return 1; + } + + std::string source_code; // We will read the contents here. + in.unsetf(std::ios::skipws); // No white space skipping! + std::copy( + std::istream_iterator<char>(in), + std::istream_iterator<char>(), + std::back_inserter(source_code)); + + typedef std::string::const_iterator base_iterator_type; + typedef client::lexer::conjure_tokens<base_iterator_type> lexer_type; + typedef lexer_type::iterator_type iterator_type; + + lexer_type lexer; // Our lexer + + base_iterator_type first = source_code.begin(); + base_iterator_type last = source_code.end(); + + iterator_type iter = lexer.begin(first, last); + iterator_type end = lexer.end(); + + client::vmachine vm; // Our virtual machine + client::ast::function_list ast; // Our AST + + client::error_handler<base_iterator_type, iterator_type> + error_handler(first, last); // Our error handler + client::parser::function<iterator_type, lexer_type> + function(error_handler, lexer); // Our parser + client::code_gen::compiler + compiler(vm, error_handler); // Our compiler + + // note: we don't need a skipper + bool success = parse(iter, end, +function, ast); + + std::cout << "-------------------------\n"; + + if (success && iter == end) + { + if (compiler(ast)) + { + // JIT the main function + client::function main_function = vm.get_function("main"); + if (!main_function) + { + std::cerr << "function main not found" << std::endl; + return 1; + } + + int nargs = argc-2; + if (main_function.arity() != nargs) + { + std::cerr << "Error: main function requires " + << main_function.arity() << " arguments." << std::endl; + std::cerr << nargs << " supplied." << std::endl; + return 1; + } + + std::cout << "Success\n"; + std::cout << "-------------------------\n"; + std::cout << "Assembler----------------\n\n"; + vm.print_assembler(); + + // Call the main function + int r; + char** args = argv + 2; + switch (nargs) + { + case 0: r = main_function(); break; + + case 1: r = main_function( + boost::lexical_cast<int>(args[0])); + break; + + case 2: r = main_function( + boost::lexical_cast<int>(args[0]), + boost::lexical_cast<int>(args[1])); + break; + + case 3: r = main_function( + boost::lexical_cast<int>(args[0]), + boost::lexical_cast<int>(args[1]), + boost::lexical_cast<int>(args[2])); + break; + + default: + std::cerr << "Function calls with more " << + "than 3 arguments not supported" << std::endl; + return 1; + } + + std::cout << "-------------------------\n"; + std::cout << "Result: " << r << std::endl; + std::cout << "-------------------------\n\n"; + } + else + { + std::cout << "Compile failure\n"; + } + } + else + { + std::cout << "Parse failure\n"; + } + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/statement.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/statement.cpp new file mode 100644 index 00000000..ca85a61c --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/statement.cpp @@ -0,0 +1,20 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "config.hpp" +#include "lexer.hpp" +#include "statement_def.hpp" + +typedef std::string::const_iterator base_iterator_type; +typedef client::lexer::conjure_tokens<base_iterator_type> lexer_type; +typedef lexer_type::iterator_type iterator_type; + +template struct client::parser::statement<iterator_type, lexer_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/statement.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/statement.hpp new file mode 100644 index 00000000..208ca247 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/statement.hpp @@ -0,0 +1,42 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_STATEMENT_HPP) +#define BOOST_SPIRIT_CONJURE_STATEMENT_HPP + +#include "expression.hpp" + +namespace client { namespace parser +{ + /////////////////////////////////////////////////////////////////////////////// + // The statement grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator, typename Lexer> + struct statement : qi::grammar<Iterator, ast::statement_list()> + { + typedef error_handler<typename Lexer::base_iterator_type, Iterator> + error_handler_type; + + statement(error_handler_type& error_handler, Lexer const& l); + + expression<Iterator, Lexer> expr; + + qi::rule<Iterator, ast::statement_list()> + statement_list, compound_statement; + + qi::rule<Iterator, ast::statement()> statement_; + qi::rule<Iterator, ast::variable_declaration()> variable_declaration; + qi::rule<Iterator, ast::assignment()> assignment; + qi::rule<Iterator, ast::if_statement()> if_statement; + qi::rule<Iterator, ast::while_statement()> while_statement; + qi::rule<Iterator, ast::return_statement()> return_statement; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/statement_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/statement_def.hpp new file mode 100644 index 00000000..4712aa5f --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/statement_def.hpp @@ -0,0 +1,126 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "statement.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" + +namespace client { namespace parser +{ + template <typename Iterator, typename Lexer> + statement<Iterator, Lexer>::statement( + error_handler<typename Lexer::base_iterator_type, Iterator>& error_handler + , Lexer const& l) + : statement::base_type(statement_list), expr(error_handler, l) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::_val_type _val; + qi::tokenid_mask_type tokenid_mask; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef client::error_handler<typename Lexer::base_iterator_type, Iterator> + error_handler_type; + typedef function<error_handler_type> error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + statement_list = + +statement_ + ; + + statement_ = + variable_declaration + | assignment + | compound_statement + | if_statement + | while_statement + | return_statement + | expr + | ';' + ; + + variable_declaration = + l("int") + > expr.identifier + > -(l("=") > expr) + > ';' + ; + + assignment = + expr.identifier + > tokenid_mask(token_ids::op_assign) + > expr + > ';' + ; + + if_statement = + l("if") + > '(' + > expr + > ')' + > statement_ + > + -( + l("else") + > statement_ + ) + ; + + while_statement = + l("while") + > '(' + > expr + > ')' + > statement_ + ; + + compound_statement = + '{' >> -statement_list >> '}' + ; + + return_statement = + l("return") + > -expr + > ';' + ; + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (statement_list) + (statement_) + (variable_declaration) + (assignment) + (if_statement) + (while_statement) + (compound_statement) + (return_statement) + ); + + // Error handling: on error in statement_list, call error_handler. + on_error<fail>(statement_list, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + // Annotation: on success in variable_declaration, + // assignment and return_statement, call annotation. + on_success(variable_declaration, + annotation_function(error_handler.iters)(_val, _1)); + on_success(assignment, + annotation_function(error_handler.iters)(_val, _1)); + on_success(return_statement, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/vm.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/vm.cpp new file mode 100644 index 00000000..5434046f --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/vm.cpp @@ -0,0 +1,43 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "config.hpp" +#include "vm.hpp" +#include <iostream> + +#if defined(_MSC_VER) +# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' + // (performance warning) +#endif + +namespace client +{ + vmachine::vmachine() + { + llvm::InitializeNativeTarget(); + llvm::LLVMContext& context = llvm::getGlobalContext(); + + // Make the module, which holds all the code. + module_ = new llvm::Module("Conjure JIT", context); + + // Create the JIT. This takes ownership of the module. + std::string error; + execution_engine_ = + llvm::EngineBuilder(module_).setErrorStr(&error).create(); + + BOOST_ASSERT(execution_engine_ != 0); + if (!execution_engine_) + { + std::cerr << + "Could not create ExecutionEngine: " << + error << std::endl; + + exit(1); + } + } +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/vm.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/vm.hpp new file mode 100644 index 00000000..68698920 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure3/vm.hpp @@ -0,0 +1,121 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_CONJURE_VM_HPP) +#define BOOST_SPIRIT_CONJURE_VM_HPP + +#include <llvm/ExecutionEngine/ExecutionEngine.h> +#include <llvm/ExecutionEngine/JIT.h> +#include <llvm/LLVMContext.h> +#include <llvm/Module.h> +#include <llvm/Target/TargetData.h> +#include <llvm/Target/TargetSelect.h> + +#include <boost/assert.hpp> + +namespace client +{ + class vmachine; + + /////////////////////////////////////////////////////////////////////////// + // A light wrapper to a function pointer returning int and accepting + // from 0 to 3 arguments, where arity is determined at runtime. + /////////////////////////////////////////////////////////////////////////// + class function + { + public: + + typedef int result_type; + + int operator()() const + { + BOOST_ASSERT(fptr != 0); + BOOST_ASSERT(arity() == 0); + int (*fp)() = (int(*)())(intptr_t)fptr; + return fp(); + } + + int operator()(int _1) const + { + BOOST_ASSERT(fptr != 0); + BOOST_ASSERT(arity() == 1); + int (*fp)(int) = (int(*)(int))(intptr_t)fptr; + return fp(_1); + } + + int operator()(int _1, int _2) const + { + BOOST_ASSERT(fptr != 0); + BOOST_ASSERT(arity() == 2); + int (*fp)(int, int) = (int(*)(int, int))(intptr_t)fptr; + return fp(_1, _2); + } + + int operator()(int _1, int _2, int _3) const + { + BOOST_ASSERT(fptr != 0); + BOOST_ASSERT(arity() == 3); + int (*fp)(int, int, int) = (int(*)(int, int, int))(intptr_t)fptr; + return fp(_1, _2, _3); + } + + unsigned arity() const { return arity_; } + bool operator!() const { return fptr == 0; } + + private: + + friend class vmachine; + function(void* fptr, unsigned arity_) + : fptr(fptr), arity_(arity_) {} + + void* fptr; + unsigned arity_; + }; + + /////////////////////////////////////////////////////////////////////////// + // The Virtual Machine (light wrapper over LLVM JIT) + /////////////////////////////////////////////////////////////////////////// + class vmachine + { + public: + + vmachine(); + + llvm::Module* module() const + { + return module_; + } + + llvm::ExecutionEngine* execution_engine() const + { + return execution_engine_; + } + + void print_assembler() const + { + module_->dump(); + } + + function get_function(char const* name) + { + llvm::Function* callee = module_->getFunction(name); + if (callee == 0) + return function(0, 0); + + // JIT the function + void *fptr = execution_engine_->getPointerToFunction(callee); + return function(fptr, callee->arg_size()); + } + + private: + + llvm::Module* module_; + llvm::ExecutionEngine* execution_engine_; + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/error.cnj b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/error.cnj new file mode 100644 index 00000000..2c7c0a94 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/error.cnj @@ -0,0 +1,16 @@ +/* conjure program with syntax error */ + +int foo(n) +{ + int a = 2; + if (n @ 3) /* we don't have @ operator in conjure */ + { + a = 3 + } + return a; +} + +int main() +{ + return foo(10); +}
\ No newline at end of file diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/factorial.cnj b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/factorial.cnj new file mode 100644 index 00000000..5ea05731 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/factorial.cnj @@ -0,0 +1,15 @@ +/* The factorial */ + +int factorial(n) +{ + if (n <= 0) + return 1; + else + return n * factorial(n-1); +} + +int main(n) +{ + return factorial(n); +} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/operators.cnj b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/operators.cnj new file mode 100644 index 00000000..8f8aad56 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/operators.cnj @@ -0,0 +1,137 @@ +/* More operators tests */ +/* Conjure >=3 only!!! */ + +// assign ops + +int aplus(x, y) +{ + int t = x; + t += y; + return t; +} + +int aminus(x, y) +{ + int t = x; + t -= y; + return t; +} + +int ashl(x, y) +{ + int t = x; + t <<= y; + return t; +} + +int adiv(x, y) +{ + int t = x; + t /= y; + return t; +} + +int amult(x, y) +{ + int t = x; + t *= y; + return t; +} + +int amod(x, y) +{ + int t = x; + t %= y; + return t; +} + +int aor(x, y) +{ + int t = x; + t |= y; + return t; +} + +int aand(x, y) +{ + int t = x; + t &= y; + return t; +} + +int axor(x, y) +{ + int t = x; + t ^= y; + return t; +} + +int ashr(x, y) +{ + int t = x; + t >>= y; + return t; +} + +// binary ops + +int plus(x, y) { return x + y; } +int minus(x, y) { return x - y; } +int shl(x, y) { return x << y; } +int div(x, y) { return x / y; } +int mult(x, y) { return x * y; } +int mod(x, y) { return x % y; } +int or(x, y) { return x | y; } +int and(x, y) { return x & y; } +int xor(x, y) { return x ^ y; } +int shr(x, y) { return x >> y; } + +int assign() +{ + int a = aplus(2, 3); // 5 + int b = ashl(a, 2); // 20 + int c = aminus(b, 2); // 18 + int d = adiv(c, 2); // 9 + int e = amult(d, c); // 162 + int f = amod(e, 10); // 2 + int g = aor(f, 45); // 47 + int h = aand(g, 48); // 32 + int j = axor(h, h); // 0 + int k = aor(j, 65535); // 65535 + int l = ashr(k, 3); // 8191 + return l; +} + +int binary() +{ + int a = plus(2, 3); // 5 + int b = shl(a, 2); // 20 + int c = minus(b, 2); // 18 + int d = div(c, 2); // 9 + int e = mult(d, c); // 162 + int f = mod(e, 10); // 2 + int g = or(f, 45); // 47 + int h = and(g, 48); // 32 + int j = xor(h, h); // 0 + int k = or(j, 65535); // 65535 + int l = shr(k, 3); // 8191 + return l; +} + +int zero() { return 0; } + +int unary() +{ + int i = ~zero(); // -1 + int j = -i; // 1 + ++j; // 2 + ++++j; // 4 + --j; // 3 + return j; +} + +int main() +{ + return assign() + binary() + unary(); // 16385 +} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/pow2.cnj b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/pow2.cnj new file mode 100644 index 00000000..4d22fd70 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/pow2.cnj @@ -0,0 +1,19 @@ +/* My first conjure program */ + +int pow2(n) +{ + int a = 2; + int i = 1; + while (i < n) + { + a = a * 2; + i = i + 1; + } + return a; +} + +int main() +{ + return pow2(10); +} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/precedence.cnj b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/precedence.cnj new file mode 100644 index 00000000..eb91b92e --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure_samples/precedence.cnj @@ -0,0 +1,8 @@ +/* testing the shunting yard operator precedence algorithm */ + +int main() +{ + return 1 + 2 + 3 + 5 * 4 * 6 + 5; /* answer is 131 */ +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/annotation.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/annotation.hpp new file mode 100644 index 00000000..9e7e814e --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/annotation.hpp @@ -0,0 +1,95 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_MINIC_ANNOTATION_HPP) +#define BOOST_SPIRIT_MINIC_ANNOTATION_HPP + +#include <map> +#include <boost/variant/apply_visitor.hpp> +#include <boost/type_traits/is_base_of.hpp> +#include <boost/mpl/bool.hpp> +#include "ast.hpp" + +namespace client +{ + /////////////////////////////////////////////////////////////////////////////// + // The annotation handler links the AST to a map of iterator positions + // for the purpose of subsequent semantic error handling when the + // program is being compiled. + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct annotation + { + template <typename, typename> + struct result { typedef void type; }; + + std::vector<Iterator>& iters; + annotation(std::vector<Iterator>& iters) + : iters(iters) {} + + struct set_id + { + typedef void result_type; + + int id; + set_id(int id) : id(id) {} + + void operator()(ast::function_call& x) const + { + x.function_name.id = id; + } + + void operator()(ast::identifier& x) const + { + x.id = id; + } + + template <typename T> + void operator()(T& x) const + { + // no-op + } + }; + + void operator()(ast::operand& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + boost::apply_visitor(set_id(id), ast); + } + + void operator()(ast::variable_declaration& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.lhs.id = id; + } + + void operator()(ast::assignment& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.lhs.id = id; + } + + void operator()(ast::return_statement& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.id = id; + } + + void operator()(ast::identifier& ast, Iterator pos) const + { + int id = iters.size(); + iters.push_back(pos); + ast.id = id; + } + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/ast.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/ast.hpp new file mode 100644 index 00000000..fc755064 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/ast.hpp @@ -0,0 +1,225 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_MINIC_AST_HPP) +#define BOOST_SPIRIT_MINIC_AST_HPP + +#include <boost/config/warning_disable.hpp> +#include <boost/variant/recursive_variant.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/fusion/include/io.hpp> +#include <boost/optional.hpp> +#include <list> + +namespace client { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + // The AST + /////////////////////////////////////////////////////////////////////////// + struct tagged + { + int id; // Used to annotate the AST with the iterator position. + // This id is used as a key to a map<int, Iterator> + // (not really part of the AST.) + }; + + struct nil {}; + struct unary; + struct function_call; + struct expression; + + struct identifier : tagged + { + identifier(std::string const& name = "") : name(name) {} + std::string name; + }; + + typedef boost::variant< + nil + , bool + , unsigned int + , identifier + , boost::recursive_wrapper<unary> + , boost::recursive_wrapper<function_call> + , boost::recursive_wrapper<expression> + > + operand; + + enum optoken + { + op_plus, + op_minus, + op_times, + op_divide, + op_positive, + op_negative, + op_not, + op_equal, + op_not_equal, + op_less, + op_less_equal, + op_greater, + op_greater_equal, + op_and, + op_or + }; + + struct unary + { + optoken operator_; + operand operand_; + }; + + struct operation + { + optoken operator_; + operand operand_; + }; + + struct function_call + { + identifier function_name; + std::list<expression> args; + }; + + struct expression + { + operand first; + std::list<operation> rest; + }; + + struct assignment + { + identifier lhs; + expression rhs; + }; + + struct variable_declaration + { + identifier lhs; + boost::optional<expression> rhs; + }; + + struct if_statement; + struct while_statement; + struct statement_list; + struct return_statement; + + typedef boost::variant< + variable_declaration + , assignment + , boost::recursive_wrapper<if_statement> + , boost::recursive_wrapper<while_statement> + , boost::recursive_wrapper<return_statement> + , boost::recursive_wrapper<statement_list> + > + statement; + + struct statement_list : std::list<statement> {}; + + struct if_statement + { + expression condition; + statement then; + boost::optional<statement> else_; + }; + + struct while_statement + { + expression condition; + statement body; + }; + + struct return_statement : tagged + { + boost::optional<expression> expr; + }; + + struct function + { + std::string return_type; + identifier function_name; + std::list<identifier> args; + statement_list body; + }; + + typedef std::list<function> function_list; + + // print functions for debugging + inline std::ostream& operator<<(std::ostream& out, nil) + { + out << "nil"; return out; + } + + inline std::ostream& operator<<(std::ostream& out, identifier const& id) + { + out << id.name; return out; + } +}} + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::unary, + (client::ast::optoken, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::operation, + (client::ast::optoken, operator_) + (client::ast::operand, operand_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::function_call, + (client::ast::identifier, function_name) + (std::list<client::ast::expression>, args) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::expression, + (client::ast::operand, first) + (std::list<client::ast::operation>, rest) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::variable_declaration, + (client::ast::identifier, lhs) + (boost::optional<client::ast::expression>, rhs) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::assignment, + (client::ast::identifier, lhs) + (client::ast::expression, rhs) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::if_statement, + (client::ast::expression, condition) + (client::ast::statement, then) + (boost::optional<client::ast::statement>, else_) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::while_statement, + (client::ast::expression, condition) + (client::ast::statement, body) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::return_statement, + (boost::optional<client::ast::expression>, expr) +) + +BOOST_FUSION_ADAPT_STRUCT( + client::ast::function, + (std::string, return_type) + (client::ast::identifier, function_name) + (std::list<client::ast::identifier>, args) + (client::ast::statement_list, body) +) + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/compiler.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/compiler.cpp new file mode 100644 index 00000000..5a17ee07 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/compiler.cpp @@ -0,0 +1,538 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "compiler.hpp" +#include "vm.hpp" +#include <boost/foreach.hpp> +#include <boost/variant/apply_visitor.hpp> +#include <boost/assert.hpp> +#include <boost/lexical_cast.hpp> +#include <set> + +namespace client { namespace code_gen +{ + void function::op(int a) + { + code.push_back(a); + size_ += 1; + } + + void function::op(int a, int b) + { + code.push_back(a); + code.push_back(b); + size_ += 2; + } + + void function::op(int a, int b, int c) + { + code.push_back(a); + code.push_back(b); + code.push_back(c); + size_ += 3; + } + + int const* function::find_var(std::string const& name) const + { + std::map<std::string, int>::const_iterator i = variables.find(name); + if (i == variables.end()) + return 0; + return &i->second; + } + + void function::add_var(std::string const& name) + { + std::size_t n = variables.size(); + variables[name] = n; + } + + void function::link_to(std::string const& name, std::size_t address) + { + function_calls[address] = name; + } + + void function::print_assembler() const + { + std::vector<int>::const_iterator pc = code.begin() + address; + + std::vector<std::string> locals(variables.size()); + typedef std::pair<std::string, int> pair; + BOOST_FOREACH(pair const& p, variables) + { + locals[p.second] = p.first; + std::cout << " local " + << p.first << ", @" << p.second << std::endl; + } + + std::map<std::size_t, std::string> lines; + std::set<std::size_t> jumps; + + while (pc != (code.begin() + address + size_)) + { + std::string line; + std::size_t address = pc - code.begin(); + + switch (*pc++) + { + case op_neg: + line += " op_neg"; + break; + + case op_not: + line += " op_not"; + break; + + case op_add: + line += " op_add"; + break; + + case op_sub: + line += " op_sub"; + break; + + case op_mul: + line += " op_mul"; + break; + + case op_div: + line += " op_div"; + break; + + case op_eq: + line += " op_eq"; + break; + + case op_neq: + line += " op_neq"; + break; + + case op_lt: + line += " op_lt"; + break; + + case op_lte: + line += " op_lte"; + break; + + case op_gt: + line += " op_gt"; + break; + + case op_gte: + line += " op_gte"; + break; + + case op_and: + line += " op_and"; + break; + + case op_or: + line += " op_or"; + break; + + case op_load: + line += " op_load "; + line += locals[*pc++]; + break; + + case op_store: + line += " op_store "; + line += locals[*pc++]; + break; + + case op_int: + line += " op_int "; + line += boost::lexical_cast<std::string>(*pc++); + break; + + case op_true: + line += " op_true"; + break; + + case op_false: + line += " op_false"; + break; + + case op_jump: + { + line += " op_jump "; + std::size_t pos = (pc - code.begin()) + *pc++; + if (pos == code.size()) + line += "end"; + else + line += boost::lexical_cast<std::string>(pos); + jumps.insert(pos); + } + break; + + case op_jump_if: + { + line += " op_jump_if "; + std::size_t pos = (pc - code.begin()) + *pc++; + if (pos == code.size()) + line += "end"; + else + line += boost::lexical_cast<std::string>(pos); + jumps.insert(pos); + } + break; + + case op_call: + { + line += " op_call "; + int nargs = *pc++; + std::size_t jump = *pc++; + line += boost::lexical_cast<std::string>(nargs) + ", "; + BOOST_ASSERT(function_calls.find(jump) != function_calls.end()); + line += function_calls.find(jump)->second; + } + break; + + case op_stk_adj: + line += " op_stk_adj "; + line += boost::lexical_cast<std::string>(*pc++); + break; + + + case op_return: + line += " op_return"; + break; + } + lines[address] = line; + } + + std::cout << "start:" << std::endl; + typedef std::pair<std::size_t, std::string> line_info; + BOOST_FOREACH(line_info const& l, lines) + { + std::size_t pos = l.first; + if (jumps.find(pos) != jumps.end()) + std::cout << pos << ':' << std::endl; + std::cout << l.second << std::endl; + } + + std::cout << "end:" << std::endl << std::endl; + } + + bool compiler::operator()(unsigned int x) + { + BOOST_ASSERT(current != 0); + current->op(op_int, x); + return true; + } + + bool compiler::operator()(bool x) + { + BOOST_ASSERT(current != 0); + current->op(x ? op_true : op_false); + return true; + } + + bool compiler::operator()(ast::identifier const& x) + { + BOOST_ASSERT(current != 0); + int const* p = current->find_var(x.name); + if (p == 0) + { + error_handler(x.id, "Undeclared variable: " + x.name); + return false; + } + current->op(op_load, *p); + return true; + } + + bool compiler::operator()(ast::operation const& x) + { + BOOST_ASSERT(current != 0); + if (!boost::apply_visitor(*this, x.operand_)) + return false; + switch (x.operator_) + { + case ast::op_plus: current->op(op_add); break; + case ast::op_minus: current->op(op_sub); break; + case ast::op_times: current->op(op_mul); break; + case ast::op_divide: current->op(op_div); break; + + case ast::op_equal: current->op(op_eq); break; + case ast::op_not_equal: current->op(op_neq); break; + case ast::op_less: current->op(op_lt); break; + case ast::op_less_equal: current->op(op_lte); break; + case ast::op_greater: current->op(op_gt); break; + case ast::op_greater_equal: current->op(op_gte); break; + + case ast::op_and: current->op(op_and); break; + case ast::op_or: current->op(op_or); break; + default: BOOST_ASSERT(0); return false; + } + return true; + } + + bool compiler::operator()(ast::unary const& x) + { + BOOST_ASSERT(current != 0); + if (!boost::apply_visitor(*this, x.operand_)) + return false; + switch (x.operator_) + { + case ast::op_negative: current->op(op_neg); break; + case ast::op_not: current->op(op_not); break; + case ast::op_positive: break; + default: BOOST_ASSERT(0); return false; + } + return true; + } + + bool compiler::operator()(ast::function_call const& x) + { + BOOST_ASSERT(current != 0); + + if (functions.find(x.function_name.name) == functions.end()) + { + error_handler(x.function_name.id, "Function not found: " + x.function_name.name); + return false; + } + + boost::shared_ptr<code_gen::function> p = functions[x.function_name.name]; + + if (p->nargs() != x.args.size()) + { + error_handler(x.function_name.id, "Wrong number of arguments: " + x.function_name.name); + return false; + } + + BOOST_FOREACH(ast::expression const& expr, x.args) + { + if (!(*this)(expr)) + return false; + } + + current->op( + op_call, + p->nargs(), + p->get_address()); + current->link_to(x.function_name.name, p->get_address()); + + return true; + } + + bool compiler::operator()(ast::expression const& x) + { + BOOST_ASSERT(current != 0); + if (!boost::apply_visitor(*this, x.first)) + return false; + BOOST_FOREACH(ast::operation const& oper, x.rest) + { + if (!(*this)(oper)) + return false; + } + return true; + } + + bool compiler::operator()(ast::assignment const& x) + { + BOOST_ASSERT(current != 0); + if (!(*this)(x.rhs)) + return false; + int const* p = current->find_var(x.lhs.name); + if (p == 0) + { + error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name); + return false; + } + current->op(op_store, *p); + return true; + } + + bool compiler::operator()(ast::variable_declaration const& x) + { + BOOST_ASSERT(current != 0); + int const* p = current->find_var(x.lhs.name); + if (p != 0) + { + error_handler(x.lhs.id, "Duplicate variable: " + x.lhs.name); + return false; + } + if (x.rhs) // if there's an RHS initializer + { + bool r = (*this)(*x.rhs); + if (r) // don't add the variable if the RHS fails + { + current->add_var(x.lhs.name); + current->op(op_store, *current->find_var(x.lhs.name)); + } + return r; + } + else + { + current->add_var(x.lhs.name); + } + return true; + } + + bool compiler::operator()(ast::statement const& x) + { + BOOST_ASSERT(current != 0); + return boost::apply_visitor(*this, x); + } + + bool compiler::operator()(ast::statement_list const& x) + { + BOOST_ASSERT(current != 0); + BOOST_FOREACH(ast::statement const& s, x) + { + if (!(*this)(s)) + return false; + } + return true; + } + + bool compiler::operator()(ast::if_statement const& x) + { + BOOST_ASSERT(current != 0); + if (!(*this)(x.condition)) + return false; + current->op(op_jump_if, 0); // we shall fill this (0) in later + std::size_t skip = current->size()-1; // mark its position + if (!(*this)(x.then)) + return false; + (*current)[skip] = current->size()-skip; // now we know where to jump to (after the if branch) + + if (x.else_) // We got an else + { + (*current)[skip] += 2; // adjust for the "else" jump + current->op(op_jump, 0); // we shall fill this (0) in later + std::size_t exit = current->size()-1; // mark its position + if (!(*this)(*x.else_)) + return false; + (*current)[exit] = current->size()-exit;// now we know where to jump to (after the else branch) + } + + return true; + } + + bool compiler::operator()(ast::while_statement const& x) + { + BOOST_ASSERT(current != 0); + std::size_t loop = current->size(); // mark our position + if (!(*this)(x.condition)) + return false; + current->op(op_jump_if, 0); // we shall fill this (0) in later + std::size_t exit = current->size()-1; // mark its position + if (!(*this)(x.body)) + return false; + current->op(op_jump, + int(loop-1) - int(current->size())); // loop back + (*current)[exit] = current->size()-exit; // now we know where to jump to (to exit the loop) + return true; + } + + bool compiler::operator()(ast::return_statement const& x) + { + if (void_return) + { + if (x.expr) + { + error_handler(x.id, "'void' function returning a value: "); + return false; + } + } + else + { + if (!x.expr) + { + error_handler(x.id, current_function_name + " function must return a value: "); + return false; + } + } + + if (x.expr) + { + if (!(*this)(*x.expr)) + return false; + } + current->op(op_return); + return true; + } + + bool compiler::operator()(ast::function const& x) + { + void_return = x.return_type == "void"; + if (functions.find(x.function_name.name) != functions.end()) + { + error_handler(x.function_name.id, "Duplicate function: " + x.function_name.name); + return false; + } + boost::shared_ptr<code_gen::function>& p = functions[x.function_name.name]; + p.reset(new code_gen::function(code, x.args.size())); + current = p.get(); + current_function_name = x.function_name.name; + + // op_stk_adj 0 for now. we'll know how many variables + // we'll have later and add them + current->op(op_stk_adj, 0); + BOOST_FOREACH(ast::identifier const& arg, x.args) + { + current->add_var(arg.name); + } + + if (!(*this)(x.body)) + return false; + (*current)[1] = current->nvars(); // now store the actual number of variables + // this includes the arguments + return true; + } + + bool compiler::operator()(ast::function_list const& x) + { + // Jump to the main function + code.push_back(op_jump); + code.push_back(0); // we will fill this in later when we finish compiling + // and we know where the main function is + + BOOST_FOREACH(ast::function const& f, x) + { + if (!(*this)(f)) + { + code.clear(); + return false; + } + } + // find the main function + boost::shared_ptr<code_gen::function> p = + find_function("main"); + + if (!p) // main function not found + { + std::cerr << "Error: main function not defined" << std::endl; + return false; + } + code[1] = p->get_address()-1; // jump to this (main function) address + + return true; + } + + void compiler::print_assembler() const + { + typedef std::pair<std::string, boost::shared_ptr<code_gen::function> > pair; + BOOST_FOREACH(pair const& p, functions) + { + std::cout << ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" << std::endl; + std::cout << p.second->get_address() << ": function " << p.first << std::endl; + p.second->print_assembler(); + } + } + + boost::shared_ptr<code_gen::function> + compiler::find_function(std::string const& name) const + { + function_table::const_iterator i = functions.find(name); + if (i == functions.end()) + return boost::shared_ptr<code_gen::function>(); + else + return i->second; + } +}} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/compiler.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/compiler.hpp new file mode 100644 index 00000000..8a3eea72 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/compiler.hpp @@ -0,0 +1,118 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_MINIC_COMPILER_HPP) +#define BOOST_SPIRIT_MINIC_COMPILER_HPP + +#include "ast.hpp" +#include "error_handler.hpp" +#include <vector> +#include <map> +#include <boost/function.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_function.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> + +namespace client { namespace code_gen +{ + /////////////////////////////////////////////////////////////////////////// + // The Function + /////////////////////////////////////////////////////////////////////////// + struct function + { + function(std::vector<int>& code, int nargs) + : code(code), address(code.size()), size_(0), nargs_(nargs) {} + + void op(int a); + void op(int a, int b); + void op(int a, int b, int c); + + int& operator[](std::size_t i) { return code[address+i]; } + int const& operator[](std::size_t i) const { return code[address+i]; } + std::size_t size() const { return size_; } + std::size_t get_address() const { return address; } + + int nargs() const { return nargs_; } + int nvars() const { return variables.size(); } + int const* find_var(std::string const& name) const; + void add_var(std::string const& name); + void link_to(std::string const& name, std::size_t address); + + void print_assembler() const; + + private: + + std::map<std::string, int> variables; + std::map<std::size_t, std::string> function_calls; + std::vector<int>& code; + std::size_t address; + std::size_t size_; + std::size_t nargs_; + }; + + /////////////////////////////////////////////////////////////////////////// + // The Compiler + /////////////////////////////////////////////////////////////////////////// + struct compiler + { + typedef bool result_type; + + template <typename ErrorHandler> + compiler(ErrorHandler& error_handler_) + : current(0) + { + using namespace boost::phoenix::arg_names; + namespace phx = boost::phoenix; + using boost::phoenix::function; + + error_handler = function<ErrorHandler>(error_handler_)( + "Error! ", _2, phx::cref(error_handler_.iters)[_1]); + } + + bool operator()(ast::nil) { BOOST_ASSERT(0); return false; } + bool operator()(unsigned int x); + bool operator()(bool x); + bool operator()(ast::identifier const& x); + bool operator()(ast::operation const& x); + bool operator()(ast::unary const& x); + bool operator()(ast::function_call const& x); + bool operator()(ast::expression const& x); + bool operator()(ast::assignment const& x); + bool operator()(ast::variable_declaration const& x); + bool operator()(ast::statement_list const& x); + bool operator()(ast::statement const& x); + bool operator()(ast::if_statement const& x); + bool operator()(ast::while_statement const& x); + bool operator()(ast::return_statement const& x); + bool operator()(ast::function const& x); + bool operator()(ast::function_list const& x); + + void print_assembler() const; + + boost::shared_ptr<code_gen::function> + find_function(std::string const& name) const; + + std::vector<int>& get_code() { return code; } + std::vector<int> const& get_code() const { return code; } + + private: + + typedef std::map<std::string, boost::shared_ptr<code_gen::function> > function_table; + + std::vector<int> code; + code_gen::function* current; + std::string current_function_name; + function_table functions; + bool void_return; + + boost::function< + void(int tag, std::string const& what)> + error_handler; + }; +}} + +#endif diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/error_handler.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/error_handler.hpp new file mode 100644 index 00000000..4ba833c6 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/error_handler.hpp @@ -0,0 +1,93 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_MINIC_ERROR_HANDLER_HPP) +#define BOOST_SPIRIT_MINIC_ERROR_HANDLER_HPP + +#include <iostream> +#include <string> +#include <vector> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////////// + // The error handler + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct error_handler + { + template <typename, typename, typename> + struct result { typedef void type; }; + + error_handler(Iterator first, Iterator last) + : first(first), last(last) {} + + template <typename Message, typename What> + void operator()( + Message const& message, + What const& what, + Iterator err_pos) const + { + int line; + Iterator line_start = get_pos(err_pos, line); + if (err_pos != last) + { + std::cout << message << what << " line " << line << ':' << std::endl; + std::cout << get_line(line_start) << std::endl; + for (; line_start != err_pos; ++line_start) + std::cout << ' '; + std::cout << '^' << std::endl; + } + else + { + std::cout << "Unexpected end of file. "; + std::cout << message << what << " line " << line << std::endl; + } + } + + Iterator get_pos(Iterator err_pos, int& line) const + { + line = 1; + Iterator i = first; + Iterator line_start = first; + while (i != err_pos) + { + bool eol = false; + if (i != err_pos && *i == '\r') // CR + { + eol = true; + line_start = ++i; + } + if (i != err_pos && *i == '\n') // LF + { + eol = true; + line_start = ++i; + } + if (eol) + ++line; + else + ++i; + } + return line_start; + } + + std::string get_line(Iterator err_pos) const + { + Iterator i = err_pos; + // position i to the next EOL + while (i != last && (*i != '\r' && *i != '\n')) + ++i; + return std::string(err_pos, i); + } + + Iterator first; + Iterator last; + std::vector<Iterator> iters; + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/expression.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/expression.cpp new file mode 100644 index 00000000..32f44adc --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/expression.cpp @@ -0,0 +1,14 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "expression_def.hpp" + +typedef std::string::const_iterator iterator_type; +template struct client::parser::expression<iterator_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/expression.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/expression.hpp new file mode 100644 index 00000000..60edceec --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/expression.hpp @@ -0,0 +1,79 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_MINIC_EXPRESSION_HPP) +#define BOOST_SPIRIT_MINIC_EXPRESSION_HPP + +/////////////////////////////////////////////////////////////////////////////// +// Spirit v2.5 allows you to suppress automatic generation +// of predefined terminals to speed up complation. With +// BOOST_SPIRIT_NO_PREDEFINED_TERMINALS defined, you are +// responsible in creating instances of the terminals that +// you need (e.g. see qi::uint_type uint_ below). +#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Uncomment this if you want to enable debugging +// #define BOOST_SPIRIT_QI_DEBUG +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/spirit/include/qi.hpp> +#include "ast.hpp" +#include "error_handler.hpp" +#include "skipper.hpp" +#include <vector> + +namespace client { namespace parser +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // The expression grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct expression : qi::grammar<Iterator, ast::expression(), skipper<Iterator> > + { + expression(error_handler<Iterator>& error_handler); + + qi::rule<Iterator, ast::expression(), skipper<Iterator> > + expr, equality_expr, relational_expr, + logical_or_expr, logical_and_expr, + additive_expr, multiplicative_expr + ; + + qi::rule<Iterator, ast::operand(), skipper<Iterator> > + unary_expr, primary_expr + ; + + qi::rule<Iterator, ast::function_call(), skipper<Iterator> > + function_call + ; + + qi::rule<Iterator, std::list<ast::expression>(), skipper<Iterator> > + argument_list + ; + + qi::rule<Iterator, std::string(), skipper<Iterator> > + identifier + ; + + qi::symbols<char, ast::optoken> + logical_or_op, logical_and_op, + equality_op, relational_op, + additive_op, multiplicative_op, unary_op + ; + + qi::symbols<char> + keywords + ; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/expression_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/expression_def.hpp new file mode 100644 index 00000000..f6f7c5d6 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/expression_def.hpp @@ -0,0 +1,181 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "expression.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" +#include <boost/spirit/include/phoenix_function.hpp> + +namespace client { namespace parser +{ + template <typename Iterator> + expression<Iterator>::expression(error_handler<Iterator>& error_handler) + : expression::base_type(expr) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::char_type char_; + qi::uint_type uint_; + qi::_val_type _val; + qi::raw_type raw; + qi::lexeme_type lexeme; + qi::alpha_type alpha; + qi::alnum_type alnum; + qi::bool_type bool_; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef function<client::error_handler<Iterator> > error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + /////////////////////////////////////////////////////////////////////// + // Tokens + logical_or_op.add + ("||", ast::op_or) + ; + + logical_and_op.add + ("&&", ast::op_and) + ; + + equality_op.add + ("==", ast::op_equal) + ("!=", ast::op_not_equal) + ; + + relational_op.add + ("<", ast::op_less) + ("<=", ast::op_less_equal) + (">", ast::op_greater) + (">=", ast::op_greater_equal) + ; + + additive_op.add + ("+", ast::op_plus) + ("-", ast::op_minus) + ; + + multiplicative_op.add + ("*", ast::op_times) + ("/", ast::op_divide) + ; + + unary_op.add + ("+", ast::op_positive) + ("-", ast::op_negative) + ("!", ast::op_not) + ; + + keywords.add + ("true") + ("false") + ("if") + ("else") + ("while") + ("int") + ("void") + ("return") + ; + + /////////////////////////////////////////////////////////////////////// + // Main expression grammar + expr = + logical_or_expr.alias() + ; + + logical_or_expr = + logical_and_expr + >> *(logical_or_op > logical_and_expr) + ; + + logical_and_expr = + equality_expr + >> *(logical_and_op > equality_expr) + ; + + equality_expr = + relational_expr + >> *(equality_op > relational_expr) + ; + + relational_expr = + additive_expr + >> *(relational_op > additive_expr) + ; + + additive_expr = + multiplicative_expr + >> *(additive_op > multiplicative_expr) + ; + + multiplicative_expr = + unary_expr + >> *(multiplicative_op > unary_expr) + ; + + unary_expr = + primary_expr + | (unary_op > unary_expr) + ; + + primary_expr = + uint_ + | function_call + | identifier + | bool_ + | '(' > expr > ')' + ; + + function_call = + (identifier >> '(') + > argument_list + > ')' + ; + + argument_list = -(expr % ','); + + identifier = + !lexeme[keywords >> !(alnum | '_')] + >> raw[lexeme[(alpha | '_') >> *(alnum | '_')]] + ; + + /////////////////////////////////////////////////////////////////////// + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (expr) + (logical_or_expr) + (logical_and_expr) + (equality_expr) + (relational_expr) + (additive_expr) + (multiplicative_expr) + (unary_expr) + (primary_expr) + (function_call) + (argument_list) + (identifier) + ); + + /////////////////////////////////////////////////////////////////////// + // Error handling: on error in expr, call error_handler. + on_error<fail>(expr, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + /////////////////////////////////////////////////////////////////////// + // Annotation: on success in primary_expr, call annotation. + on_success(primary_expr, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/function.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/function.cpp new file mode 100644 index 00000000..ababd4ad --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/function.cpp @@ -0,0 +1,14 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "function_def.hpp" + +typedef std::string::const_iterator iterator_type; +template struct client::parser::function<iterator_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/function.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/function.hpp new file mode 100644 index 00000000..cef1c82d --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/function.hpp @@ -0,0 +1,32 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_MINIC_FUNCTION_HPP) +#define BOOST_SPIRIT_MINIC_FUNCTION_HPP + +#include "statement.hpp" + +namespace client { namespace parser +{ + /////////////////////////////////////////////////////////////////////////////// + // The function grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct function : qi::grammar<Iterator, ast::function(), skipper<Iterator> > + { + function(error_handler<Iterator>& error_handler); + + statement<Iterator> body; + qi::rule<Iterator, std::string(), skipper<Iterator> > name; + qi::rule<Iterator, ast::identifier(), skipper<Iterator> > identifier; + qi::rule<Iterator, std::list<ast::identifier>(), skipper<Iterator> > argument_list; + qi::rule<Iterator, ast::function(), skipper<Iterator> > start; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/function_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/function_def.hpp new file mode 100644 index 00000000..bd2c7d02 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/function_def.hpp @@ -0,0 +1,71 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "function.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" + +namespace client { namespace parser +{ + template <typename Iterator> + function<Iterator>::function(error_handler<Iterator>& error_handler) + : function::base_type(start), body(error_handler) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::_val_type _val; + qi::raw_type raw; + qi::lexeme_type lexeme; + qi::alpha_type alpha; + qi::alnum_type alnum; + qi::string_type string; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef function<client::error_handler<Iterator> > error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + name = + !body.expr.keywords + >> raw[lexeme[(alpha | '_') >> *(alnum | '_')]] + ; + + identifier = name; + argument_list = -(identifier % ','); + + start = + lexeme[(string("void") | string("int")) + >> !(alnum | '_')] // make sure we have whole words + > identifier + > '(' > argument_list > ')' + > '{' > body > '}' + ; + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (identifier) + (argument_list) + (start) + ); + + // Error handling: on error in start, call error_handler. + on_error<fail>(start, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + // Annotation: on success in start, call annotation. + on_success(identifier, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/main.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/main.cpp new file mode 100644 index 00000000..27d4bee0 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/main.cpp @@ -0,0 +1,121 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Not a calculator anymore, right? :-) +// +// [ JDG April 10, 2007 ] spirit2 +// [ JDG February 18, 2011 ] Pure attributes. No semantic actions. +// +/////////////////////////////////////////////////////////////////////////////// + +#include "function.hpp" +#include "skipper.hpp" +#include "vm.hpp" +#include "compiler.hpp" +#include <boost/lexical_cast.hpp> +#include <fstream> + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main(int argc, char **argv) +{ + char const* filename; + if (argc > 1) + { + filename = argv[1]; + } + else + { + std::cerr << "Error: No input file provided." << std::endl; + return 1; + } + + std::ifstream in(filename, std::ios_base::in); + + if (!in) + { + std::cerr << "Error: Could not open input file: " + << filename << std::endl; + return 1; + } + + std::string source_code; // We will read the contents here. + in.unsetf(std::ios::skipws); // No white space skipping! + std::copy( + std::istream_iterator<char>(in), + std::istream_iterator<char>(), + std::back_inserter(source_code)); + + typedef std::string::const_iterator iterator_type; + iterator_type iter = source_code.begin(); + iterator_type end = source_code.end(); + + client::vmachine vm; // Our virtual machine + client::ast::function_list ast; // Our AST + + client::error_handler<iterator_type> + error_handler(iter, end); // Our error handler + client::parser::function<iterator_type> + function(error_handler); // Our parser + client::parser::skipper<iterator_type> + skipper; // Our skipper + client::code_gen::compiler + compiler(error_handler); // Our compiler + + + bool success = phrase_parse(iter, end, +function, skipper, ast); + + std::cout << "-------------------------\n"; + + if (success && iter == end) + { + if (compiler(ast)) + { + boost::shared_ptr<client::code_gen::function> + p = compiler.find_function("main"); + if (!p) + return 1; + + int nargs = argc-2; + if (p->nargs() != nargs) + { + std::cerr << "Error: main function requires " << p->nargs() << " arguments." << std::endl; + std::cerr << nargs << "supplied." << std::endl; + return 1; + } + + std::cout << "Success\n"; + std::cout << "-------------------------\n"; + std::cout << "Assembler----------------\n\n"; + compiler.print_assembler(); + + // Push the arguments into our stack + for (int i = 0; i < nargs; ++i) + vm.get_stack()[i] = boost::lexical_cast<int>(argv[i+2]); + + // Call the interpreter + int r = vm.execute(compiler.get_code()); + + std::cout << "-------------------------\n"; + std::cout << "Result: " << r << std::endl; + std::cout << "-------------------------\n\n"; + } + else + { + std::cout << "Compile failure\n"; + } + } + else + { + std::cout << "Parse failure\n"; + } + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/skipper.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/skipper.hpp new file mode 100644 index 00000000..041fb9b0 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/skipper.hpp @@ -0,0 +1,40 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_MINIC_SKIPPER_HPP) +#define BOOST_SPIRIT_MINIC_SKIPPER_HPP + +#include <boost/spirit/include/qi.hpp> + +namespace client { namespace parser +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // The skipper grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct skipper : qi::grammar<Iterator> + { + skipper() : skipper::base_type(start) + { + qi::char_type char_; + ascii::space_type space; + + start = + space // tab/space/cr/lf + | "/*" >> *(char_ - "*/") >> "*/" // C-style comments + ; + } + + qi::rule<Iterator> start; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/statement.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/statement.cpp new file mode 100644 index 00000000..54bc9ac3 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/statement.cpp @@ -0,0 +1,14 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if defined(_MSC_VER) +# pragma warning(disable: 4345) +#endif + +#include "statement_def.hpp" + +typedef std::string::const_iterator iterator_type; +template struct client::parser::statement<iterator_type>; diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/statement.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/statement.hpp new file mode 100644 index 00000000..366f8741 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/statement.hpp @@ -0,0 +1,38 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_MINIC_STATEMENT_HPP) +#define BOOST_SPIRIT_MINIC_STATEMENT_HPP + +#include "expression.hpp" + +namespace client { namespace parser +{ + /////////////////////////////////////////////////////////////////////////////// + // The statement grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct statement : qi::grammar<Iterator, ast::statement_list(), skipper<Iterator> > + { + statement(error_handler<Iterator>& error_handler); + + expression<Iterator> expr; + qi::rule<Iterator, ast::statement_list(), skipper<Iterator> > + statement_list, compound_statement; + + qi::rule<Iterator, ast::statement(), skipper<Iterator> > statement_; + qi::rule<Iterator, ast::variable_declaration(), skipper<Iterator> > variable_declaration; + qi::rule<Iterator, ast::assignment(), skipper<Iterator> > assignment; + qi::rule<Iterator, ast::if_statement(), skipper<Iterator> > if_statement; + qi::rule<Iterator, ast::while_statement(), skipper<Iterator> > while_statement; + qi::rule<Iterator, ast::return_statement(), skipper<Iterator> > return_statement; + qi::rule<Iterator, std::string(), skipper<Iterator> > identifier; + }; +}} + +#endif + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/statement_def.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/statement_def.hpp new file mode 100644 index 00000000..f99b665a --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/statement_def.hpp @@ -0,0 +1,124 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "statement.hpp" +#include "error_handler.hpp" +#include "annotation.hpp" + +namespace client { namespace parser +{ + template <typename Iterator> + statement<Iterator>::statement(error_handler<Iterator>& error_handler) + : statement::base_type(statement_list), expr(error_handler) + { + qi::_1_type _1; + qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; + + qi::_val_type _val; + qi::raw_type raw; + qi::lexeme_type lexeme; + qi::alpha_type alpha; + qi::alnum_type alnum; + qi::lit_type lit; + + using qi::on_error; + using qi::on_success; + using qi::fail; + using boost::phoenix::function; + + typedef function<client::error_handler<Iterator> > error_handler_function; + typedef function<client::annotation<Iterator> > annotation_function; + + statement_list = + +statement_ + ; + + statement_ = + variable_declaration + | assignment + | compound_statement + | if_statement + | while_statement + | return_statement + ; + + identifier = + !expr.keywords + >> raw[lexeme[(alpha | '_') >> *(alnum | '_')]] + ; + + variable_declaration = + lexeme["int" >> !(alnum | '_')] // make sure we have whole words + > identifier + > -('=' > expr) + > ';' + ; + + assignment = + identifier + > '=' + > expr + > ';' + ; + + if_statement = + lit("if") + > '(' + > expr + > ')' + > statement_ + > + -( + lexeme["else" >> !(alnum | '_')] // make sure we have whole words + > statement_ + ) + ; + + while_statement = + lit("while") + > '(' + > expr + > ')' + > statement_ + ; + + compound_statement = + '{' >> -statement_list >> '}' + ; + + return_statement = + lexeme["return" >> !(alnum | '_')] // make sure we have whole words + > -expr + > ';' + ; + + // Debugging and error handling and reporting support. + BOOST_SPIRIT_DEBUG_NODES( + (statement_list) + (identifier) + (variable_declaration) + (assignment) + ); + + // Error handling: on error in statement_list, call error_handler. + on_error<fail>(statement_list, + error_handler_function(error_handler)( + "Error! Expecting ", _4, _3)); + + // Annotation: on success in variable_declaration, + // assignment and return_statement, call annotation. + on_success(variable_declaration, + annotation_function(error_handler.iters)(_val, _1)); + on_success(assignment, + annotation_function(error_handler.iters)(_val, _1)); + on_success(return_statement, + annotation_function(error_handler.iters)(_val, _1)); + } +}} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/vm.cpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/vm.cpp new file mode 100644 index 00000000..8740bf9c --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/vm.cpp @@ -0,0 +1,159 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include "vm.hpp" + +#if defined(_MSC_VER) +# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' + // (performance warning) +#endif + +namespace client +{ + int vmachine::execute( + std::vector<int> const& code + , std::vector<int>::const_iterator pc + , std::vector<int>::iterator frame_ptr + ) + { + std::vector<int>::iterator stack_ptr = frame_ptr; + + while (true) + { + switch (*pc++) + { + case op_neg: + stack_ptr[-1] = -stack_ptr[-1]; + break; + + case op_not: + stack_ptr[-1] = !bool(stack_ptr[-1]); + break; + + case op_add: + --stack_ptr; + stack_ptr[-1] += stack_ptr[0]; + break; + + case op_sub: + --stack_ptr; + stack_ptr[-1] -= stack_ptr[0]; + break; + + case op_mul: + --stack_ptr; + stack_ptr[-1] *= stack_ptr[0]; + break; + + case op_div: + --stack_ptr; + stack_ptr[-1] /= stack_ptr[0]; + break; + + case op_eq: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] == stack_ptr[0]); + break; + + case op_neq: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] != stack_ptr[0]); + break; + + case op_lt: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] < stack_ptr[0]); + break; + + case op_lte: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] <= stack_ptr[0]); + break; + + case op_gt: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] > stack_ptr[0]); + break; + + case op_gte: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1] >= stack_ptr[0]); + break; + + case op_and: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1]) && bool(stack_ptr[0]); + break; + + case op_or: + --stack_ptr; + stack_ptr[-1] = bool(stack_ptr[-1]) || bool(stack_ptr[0]); + break; + + case op_load: + *stack_ptr++ = frame_ptr[*pc++]; + break; + + case op_store: + --stack_ptr; + frame_ptr[*pc++] = stack_ptr[0]; + break; + + case op_int: + *stack_ptr++ = *pc++; + break; + + case op_true: + *stack_ptr++ = true; + break; + + case op_false: + *stack_ptr++ = false; + break; + + case op_jump: + pc += *pc; + break; + + case op_jump_if: + if (!bool(stack_ptr[-1])) + pc += *pc; + else + ++pc; + --stack_ptr; + break; + + case op_stk_adj: + stack_ptr += *pc++; + break; + + case op_call: + { + int nargs = *pc++; + int jump = *pc++; + + // a function call is a recursive call to execute + int r = execute( + code + , code.begin() + jump + , stack_ptr - nargs + ); + + // cleanup after return from function + stack_ptr[-nargs] = r; // get return value + stack_ptr -= (nargs - 1); // the stack will now contain + // the return value + } + break; + + case op_return: + return stack_ptr[-1]; + } + } + } +} + + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/vm.hpp b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/vm.hpp new file mode 100644 index 00000000..eb4cc294 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/vm.hpp @@ -0,0 +1,82 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined(BOOST_SPIRIT_MINIC_VM_HPP) +#define BOOST_SPIRIT_MINIC_VM_HPP + +#include <vector> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // The Virtual Machine + /////////////////////////////////////////////////////////////////////////// + enum byte_code + { + op_neg, // negate the top stack entry + op_add, // add top two stack entries + op_sub, // subtract top two stack entries + op_mul, // multiply top two stack entries + op_div, // divide top two stack entries + + op_not, // boolean negate the top stack entry + op_eq, // compare the top two stack entries for == + op_neq, // compare the top two stack entries for != + op_lt, // compare the top two stack entries for < + op_lte, // compare the top two stack entries for <= + op_gt, // compare the top two stack entries for > + op_gte, // compare the top two stack entries for >= + + op_and, // logical and top two stack entries + op_or, // logical or top two stack entries + + op_load, // load a variable + op_store, // store a variable + + op_int, // push constant integer into the stack + op_true, // push constant 0 into the stack + op_false, // push constant 1 into the stack + + op_jump_if, // jump to a relative position in the code if top stack + // evaluates to false + op_jump, // jump to a relative position in the code + + op_stk_adj, // adjust the stack (for args and locals) + op_call, // function call + op_return // return from function + }; + + class vmachine + { + public: + + vmachine(unsigned stackSize = 4096) + : stack(stackSize) + { + } + + int execute(std::vector<int> const& code) + { + return execute(code, code.begin(), stack.begin()); + } + + std::vector<int> const& get_stack() const { return stack; }; + std::vector<int>& get_stack() { return stack; }; + + private: + + int execute( + std::vector<int> const& code // the program code + , std::vector<int>::const_iterator pc // program counter + , std::vector<int>::iterator frame_ptr // start of arguments and locals + ); + + std::vector<int> stack; + }; +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c_samples/1.mini b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c_samples/1.mini new file mode 100644 index 00000000..bd22c869 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c_samples/1.mini @@ -0,0 +1,19 @@ +/* My first mini program */ + +int pow2(n) +{ + int a = 2; + int i = 1; + while (i < n) + { + a = a * 2; + i = i + 1; + } + return a; +} + +int main() +{ + return pow2(10); +} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c_samples/2.mini b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c_samples/2.mini new file mode 100644 index 00000000..5ea05731 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c_samples/2.mini @@ -0,0 +1,15 @@ +/* The factorial */ + +int factorial(n) +{ + if (n <= 0) + return 1; + else + return n * factorial(n-1); +} + +int main(n) +{ + return factorial(n); +} + diff --git a/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c_samples/3.mini b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c_samples/3.mini new file mode 100644 index 00000000..5c407d6e --- /dev/null +++ b/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c_samples/3.mini @@ -0,0 +1,17 @@ +/* mini program with syntax error */ + +int foo(n) +{ + int a = 2; + if (n @ 3) /* we don't have @ operator in mini_c */ + { + a = 3 + } + return a; +} + +int main() +{ + return foo(10); +} + diff --git a/src/boost/libs/spirit/example/qi/complex_number.cpp b/src/boost/libs/spirit/example/qi/complex_number.cpp new file mode 100644 index 00000000..a4400e0c --- /dev/null +++ b/src/boost/libs/spirit/example/qi/complex_number.cpp @@ -0,0 +1,101 @@ +/*============================================================================= + Copyright (c) 2002-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A complex number micro parser. +// +// [ JDG May 10, 2002 ] spirit1 +// [ JDG May 9, 2007 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> + +#include <iostream> +#include <string> +#include <complex> + +/////////////////////////////////////////////////////////////////////////////// +// Our complex number parser/compiler +/////////////////////////////////////////////////////////////////////////////// +//[tutorial_complex_number +namespace client +{ + template <typename Iterator> + bool parse_complex(Iterator first, Iterator last, std::complex<double>& c) + { + using boost::spirit::qi::double_; + using boost::spirit::qi::_1; + using boost::spirit::qi::phrase_parse; + using boost::spirit::ascii::space; + using boost::phoenix::ref; + + double rN = 0.0; + double iN = 0.0; + bool r = phrase_parse(first, last, + + // Begin grammar + ( + '(' >> double_[ref(rN) = _1] + >> -(',' >> double_[ref(iN) = _1]) >> ')' + | double_[ref(rN) = _1] + ), + // End grammar + + space); + + if (!r || first != last) // fail if we did not get a full match + return false; + c = std::complex<double>(rN, iN); + return r; + } +} +//] + +//////////////////////////////////////////////////////////////////////////// +// Main program +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA complex number micro parser for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a complex number of the form r or (r) or (r,i) \n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::complex<double> c; + if (client::parse_complex(str.begin(), str.end(), c)) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "got: " << c << std::endl; + std::cout << "\n-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/custom_string.cpp b/src/boost/libs/spirit/example/qi/custom_string.cpp new file mode 100644 index 00000000..e5e78221 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/custom_string.cpp @@ -0,0 +1,113 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This example demonstrates the steps needed to integrate a custom container +// type to be usable with Spirit.Qi. It shows how to utilize the QString data +// type as a Qi attribute. + +// Note: you need to have Qt4 installed on your system and you have to make +// sure your compiler finds the includes and your linker finds the +// proper libraries. + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> + +#include <Qt/qstring.h> + +namespace boost { namespace spirit { namespace traits +{ + // Make Qi recognize QString as a container + template <> struct is_container<QString> : mpl::true_ {}; + + // Expose the container's (QString's) value_type + template <> struct container_value<QString> : mpl::identity<QChar> {}; + + // Define how to insert a new element at the end of the container (QString) + template <> + struct push_back_container<QString, QChar> + { + static bool call(QString& c, QChar const& val) + { + c.append(val); + return true; + } + }; + + // Test if a QString is empty (required for debug) + template <> + struct is_empty_container<QString> + { + static bool call(QString const& c) + { + return c.isEmpty(); + } + }; + + // Define how to stream a QString (required for debug) + template <typename Out, typename Enable> + struct print_attribute_debug<Out, QString, Enable> + { + static void call(Out& out, QString const& val) + { + out << val.toStdString(); + } + }; +}}} + +/////////////////////////////////////////////////////////////////////////////// +namespace client +{ + template <typename Iterator> + bool parse_qstring(Iterator first, Iterator last, QString& t) + { + using boost::spirit::qi::char_; + using boost::spirit::ascii::space; + using boost::spirit::qi::phrase_parse; + + bool r = phrase_parse(first, last, +char_, space, t); + if (!r || first != last) // fail if we did not get a full match + return false; + + return r; + } +} + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tParsing into a QString from Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a complex number of the form r or (r) or (r,i) \n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + QString t; + if (client::parse_qstring(str.begin(), str.end(), t)) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "got: " << t.toStdString() << std::endl; + std::cout << "\n-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/display_attribute_type.cpp b/src/boost/libs/spirit/example/qi/display_attribute_type.cpp new file mode 100644 index 00000000..11f086b5 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/display_attribute_type.cpp @@ -0,0 +1,22 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This example implements a simple utility allowing to print the attribute +// type as it is exposed by an arbitrary Qi parser expression. Just insert +// your expression below, compile and run this example to see what Qi is +// seeing! + +#include "display_attribute_type.hpp" + +namespace qi = boost::spirit::qi; + +int main() +{ + tools::display_attribute_of_parser( + std::cerr, // put the required output stream here + qi::int_ >> qi::double_ // put your parser expression here + ); + return 0; +} diff --git a/src/boost/libs/spirit/example/qi/display_attribute_type.hpp b/src/boost/libs/spirit/example/qi/display_attribute_type.hpp new file mode 100644 index 00000000..84c2245d --- /dev/null +++ b/src/boost/libs/spirit/example/qi/display_attribute_type.hpp @@ -0,0 +1,59 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// This example implements a simple utility allowing to print the attribute +// type as it is exposed by an arbitrary Qi parser expression. Just insert +// your expression below, compile and run this example to see what Qi is +// seeing! + +#if !defined (DISPLAY_ATTRIBUTE_OF_PARSER_JAN_2010_30_0722PM) +#define DISPLAY_ATTRIBUTE_OF_PARSER_JAN_2010_30_0722PM + +#include <iostream> +#include <boost/spirit/include/qi.hpp> + +namespace tools +{ + namespace spirit = boost::spirit; + + template <typename Expr, typename Iterator = spirit::unused_type> + struct attribute_of_parser + { + typedef typename spirit::result_of::compile< + spirit::qi::domain, Expr + >::type parser_expression_type; + + typedef typename spirit::traits::attribute_of< + parser_expression_type, spirit::unused_type, Iterator + >::type type; + }; + + template <typename T> + void display_attribute_of_parser(T const &) + { + // Report invalid expression error as early as possible. + // If you got an error_invalid_expression error message here, + // then the expression (expr) is not a valid spirit qi expression. + BOOST_SPIRIT_ASSERT_MATCH(spirit::qi::domain, T); + + typedef typename attribute_of_parser<T>::type type; + std::cout << typeid(type).name() << std::endl; + } + + template <typename T> + void display_attribute_of_parser(std::ostream& os, T const &) + { + // Report invalid expression error as early as possible. + // If you got an error_invalid_expression error message here, + // then the expression (expr) is not a valid spirit qi expression. + BOOST_SPIRIT_ASSERT_MATCH(spirit::qi::domain, T); + + typedef typename attribute_of_parser<T>::type type; + os << typeid(type).name() << std::endl; + } +} + +#endif + diff --git a/src/boost/libs/spirit/example/qi/employee.cpp b/src/boost/libs/spirit/example/qi/employee.cpp new file mode 100644 index 00000000..c303ff8b --- /dev/null +++ b/src/boost/libs/spirit/example/qi/employee.cpp @@ -0,0 +1,151 @@ +/*============================================================================= + Copyright (c) 2002-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A parser for arbitrary tuples. This example presents a parser +// for an employee structure. +// +// [ JDG May 9, 2007 ] +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/spirit/include/phoenix_object.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/fusion/include/io.hpp> + +#include <iostream> +#include <string> +#include <complex> + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////// + // Our employee struct + /////////////////////////////////////////////////////////////////////////// + //[tutorial_employee_struct + struct employee + { + int age; + std::string surname; + std::string forename; + double salary; + }; + //] +} + +// We need to tell fusion about our employee struct +// to make it a first-class fusion citizen. This has to +// be in global scope. + +//[tutorial_employee_adapt_struct +BOOST_FUSION_ADAPT_STRUCT( + client::employee, + (int, age) + (std::string, surname) + (std::string, forename) + (double, salary) +) +//] + +namespace client +{ + /////////////////////////////////////////////////////////////////////////////// + // Our employee parser + /////////////////////////////////////////////////////////////////////////////// + //[tutorial_employee_parser + template <typename Iterator> + struct employee_parser : qi::grammar<Iterator, employee(), ascii::space_type> + { + employee_parser() : employee_parser::base_type(start) + { + using qi::int_; + using qi::lit; + using qi::double_; + using qi::lexeme; + using ascii::char_; + + quoted_string %= lexeme['"' >> +(char_ - '"') >> '"']; + + start %= + lit("employee") + >> '{' + >> int_ >> ',' + >> quoted_string >> ',' + >> quoted_string >> ',' + >> double_ + >> '}' + ; + } + + qi::rule<Iterator, std::string(), ascii::space_type> quoted_string; + qi::rule<Iterator, employee(), ascii::space_type> start; + }; + //] +} + +//////////////////////////////////////////////////////////////////////////// +// Main program +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tAn employee parser for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout + << "Give me an employee of the form :" + << "employee{age, \"surname\", \"forename\", salary } \n"; + std::cout << "Type [q or Q] to quit\n\n"; + + using boost::spirit::ascii::space; + typedef std::string::const_iterator iterator_type; + typedef client::employee_parser<iterator_type> employee_parser; + + employee_parser g; // Our grammar + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + client::employee emp; + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + bool r = phrase_parse(iter, end, g, space, emp); + + if (r && iter == end) + { + std::cout << boost::fusion::tuple_open('['); + std::cout << boost::fusion::tuple_close(']'); + std::cout << boost::fusion::tuple_delimiter(", "); + + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "got: " << boost::fusion::as_vector(emp) << std::endl; + std::cout << "\n-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/expect.cpp b/src/boost/libs/spirit/example/qi/expect.cpp new file mode 100644 index 00000000..ecbc24aa --- /dev/null +++ b/src/boost/libs/spirit/example/qi/expect.cpp @@ -0,0 +1,112 @@ +/*============================================================================= +Copyright (c) 2016 Frank Hein, maxence business consulting gmbh + +Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +==============================================================================*/ + +#include <iostream> +#include <map> + +#include <boost/spirit/home/qi.hpp> +#include <boost/spirit/home/qi/nonterminal/grammar.hpp> +#include <boost/spirit/include/phoenix.hpp> +#include <boost/foreach.hpp> + +namespace qi = boost::spirit::qi; + +typedef std::string::const_iterator iterator_type; +typedef std::string result_type; + +template<typename Parser> +void parse(const std::string message, const std::string& input, const std::string& rule, const Parser& parser) { + iterator_type iter = input.begin(), end = input.end(); + + std::vector<result_type> parsed_result; + + std::cout << "-------------------------\n"; + std::cout << message << "\n"; + std::cout << "Rule: " << rule << std::endl; + std::cout << "Parsing: \"" << input << "\"\n"; + + bool result = qi::phrase_parse(iter, end, parser, qi::space, parsed_result); + if (result) + { + std::cout << "Parser succeeded.\n"; + std::cout << "Parsed " << parsed_result.size() << " elements:"; + BOOST_FOREACH(result_type const& str, parsed_result) + { + std::cout << "[" << str << "]"; + } + std::cout << std::endl; + } + else + { + std::cout << "Parser failed" << std::endl; + } + if (iter == end) { + std::cout << "EOI reached." << std::endl; + } + else { + std::cout << "EOI not reached. Unparsed: \"" << std::string(iter, end) << "\"" << std::endl; + } + std::cout << "-------------------------\n"; + +} + +namespace grammars { + namespace phx = boost::phoenix; + + template <typename Iterator> + struct ident : qi::grammar < Iterator, std::string(), qi::space_type> + { + ident(); + + qi::rule <iterator_type, std::string(), qi::space_type> + id, id_list, qualified_id; + }; + + template <typename Iterator> + ident<Iterator>::ident() : ident::base_type(id_list) { + + using qi::on_error; + using qi::fail; + using qi::expect; + + id = (qi::alpha | qi::char_('_')) >> *(qi::alnum | qi::char_('_')); + + id_list = expect[id >> qi::lit(';')]; + + on_error<fail>(id_list, + phx::ref(std::cout) + << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl + << "Error! Expecting " + << qi::_4 + << " here: " + << phx::construct<std::string>(qi::_3, qi::_2) << std::endl + << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl + ); + } +} + +int main() { + + grammars::ident<iterator_type> id; + + parse("expect directive, fail on first" + , "1234; id2;" + , "qi::expect[ id >> qi::lit(';') ]" + , id); + + parse("expect directive, fail on second" + , "id1, id2" + , "qi::expect[ id >> qi::lit(';') ]" + , id); + + parse("expect directive, success" + , "id1;" + , "qi::expect[ id >> qi::lit(';') ]" + , id); + + return 0; +} diff --git a/src/boost/libs/spirit/example/qi/german_floating_point.cpp b/src/boost/libs/spirit/example/qi/german_floating_point.cpp new file mode 100644 index 00000000..c091ca92 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/german_floating_point.cpp @@ -0,0 +1,48 @@ +// Copyright (c) 2001-2011 Hartmut Kaiser +// Copyright (c) 2011 Michael Caisse +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/spirit/include/qi.hpp> + +namespace qi = boost::spirit::qi; + +template <typename T> +struct german_real_policies : qi::real_policies<T> +{ + template <typename Iterator> + static bool parse_dot(Iterator& first, Iterator const& last) + { + if (first == last || *first != ',') + return false; + ++first; + return true; + } +}; + +qi::real_parser<double, german_real_policies<double> > const german_double; + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::string input("123,456"); + std::string::iterator begin = input.begin(); + std::string::iterator end = input.end(); + + double value = 0; + if (!qi::parse(begin, end, german_double, value)) + { + std::cout << "-------------------------------- \n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------------- \n"; + } + else + { + std::cout << "-------------------------------- \n"; + std::cout << "Parsing succeeded, got: " << value << "\n"; + std::cout << "---------------------------------\n"; + } + return 0; +} + diff --git a/src/boost/libs/spirit/example/qi/iter_pos.hpp b/src/boost/libs/spirit/example/qi/iter_pos.hpp new file mode 100644 index 00000000..b6259fd7 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/iter_pos.hpp @@ -0,0 +1,83 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(ITER_POS_NOV_20_2009_1245PM) +#define ITER_POS_NOV_20_2009_1245PM + +#include <boost/spirit/include/qi_parse.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// definition the place holder +namespace custom_parser +{ + BOOST_SPIRIT_TERMINAL(iter_pos) +} + +/////////////////////////////////////////////////////////////////////////////// +// implementation the enabler +namespace boost { namespace spirit +{ + // We want custom_parser::iter_pos to be usable as a terminal only, + // and only for parser expressions (qi::domain). + template <> + struct use_terminal<qi::domain, custom_parser::tag::iter_pos> + : mpl::true_ + {}; +}} + +/////////////////////////////////////////////////////////////////////////////// +// implementation of the parser +namespace custom_parser +{ + struct iter_pos_parser + : boost::spirit::qi::primitive_parser<iter_pos_parser> + { + // Define the attribute type exposed by this parser component + template <typename Context, typename Iterator> + struct attribute + { + typedef Iterator type; + }; + + // This function is called during the actual parsing process + template <typename Iterator, typename Context + , typename Skipper, typename Attribute> + bool parse(Iterator& first, Iterator const& last + , Context&, Skipper const& skipper, Attribute& attr) const + { + boost::spirit::qi::skip_over(first, last, skipper); + boost::spirit::traits::assign_to(first, attr); + return true; + } + + // This function is called during error handling to create + // a human readable string for the error context. + template <typename Context> + boost::spirit::info what(Context&) const + { + return boost::spirit::info("iter_pos"); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// instantiation of the parser +namespace boost { namespace spirit { namespace qi +{ + // This is the factory function object invoked in order to create + // an instance of our iter_pos_parser. + template <typename Modifiers> + struct make_primitive<custom_parser::tag::iter_pos, Modifiers> + { + typedef custom_parser::iter_pos_parser result_type; + + result_type operator()(unused_type, unused_type) const + { + return result_type(); + } + }; +}}} + +#endif diff --git a/src/boost/libs/spirit/example/qi/iter_pos_parser.cpp b/src/boost/libs/spirit/example/qi/iter_pos_parser.cpp new file mode 100644 index 00000000..92ff4b00 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/iter_pos_parser.cpp @@ -0,0 +1,51 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// The purpose of this example is to show how a simple custom primitive parser +// component can be written. We develop a custom parser exposing the current +// iterator position as its attribute. +// +// For more information see: http://spirit.sourceforge.net/home/?page_id=567 + +#include <boost/spirit/include/qi_parse_attr.hpp> +#include <boost/spirit/include/qi_char.hpp> +#include <boost/spirit/include/qi_operator.hpp> + +#include <string> +#include "iter_pos.hpp" + +namespace qi = boost::spirit::qi; + +int main() +{ + using custom_parser::iter_pos; + + std::string prefix, suffix; // attributes receiving the + std::string::iterator position; // parsed values + + std::string input("prefix1234567"); + std::string::iterator first = input.begin(); + bool result = + qi::parse(first, input.end() + , +qi::alpha >> iter_pos >> +qi::digit + , prefix, position, suffix); + + if (result) + { + std::cout << "-------------------------------- \n"; + std::cout << "Parsing succeeded\n"; + std::cout << "prefix is: " << prefix << "\n"; + std::cout << "suffix is: " << suffix << "\n"; + std::cout << "position is: " << std::distance(input.begin(), position) << "\n"; + std::cout << "-------------------------------- \n"; + } + else + { + std::cout << "-------------------------------- \n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------------- \n"; + } + return 0; +} diff --git a/src/boost/libs/spirit/example/qi/key_value_sequence.cpp b/src/boost/libs/spirit/example/qi/key_value_sequence.cpp new file mode 100644 index 00000000..3e75786d --- /dev/null +++ b/src/boost/libs/spirit/example/qi/key_value_sequence.cpp @@ -0,0 +1,78 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// The purpose of this example is to show how to parse arbitrary key/value +// pairs delimited by some separator into a std::map. Parsing the URL query +// format is the example we use to demonstrate how this can be done +// (i.e. things like: key1=value1;key2=value2;...;keyN=valueN). +// +// For a more elaborate explanation see here: http://spirit.sourceforge.net/home/?p=371 + +#include <boost/spirit/include/qi.hpp> +#include <boost/fusion/include/std_pair.hpp> + +#include <iostream> +#include <map> + +namespace client +{ + namespace qi = boost::spirit::qi; + + typedef std::map<std::string, std::string> pairs_type; + + template <typename Iterator> + struct key_value_sequence + : qi::grammar<Iterator, pairs_type()> + { + key_value_sequence() + : key_value_sequence::base_type(query) + { + query = pair >> *((qi::lit(';') | '&') >> pair); + pair = key >> -('=' >> value); + key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9"); + value = +qi::char_("a-zA-Z_0-9"); + } + + qi::rule<Iterator, pairs_type()> query; + qi::rule<Iterator, std::pair<std::string, std::string>()> pair; + qi::rule<Iterator, std::string()> key, value; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + namespace qi = boost::spirit::qi; + + std::string input("key1=value1;key2;key3=value3"); + std::string::iterator begin = input.begin(); + std::string::iterator end = input.end(); + + client::key_value_sequence<std::string::iterator> p; + client::pairs_type m; + + if (!qi::parse(begin, end, p, m)) + { + std::cout << "-------------------------------- \n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------------- \n"; + } + else + { + std::cout << "-------------------------------- \n"; + std::cout << "Parsing succeeded, found entries:\n"; + client::pairs_type::iterator end = m.end(); + for (client::pairs_type::iterator it = m.begin(); it != end; ++it) + { + std::cout << (*it).first; + if (!(*it).second.empty()) + std::cout << "=" << (*it).second; + std::cout << std::endl; + } + std::cout << "---------------------------------\n"; + } + return 0; +} + diff --git a/src/boost/libs/spirit/example/qi/key_value_sequence_empty_value.cpp b/src/boost/libs/spirit/example/qi/key_value_sequence_empty_value.cpp new file mode 100644 index 00000000..8cb8e20d --- /dev/null +++ b/src/boost/libs/spirit/example/qi/key_value_sequence_empty_value.cpp @@ -0,0 +1,83 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// The purpose of this example is to show how to parse arbitrary key/value +// pairs delimited by some separator into a std::vector. The difference to +// the example 'key_value_sequence.cpp' is that we preserve the order of the +// elements in the parsed sequence as well as possibly existing duplicates. +// In addition to the example 'key_value_sequence_ordered.cpp' we allow for +// empty values, i.e. the grammar allows to distinguish between 'key=;' and +// 'key;", where the first stores an empty string as the value, while the +// second does not initialize the optional holding the value. +// +// For a more elaborate explanation see here: http://spirit.sourceforge.net/home/?p=371 + +#include <boost/spirit/include/qi.hpp> +#include <boost/fusion/include/std_pair.hpp> + +#include <iostream> +#include <map> + +namespace client +{ + namespace qi = boost::spirit::qi; + + typedef std::pair<std::string, boost::optional<std::string> > pair_type; + typedef std::vector<pair_type> pairs_type; + + template <typename Iterator> + struct key_value_sequence_empty_value + : qi::grammar<Iterator, pairs_type()> + { + key_value_sequence_empty_value() + : key_value_sequence_empty_value::base_type(query) + { + query = pair >> *((qi::lit(';') | '&') >> pair); + pair = key >> -('=' >> -value); + key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9"); + value = +qi::char_("a-zA-Z_0-9"); + } + + qi::rule<Iterator, pairs_type()> query; + qi::rule<Iterator, pair_type()> pair; + qi::rule<Iterator, std::string()> key, value; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + namespace qi = boost::spirit::qi; + + std::string input("key1=value1;key2;key3=value3;key4="); + std::string::iterator begin = input.begin(); + std::string::iterator end = input.end(); + + client::key_value_sequence_empty_value<std::string::iterator> p; + client::pairs_type m; + + if (!qi::parse(begin, end, p, m)) + { + std::cout << "-------------------------------- \n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------------- \n"; + } + else + { + std::cout << "-------------------------------- \n"; + std::cout << "Parsing succeeded, found entries:\n"; + client::pairs_type::iterator end = m.end(); + for (client::pairs_type::iterator it = m.begin(); it != end; ++it) + { + std::cout << (*it).first; + if ((*it).second) + std::cout << "=" << boost::get<std::string>((*it).second); + std::cout << std::endl; + } + std::cout << "---------------------------------\n"; + } + return 0; +} + diff --git a/src/boost/libs/spirit/example/qi/key_value_sequence_ordered.cpp b/src/boost/libs/spirit/example/qi/key_value_sequence_ordered.cpp new file mode 100644 index 00000000..21689239 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/key_value_sequence_ordered.cpp @@ -0,0 +1,78 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// The purpose of this example is to show how to parse arbitrary key/value +// pairs delimited by some separator into a std::vector. The difference to +// the example 'key_value_sequence.cpp' is that we preserve the order of the +// elements in the parsed seqeunce as well as possibly existing duplicates. +// +// For a more elaborate explanation see here: http://spirit.sourceforge.net/home/?p=371 + +#include <boost/spirit/include/qi.hpp> +#include <boost/fusion/include/std_pair.hpp> + +#include <iostream> +#include <map> + +namespace client +{ + namespace qi = boost::spirit::qi; + + typedef std::vector<std::pair<std::string, std::string> > pairs_type; + + template <typename Iterator> + struct key_value_sequence_ordered + : qi::grammar<Iterator, pairs_type()> + { + key_value_sequence_ordered() + : key_value_sequence_ordered::base_type(query) + { + query = pair >> *((qi::lit(';') | '&') >> pair); + pair = key >> -('=' >> value); + key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9"); + value = +qi::char_("a-zA-Z_0-9"); + } + + qi::rule<Iterator, pairs_type()> query; + qi::rule<Iterator, std::pair<std::string, std::string>()> pair; + qi::rule<Iterator, std::string()> key, value; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + namespace qi = boost::spirit::qi; + + std::string input("key2=value2;key1;key3=value3"); + std::string::iterator begin = input.begin(); + std::string::iterator end = input.end(); + + client::key_value_sequence_ordered<std::string::iterator> p; + client::pairs_type v; + + if (!qi::parse(begin, end, p, v)) + { + std::cout << "-------------------------------- \n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------------- \n"; + } + else + { + std::cout << "-------------------------------- \n"; + std::cout << "Parsing succeeded, found entries:\n"; + client::pairs_type::iterator end = v.end(); + for (client::pairs_type::iterator it = v.begin(); it != end; ++it) + { + std::cout << (*it).first; + if (!(*it).second.empty()) + std::cout << "=" << (*it).second; + std::cout << std::endl; + } + std::cout << "---------------------------------\n"; + } + return 0; +} + diff --git a/src/boost/libs/spirit/example/qi/mini_xml1.cpp b/src/boost/libs/spirit/example/qi/mini_xml1.cpp new file mode 100644 index 00000000..1a27eda4 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/mini_xml1.cpp @@ -0,0 +1,242 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A mini XML-like parser +// +// [ JDG March 25, 2007 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/spirit/include/phoenix_fusion.hpp> +#include <boost/spirit/include/phoenix_stl.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/variant/recursive_variant.hpp> +#include <boost/foreach.hpp> + +#include <iostream> +#include <fstream> +#include <string> +#include <vector> + +namespace client +{ + namespace fusion = boost::fusion; + namespace phoenix = boost::phoenix; + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////// + // Our mini XML tree representation + /////////////////////////////////////////////////////////////////////////// + //[tutorial_xml1_structures + struct mini_xml; + + typedef + boost::variant< + boost::recursive_wrapper<mini_xml> + , std::string + > + mini_xml_node; + + struct mini_xml + { + std::string name; // tag name + std::vector<mini_xml_node> children; // children + }; + //] +} + +// We need to tell fusion about our mini_xml struct +// to make it a first-class fusion citizen +//[tutorial_xml1_adapt_structures +BOOST_FUSION_ADAPT_STRUCT( + client::mini_xml, + (std::string, name) + (std::vector<client::mini_xml_node>, children) +) +//] + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // Print out the mini xml tree + /////////////////////////////////////////////////////////////////////////// + int const tabsize = 4; + + void tab(int indent) + { + for (int i = 0; i < indent; ++i) + std::cout << ' '; + } + + struct mini_xml_printer + { + mini_xml_printer(int indent = 0) + : indent(indent) + { + } + + void operator()(mini_xml const& xml) const; + + int indent; + }; + + struct mini_xml_node_printer : boost::static_visitor<> + { + mini_xml_node_printer(int indent = 0) + : indent(indent) + { + } + + void operator()(mini_xml const& xml) const + { + mini_xml_printer(indent+tabsize)(xml); + } + + void operator()(std::string const& text) const + { + tab(indent+tabsize); + std::cout << "text: \"" << text << '"' << std::endl; + } + + int indent; + }; + + void mini_xml_printer::operator()(mini_xml const& xml) const + { + tab(indent); + std::cout << "tag: " << xml.name << std::endl; + tab(indent); + std::cout << '{' << std::endl; + + BOOST_FOREACH(mini_xml_node const& node, xml.children) + { + boost::apply_visitor(mini_xml_node_printer(indent), node); + } + + tab(indent); + std::cout << '}' << std::endl; + } + + /////////////////////////////////////////////////////////////////////////// + // Our mini XML grammar definition + /////////////////////////////////////////////////////////////////////////// + //[tutorial_xml1_grammar + template <typename Iterator> + struct mini_xml_grammar : qi::grammar<Iterator, mini_xml(), ascii::space_type> + { + mini_xml_grammar() : mini_xml_grammar::base_type(xml) + { + using qi::lit; + using qi::lexeme; + using ascii::char_; + using ascii::string; + using namespace qi::labels; + + using phoenix::at_c; + using phoenix::push_back; + + text = lexeme[+(char_ - '<') [_val += _1]]; + node = (xml | text) [_val = _1]; + + start_tag = + '<' + >> !lit('/') + >> lexeme[+(char_ - '>') [_val += _1]] + >> '>' + ; + + end_tag = + "</" + >> lit(_r1) + >> '>' + ; + + xml = + start_tag [at_c<0>(_val) = _1] + >> *node [push_back(at_c<1>(_val), _1)] + >> end_tag(at_c<0>(_val)) + ; + } + + qi::rule<Iterator, mini_xml(), ascii::space_type> xml; + qi::rule<Iterator, mini_xml_node(), ascii::space_type> node; + qi::rule<Iterator, std::string(), ascii::space_type> text; + qi::rule<Iterator, std::string(), ascii::space_type> start_tag; + qi::rule<Iterator, void(std::string), ascii::space_type> end_tag; + }; + //] +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main(int argc, char **argv) +{ + char const* filename; + if (argc > 1) + { + filename = argv[1]; + } + else + { + std::cerr << "Error: No input file provided." << std::endl; + return 1; + } + + std::ifstream in(filename, std::ios_base::in); + + if (!in) + { + std::cerr << "Error: Could not open input file: " + << filename << std::endl; + return 1; + } + + std::string storage; // We will read the contents here. + in.unsetf(std::ios::skipws); // No white space skipping! + std::copy( + std::istream_iterator<char>(in), + std::istream_iterator<char>(), + std::back_inserter(storage)); + + typedef client::mini_xml_grammar<std::string::const_iterator> mini_xml_grammar; + mini_xml_grammar xml; // Our grammar + client::mini_xml ast; // Our tree + + using boost::spirit::ascii::space; + std::string::const_iterator iter = storage.begin(); + std::string::const_iterator end = storage.end(); + bool r = phrase_parse(iter, end, xml, space, ast); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "-------------------------\n"; + client::mini_xml_printer printer; + printer(ast); + return 0; + } + else + { + std::string::const_iterator some = iter + std::min(30, int(end - iter)); + std::string context(iter, (some>end)?end:some); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \"" << context << "...\"\n"; + std::cout << "-------------------------\n"; + return 1; + } +} + + diff --git a/src/boost/libs/spirit/example/qi/mini_xml2.cpp b/src/boost/libs/spirit/example/qi/mini_xml2.cpp new file mode 100644 index 00000000..6d56374b --- /dev/null +++ b/src/boost/libs/spirit/example/qi/mini_xml2.cpp @@ -0,0 +1,237 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A mini XML-like parser +// +// [ JDG March 25, 2007 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/spirit/include/phoenix_fusion.hpp> +#include <boost/spirit/include/phoenix_stl.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/variant/recursive_variant.hpp> +#include <boost/foreach.hpp> + +#include <iostream> +#include <fstream> +#include <string> +#include <vector> + +namespace client +{ + namespace fusion = boost::fusion; + namespace phoenix = boost::phoenix; + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////// + // Our mini XML tree representation + /////////////////////////////////////////////////////////////////////////// + struct mini_xml; + + typedef + boost::variant< + boost::recursive_wrapper<mini_xml> + , std::string + > + mini_xml_node; + + struct mini_xml + { + std::string name; // tag name + std::vector<mini_xml_node> children; // children + }; +} + +// We need to tell fusion about our mini_xml struct +// to make it a first-class fusion citizen +BOOST_FUSION_ADAPT_STRUCT( + client::mini_xml, + (std::string, name) + (std::vector<client::mini_xml_node>, children) +) + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // Print out the mini xml tree + /////////////////////////////////////////////////////////////////////////// + int const tabsize = 4; + + void tab(int indent) + { + for (int i = 0; i < indent; ++i) + std::cout << ' '; + } + + struct mini_xml_printer + { + mini_xml_printer(int indent = 0) + : indent(indent) + { + } + + void operator()(mini_xml const& xml) const; + + int indent; + }; + + struct mini_xml_node_printer : boost::static_visitor<> + { + mini_xml_node_printer(int indent = 0) + : indent(indent) + { + } + + void operator()(mini_xml const& xml) const + { + mini_xml_printer(indent+tabsize)(xml); + } + + void operator()(std::string const& text) const + { + tab(indent+tabsize); + std::cout << "text: \"" << text << '"' << std::endl; + } + + int indent; + }; + + void mini_xml_printer::operator()(mini_xml const& xml) const + { + tab(indent); + std::cout << "tag: " << xml.name << std::endl; + tab(indent); + std::cout << '{' << std::endl; + + BOOST_FOREACH(mini_xml_node const& node, xml.children) + { + boost::apply_visitor(mini_xml_node_printer(indent), node); + } + + tab(indent); + std::cout << '}' << std::endl; + } + + /////////////////////////////////////////////////////////////////////////// + // Our mini XML grammar definition + /////////////////////////////////////////////////////////////////////////// + //[tutorial_xml2_grammar + template <typename Iterator> + struct mini_xml_grammar + : qi::grammar<Iterator, mini_xml(), qi::locals<std::string>, ascii::space_type> + { + mini_xml_grammar() + : mini_xml_grammar::base_type(xml) + { + using qi::lit; + using qi::lexeme; + using ascii::char_; + using ascii::string; + using namespace qi::labels; + + text %= lexeme[+(char_ - '<')]; + node %= xml | text; + + start_tag %= + '<' + >> !lit('/') + >> lexeme[+(char_ - '>')] + >> '>' + ; + + end_tag = + "</" + >> lit(_r1) + >> '>' + ; + + xml %= + start_tag[_a = _1] + >> *node + >> end_tag(_a) + ; + } + + qi::rule<Iterator, mini_xml(), qi::locals<std::string>, ascii::space_type> xml; + qi::rule<Iterator, mini_xml_node(), ascii::space_type> node; + qi::rule<Iterator, std::string(), ascii::space_type> text; + qi::rule<Iterator, std::string(), ascii::space_type> start_tag; + qi::rule<Iterator, void(std::string), ascii::space_type> end_tag; + }; + //] +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main(int argc, char **argv) +{ + char const* filename; + if (argc > 1) + { + filename = argv[1]; + } + else + { + std::cerr << "Error: No input file provided." << std::endl; + return 1; + } + + std::ifstream in(filename, std::ios_base::in); + + if (!in) + { + std::cerr << "Error: Could not open input file: " + << filename << std::endl; + return 1; + } + + std::string storage; // We will read the contents here. + in.unsetf(std::ios::skipws); // No white space skipping! + std::copy( + std::istream_iterator<char>(in), + std::istream_iterator<char>(), + std::back_inserter(storage)); + + typedef client::mini_xml_grammar<std::string::const_iterator> mini_xml_grammar; + mini_xml_grammar xml; // Our grammar + client::mini_xml ast; // Our tree + + using boost::spirit::ascii::space; + std::string::const_iterator iter = storage.begin(); + std::string::const_iterator end = storage.end(); + bool r = phrase_parse(iter, end, xml, space, ast); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "-------------------------\n"; + client::mini_xml_printer printer; + printer(ast); + return 0; + } + else + { + std::string::const_iterator some = iter + std::min(30, int(end - iter)); + std::string context(iter, (some>end)?end:some); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \"" << context << "...\"\n"; + std::cout << "-------------------------\n"; + return 1; + } +} + + diff --git a/src/boost/libs/spirit/example/qi/mini_xml3.cpp b/src/boost/libs/spirit/example/qi/mini_xml3.cpp new file mode 100644 index 00000000..d8926c1a --- /dev/null +++ b/src/boost/libs/spirit/example/qi/mini_xml3.cpp @@ -0,0 +1,258 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A mini XML-like parser +// +// [ JDG March 25, 2007 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/spirit/include/phoenix_fusion.hpp> +#include <boost/spirit/include/phoenix_stl.hpp> +#include <boost/spirit/include/phoenix_object.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/variant/recursive_variant.hpp> +#include <boost/foreach.hpp> + +#include <iostream> +#include <fstream> +#include <string> +#include <vector> + +namespace client +{ + namespace fusion = boost::fusion; + namespace phoenix = boost::phoenix; + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////// + // Our mini XML tree representation + /////////////////////////////////////////////////////////////////////////// + struct mini_xml; + + typedef + boost::variant< + boost::recursive_wrapper<mini_xml> + , std::string + > + mini_xml_node; + + struct mini_xml + { + std::string name; // tag name + std::vector<mini_xml_node> children; // children + }; +} + +// We need to tell fusion about our mini_xml struct +// to make it a first-class fusion citizen +BOOST_FUSION_ADAPT_STRUCT( + client::mini_xml, + (std::string, name) + (std::vector<client::mini_xml_node>, children) +) + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // Print out the mini xml tree + /////////////////////////////////////////////////////////////////////////// + int const tabsize = 4; + + void tab(int indent) + { + for (int i = 0; i < indent; ++i) + std::cout << ' '; + } + + struct mini_xml_printer + { + mini_xml_printer(int indent = 0) + : indent(indent) + { + } + + void operator()(mini_xml const& xml) const; + + int indent; + }; + + struct mini_xml_node_printer : boost::static_visitor<> + { + mini_xml_node_printer(int indent = 0) + : indent(indent) + { + } + + void operator()(mini_xml const& xml) const + { + mini_xml_printer(indent+tabsize)(xml); + } + + void operator()(std::string const& text) const + { + tab(indent+tabsize); + std::cout << "text: \"" << text << '"' << std::endl; + } + + int indent; + }; + + void mini_xml_printer::operator()(mini_xml const& xml) const + { + tab(indent); + std::cout << "tag: " << xml.name << std::endl; + tab(indent); + std::cout << '{' << std::endl; + + BOOST_FOREACH(mini_xml_node const& node, xml.children) + { + boost::apply_visitor(mini_xml_node_printer(indent), node); + } + + tab(indent); + std::cout << '}' << std::endl; + } + + /////////////////////////////////////////////////////////////////////////// + // Our mini XML grammar definition + /////////////////////////////////////////////////////////////////////////// + //[tutorial_xml3_grammar + template <typename Iterator> + struct mini_xml_grammar + : qi::grammar<Iterator, mini_xml(), qi::locals<std::string>, ascii::space_type> + { + mini_xml_grammar() + : mini_xml_grammar::base_type(xml, "xml") + { + using qi::lit; + using qi::lexeme; + using qi::on_error; + using qi::fail; + using ascii::char_; + using ascii::string; + using namespace qi::labels; + + using phoenix::construct; + using phoenix::val; + + text %= lexeme[+(char_ - '<')]; + node %= xml | text; + + start_tag %= + '<' + >> !lit('/') + > lexeme[+(char_ - '>')] + > '>' + ; + + end_tag = + "</" + > lit(_r1) + > '>' + ; + + xml %= + start_tag[_a = _1] + > *node + > end_tag(_a) + ; + + xml.name("xml"); + node.name("node"); + text.name("text"); + start_tag.name("start_tag"); + end_tag.name("end_tag"); + + on_error<fail> + ( + xml + , std::cout + << val("Error! Expecting ") + << _4 // what failed? + << val(" here: \"") + << construct<std::string>(_3, _2) // iterators to error-pos, end + << val("\"") + << std::endl + ); + } + + qi::rule<Iterator, mini_xml(), qi::locals<std::string>, ascii::space_type> xml; + qi::rule<Iterator, mini_xml_node(), ascii::space_type> node; + qi::rule<Iterator, std::string(), ascii::space_type> text; + qi::rule<Iterator, std::string(), ascii::space_type> start_tag; + qi::rule<Iterator, void(std::string), ascii::space_type> end_tag; + }; + //] +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main(int argc, char **argv) +{ + char const* filename; + if (argc > 1) + { + filename = argv[1]; + } + else + { + std::cerr << "Error: No input file provided." << std::endl; + return 1; + } + + std::ifstream in(filename, std::ios_base::in); + + if (!in) + { + std::cerr << "Error: Could not open input file: " + << filename << std::endl; + return 1; + } + + std::string storage; // We will read the contents here. + in.unsetf(std::ios::skipws); // No white space skipping! + std::copy( + std::istream_iterator<char>(in), + std::istream_iterator<char>(), + std::back_inserter(storage)); + + typedef client::mini_xml_grammar<std::string::const_iterator> mini_xml_grammar; + mini_xml_grammar xml; // Our grammar + client::mini_xml ast; // Our tree + + using boost::spirit::ascii::space; + std::string::const_iterator iter = storage.begin(); + std::string::const_iterator end = storage.end(); + bool r = phrase_parse(iter, end, xml, space, ast); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "-------------------------\n"; + client::mini_xml_printer printer; + printer(ast); + return 0; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + return 1; + } +} + + diff --git a/src/boost/libs/spirit/example/qi/mini_xml_samples/1.toyxml b/src/boost/libs/spirit/example/qi/mini_xml_samples/1.toyxml new file mode 100644 index 00000000..54181ed4 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/mini_xml_samples/1.toyxml @@ -0,0 +1 @@ +<foo></foo>
\ No newline at end of file diff --git a/src/boost/libs/spirit/example/qi/mini_xml_samples/2.toyxml b/src/boost/libs/spirit/example/qi/mini_xml_samples/2.toyxml new file mode 100644 index 00000000..266e4b1f --- /dev/null +++ b/src/boost/libs/spirit/example/qi/mini_xml_samples/2.toyxml @@ -0,0 +1 @@ +<foo><bar></bar></foo>
\ No newline at end of file diff --git a/src/boost/libs/spirit/example/qi/mini_xml_samples/3.toyxml b/src/boost/libs/spirit/example/qi/mini_xml_samples/3.toyxml new file mode 100644 index 00000000..9d89cf7b --- /dev/null +++ b/src/boost/libs/spirit/example/qi/mini_xml_samples/3.toyxml @@ -0,0 +1,5 @@ +<foo> + <bar>bar 1</bar> + <bar>bar 2</bar> + <bar>bar 3</bar> +</foo>
\ No newline at end of file diff --git a/src/boost/libs/spirit/example/qi/mini_xml_samples/4.toyxml b/src/boost/libs/spirit/example/qi/mini_xml_samples/4.toyxml new file mode 100644 index 00000000..0f220f1e --- /dev/null +++ b/src/boost/libs/spirit/example/qi/mini_xml_samples/4.toyxml @@ -0,0 +1 @@ +<foo><bar></foo></bar>
\ No newline at end of file diff --git a/src/boost/libs/spirit/example/qi/nabialek.cpp b/src/boost/libs/spirit/example/qi/nabialek.cpp new file mode 100644 index 00000000..4795578c --- /dev/null +++ b/src/boost/libs/spirit/example/qi/nabialek.cpp @@ -0,0 +1,98 @@ +/*============================================================================= + Copyright (c) 2003 Sam Nabialek + Copyright (c) 2001-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// The Nabialek trick. +// +// [ Sam Nabialek; Somewhere, sometime in 2003... ] spirit1 +// [ JDG November 17, 2009 ] spirit2 +// [ JDG January 10, 2010 ] Updated to use rule pointers +// for efficiency. +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <iostream> +#include <string> + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // Our nabialek_trick grammar + /////////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + struct nabialek_trick : qi::grammar< + Iterator, ascii::space_type, qi::locals<qi::rule<Iterator, ascii::space_type>*> > + { + nabialek_trick() : nabialek_trick::base_type(start) + { + using ascii::alnum; + using qi::lexeme; + using qi::lazy; + using qi::_a; + using qi::_1; + + id = lexeme[*(ascii::alnum | '_')]; + one = id; + two = id >> ',' >> id; + + keyword.add + ("one", &one) + ("two", &two) + ; + + start = *(keyword[_a = _1] >> lazy(*_a)); + } + + qi::rule<Iterator, ascii::space_type> id, one, two; + qi::rule<Iterator, ascii::space_type, qi::locals<qi::rule<Iterator, ascii::space_type>*> > start; + qi::symbols<char, qi::rule<Iterator, ascii::space_type>*> keyword; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + using boost::spirit::ascii::space; + typedef std::string::const_iterator iterator_type; + typedef client::nabialek_trick<iterator_type> nabialek_trick; + + nabialek_trick g; // Our grammar + + std::string str = "one only\none again\ntwo first,second"; + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + bool r = phrase_parse(iter, end, g, space); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "-------------------------\n"; + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \": " << rest << "\"\n"; + std::cout << "-------------------------\n"; + } + + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/num_list1.cpp b/src/boost/libs/spirit/example/qi/num_list1.cpp new file mode 100644 index 00000000..dc2e696d --- /dev/null +++ b/src/boost/libs/spirit/example/qi/num_list1.cpp @@ -0,0 +1,90 @@ +/*============================================================================= + Copyright (c) 2002-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This sample demontrates a parser for a comma separated list of numbers. +// No actions. +// +// [ JDG May 10, 2002 ] spirit1 +// [ JDG March 24, 2007 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> + +#include <iostream> +#include <string> +#include <vector> + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////// + // Our number list parser + /////////////////////////////////////////////////////////////////////////// + //[tutorial_numlist1 + template <typename Iterator> + bool parse_numbers(Iterator first, Iterator last) + { + using qi::double_; + using qi::phrase_parse; + using ascii::space; + + bool r = phrase_parse( + first, /*< start iterator >*/ + last, /*< end iterator >*/ + double_ >> *(',' >> double_), /*< the parser >*/ + space /*< the skip-parser >*/ + ); + if (first != last) // fail if we did not get a full match + return false; + return r; + } + //] +} + +//////////////////////////////////////////////////////////////////////////// +// Main program +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA comma separated list parser for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a comma separated list of numbers.\n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + if (client::parse_numbers(str.begin(), str.end())) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << str << " Parses OK: " << std::endl; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/num_list2.cpp b/src/boost/libs/spirit/example/qi/num_list2.cpp new file mode 100644 index 00000000..9fb854e7 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/num_list2.cpp @@ -0,0 +1,109 @@ +/*============================================================================= + Copyright (c) 2002-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This sample demontrates a parser for a comma separated list of numbers. +// The numbers are inserted in a vector using phoenix. +// +// [ JDG May 10, 2002 ] spirit1 +// [ JDG March 24, 2007 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/spirit/include/phoenix_stl.hpp> + +#include <iostream> +#include <string> +#include <vector> + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + namespace phoenix = boost::phoenix; + + /////////////////////////////////////////////////////////////////////////// + // Our number list compiler + /////////////////////////////////////////////////////////////////////////// + //[tutorial_numlist2 + template <typename Iterator> + bool parse_numbers(Iterator first, Iterator last, std::vector<double>& v) + { + using qi::double_; + using qi::phrase_parse; + using qi::_1; + using ascii::space; + using phoenix::push_back; + + bool r = phrase_parse(first, last, + + // Begin grammar + ( + double_[push_back(phoenix::ref(v), _1)] + >> *(',' >> double_[push_back(phoenix::ref(v), _1)]) + ) + , + // End grammar + + space); + + if (first != last) // fail if we did not get a full match + return false; + return r; + } + //] +} + +//////////////////////////////////////////////////////////////////////////// +// Main program +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA comma separated list parser for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a comma separated list of numbers.\n"; + std::cout << "The numbers will be inserted in a vector of numbers\n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::vector<double> v; + if (client::parse_numbers(str.begin(), str.end(), v)) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << str << " Parses OK: " << std::endl; + + for (std::vector<double>::size_type i = 0; i < v.size(); ++i) + std::cout << i << ": " << v[i] << std::endl; + + std::cout << "\n-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/num_list3.cpp b/src/boost/libs/spirit/example/qi/num_list3.cpp new file mode 100644 index 00000000..3ba09ffb --- /dev/null +++ b/src/boost/libs/spirit/example/qi/num_list3.cpp @@ -0,0 +1,108 @@ +/*============================================================================= + Copyright (c) 2002-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This sample demontrates a parser for a comma separated list of numbers. +// The numbers are inserted in a vector using phoenix. +// +// [ JDG May 10, 2002 ] spirit1 +// [ JDG March 24, 2007 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/spirit/include/phoenix_stl.hpp> + +#include <iostream> +#include <string> +#include <vector> + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + namespace phoenix = boost::phoenix; + + /////////////////////////////////////////////////////////////////////////////// + // Our number list compiler + /////////////////////////////////////////////////////////////////////////////// + //[tutorial_numlist3 + template <typename Iterator> + bool parse_numbers(Iterator first, Iterator last, std::vector<double>& v) + { + using qi::double_; + using qi::phrase_parse; + using qi::_1; + using ascii::space; + using phoenix::push_back; + + bool r = phrase_parse(first, last, + + // Begin grammar + ( + double_[push_back(phoenix::ref(v), _1)] % ',' + ) + , + // End grammar + + space); + + if (first != last) // fail if we did not get a full match + return false; + return r; + } + //] +} + +//////////////////////////////////////////////////////////////////////////// +// Main program +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA comma separated list parser for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a comma separated list of numbers.\n"; + std::cout << "The numbers will be inserted in a vector of numbers\n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::vector<double> v; + if (client::parse_numbers(str.begin(), str.end(), v)) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << str << " Parses OK: " << std::endl; + + for (std::vector<double>::size_type i = 0; i < v.size(); ++i) + std::cout << i << ": " << v[i] << std::endl; + + std::cout << "\n-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/num_list4.cpp b/src/boost/libs/spirit/example/qi/num_list4.cpp new file mode 100644 index 00000000..552dd8d1 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/num_list4.cpp @@ -0,0 +1,106 @@ +/*============================================================================= + Copyright (c) 2002-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This sample demontrates a parser for a comma separated list of numbers. +// The numbers are inserted in a vector using phoenix. +// +// [ JDG May 10, 2002 ] spirit1 +// [ JDG March 24, 2007 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/spirit/include/phoenix_stl.hpp> + +#include <iostream> +#include <string> +#include <vector> + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////// + // Our number list compiler + /////////////////////////////////////////////////////////////////////////// + //[tutorial_numlist4 + template <typename Iterator> + bool parse_numbers(Iterator first, Iterator last, std::vector<double>& v) + { + using qi::double_; + using qi::phrase_parse; + using qi::_1; + using ascii::space; + + bool r = phrase_parse(first, last, + + // Begin grammar + ( + double_ % ',' + ) + , + // End grammar + + space, v); + + if (first != last) // fail if we did not get a full match + return false; + return r; + } + //] +} + +//////////////////////////////////////////////////////////////////////////// +// Main program +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA comma separated list parser for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a comma separated list of numbers.\n"; + std::cout << "The numbers will be inserted in a vector of numbers\n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::vector<double> v; + if (client::parse_numbers(str.begin(), str.end(), v)) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << str << " Parses OK: " << std::endl; + + for (std::vector<double>::size_type i = 0; i < v.size(); ++i) + std::cout << i << ": " << v[i] << std::endl; + + std::cout << "\n-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/parse_date.cpp b/src/boost/libs/spirit/example/qi/parse_date.cpp new file mode 100644 index 00000000..82b5092d --- /dev/null +++ b/src/boost/libs/spirit/example/qi/parse_date.cpp @@ -0,0 +1,125 @@ +/*============================================================================= + Copyright (c) 2001-2010 Hartmut Kaiser + Copyright (c) 2001-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +// This example is not meant to be a sophisticated date parser. It's sole +// purpose is to demonstrate the intrinsic attribute transformation +// capabilities of a rule. +// +// Note how the rule exposes a fusion sequence, but gets passed an instance of +// a boost::gregorian::date as the attribute. In order to make these types +// compatible for the rule we define a specialization of the customization +// point called 'transform_attribute'. + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/fusion/include/vector.hpp> +#include <boost/date_time.hpp> + +// define custom transformation +namespace boost { namespace spirit { namespace traits +{ + // This specialization of the customization point transform_attribute + // allows to pass a boost::gregorian::date to a rule which is expecting + // a fusion sequence consisting out of three integers as its attribute. + template<> + struct transform_attribute< + boost::gregorian::date, fusion::vector<int, int, int>, qi::domain> + { + typedef fusion::vector<int, int, int> date_parts; + + // The embedded typedef 'type' exposes the attribute as it will be + // passed to the right hand side of the rule. + typedef date_parts type; + + // The function pre() is called for down-stream conversion of the + // attribute supplied to the rule to the attribute expected by the + // right hand side. + // The supplied attribute might have been pre-initialized by parsers + // (i.e. semantic actions) higher up the parser hierarchy (in the + // grammar), in which case we would need to properly initialize the + // returned value from the argument. In this example this is not + // required, so we just create a new instance of a date_parts. + static date_parts pre(boost::gregorian::date) + { + return date_parts(); + } + + // The function post() is called for up-stream conversion of the + // results returned from parsing the right hand side of the rule. + // We need to initialize the attribute supplied to the rule (referenced + // by the first argument) with the values taken from the parsing + // results (referenced by the second argument). + static void post(boost::gregorian::date& d, date_parts const& v) + { + d = boost::gregorian::date(fusion::at_c<0>(v), fusion::at_c<1>(v) + , fusion::at_c<2>(v)); + } + + // The function fail() is called whenever the parsing of the right hand + // side of the rule fails. We don't need to do anything here. + static void fail(boost::gregorian::date&) {} + }; +}}} + +/////////////////////////////////////////////////////////////////////////////// +namespace client +{ + namespace qi = boost::spirit::qi; + + template <typename Iterator> + bool parse_date(Iterator& first, Iterator last, boost::gregorian::date& d) + { + typedef boost::fusion::vector<int, int, int> date_parts; + qi::rule<Iterator, date_parts(), qi::space_type> date = + qi::int_ >> '-' >> qi::int_ >> '-' >> qi::int_; + + return phrase_parse(first, last, date, qi::space, d); + } +} + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA date parser for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a date of the form : year-month-day\n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + boost::gregorian::date d; + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + bool r = client::parse_date(iter, end, d); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "got: " << d << std::endl; + std::cout << "\n-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/porting_guide_classic.cpp b/src/boost/libs/spirit/example/qi/porting_guide_classic.cpp new file mode 100644 index 00000000..b12f0f22 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/porting_guide_classic.cpp @@ -0,0 +1,108 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + http://spirit.sourceforge.net/ + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +//[porting_guide_classic_includes +#include <boost/spirit/include/classic.hpp> +#include <boost/spirit/include/phoenix1.hpp> +#include <iostream> +#include <string> +//] + +//[porting_guide_classic_namespace +using namespace boost::spirit::classic; +//] + +//[porting_guide_classic_grammar +struct roman : public grammar<roman> +{ + template <typename ScannerT> + struct definition + { + definition(roman const& self) + { + hundreds.add + ("C" , 100)("CC" , 200)("CCC" , 300)("CD" , 400)("D" , 500) + ("DC" , 600)("DCC" , 700)("DCCC" , 800)("CM" , 900) ; + + tens.add + ("X" , 10)("XX" , 20)("XXX" , 30)("XL" , 40)("L" , 50) + ("LX" , 60)("LXX" , 70)("LXXX" , 80)("XC" , 90) ; + + ones.add + ("I" , 1)("II" , 2)("III" , 3)("IV" , 4)("V" , 5) + ("VI" , 6)("VII" , 7)("VIII" , 8)("IX" , 9) ; + + first = eps_p [phoenix::var(self.r) = phoenix::val(0)] + >> ( +ch_p('M') [phoenix::var(self.r) += phoenix::val(1000)] + || hundreds [phoenix::var(self.r) += phoenix::_1] + || tens [phoenix::var(self.r) += phoenix::_1] + || ones [phoenix::var(self.r) += phoenix::_1] + ) ; + } + + rule<ScannerT> first; + symbols<unsigned> hundreds; + symbols<unsigned> tens; + symbols<unsigned> ones; + + rule<ScannerT> const& start() const { return first; } + }; + + roman(unsigned& r_) : r(r_) {} + unsigned& r; +}; +//] + +int main() +{ + { + //[porting_guide_classic_parse + std::string input("1,1"); + parse_info<std::string::iterator> pi = parse(input.begin(), input.end(), int_p); + + if (pi.hit) + std::cout << "successful match!\n"; + + if (pi.full) + std::cout << "full match!\n"; + else + std::cout << "stopped at: " << std::string(pi.stop, input.end()) << "\n"; + + std::cout << "matched length: " << pi.length << "\n"; + //] + } + + { + //[porting_guide_classic_phrase_parse + std::string input(" 1, 1"); + parse_info<std::string::iterator> pi = parse(input.begin(), input.end(), int_p, space_p); + + if (pi.hit) + std::cout << "successful match!\n"; + + if (pi.full) + std::cout << "full match!\n"; + else + std::cout << "stopped at: " << std::string(pi.stop, input.end()) << "\n"; + + std::cout << "matched length: " << pi.length << "\n"; + //] + } + + { + //[porting_guide_classic_use_grammar + std::string input("MMIX"); // MMIX == 2009 + unsigned value = 0; + roman r(value); + parse_info<std::string::iterator> pi = parse(input.begin(), input.end(), r); + if (pi.hit) + std::cout << "successfully matched: " << value << "\n"; + //] + } + return 0; +} + diff --git a/src/boost/libs/spirit/example/qi/porting_guide_qi.cpp b/src/boost/libs/spirit/example/qi/porting_guide_qi.cpp new file mode 100644 index 00000000..d1ec0335 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/porting_guide_qi.cpp @@ -0,0 +1,106 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + http://spirit.sourceforge.net/ + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +//[porting_guide_qi_includes +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <iostream> +#include <string> +#include <algorithm> +//] + +//[porting_guide_qi_namespace +using namespace boost::spirit; +//] + +//[porting_guide_qi_grammar +template <typename Iterator> +struct roman : qi::grammar<Iterator, unsigned()> +{ + roman() : roman::base_type(first) + { + hundreds.add + ("C" , 100)("CC" , 200)("CCC" , 300)("CD" , 400)("D" , 500) + ("DC" , 600)("DCC" , 700)("DCCC" , 800)("CM" , 900) ; + + tens.add + ("X" , 10)("XX" , 20)("XXX" , 30)("XL" , 40)("L" , 50) + ("LX" , 60)("LXX" , 70)("LXXX" , 80)("XC" , 90) ; + + ones.add + ("I" , 1)("II" , 2)("III" , 3)("IV" , 4)("V" , 5) + ("VI" , 6)("VII" , 7)("VIII" , 8)("IX" , 9) ; + + // qi::_val refers to the attribute of the rule on the left hand side + first = eps [qi::_val = 0] + >> ( +lit('M') [qi::_val += 1000] + || hundreds [qi::_val += qi::_1] + || tens [qi::_val += qi::_1] + || ones [qi::_val += qi::_1] + ) ; + } + + qi::rule<Iterator, unsigned()> first; + qi::symbols<char, unsigned> hundreds; + qi::symbols<char, unsigned> tens; + qi::symbols<char, unsigned> ones; +}; +//] + +int main() +{ + { + //[porting_guide_qi_parse + std::string input("1,1"); + std::string::iterator it = input.begin(); + bool result = qi::parse(it, input.end(), qi::int_); + + if (result) + std::cout << "successful match!\n"; + + if (it == input.end()) + std::cout << "full match!\n"; + else + std::cout << "stopped at: " << std::string(it, input.end()) << "\n"; + + // seldomly needed: use std::distance to calculate the length of the match + std::cout << "matched length: " << std::distance(input.begin(), it) << "\n"; + //] + } + + { + //[porting_guide_qi_phrase_parse + std::string input(" 1, 1"); + std::string::iterator it = input.begin(); + bool result = qi::phrase_parse(it, input.end(), qi::int_, ascii::space); + + if (result) + std::cout << "successful match!\n"; + + if (it == input.end()) + std::cout << "full match!\n"; + else + std::cout << "stopped at: " << std::string(it, input.end()) << "\n"; + + // seldomly needed: use std::distance to calculate the length of the match + std::cout << "matched length: " << std::distance(input.begin(), it) << "\n"; + //] + } + + { + //[porting_guide_qi_use_grammar + std::string input("MMIX"); // MMIX == 2009 + std::string::iterator it = input.begin(); + unsigned value = 0; + roman<std::string::iterator> r; + if (qi::parse(it, input.end(), r, value)) + std::cout << "successfully matched: " << value << "\n"; + //] + } + return 0; +} + diff --git a/src/boost/libs/spirit/example/qi/reference.cpp b/src/boost/libs/spirit/example/qi/reference.cpp new file mode 100644 index 00000000..4cd8a147 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/reference.cpp @@ -0,0 +1,1481 @@ +/*============================================================================= + Copyright (c) 2001-2011 Joel de Guzman + http://spirit.sourceforge.net/ + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +// this code is not supposed to be executed, so the asserts are for +// demonstration purposes only +// boostinspect:naassert_macro + +//[reference_includes +#include <boost/spirit/include/support_utree.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/assert.hpp> +#include <boost/predef/other/endian.h> +#include <iostream> +#include <string> +#include <cstdlib> +//] + +//[reference_test +template <typename P> +void test_parser( + char const* input, P const& p, bool full_match = true) +{ + using boost::spirit::qi::parse; + + char const* f(input); + char const* l(f + strlen(f)); + if (parse(f, l, p) && (!full_match || (f == l))) + std::cout << "ok" << std::endl; + else + std::cout << "fail" << std::endl; +} + +template <typename P> +void test_phrase_parser( + char const* input, P const& p, bool full_match = true) +{ + using boost::spirit::qi::phrase_parse; + using boost::spirit::qi::ascii::space; + + char const* f(input); + char const* l(f + strlen(f)); + if (phrase_parse(f, l, p, space) && (!full_match || (f == l))) + std::cout << "ok" << std::endl; + else + std::cout << "fail" << std::endl; +} +//] + +//[reference_test_attr +template <typename P, typename T> +void test_parser_attr( + char const* input, P const& p, T& attr, bool full_match = true) +{ + using boost::spirit::qi::parse; + + char const* f(input); + char const* l(f + strlen(f)); + if (parse(f, l, p, attr) && (!full_match || (f == l))) + std::cout << "ok" << std::endl; + else + std::cout << "fail" << std::endl; +} + +template <typename P, typename T> +void test_phrase_parser_attr( + char const* input, P const& p, T& attr, bool full_match = true) +{ + using boost::spirit::qi::phrase_parse; + using boost::spirit::qi::ascii::space; + + char const* f(input); + char const* l(f + strlen(f)); + if (phrase_parse(f, l, p, space, attr) && (!full_match || (f == l))) + std::cout << "ok" << std::endl; + else + std::cout << "fail" << std::endl; +} +//] + +//[reference_print_info +struct printer +{ + typedef boost::spirit::utf8_string string; + + void element(string const& tag, string const& value, int depth) const + { + for (int i = 0; i < (depth*4); ++i) // indent to depth + std::cout << ' '; + + std::cout << "tag: " << tag; + if (value != "") + std::cout << ", value: " << value; + std::cout << std::endl; + } +}; + +void print_info(boost::spirit::info const& what) +{ + using boost::spirit::basic_info_walker; + + printer pr; + basic_info_walker<printer> walker(pr, what.tag, 0); + boost::apply_visitor(walker, what.value); +} +//] + +//[reference_test_real_policy +/////////////////////////////////////////////////////////////////////////////// +// These policies can be used to parse thousand separated +// numbers with at most 2 decimal digits after the decimal +// point. e.g. 123,456,789.01 +/////////////////////////////////////////////////////////////////////////////// +template <typename T> +struct ts_real_policies : boost::spirit::qi::ureal_policies<T> +{ + // 2 decimal places Max + template <typename Iterator, typename Attribute> + static bool + parse_frac_n(Iterator& first, Iterator const& last, Attribute& attr, + int& frac_digits) + { + Iterator savef = first; + bool r = boost::spirit::qi:: + extract_uint<T, 10, 1, 2, true>::call(first, last, attr); + if (r) { + // Optimization note: don't compute frac_digits if T is + // an unused_type. This should be optimized away by the compiler. + if (!boost::is_same<T, boost::spirit::unused_type>::value) + frac_digits = static_cast<int>(std::distance(savef, first)); + } + return r; + } + + // No exponent + template <typename Iterator> + static bool + parse_exp(Iterator&, Iterator const&) + { + return false; + } + + // No exponent + template <typename Iterator, typename Attribute> + static bool + parse_exp_n(Iterator&, Iterator const&, Attribute&) + { + return false; + } + + // Thousands separated numbers + template <typename Iterator, typename Accumulator> + static bool + parse_n(Iterator& first, Iterator const& last, Accumulator& result) + { + using boost::spirit::qi::uint_parser; + namespace qi = boost::spirit::qi; + + uint_parser<unsigned, 10, 1, 3> uint3; + uint_parser<unsigned, 10, 3, 3> uint3_3; + + if (parse(first, last, uint3, result)) + { + Accumulator n; + Iterator iter = first; + + while (qi::parse(iter, last, ',') && qi::parse(iter, last, uint3_3, n)) + { + result = result * 1000 + n; + first = iter; + } + + return true; + } + return false; + } +}; +//] + +//[reference_test_bool_policy +/////////////////////////////////////////////////////////////////////////////// +// These policies can be used to parse "eurt" (i.e. "true" spelled backwards) +// as `false` +/////////////////////////////////////////////////////////////////////////////// +struct backwards_bool_policies : boost::spirit::qi::bool_policies<> +{ + // we want to interpret a 'true' spelled backwards as 'false' + template <typename Iterator, typename Attribute> + static bool + parse_false(Iterator& first, Iterator const& last, Attribute& attr) + { + namespace qi = boost::spirit::qi; + if (qi::detail::string_parse("eurt", first, last, qi::unused)) + { + namespace traits = boost::spirit::traits; + traits::assign_to(false, attr); // result is false + return true; + } + return false; + } +}; +//] + +//[reference_qi_complex +// a simple complex number representation z = a + bi +struct complex +{ + complex (double a = 0.0, double b = 0.0) + : a(a), b(b) + {} + + double a; + double b; +}; +//] + +//[reference_qi_stream_complex +// define streaming operator for the type complex +std::istream& +operator>> (std::istream& is, complex& z) +{ + char lbrace = '\0', comma = '\0', rbrace = '\0'; + is >> lbrace >> z.a >> comma >> z.b >> rbrace; + if (lbrace != '{' || comma != ',' || rbrace != '}') + is.setstate(std::ios_base::failbit); + return is; +} +//] + +//[reference_qi_auto_complex +/*`The following construct is required to allow the `complex` data structure + to be utilized as a __fusion__ sequence. This is required as we will + emit output for this data structure with a __qi__ sequence: + `'{' >> qi::double_ >> ',' >> qi::double_ >> '}'`. +*/ +BOOST_FUSION_ADAPT_STRUCT( + complex, + (double, a) + (double, b) +) + +/*`We add a specialization for the create_parser customization point + defining a custom output format for the complex type. Generally, any + specialization for create_parser is expected to return the proto + expression to be used to match input for the type the customization + point has been specialized for. + */ +/*`We need to utilize `proto::deep_copy` as the expression contains literals + (the `'{'`, `','`, and `'}'`) which normally get embedded in the proto + expression by reference only. The deep copy converts the proto tree to + hold this by value. The deep copy operation can be left out for simpler + proto expressions (not containing references to temporaries). Alternatively + you could use the `proto::make_expr` facility to build the required + proto expression. +*/ +namespace boost { namespace spirit { namespace traits +{ + template <> + struct create_parser<complex> + { + typedef proto::result_of::deep_copy< + BOOST_TYPEOF('{' >> qi::double_ >> ',' >> qi::double_ >> '}') + >::type type; + + static type call() + { + return proto::deep_copy( + '{' >> qi::double_ >> ',' >> qi::double_ >> '}'); + } + }; +}}} +//] + +//[reference_qi_auxiliary_attr_cast_data1 +// this is just a test structure we want to use in place of an int +struct int_data +{ + int i; +}; + + +// we provide a custom attribute transformation to allow its use as an int +namespace boost { namespace spirit { namespace traits +{ + // in this case we just expose the embedded 'int' as the attribute instance + // to use, allowing to leave the function 'post()' empty + template <> + struct transform_attribute<int_data, int, qi::domain> + { + typedef int& type; + static int& pre(int_data& d) { return d.i; } + static void post(int_data& val, int const& attr) {} + static void fail(int_data&) {} + }; +}}} +//] + +namespace client +{ + using boost::spirit::qi::grammar; + using boost::spirit::qi::rule; + using boost::spirit::ascii::space_type; + +//[reference_grammar_definition +/*`Basic grammar usage: + */ + struct num_list : grammar<char const*, space_type> + { + num_list() : base_type(start) + { + using boost::spirit::int_; + num = int_; + start = num >> *(',' >> num); + } + + rule<char const*, space_type> start, num; + }; +//] +} + +int +main() +{ + { + //[reference_using_declarations_lit_char + using boost::spirit::qi::lit; + using boost::spirit::ascii::char_; + //] + + //[reference_char_literals + test_parser("x", 'x'); // plain literal + test_parser("x", lit('x')); // explicit literal + test_parser("x", char_('x')); // ascii::char_ + //] + + //[reference_char_range + char ch; + test_parser_attr("5", char_('0','9'), ch); // ascii::char_ range + std::cout << ch << std::endl; // prints '5' + //] + + //[reference_char_set + test_parser_attr("5", char_("0-9"), ch); // ascii::char_ set + std::cout << ch << std::endl; // prints '5' + //] + + //[reference_char_phoenix + namespace phx = boost::phoenix; + test_parser("x", phx::val('x')); // direct + test_parser("5", + char_(phx::val('0'),phx::val('9'))); // ascii::char_ range + //] + } + + { + //[reference_using_declarations_lit_string + using boost::spirit::qi::lit; + using boost::spirit::ascii::string; + //] + + //[reference_string_literals + test_parser("boost", "boost"); // plain literal + test_parser("boost", lit("boost")); // explicit literal + test_parser("boost", string("boost")); // ascii::string + //] + } + + { + using boost::spirit::qi::lit; + using boost::spirit::ascii::string; + + //[reference_string_std_string + std::string s("boost"); + test_parser("boost", s); // direct + test_parser("boost", lit(s)); // explicit + test_parser("boost", string(s)); // ascii::string + //] + } + + { + using boost::spirit::qi::lit; + using boost::spirit::ascii::string; + + //[reference_string_phoenix + namespace phx = boost::phoenix; + test_parser("boost", phx::val("boost")); // direct + test_parser("boost", lit(phx::val("boost"))); // explicit + test_parser("boost", string(phx::val("boost"))); // ascii::string + //] + } + + { + //[reference_using_declarations_symbols + using boost::spirit::qi::symbols; + //] + + //[reference_symbols_with_data + symbols<char, int> sym; + + sym.add + ("Apple", 1) + ("Banana", 2) + ("Orange", 3) + ; + + int i; + test_parser_attr("Banana", sym, i); + std::cout << i << std::endl; + //] + } + + { + //[reference_using_declarations_lexeme + using boost::spirit::qi::lexeme; + using boost::spirit::qi::lit; + using boost::spirit::ascii::digit; + //] + + //[reference_lexeme + /*`The use of lexeme here will prevent skipping in between the + digits and the sign making inputs such as `"1 2 345"` erroneous.*/ + test_phrase_parser("12345", lexeme[ -(lit('+') | '-') >> +digit ]); + //] + } + + // as + { + //[reference_using_declarations_as + using boost::spirit::utree; + using boost::spirit::utree_type; + using boost::spirit::utf8_symbol_type; + using boost::spirit::qi::as; + using boost::spirit::qi::as_string; + using boost::spirit::qi::char_; + //] + + //[reference_as + /*`To properly handle string concatenation with __utree__, we + make use of `as_string[]`. We also use `as<T>` to explicitly create + a __utree__ symbol node.*/ + utree ut; + + typedef as<utf8_symbol_type> as_symbol_type; + as_symbol_type const as_symbol = as_symbol_type(); + + test_parser_attr("foo", as_string[*char_], ut); + std::cout << ut << std::endl; // will output >"foo"< + BOOST_ASSERT(ut.which() == utree_type::string_type); + ut.clear(); + + test_parser_attr("foo", as<std::string>()[*char_], ut); + std::cout << ut << std::endl; // will output >"foo"< + BOOST_ASSERT(ut.which() == utree_type::string_type); + ut.clear(); + + test_parser_attr("foo", as_symbol[*char_], ut); + std::cout << ut << std::endl; // will output >foo< + BOOST_ASSERT(ut.which() == utree_type::symbol_type); + ut.clear(); + + test_parser_attr("foo", as<utf8_symbol_type>()[*char_], ut); + std::cout << ut << std::endl; // will output >foo< + BOOST_ASSERT(ut.which() == utree_type::symbol_type); + //] + } + + { + //[reference_using_declarations_no_skip + using boost::spirit::qi::no_skip; + using boost::spirit::qi::char_; + //] + + //[reference_no_skip + /*`The use of no_skip here will prevent skipping of whitespace in front + and in between the characters of the string `' abc '`.*/ + + std::string str; + test_phrase_parser_attr("' abc '", + '\'' >> no_skip[+~char_('\'')] >> '\'', str); + std::cout << str << std::endl; // will output: > abc < + //] + } + + { + //[reference_using_declarations_hold + using boost::spirit::qi::hold; + using boost::spirit::qi::int_; + using boost::spirit::qi::attr; + //] + + //[reference_hold + /*`The use of `hold[]` here will make sure the changes to the attribute + caused by the (failing) first alternative will not be visible after + the whole parsing succeeded. */ + + std::vector<int> v; + test_phrase_parser_attr("123", + hold[int_ >> ':' >> int_] | int_ >> attr(0), v); + std::cout << v[0] << "," << v[1] << std::endl; // will output: >123,0< + //] + } + + { + //[reference_using_declarations_no_case + using boost::spirit::ascii::no_case; + using boost::spirit::ascii::char_; + using boost::spirit::ascii::alnum; + using boost::spirit::qi::symbols; + //] + + //[reference_no_case + test_parser("X", no_case[char_('x')]); + test_parser("6", no_case[alnum]); + //] + + //[reference_symbols_with_no_case + symbols<char, int> sym; + + sym.add + ("apple", 1) // symbol strings are added in lowercase... + ("banana", 2) + ("orange", 3) + ; + + int i; + // ...because sym is used for case-insensitive parsing + test_parser_attr("Apple", no_case[ sym ], i); + std::cout << i << std::endl; + test_parser_attr("ORANGE", no_case[ sym ], i); + std::cout << i << std::endl; + //] + } + + { + //[reference_using_declarations_omit + using boost::spirit::qi::omit; + using boost::spirit::qi::int_; + using boost::spirit::ascii::char_; + //] + + //[reference_omit + /*`This parser ignores the first two characters + and extracts the succeeding `int`:*/ + int i; + test_parser_attr("xx345", omit[char_ >> char_] >> int_, i); + std::cout << i << std::endl; // should print 345 + //] + } + + { + //[reference_using_declarations_matches + using boost::spirit::qi::matches; + using boost::spirit::qi::int_; + //] + + //[reference_matches + /*`This parser tries to match an `int` and returns `true` a its + attribute as it succeeded matching: */ + bool result = false; + test_parser_attr("345", matches[int_], result); + std::cout << std::boolalpha << result << std::endl; // should print: true + + /*`This parser tries to match an `int` as well and returns `false` as + its attribute as it fails matching: */ + result = true; + test_parser_attr("abc", matches[int_], result); + std::cout << std::boolalpha << result << std::endl; // should print: false + //] + } + + { + //[reference_using_declarations_raw + using boost::spirit::qi::raw; + using boost::spirit::ascii::alpha; + using boost::spirit::ascii::alnum; + //] + + //[reference_raw + //`This parser matches and extracts C++ identifiers: + std::string id; + test_parser_attr("James007", raw[(alpha | '_') >> *(alnum | '_')], id); + std::cout << id << std::endl; // should print James007 + //] + } + + { + //[reference_using_declarations_repeat + using boost::spirit::qi::repeat; + using boost::spirit::qi::lit; + using boost::spirit::qi::uint_parser; + using boost::spirit::qi::_1; + using boost::spirit::ascii::char_; + namespace phx = boost::phoenix; + //] + + //[reference_repeat + //`A parser for a file name with a maximum of 255 characters: + test_parser("batman.jpeg", repeat(1, 255)[char_("a-zA-Z_./")]); + + /*`A parser for a specific bitmap file format which has exactly 4096 RGB color information. + (for the purpose of this example, we will be testing only 3 RGB color information.) + */ + uint_parser<unsigned, 16, 6, 6> rgb; + std::vector<unsigned> colors; + test_parser_attr("ffffff0000003f3f3f", repeat(3)[rgb], colors); + std::cout + << std::hex + << colors[0] << ',' + << colors[1] << ',' + << colors[2] << std::endl; + + /*`A 256 bit binary string (1..256 1s or 0s). (For the purpose of this example, + we will be testing only 16 bits.) + */ + test_parser("1011101011110010", repeat(16)[lit('1') | '0']); + //] + + std::cout << std::dec; // reset to decimal + + //[reference_repeat_pascal + /*`This trivial example cannot be practically defined in traditional EBNF. + Although some EBNF variants allow more powerful repetition constructs other + than the Kleene Star, we are still limited to parsing fixed strings. + The nature of EBNF forces the repetition factor to be a constant. + On the other hand, Spirit allows the repetition factor to be variable at + run time. We could write a grammar that accepts the input string above. + Example using phoenix: + */ + std::string str; + int n; + test_parser_attr("\x0bHello World", + char_[phx::ref(n) = _1] >> repeat(phx::ref(n))[char_], str); + std::cout << n << ',' << str << std::endl; // will print "11,Hello World" + //] + } + + { + //[reference_using_declarations_skip + using boost::spirit::qi::skip; + using boost::spirit::qi::int_; + using boost::spirit::ascii::space; + //] + + //[reference_skip + /*`Explicitly specify a skip parser. This parser parses comma + delimited numbers, ignoring spaces.*/ + test_parser("1, 2, 3, 4, 5", skip(space)[int_ >> *(',' >> int_)]); + //] + } + + // attr() + { + //[reference_using_declarations_attr + namespace phx = boost::phoenix; + using boost::spirit::qi::attr; + //] + + //[reference_attr + std::string str; + test_parser_attr("", attr("boost"), str); + std::cout << str << std::endl; // will print 'boost' + + double d; + test_parser_attr("", attr(1.0), d); + std::cout << d << std::endl; // will print '1.0' + //] + + //[reference_attr_phoenix + d = 0.0; + double d1 = 1.2; + test_parser_attr("", attr(phx::ref(d1)), d); + std::cout << d << std::endl; // will print '1.2' + //] + } + + // attr_cast + { + //[reference_qi_using_declarations_attr_cast + using boost::spirit::qi::int_; + //] + + //[reference_qi_attr_cast1 + int_data d = { 0 }; + test_parser_attr("1", boost::spirit::qi::attr_cast(int_), d); + std::cout << d.i << std::endl; + //] + } + + // eol + { + //[reference_using_declarations_eol + using boost::spirit::qi::eol; + //] + + //[reference_eol + test_parser("\n", eol); + //] + } + + // eoi + { + //[reference_using_declarations_eoi + using boost::spirit::qi::eoi; + //] + + //[reference_eoi + test_parser("", eoi); + //] + } + + // eps + { + //[reference_using_declarations_eps + using boost::spirit::qi::eps; + using boost::spirit::qi::int_; + using boost::spirit::qi::_1; + namespace phx = boost::phoenix; + //] + + //[reference_eps + //`Basic `eps`: + test_parser("", eps); // always matches + //] + + //[reference_eps_if + /*`This example simulates the "classic" `if_p` parser. Here, `int_` will be + tried only if the condition, `c`, is true. + */ + bool c = true; // a flag + test_parser("1234", eps(phx::ref(c) == true) >> int_); + //] + + //[reference_eps_while + /*`This example simulates the "classic" `while_p` parser. Here, the kleene loop + will exit once the condition, `c`, becomes true. Notice that the condition, `c`, + is turned to `false` when we get to parse `4`. + */ + test_phrase_parser("1 2 3 4", + *(eps(phx::ref(c) == true) >> int_[phx::ref(c) = (_1 == 4)])); + //] + } + + // lazy + { + //[reference_using_declarations_lazy + using boost::spirit::qi::lazy; + using boost::spirit::ascii::string; + using boost::phoenix::val; + //] + + //[reference_lazy + /*` Here, the phoenix::val expression creates a function + that returns its argument when invoked. The lazy expression + defers the invocation of this function at parse time. Then, + this parser (string parser) is called into action. All this + takes place at parse time. + */ + test_parser("Hello", lazy(val(string("Hello")))); + + //` The above is equivalent to: + test_parser("Hello", string("Hello")); + //] + } + + // char class + { + //[reference_using_declarations_char_class + using boost::spirit::ascii::alnum; + using boost::spirit::ascii::blank; + using boost::spirit::ascii::digit; + using boost::spirit::ascii::lower; + //] + + //[reference_char_class + test_parser("1", alnum); + test_parser(" ", blank); + test_parser("1", digit); + test_parser("a", lower); + //] + } + + // uint + { + //[reference_using_declarations_uint + using boost::phoenix::val; + using boost::spirit::qi::lit; + using boost::spirit::qi::uint_; + using boost::spirit::qi::uint_parser; + //] + + //[reference_uint + // unsigned int + test_parser("12345", uint_); + test_parser("12345", uint_(12345)); + test_parser("12345", uint_(val(12345))); + + // literals + test_parser("12345", lit(12345)); + test_parser("12345", lit(val(12345))); + //] + + //[reference_thousand_separated + //`Thousand separated number parser: + uint_parser<unsigned, 10, 1, 3> uint3_p; // 1..3 digits + uint_parser<unsigned, 10, 3, 3> uint3_3_p; // exactly 3 digits + test_parser("12,345,678", uint3_p >> *(',' >> uint3_3_p)); + //] + } + + // int + { + //[reference_using_declarations_int + using boost::phoenix::val; + using boost::spirit::qi::lit; + using boost::spirit::qi::int_; + //] + + //[reference_int + // signed int + test_parser("+12345", int_); + test_parser("-12345", int_); + test_parser("+12345", int_(12345)); + test_parser("-12345", int_(-12345)); + test_parser("+12345", int_(val(12345))); + test_parser("-12345", int_(val(-12345))); + + // literals + test_parser("+12345", lit(12345)); + test_parser("-12345", lit(-12345)); + test_parser("+12345", lit(val(12345))); + test_parser("-12345", lit(val(-12345))); + //] + } + + // real + { + //[reference_using_declarations_real + using boost::phoenix::val; + using boost::spirit::qi::double_; + using boost::spirit::qi::real_parser; + using boost::spirit::qi::lit; + //] + + //[reference_real + // double + test_parser("+12345e6", double_); + test_parser("-12345e6", double_); + test_parser("+12345e6", double_(12345e6)); + test_parser("-12345e6", double_(-123456e6)); + test_parser("+12345e6", double_(val(12345e6))); + test_parser("-12345e6", double_(val(-123456e6))); + + // literals + test_parser("+12345e6", lit(12345e6)); + test_parser("-12345e6", lit(-123456e6)); + test_parser("+12345e6", lit(val(12345e6))); + test_parser("-12345e6", lit(val(-123456e6))); + //] + + //[reference_custom_real + real_parser<double, ts_real_policies<double> > ts_real; + test_parser("123,456,789.01", ts_real); + test_parser("123,456,789.01", ts_real(123456789.01)); + //] + } + + // bool_ + { + //[reference_using_declarations_bool + using boost::phoenix::val; + using boost::spirit::qi::bool_; + using boost::spirit::qi::bool_parser; + using boost::spirit::qi::lit; + //] + + //[reference_bool + // bool + test_parser("true", bool_); + test_parser("false", bool_); + test_parser("true", bool_(true)); + test_parser("false", bool_(false)); + test_parser("true", bool_(val(true))); + test_parser("false", bool_(val(false))); + + // literals + test_parser("true", lit(true)); + test_parser("false", lit(false)); + test_parser("true", lit(val(true))); + test_parser("false", lit(val(false))); + //] + + //[reference_custom_bool + bool_parser<bool, backwards_bool_policies> backwards_bool; + test_parser("true", backwards_bool); + test_parser("eurt", backwards_bool); + test_parser("true", backwards_bool(true)); + test_parser("eurt", backwards_bool(false)); + //] + } + + // sequence + { + //[reference_using_declarations_sequence + using boost::spirit::ascii::char_; + using boost::spirit::qi::_1; + using boost::spirit::qi::_2; + namespace bf = boost::fusion; + //] + + //[reference_sequence + //`Simple usage: + test_parser("xy", char_ >> char_); + + //`Extracting the attribute tuple (using __fusion__): + bf::vector<char, char> attr; + test_parser_attr("xy", char_ >> char_, attr); + std::cout << bf::at_c<0>(attr) << ',' << bf::at_c<1>(attr) << std::endl; + + //`Extracting the attribute vector (using __stl__): + std::vector<char> vec; + test_parser_attr("xy", char_ >> char_, vec); + std::cout << vec[0] << ',' << vec[1] << std::endl; + + //`Extracting the attributes using __qi_semantic_actions__ (using __phoenix__): + test_parser("xy", (char_ >> char_)[std::cout << _1 << ',' << _2 << std::endl]); + //] + } + + // sequential_or + { + //[reference_using_declarations_sequential_or + using boost::spirit::qi::int_; + //] + + //[reference_sequential_or + //`Correctly parsing a number with optional fractional digits: + test_parser("123.456", int_ || ('.' >> int_)); // full + test_parser("123", int_ || ('.' >> int_)); // just the whole number + test_parser(".456", int_ || ('.' >> int_)); // just the fraction + + /*`A naive but incorrect solution would try to do this using optionals (e.g.): + + int_ >> -('.' >> int_) // will not match ".456" + -int_ >> ('.' >> int_) // will not match "123" + -int_ >> -('.' >> int_) // will match empty strings! Ooops. + */ + //] + } + + // alternative + { + //[reference_using_declarations_alternative + using boost::spirit::ascii::string; + using boost::spirit::qi::int_; + using boost::spirit::qi::_1; + using boost::variant; + //] + + //[reference_alternative + //`Simple usage: + test_parser("Hello", string("Hello") | int_); + test_parser("123", string("Hello") | int_); + + //`Extracting the attribute variant (using __boost_variant__): + variant<std::string, int> attr; + test_parser_attr("Hello", string("Hello") | int_, attr); + + /*`This should print `"Hello"`. Note: There are better ways to extract the value + from the variant. See __boost_variant__ visitation. This code is solely + for demonstration. + */ + if (boost::get<int>(&attr)) + std::cout << boost::get<int>(attr) << std::endl; + else + std::cout << boost::get<std::string>(attr) << std::endl; + + /*`Extracting the attributes using __qi_semantic_actions__ with __phoenix__ + (this should print `123`): + */ + test_parser("123", (string("Hello") | int_)[std::cout << _1 << std::endl]); + //] + + } + + // permutation + { + //[reference_using_declarations_permutation + using boost::spirit::ascii::char_; + //] + + //[reference_permutation + //`Parse a string containing DNA codes (ACTG) + test_parser("ACTGGCTAGACT", *(char_('A') ^ 'C' ^ 'T' ^ 'G')); + //] + } + + // expect + { + //[reference_using_declarations_expect + using boost::spirit::ascii::char_; + using boost::spirit::qi::expectation_failure; + //] + + //[reference_expect + /*`The code below uses an expectation operator to throw an __qi_expectation_failure__ + with a deliberate parsing error when `"o"` is expected and `"i"` is what is + found in the input. The `catch` block prints the information related to the + error. Note: This is low level code that demonstrates the /bare-metal/. Typically, + you use an __qi_error_handler__ to deal with the error. + */ + try + { + test_parser("xi", char_('x') > char_('o')); // should throw an exception + } + catch (expectation_failure<char const*> const& x) + { + std::cout << "expected: "; print_info(x.what_); + std::cout << "got: \"" << std::string(x.first, x.last) << '"' << std::endl; + } + /*`The code above will print:[teletype] + + expected: tag: literal-char, value: o + got: "i"``[c++]`` + */ + //] + } + + // expectd + { + //[reference_using_declarations_expectd + using boost::spirit::ascii::char_; + using boost::spirit::qi::expect; + using boost::spirit::qi::expectation_failure; + //] + + //[reference_expectd + /*`The code below uses an expectation operator to throw an __qi_expectation_failure__ + with a deliberate parsing error when `"o"` is expected and `"x"` is what is + found in the input. The `catch` block prints the information related to the + error. Note: This is low level code that demonstrates the /bare-metal/. Typically, + you use an __qi_error_handler__ to deal with the error. + */ + try + { + test_parser("xi", expect[char_('o')]); // should throw an exception + } + catch (expectation_failure<char const*> const& x) + { + std::cout << "expected: "; print_info(x.what_); + std::cout << "got: \"" << std::string(x.first, x.last) << '"' << std::endl; + } + /*`The code above will print:[teletype] + + expected: tag: literal-char, value: o + got: "x"``[c++]`` + */ + //] + } + + // and-predicate + { + //[reference_and_predicate + //`Some using declarations: + using boost::spirit::lit; + + /*`Basic look-ahead example: make sure that the last character is a + semicolon, but don't consume it, just peek at the next character: + */ + test_phrase_parser("Hello ;", lit("Hello") >> &lit(';'), false); + //] + } + + // not-predicate + { + //[reference_not_predicate + //`Some using declarations: + using boost::spirit::ascii::char_; + using boost::spirit::ascii::alpha; + using boost::spirit::qi::lit; + using boost::spirit::qi::symbols; + + /*`Here's an alternative to the `*(r - x) >> x` idiom using the + not-predicate instead. This parses a list of characters terminated + by a ';': + */ + test_parser("abcdef;", *(!lit(';') >> char_) >> ';'); + + /*`The following parser ensures that we match distinct keywords + (stored in a symbol table). To do this, we make sure that the + keyword does not follow an alpha or an underscore: + */ + symbols<char, int> keywords; + keywords = "begin", "end", "for"; + + // This should fail: + test_parser("beginner", keywords >> !(alpha | '_')); + + // This is ok: + test_parser("end ", keywords >> !(alpha | '_'), false); + + // This is ok: + test_parser("for()", keywords >> !(alpha | '_'), false); + //] + } + + // difference + { + //[reference_difference + //`Some using declarations: + using boost::spirit::ascii::char_; + + /*`Parse a C/C++ style comment: + */ + test_parser("/*A Comment*/", "/*" >> *(char_ - "*/") >> "*/"); + //] + } + + // kleene + { + //[reference_kleene + //`Some using declarations: + using boost::spirit::qi::int_; + + /*`Parse a comma separated list of numbers and put them in a vector: + */ + std::vector<int> attr; + test_phrase_parser_attr( + "111, 222, 333, 444, 555", int_ >> *(',' >> int_), attr); + std::cout + << attr[0] << ',' << attr[1] << ',' << attr[2] << ',' + << attr[3] << ',' << attr[4] + << std::endl; + //] + } + + // plus + { + //[reference_plus + //`Some using declarations: + using boost::spirit::ascii::alpha; + using boost::spirit::qi::lexeme; + + /*`Parse one or more strings containing one or more alphabetic + characters and put them in a vector: + */ + std::vector<std::string> attr; + test_phrase_parser_attr("yaba daba doo", +lexeme[+alpha], attr); + std::cout << attr[0] << ',' << attr[1] << ',' << attr[2] << std::endl; + //] + } + + // optional + { + //[reference_optional + //`Some using declarations: + using boost::spirit::ascii::char_; + using boost::spirit::qi::lexeme; + using boost::spirit::qi::int_; + using boost::fusion::vector; + using boost::fusion::at_c; + using boost::optional; + + /*`Parse a person info with name (in quotes) optional age [footnote + James Bond is shy about his age :-)] and optional sex, all + separated by comma. + */ + vector<std::string, optional<int>, optional<char> > attr; + + test_phrase_parser_attr( + "\"James Bond\", M" + , lexeme['"' >> +(char_ - '"') >> '"'] // name + >> -(',' >> int_) // optional age + >> -(',' >> char_) // optional sex + , attr); + + // Should print: James Bond,M + std::cout << at_c<0>(attr); // print name + if (at_c<1>(attr)) // print optional age + std::cout << ',' << *at_c<1>(attr); + if (at_c<2>(attr)) // print optional sex + std::cout << ',' << *at_c<2>(attr); + std::cout << std::endl; + //] + } + + // list + { + //[reference_list + //`Some using declarations: + using boost::spirit::qi::int_; + + /*`Parse a comma separated list of numbers and put them in a vector: + */ + std::vector<int> attr; + test_phrase_parser_attr( + "111, 222, 333, 444, 555", int_ % ',', attr); + std::cout + << attr[0] << ',' << attr[1] << ',' << attr[2] << ',' + << attr[3] << ',' << attr[4] + << std::endl; + //] + } + + // stream + { + //[reference_qi_stream + //`Using declarations and variables: + using boost::spirit::qi::stream; + using boost::spirit::qi::stream_parser; + + /*`Parse a simple string using the operator>>(istream&, std::string&); + */ + std::string str; + test_parser_attr("abc", stream, str); + std::cout << str << std::endl; // prints: abc + + /*`Parse our complex type using the operator>>(istream&, complex&); + */ + complex c; + test_parser_attr("{1.0,2.5}", stream_parser<char, complex>(), c); + std::cout << c.a << "," << c.b << std::endl; // prints: 1.0,2.5 + //] + } + + /////////////////////////////////////////////////////////////////////////// + // auto module + { + //[reference_qi_using_declarations_auto + using boost::spirit::qi::auto_; + //] + + //[reference_qi_auto + /*`Parse a simple integer using the generated parser component `int_`: + */ + int i = 0; + test_parser_attr("123", auto_, i); + std::cout << i << std::endl; // prints: 123 + + /*`Parse an instance of the `complex` data type as defined above using + the parser as generated by the defined customization point: + */ + complex c; + test_parser_attr("{1.2,2.4}", auto_, c); + std::cout << c.a << "," << c.b << std::endl; // prints: 1.2,2.4 + //] + } + + // native binary + { + //[reference_qi_native_binary + //`Using declarations and variables: + using boost::spirit::qi::byte_; + using boost::spirit::qi::word; + using boost::spirit::qi::dword; + using boost::spirit::qi::qword; + + boost::uint8_t uc; + boost::uint16_t us; + boost::uint32_t ui; +//<- +#ifdef BOOST_HAS_LONG_LONG +//-> + boost::uint64_t ul; +//<- +#endif + +#if BOOST_ENDIAN_LITTLE_BYTE +//-> + //`Basic usage of the native binary parsers for little endian platforms: + test_parser_attr("\x01", byte_, uc); assert(uc == 0x01); + test_parser_attr("\x01\x02", word, us); assert(us == 0x0201); + test_parser_attr("\x01\x02\x03\x04", dword, ui); assert(ui == 0x04030201); +//<- +#ifdef BOOST_HAS_LONG_LONG +//-> + test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", qword, ul); + assert(ul == 0x0807060504030201LL); + +//<- +#endif +//-> + test_parser("\x01", byte_(0x01)); + test_parser("\x01\x02", word(0x0201)); + test_parser("\x01\x02\x03\x04", dword(0x04030201)); +//<- +#ifdef BOOST_HAS_LONG_LONG +//-> + test_parser("\x01\x02\x03\x04\x05\x06\x07\x08", + qword(0x0807060504030201LL)); +//<- +#endif +#else +//-> + //`Basic usage of the native binary parsers for big endian platforms: + test_parser_attr("\x01", byte_, uc); assert(uc == 0x01); + test_parser_attr("\x01\x02", word, us); assert(us == 0x0102); + test_parser_attr("\x01\x02\x03\x04", dword, ui); assert(ui == 0x01020304); +//<- +#ifdef BOOST_HAS_LONG_LONG +//-> + test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", qword, ul); + assert(0x0102030405060708LL); + +//<- +#endif +//-> + test_parser("\x01", byte_(0x01)); + test_parser("\x01\x02", word(0x0102)); + test_parser("\x01\x02\x03\x04", dword(0x01020304)); +//<- +#ifdef BOOST_HAS_LONG_LONG +//-> + test_parser("\x01\x02\x03\x04\x05\x06\x07\x08", + qword(0x0102030405060708LL)); +//<- +#endif +#endif +//-> + //] + } + + // little binary + { + //[reference_qi_little_binary + //`Using declarations and variables: + using boost::spirit::qi::little_word; + using boost::spirit::qi::little_dword; + using boost::spirit::qi::little_qword; + + boost::uint16_t us; + boost::uint32_t ui; +//<- +#ifdef BOOST_HAS_LONG_LONG +//-> + boost::uint64_t ul; +//<- +#endif + +//-> + //`Basic usage of the little endian binary parsers: + test_parser_attr("\x01\x02", little_word, us); assert(us == 0x0201); + test_parser_attr("\x01\x02\x03\x04", little_dword, ui); assert(ui == 0x04030201); +//<- +#ifdef BOOST_HAS_LONG_LONG +//-> + test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", little_qword, ul); + assert(ul == 0x0807060504030201LL); + +//<- +#endif +//-> + test_parser("\x01\x02", little_word(0x0201)); + test_parser("\x01\x02\x03\x04", little_dword(0x04030201)); +//<- +#ifdef BOOST_HAS_LONG_LONG +//-> + test_parser("\x01\x02\x03\x04\x05\x06\x07\x08", + little_qword(0x0807060504030201LL)); +//<- +#endif +//-> + //] + } + + // big binary + { + //[reference_qi_big_binary + //`Using declarations and variables: + using boost::spirit::qi::big_word; + using boost::spirit::qi::big_dword; + using boost::spirit::qi::big_qword; + + boost::uint16_t us; + boost::uint32_t ui; +//<- +#ifdef BOOST_HAS_LONG_LONG +//-> + boost::uint64_t ul; +//<- +#endif + +//-> + //`Basic usage of the big endian binary parsers: + test_parser_attr("\x01\x02", big_word, us); assert(us == 0x0102); + test_parser_attr("\x01\x02\x03\x04", big_dword, ui); assert(ui == 0x01020304); +//<- +#ifdef BOOST_HAS_LONG_LONG +//-> + test_parser_attr("\x01\x02\x03\x04\x05\x06\x07\x08", big_qword, ul); + assert(0x0102030405060708LL); + +//<- +#endif +//-> + test_parser("\x01\x02", big_word(0x0102)); + test_parser("\x01\x02\x03\x04", big_dword(0x01020304)); +//<- +#ifdef BOOST_HAS_LONG_LONG +//-> + test_parser("\x01\x02\x03\x04\x05\x06\x07\x08", + big_qword(0x0102030405060708LL)); +//<- +#endif +//-> + //] + } + + // rule + { + //[reference_rule + //`Some using declarations: + using boost::spirit::qi::rule; + using boost::spirit::qi::int_; + using boost::spirit::qi::locals; + using boost::spirit::qi::_1; + using boost::spirit::qi::_a; + using boost::spirit::ascii::alpha; + using boost::spirit::ascii::char_; + using boost::spirit::ascii::space_type; + + /*`Basic rule: + */ + rule<char const*> r; + r = int_; + test_parser("123", r); + + /*`Rule with synthesized attribute: + */ + rule<char const*, int()> ra; + ra = int_; + int i; + test_parser_attr("123", ra, i); + assert(i == 123); + + /*`Rule with skipper and synthesized attribute: + */ + rule<char const*, std::vector<int>(), space_type> rs; + rs = *int_; + std::vector<int> v; + test_phrase_parser_attr("123 456 789", rs, v); + assert(v[0] == 123); + assert(v[1] == 456); + assert(v[2] == 789); + + /*`Rule with one local variable: + */ + rule<char const*, locals<char> > rl; + rl = alpha[_a = _1] >> char_(_a); // get two identical characters + test_parser("aa", rl); // pass + test_parser("ax", rl); // fail + //] + } + + // grammar + { + using client::num_list; + + //[reference_grammar_using + //`Some using declarations: + using boost::spirit::ascii::space_type; + using boost::spirit::int_; + using boost::spirit::qi::grammar; + using boost::spirit::qi::rule; + //] + + //[reference_grammar + //`How to use the example grammar: + num_list nlist; + test_phrase_parser("123, 456, 789", nlist); + //] + } + + return 0; +} diff --git a/src/boost/libs/spirit/example/qi/reorder_struct.cpp b/src/boost/libs/spirit/example/qi/reorder_struct.cpp new file mode 100644 index 00000000..5f5a50b1 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/reorder_struct.cpp @@ -0,0 +1,130 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// The main purpose of this example is to show how a single fusion sequence +// can be filled from a parsed input of the elements in different sequences + +#include <boost/config/warning_disable.hpp> +#include <boost/mpl/print.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/fusion/include/struct.hpp> +#include <boost/fusion/include/nview.hpp> +#include <boost/foreach.hpp> + +namespace fusion = boost::fusion; +namespace qi = boost::spirit::qi; + +/////////////////////////////////////////////////////////////////////////////// +namespace client +{ + // Our employee struct + struct employee + { + std::string surname; + std::string forename; + int age; + double salary; + std::string department; + }; + + // define iterator type + typedef std::string::const_iterator iterator_type; + + // This is the output routine taking a format description and the data to + // print + template <typename Parser, typename Sequence> + bool parse(std::string const& input, Parser const& p, Sequence& s) + { + iterator_type begin = input.begin(); + return qi::parse(begin, input.end(), p, s); + } +} + +// We need to tell fusion about our employee struct to make it a first-class +// fusion citizen. This has to be in global scope. Note that we don't need to +// list the members of our struct in the same sequence a they are defined +BOOST_FUSION_ADAPT_STRUCT( + client::employee, + (int, age) + (std::string, surname) + (std::string, forename) + (std::string, department) + (double, salary) +) + +/////////////////////////////////////////////////////////////////////////////// +// that's the different types we need to reorder the attributes +typedef fusion::result_of::as_nview<client::employee, 2, 0>::type name_and_age; +typedef fusion::result_of::as_nview<client::employee, 1, 2, 4>::type names_and_salary; +typedef fusion::result_of::as_nview<client::employee, 2, 0, 3>::type name_age_and_department; + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::string str; + + // some employees + client::employee john; + client::employee mary; + client::employee tom; + + // print data about employees in different formats + { + // parse forename and age only + name_and_age johnview(fusion::as_nview<2, 0>(john)); + bool r = client::parse( + "John, 25", + *(qi::char_ - ',') >> ", " >> qi::int_, + johnview); + if (r) { + std::cout << "Parsed: " << john.forename << ", " << john.age + << std::endl; + } + + // parse surname, forename, and salary + names_and_salary maryview(fusion::as_nview<1, 2, 4>(mary)); + r = client::parse( + "Higgins, Mary: 2200.36", + *(qi::char_ - ',') >> ", " >> *(qi::char_ - ':') >> ": " >> qi::double_, + maryview); + if (r) { + std::cout << "Parsed: " << mary.forename << ", " << mary.surname + << ", " << mary.salary << std::endl; + } + + // parse forename, age, and department + name_age_and_department tomview(fusion::as_nview<2, 0, 3>(tom)); + client::parse( + "Tom: 48 (Boss)", + *(qi::char_ - ':') >> ": " >> qi::int_ >> " (" >> *(qi::char_ - ')') >> ')', + tomview); + if (r) { + std::cout << "Parsed: " << tom.forename << ", " << tom.age + << ", " << tom.department << std::endl; + } + } + + // now parse a list of several employees and print them all + std::vector<client::employee> employees; + + // parse surname, forename, and salary for all employees + { + qi::rule<client::iterator_type, names_and_salary()> r = + *(qi::char_ - ',') >> ", " >> *(qi::char_ - ',') >> ", " >> qi::double_; + + bool result = client::parse( + "John, Smith, 2000.50\n" "Mary, Higgins, 2200.36\n" "Tom, Taylor, 3200.00\n", + r % qi::eol, employees); + + std::cout << "Parsed: " << std::endl; + BOOST_FOREACH(client::employee const& e, employees) + { + std::cout << e.forename << ", " << e.surname << ", " << e.salary + << std::endl; + } + } + return 0; +} + diff --git a/src/boost/libs/spirit/example/qi/roman.cpp b/src/boost/libs/spirit/example/qi/roman.cpp new file mode 100644 index 00000000..e98c2a8a --- /dev/null +++ b/src/boost/libs/spirit/example/qi/roman.cpp @@ -0,0 +1,188 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A Roman Numerals Parser (demonstrating the symbol table). This is +// discussed in the "Symbols" chapter in the Spirit User's Guide. +// +// [ JDG August 22, 2002 ] spirit1 +// [ JDG March 13, 2007 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> + +#include <iostream> +#include <string> + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////////// + // Parse roman hundreds (100..900) numerals using the symbol table. + // Notice that the data associated with each slot is the parser's attribute + // (which is passed to attached semantic actions). + /////////////////////////////////////////////////////////////////////////////// + //[tutorial_roman_hundreds + struct hundreds_ : qi::symbols<char, unsigned> + { + hundreds_() + { + add + ("C" , 100) + ("CC" , 200) + ("CCC" , 300) + ("CD" , 400) + ("D" , 500) + ("DC" , 600) + ("DCC" , 700) + ("DCCC" , 800) + ("CM" , 900) + ; + } + + } hundreds; + //] + + /////////////////////////////////////////////////////////////////////////////// + // Parse roman tens (10..90) numerals using the symbol table. + /////////////////////////////////////////////////////////////////////////////// + //[tutorial_roman_tens + struct tens_ : qi::symbols<char, unsigned> + { + tens_() + { + add + ("X" , 10) + ("XX" , 20) + ("XXX" , 30) + ("XL" , 40) + ("L" , 50) + ("LX" , 60) + ("LXX" , 70) + ("LXXX" , 80) + ("XC" , 90) + ; + } + + } tens; + //] + + /////////////////////////////////////////////////////////////////////////////// + // Parse roman ones (1..9) numerals using the symbol table. + /////////////////////////////////////////////////////////////////////////////// + //[tutorial_roman_ones + struct ones_ : qi::symbols<char, unsigned> + { + ones_() + { + add + ("I" , 1) + ("II" , 2) + ("III" , 3) + ("IV" , 4) + ("V" , 5) + ("VI" , 6) + ("VII" , 7) + ("VIII" , 8) + ("IX" , 9) + ; + } + + } ones; + //] + + /////////////////////////////////////////////////////////////////////////////// + // roman (numerals) grammar + // + // Note the use of the || operator. The expression + // a || b reads match a or b and in sequence. Try + // defining the roman numerals grammar in YACC or + // PCCTS. Spirit rules! :-) + /////////////////////////////////////////////////////////////////////////////// + //[tutorial_roman_grammar + template <typename Iterator> + struct roman : qi::grammar<Iterator, unsigned()> + { + roman() : roman::base_type(start) + { + using qi::eps; + using qi::lit; + using qi::_val; + using qi::_1; + using ascii::char_; + + start = eps [_val = 0] >> + ( + +lit('M') [_val += 1000] + || hundreds [_val += _1] + || tens [_val += _1] + || ones [_val += _1] + ) + ; + } + + qi::rule<Iterator, unsigned()> start; + }; + //] +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tRoman Numerals Parser\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type a Roman Numeral ...or [q or Q] to quit\n\n"; + + typedef std::string::const_iterator iterator_type; + typedef client::roman<iterator_type> roman; + + roman roman_parser; // Our grammar + + std::string str; + unsigned result; + while (std::getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + //[tutorial_roman_grammar_parse + bool r = parse(iter, end, roman_parser, result); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "result = " << result << std::endl; + std::cout << "-------------------------\n"; + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \": " << rest << "\"\n"; + std::cout << "-------------------------\n"; + } + //] + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/sum.cpp b/src/boost/libs/spirit/example/qi/sum.cpp new file mode 100644 index 00000000..33310aa5 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/sum.cpp @@ -0,0 +1,106 @@ +/*============================================================================= + Copyright (c) 2002-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// A parser for summing a comma-separated list of numbers using phoenix. +// +// [ JDG June 28, 2002 ] spirit1 +// [ JDG March 24, 2007 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +//[tutorial_adder_includes +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <iostream> +#include <string> +//] + +namespace client +{ + //[tutorial_adder_using + namespace qi = boost::spirit::qi; + namespace ascii = boost::spirit::ascii; + namespace phoenix = boost::phoenix; + + using qi::double_; + using qi::_1; + using ascii::space; + using phoenix::ref; + //] + + /////////////////////////////////////////////////////////////////////////// + // Our adder + /////////////////////////////////////////////////////////////////////////// + + //[tutorial_adder + template <typename Iterator> + bool adder(Iterator first, Iterator last, double& n) + { + bool r = qi::phrase_parse(first, last, + + // Begin grammar + ( + double_[ref(n) = _1] >> *(',' >> double_[ref(n) += _1]) + ) + , + // End grammar + + space); + + if (first != last) // fail if we did not get a full match + return false; + return r; + } + //] +} + +//////////////////////////////////////////////////////////////////////////// +// Main program +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA parser for summing a list of numbers...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a comma separated list of numbers.\n"; + std::cout << "The numbers are added using Phoenix.\n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + double n; + if (client::adder(str.begin(), str.end(), n)) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << str << " Parses OK: " << std::endl; + + std::cout << "sum = " << n; + std::cout << "\n-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/typeof.cpp b/src/boost/libs/spirit/example/qi/typeof.cpp new file mode 100644 index 00000000..90e8fb0e --- /dev/null +++ b/src/boost/libs/spirit/example/qi/typeof.cpp @@ -0,0 +1,65 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/qi_copy.hpp> +#include <boost/spirit/include/support_auto.hpp> +#include <iostream> +#include <string> + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// + +int +main() +{ + using boost::spirit::ascii::space; + using boost::spirit::ascii::char_; + using boost::spirit::qi::parse; + typedef std::string::const_iterator iterator_type; + +/////////////////////////////////////////////////////////////////////////////// +// this works for non-c++11 compilers +#ifdef BOOST_NO_CXX11_AUTO_DECLARATIONS + + BOOST_SPIRIT_AUTO(qi, comment, "/*" >> *(char_ - "*/") >> "*/"); + +/////////////////////////////////////////////////////////////////////////////// +// but this is better for c++11 compilers with auto +#else + + using boost::spirit::qi::copy; + + auto comment = copy("/*" >> *(char_ - "*/") >> "*/"); + +#endif + + std::string str = "/*This is a comment*/"; + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + bool r = parse(iter, end, comment); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "-------------------------\n"; + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \": " << rest << "\"\n"; + std::cout << "-------------------------\n"; + } + + return 0; +} + + diff --git a/src/boost/libs/spirit/example/qi/unescaped_string.cpp b/src/boost/libs/spirit/example/qi/unescaped_string.cpp new file mode 100644 index 00000000..4a0d6002 --- /dev/null +++ b/src/boost/libs/spirit/example/qi/unescaped_string.cpp @@ -0,0 +1,72 @@ +// Copyright (c) 2010 Jeroen Habraken +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/spirit/include/qi.hpp> + +#include <iostream> +#include <ostream> +#include <string> + +namespace client +{ + namespace qi = boost::spirit::qi; + + template <typename InputIterator> + struct unescaped_string + : qi::grammar<InputIterator, std::string(char const*)> + { + unescaped_string() + : unescaped_string::base_type(unesc_str) + { + unesc_char.add("\\a", '\a')("\\b", '\b')("\\f", '\f')("\\n", '\n') + ("\\r", '\r')("\\t", '\t')("\\v", '\v')("\\\\", '\\') + ("\\\'", '\'')("\\\"", '\"') + ; + + unesc_str = qi::lit(qi::_r1) + >> *(unesc_char | qi::alnum | "\\x" >> qi::hex) + >> qi::lit(qi::_r1) + ; + } + + qi::rule<InputIterator, std::string(char const*)> unesc_str; + qi::symbols<char const, char const> unesc_char; + }; + +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + namespace qi = boost::spirit::qi; + + typedef std::string::const_iterator iterator_type; + + std::string parsed; + + std::string str("'''string\\x20to\\x20unescape\\x3a\\x20\\n\\r\\t\\\"\\'\\x41'''"); + char const* quote = "'''"; + + iterator_type iter = str.begin(); + iterator_type end = str.end(); + + client::unescaped_string<iterator_type> p; + if (!qi::parse(iter, end, p(quote), parsed)) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsed: " << parsed << "\n"; + std::cout << "-------------------------\n"; + } + + return 0; +} |