• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001-2011 Hartmut Kaiser
3     Copyright (c) 2001-2011 Joel de Guzman
4 
5     Distributed under the Boost Software License, Version 1.0. (See accompanying
6     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
8 ///////////////////////////////////////////////////////////////////////////////
9 //
10 //  Plain calculator example demonstrating the grammar. The parser is a
11 //  syntax checker only and does not do any semantic evaluation.
12 //
13 //  [ JDG May 10, 2002 ]        spirit1
14 //  [ JDG March 4, 2007 ]       spirit2
15 //  [ HK November 30, 2010 ]    spirit2/utree
16 //
17 ///////////////////////////////////////////////////////////////////////////////
18 
19 // #define BOOST_SPIRIT_DEBUG
20 
21 #include <boost/config/warning_disable.hpp>
22 #include <boost/spirit/include/support_utree.hpp>
23 #include <boost/spirit/include/qi.hpp>
24 #include <boost/spirit/include/phoenix_operator.hpp>
25 #include <boost/spirit/include/phoenix_function.hpp>
26 
27 #include <iostream>
28 #include <string>
29 
30 namespace client
31 {
32     namespace qi = boost::spirit::qi;
33     namespace ascii = boost::spirit::ascii;
34     namespace spirit = boost::spirit;
35 
36     struct expr
37     {
38         template <typename T1, typename T2 = void>
39         struct result { typedef void type; };
40 
exprclient::expr41         expr(char op) : op(op) {}
42 
operator ()client::expr43         void operator()(spirit::utree& expr, spirit::utree const& rhs) const
44         {
45             spirit::utree lhs;
46             lhs.swap(expr);
47             expr.push_back(spirit::utf8_symbol_range_type(&op, &op+1));
48             expr.push_back(lhs);
49             expr.push_back(rhs);
50         }
51 
52         char const op;
53     };
54     boost::phoenix::function<expr> const plus = expr('+');
55     boost::phoenix::function<expr> const minus = expr('-');
56     boost::phoenix::function<expr> const times = expr('*');
57     boost::phoenix::function<expr> const divide = expr('/');
58 
59     struct negate_expr
60     {
61         template <typename T1, typename T2 = void>
62         struct result { typedef void type; };
63 
operator ()client::negate_expr64         void operator()(spirit::utree& expr, spirit::utree const& rhs) const
65         {
66             char const op = '-';
67             expr.clear();
68             expr.push_back(spirit::utf8_symbol_range_type(&op, &op+1));
69             expr.push_back(rhs);
70         }
71     };
72     boost::phoenix::function<negate_expr> neg;
73 
74     ///////////////////////////////////////////////////////////////////////////////
75     //  Our calculator grammar
76     ///////////////////////////////////////////////////////////////////////////////
77     template <typename Iterator>
78     struct calculator : qi::grammar<Iterator, ascii::space_type, spirit::utree()>
79     {
calculatorclient::calculator80         calculator() : calculator::base_type(expression)
81         {
82             using qi::uint_;
83             using qi::_val;
84             using qi::_1;
85 
86             expression =
87                 term                            [_val = _1]
88                 >> *(   ('+' >> term            [plus(_val, _1)])
89                     |   ('-' >> term            [minus(_val, _1)])
90                     )
91                 ;
92 
93             term =
94                 factor                          [_val = _1]
95                 >> *(   ('*' >> factor          [times(_val, _1)])
96                     |   ('/' >> factor          [divide(_val, _1)])
97                     )
98                 ;
99 
100             factor =
101                 uint_                           [_val = _1]
102                 |   '(' >> expression           [_val = _1] >> ')'
103                 |   ('-' >> factor              [neg(_val, _1)])
104                 |   ('+' >> factor              [_val = _1])
105                 ;
106 
107             BOOST_SPIRIT_DEBUG_NODE(expression);
108             BOOST_SPIRIT_DEBUG_NODE(term);
109             BOOST_SPIRIT_DEBUG_NODE(factor);
110         }
111 
112         qi::rule<Iterator, ascii::space_type, spirit::utree()> expression, term, factor;
113     };
114 }
115 
116 ///////////////////////////////////////////////////////////////////////////////
117 //  Main program
118 ///////////////////////////////////////////////////////////////////////////////
main()119 int main()
120 {
121     std::cout << "/////////////////////////////////////////////////////////\n\n";
122     std::cout << "Expression parser...\n\n";
123     std::cout << "/////////////////////////////////////////////////////////\n\n";
124     std::cout << "Type an expression...or [q or Q] to quit\n\n";
125 
126     using boost::spirit::ascii::space;
127     using boost::spirit::utree;
128     typedef std::string::const_iterator iterator_type;
129     typedef client::calculator<iterator_type> calculator;
130 
131     calculator calc; // Our grammar
132 
133     std::string str;
134     while (std::getline(std::cin, str))
135     {
136         if (str.empty() || str[0] == 'q' || str[0] == 'Q')
137             break;
138 
139         std::string::const_iterator iter = str.begin();
140         std::string::const_iterator end = str.end();
141         utree ut;
142         bool r = phrase_parse(iter, end, calc, space, ut);
143 
144         if (r && iter == end)
145         {
146             std::cout << "-------------------------\n";
147             std::cout << "Parsing succeeded: " << ut << "\n";
148             std::cout << "-------------------------\n";
149         }
150         else
151         {
152             std::string rest(iter, end);
153             std::cout << "-------------------------\n";
154             std::cout << "Parsing failed\n";
155             std::cout << "stopped at: \": " << rest << "\"\n";
156             std::cout << "-------------------------\n";
157         }
158     }
159 
160     std::cout << "Bye... :-) \n\n";
161     return 0;
162 }
163 
164 
165