Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r67372 - trunk/libs/spirit/example/qi
From: hartmut.kaiser_at_[hidden]
Date: 2010-12-20 14:32:42


Author: hkaiser
Date: 2010-12-20 14:32:40 EST (Mon, 20 Dec 2010)
New Revision: 67372
URL: http://svn.boost.org/trac/boost/changeset/67372

Log:
Spirit: adding examples demonstrating parsing with utree
Added:
   trunk/libs/spirit/example/qi/calc_utree_ast.cpp
      - copied, changed from r67358, /trunk/libs/spirit/example/qi/calc_utree.cpp
   trunk/libs/spirit/example/qi/calc_utree_naive.cpp (contents, props changed)
Text files modified:
   trunk/libs/spirit/example/qi/Jamfile | 2 +
   trunk/libs/spirit/example/qi/calc_utree.cpp | 72 +++++++++++++++++++++++++++++++--------
   trunk/libs/spirit/example/qi/calc_utree_ast.cpp | 72 +++++++++++++++++++++++++++++++--------
   3 files changed, 115 insertions(+), 31 deletions(-)

Modified: trunk/libs/spirit/example/qi/Jamfile
==============================================================================
--- trunk/libs/spirit/example/qi/Jamfile (original)
+++ trunk/libs/spirit/example/qi/Jamfile 2010-12-20 14:32:40 EST (Mon, 20 Dec 2010)
@@ -62,6 +62,8 @@
     calc7/calc7c.cpp
     ;
 
+exe calc_utree_naive : calc_utree_naive.cpp ;
+exe calc_utree_ast : calc_utree_ast.cpp ;
 exe calc_utree : calc_utree.cpp ;
 
 exe mini_c_interp :

Modified: trunk/libs/spirit/example/qi/calc_utree.cpp
==============================================================================
--- trunk/libs/spirit/example/qi/calc_utree.cpp (original)
+++ trunk/libs/spirit/example/qi/calc_utree.cpp 2010-12-20 14:32:40 EST (Mon, 20 Dec 2010)
@@ -1,6 +1,6 @@
 /*=============================================================================
- Copyright (c) 2001-2010 Hartmut Kaiser
- Copyright (c) 2001-2010 Joel de Guzman
+ 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)
@@ -21,10 +21,52 @@
 #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 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;
@@ -40,27 +82,28 @@
         calculator() : calculator::base_type(expression)
         {
             using qi::uint_;
- using qi::char_;
+ using qi::_val;
+ using qi::_1;
 
             expression =
- term
- >> *( (char_('+') >> term)
- | (char_('-') >> term)
+ term [_val = _1]
+ >> *( ('+' >> term [_val = _val + _1])
+ | ('-' >> term [_val = _val - _1])
                     )
                 ;
 
             term =
- factor
- >> *( (char_('*') >> factor)
- | (char_('/') >> factor)
+ factor [_val = _1]
+ >> *( ('*' >> factor [_val = _val * _1])
+ | ('/' >> factor [_val = _val / _1])
                     )
                 ;
 
             factor =
- uint_
- | char_('(') >> expression >> char_(')')
- | (char_('-') >> factor)
- | (char_('+') >> factor)
+ uint_ [_val = _1]
+ | '(' >> expression [_val = _1] >> ')'
+ | ('-' >> factor [_val = -_1])
+ | ('+' >> factor [_val = _1])
                 ;
 
             BOOST_SPIRIT_DEBUG_NODE(expression);
@@ -75,8 +118,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 // Main program
 ///////////////////////////////////////////////////////////////////////////////
-int
-main()
+int main()
 {
     std::cout << "/////////////////////////////////////////////////////////\n\n";
     std::cout << "Expression parser...\n\n";

Copied: trunk/libs/spirit/example/qi/calc_utree_ast.cpp (from r67358, /trunk/libs/spirit/example/qi/calc_utree.cpp)
==============================================================================
--- /trunk/libs/spirit/example/qi/calc_utree.cpp (original)
+++ trunk/libs/spirit/example/qi/calc_utree_ast.cpp 2010-12-20 14:32:40 EST (Mon, 20 Dec 2010)
@@ -1,6 +1,6 @@
 /*=============================================================================
- Copyright (c) 2001-2010 Hartmut Kaiser
- Copyright (c) 2001-2010 Joel de Guzman
+ 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)
@@ -19,8 +19,10 @@
 // #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/qi.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/spirit/include/phoenix_function.hpp>
 
 #include <iostream>
 #include <string>
@@ -31,6 +33,44 @@
     namespace ascii = boost::spirit::ascii;
     namespace spirit = boost::spirit;
 
+ struct expr
+ {
+ template <typename T1, typename T2>
+ 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>
+ 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
     ///////////////////////////////////////////////////////////////////////////////
@@ -40,27 +80,28 @@
         calculator() : calculator::base_type(expression)
         {
             using qi::uint_;
- using qi::char_;
+ using qi::_val;
+ using qi::_1;
 
             expression =
- term
- >> *( (char_('+') >> term)
- | (char_('-') >> term)
+ term [_val = _1]
+ >> *( ('+' >> term [plus(_val, _1)])
+ | ('-' >> term [minus(_val, _1)])
                     )
                 ;
 
             term =
- factor
- >> *( (char_('*') >> factor)
- | (char_('/') >> factor)
+ factor [_val = _1]
+ >> *( ('*' >> factor [times(_val, _1)])
+ | ('/' >> factor [divide(_val, _1)])
                     )
                 ;
 
             factor =
- uint_
- | char_('(') >> expression >> char_(')')
- | (char_('-') >> factor)
- | (char_('+') >> factor)
+ uint_ [_val = _1]
+ | '(' >> expression [_val = _1] >> ')'
+ | ('-' >> factor [neg(_val, _1)])
+ | ('+' >> factor [_val = _1])
                 ;
 
             BOOST_SPIRIT_DEBUG_NODE(expression);
@@ -75,8 +116,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 // Main program
 ///////////////////////////////////////////////////////////////////////////////
-int
-main()
+int main()
 {
     std::cout << "/////////////////////////////////////////////////////////\n\n";
     std::cout << "Expression parser...\n\n";

Added: trunk/libs/spirit/example/qi/calc_utree_naive.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/example/qi/calc_utree_naive.cpp 2010-12-20 14:32:40 EST (Mon, 20 Dec 2010)
@@ -0,0 +1,132 @@
+/*=============================================================================
+ 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_
+ | char_('(') >> expression >> char_(')')
+ | (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, 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;
+}
+
+


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk