• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001-2014 Joel de Guzman
3     Copyright (c) 2013-2014 Agustin Berge
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 //  A Calculator example demonstrating generation of AST. The AST,
11 //  once created, is traversed, 1) To print its contents and
12 //  2) To evaluate the result.
13 //
14 //  [ JDG April 28, 2008 ]      For BoostCon 2008
15 //  [ JDG February 18, 2011 ]   Pure attributes. No semantic actions.
16 //  [ JDG January 9, 2013 ]     Spirit X3
17 //
18 ///////////////////////////////////////////////////////////////////////////////
19 
20 #if defined(_MSC_VER)
21 # pragma warning(disable: 4345)
22 #endif
23 
24 #include <boost/config/warning_disable.hpp>
25 #include <boost/spirit/home/x3.hpp>
26 #include <boost/spirit/home/x3/support/ast/variant.hpp>
27 #include <boost/variant/recursive_variant.hpp>
28 #include <boost/variant/apply_visitor.hpp>
29 #include <boost/fusion/include/adapt_struct.hpp>
30 
31 #include <list>
32 #include <numeric>
33 
34 namespace x3 = boost::spirit::x3;
35 
36 namespace client { namespace ast
37 {
38     ///////////////////////////////////////////////////////////////////////////
39     //  The AST
40     ///////////////////////////////////////////////////////////////////////////
41     struct nil {};
42     struct signed_;
43     struct program;
44 
45     typedef x3::variant<
46             nil
47           , unsigned int
48           , x3::forward_ast<signed_>
49           , x3::forward_ast<program>
50         >
51     operand;
52 
53     struct signed_
54     {
55         char sign;
56         operand operand_;
57     };
58 
59     struct operation
60     {
61         char operator_;
62         operand operand_;
63     };
64 
65     struct program
66     {
67         operand first;
68         std::list<operation> rest;
69     };
70 }}
71 
72 BOOST_FUSION_ADAPT_STRUCT(client::ast::signed_,
73     sign, operand_
74 )
75 
76 BOOST_FUSION_ADAPT_STRUCT(client::ast::operation,
77     operator_, operand_
78 )
79 
80 BOOST_FUSION_ADAPT_STRUCT(client::ast::program,
81     first, rest
82 )
83 
84 namespace client { namespace ast
85 {
86     ///////////////////////////////////////////////////////////////////////////
87     //  The AST Printer
88     ///////////////////////////////////////////////////////////////////////////
89     struct printer
90     {
91         typedef void result_type;
92 
operator ()client::ast::printer93         void operator()(nil) const {}
operator ()client::ast::printer94         void operator()(unsigned int n) const { std::cout << n; }
95 
operator ()client::ast::printer96         void operator()(operation const& x) const
97         {
98             boost::apply_visitor(*this, x.operand_);
99             switch (x.operator_)
100             {
101                 case '+': std::cout << " add"; break;
102                 case '-': std::cout << " subt"; break;
103                 case '*': std::cout << " mult"; break;
104                 case '/': std::cout << " div"; break;
105             }
106         }
107 
operator ()client::ast::printer108         void operator()(signed_ const& x) const
109         {
110             boost::apply_visitor(*this, x.operand_);
111             switch (x.sign)
112             {
113                 case '-': std::cout << " neg"; break;
114                 case '+': std::cout << " pos"; break;
115             }
116         }
117 
operator ()client::ast::printer118         void operator()(program const& x) const
119         {
120             boost::apply_visitor(*this, x.first);
121             for (operation const& oper: x.rest)
122             {
123                 std::cout << ' ';
124                 (*this)(oper);
125             }
126         }
127     };
128 
129     ///////////////////////////////////////////////////////////////////////////
130     //  The AST evaluator
131     ///////////////////////////////////////////////////////////////////////////
132     struct eval
133     {
134         typedef int result_type;
135 
operator ()client::ast::eval136         int operator()(nil) const { BOOST_ASSERT(0); return 0; }
operator ()client::ast::eval137         int operator()(unsigned int n) const { return n; }
138 
operator ()client::ast::eval139         int operator()(int lhs, operation const& x) const
140         {
141             int rhs = boost::apply_visitor(*this, x.operand_);
142             switch (x.operator_)
143             {
144                 case '+': return lhs + rhs;
145                 case '-': return lhs - rhs;
146                 case '*': return lhs * rhs;
147                 case '/': return lhs / rhs;
148             }
149             BOOST_ASSERT(0);
150             return 0;
151         }
152 
operator ()client::ast::eval153         int operator()(signed_ const& x) const
154         {
155             int rhs = boost::apply_visitor(*this, x.operand_);
156             switch (x.sign)
157             {
158                 case '-': return -rhs;
159                 case '+': return +rhs;
160             }
161             BOOST_ASSERT(0);
162             return 0;
163         }
164 
operator ()client::ast::eval165         int operator()(program const& x) const
166         {
167             return std::accumulate( x.rest.begin(), x.rest.end()
168                                     , boost::apply_visitor(*this, x.first)
169                                     , *this);
170         }
171     };
172 }}
173 
174 namespace client
175 {
176     ///////////////////////////////////////////////////////////////////////////////
177     //  The calculator grammar
178     ///////////////////////////////////////////////////////////////////////////////
179     namespace calculator_grammar
180     {
181         using parser_type =
182             x3::any_parser<
183                 std::string::const_iterator
184               , ast::program
185               , decltype(x3::make_context<x3::skipper_tag>(x3::ascii::space))
186             >;
187 
188         parser_type calculator();
189     }
190 
191     auto const calculator = calculator_grammar::calculator();
192 }
193