1 /*=============================================================================
2 Copyright (c) 2001-2010 Joel de Guzman
3 Copyright (c) 2001-2010 Hartmut Kaiser
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 ///////////////////////////////////////////////////////////////////////////////
10 // A Calculator example demonstrating generation of AST which gets dumped into
11 // a reverse polish notation afterwards.
13 // [ JDG April 28, 2008 ]
14 // [ HK April 28, 2008 ]
16 ///////////////////////////////////////////////////////////////////////////////
17 #include <boost/config/warning_disable.hpp>
23 #include "calc2_ast.hpp"
25 #include <boost/spirit/include/qi.hpp>
26 #include <boost/spirit/include/karma.hpp>
27 #include <boost/fusion/include/adapt_struct.hpp>
29 using namespace boost::spirit
;
30 using namespace boost::spirit::ascii
;
32 ///////////////////////////////////////////////////////////////////////////////
33 // Our calculator parser grammar
34 ///////////////////////////////////////////////////////////////////////////////
35 template <typename Iterator
>
37 : qi::grammar
<Iterator
, expression_ast(), space_type
>
39 calculator() : calculator::base_type(expression
)
43 >> *( ('+' >> term
[_val
+= _1
])
44 | ('-' >> term
[_val
-= _1
])
50 >> *( ('*' >> factor
[_val
*= _1
])
51 | ('/' >> factor
[_val
/= _1
])
57 | '(' >> expression
[_val
= _1
] >> ')'
58 | ('-' >> factor
[_val
= neg(_1
)])
59 | ('+' >> factor
[_val
= pos(_1
)])
63 qi::rule
<Iterator
, expression_ast(), space_type
> expression
, term
, factor
;
66 // We need to tell fusion about our binary_op and unary_op structs
67 // to make them a first-class fusion citizen
69 // Note: we register the members exactly in the same sequence as we need them
71 BOOST_FUSION_ADAPT_STRUCT(
73 (expression_ast
, left
)
74 (expression_ast
, right
)
78 BOOST_FUSION_ADAPT_STRUCT(
80 (expression_ast
, right
)
84 ///////////////////////////////////////////////////////////////////////////////
85 // Our AST grammar for the generator, this prints the AST in reverse polish
87 ///////////////////////////////////////////////////////////////////////////////
88 template <typename OuputIterator
>
90 : karma::grammar
<OuputIterator
, expression_ast(), space_type
>
92 ast_rpn() : ast_rpn::base_type(ast_node
)
94 ast_node
%= int_
| binary_node
| unary_node
;
95 binary_node
%= ast_node
<< ast_node
<< char_
;
96 unary_node
%= '(' << ast_node
<< char_
<< ')';
99 karma::rule
<OuputIterator
, expression_ast(), space_type
> ast_node
;
100 karma::rule
<OuputIterator
, binary_op(), space_type
> binary_node
;
101 karma::rule
<OuputIterator
, unary_op(), space_type
> unary_node
;
104 ///////////////////////////////////////////////////////////////////////////////
106 ///////////////////////////////////////////////////////////////////////////////
110 std::cout
<< "/////////////////////////////////////////////////////////\n\n";
111 std::cout
<< "RPN generator for simple expressions...\n\n";
112 std::cout
<< "/////////////////////////////////////////////////////////\n\n";
113 std::cout
<< "Type an expression...or [q or Q] to quit\n\n";
115 // Our parser grammar definitions
116 typedef std::string::const_iterator iterator_type
;
117 typedef calculator
<iterator_type
> calculator
;
121 // Our generator grammar definitions
122 typedef std::back_insert_iterator
<std::string
> output_iterator_type
;
123 typedef ast_rpn
<output_iterator_type
> ast_rpn
;
128 while (std::getline(std::cin
, str
))
130 if (str
.empty() || str
[0] == 'q' || str
[0] == 'Q')
133 expression_ast ast
; // this will hold the generated AST
135 std::string::const_iterator iter
= str
.begin();
136 std::string::const_iterator end
= str
.end();
137 bool r
= qi::phrase_parse(iter
, end
, calc
, space
, ast
);
139 if (r
&& iter
== end
)
141 std::string generated
;
142 output_iterator_type
outit(generated
);
143 r
= karma::generate_delimited(outit
, ast_grammar
, space
, ast
);
147 std::cout
<< "RPN for '" << str
<< "': \n" << generated
149 std::cout
<< "-------------------------\n";
153 std::cout
<< "-------------------------\n";
154 std::cout
<< "Generating failed\n";
155 std::cout
<< "-------------------------\n";
160 std::string
rest(iter
, end
);
161 std::cout
<< "-------------------------\n";
162 std::cout
<< "Parsing failed\n";
163 std::cout
<< "stopped at: \": " << rest
<< "\"\n";
164 std::cout
<< "-------------------------\n";
168 std::cout
<< "Bye... :-) \n\n";