1 /*=============================================================================
2     Copyright (c) 2001-2010 Joel de Guzman
3     Copyright (c) 2001-2010 Hartmut Kaiser
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 which gets dumped into
11 //  a human readable format afterwards.
12 //
13 //  [ JDG April 28, 2008 ]
14 //  [ HK April 28, 2008 ]
15 //
16 ///////////////////////////////////////////////////////////////////////////////
17 #include <boost/config/warning_disable.hpp>
18 
19 #include <iostream>
20 #include <vector>
21 #include <string>
22 
23 #include "calc2_ast.hpp"
24 
25 #include <boost/spirit/include/qi.hpp>
26 #include <boost/spirit/include/karma.hpp>
27 #include <boost/fusion/include/adapt_struct.hpp>
28 
29 using namespace boost::spirit;
30 using namespace boost::spirit::ascii;
31 
32 ///////////////////////////////////////////////////////////////////////////////
33 //  Our calculator parser grammar
34 ///////////////////////////////////////////////////////////////////////////////
35 template <typename Iterator>
36 struct calculator
37   : qi::grammar<Iterator, expression_ast(), space_type>
38 {
calculatorcalculator39     calculator() : calculator::base_type(expression)
40     {
41         expression =
42             term                            [_val = _1]
43             >> *(   ('+' >> term            [_val += _1])
44                 |   ('-' >> term            [_val -= _1])
45                 )
46             ;
47 
48         term =
49             factor                          [_val = _1]
50             >> *(   ('*' >> factor          [_val *= _1])
51                 |   ('/' >> factor          [_val /= _1])
52                 )
53             ;
54 
55         factor =
56             uint_                           [_val = _1]
57             |   '(' >> expression           [_val = _1] >> ')'
58             |   ('-' >> factor              [_val = neg(_1)])
59             |   ('+' >> factor              [_val = pos(_1)])
60             ;
61     }
62 
63     qi::rule<Iterator, expression_ast(), space_type> expression, term, factor;
64 };
65 
66 // We need to tell fusion about our binary_op and unary_op structs
67 // to make them a first-class fusion citizen
68 //
69 // Note: we register the members exactly in the same sequence as we need them
70 //       in the grammar
71 BOOST_FUSION_ADAPT_STRUCT(
72     binary_op,
73     (expression_ast, left)
74     (char, op)
75     (expression_ast, right)
76 )
77 
78 BOOST_FUSION_ADAPT_STRUCT(
79     unary_op,
80     (char, op)
81     (expression_ast, right)
82 )
83 
84 ///////////////////////////////////////////////////////////////////////////////
85 //  Our AST grammar for the generator, this just dumps the AST as a expression
86 ///////////////////////////////////////////////////////////////////////////////
87 template <typename OuputIterator>
88 struct dump_ast
89   : karma::grammar<OuputIterator, expression_ast(), space_type>
90 {
dump_astdump_ast91     dump_ast() : dump_ast::base_type(ast_node)
92     {
93         ast_node %= int_ | binary_node | unary_node;
94         binary_node %= '(' << ast_node << char_ << ast_node << ')';
95         unary_node %= '(' << char_ << ast_node << ')';
96     }
97 
98     karma::rule<OuputIterator, expression_ast(), space_type> ast_node;
99     karma::rule<OuputIterator, binary_op(), space_type> binary_node;
100     karma::rule<OuputIterator, unary_op(), space_type> unary_node;
101 };
102 
103 ///////////////////////////////////////////////////////////////////////////////
104 //  Main program
105 ///////////////////////////////////////////////////////////////////////////////
106 int
main()107 main()
108 {
109     std::cout << "/////////////////////////////////////////////////////////\n\n";
110     std::cout << "Dump AST's for simple expressions...\n\n";
111     std::cout << "/////////////////////////////////////////////////////////\n\n";
112     std::cout << "Type an expression...or [q or Q] to quit\n\n";
113 
114     //  Our parser grammar definitions
115     typedef std::string::const_iterator iterator_type;
116     typedef calculator<iterator_type> calculator;
117 
118     calculator calc;
119 
120     // Our generator grammar definitions
121     typedef std::back_insert_iterator<std::string> output_iterator_type;
122     typedef dump_ast<output_iterator_type> dump_ast;
123 
124     dump_ast ast_grammar;
125 
126     std::string str;
127     while (std::getline(std::cin, str))
128     {
129         if (str.empty() || str[0] == 'q' || str[0] == 'Q')
130             break;
131 
132         expression_ast ast;
133         std::string::const_iterator iter = str.begin();
134         std::string::const_iterator end = str.end();
135         bool r = qi::phrase_parse(iter, end, calc, space, ast);
136 
137         if (r && iter == end)
138         {
139             std::string generated;
140             output_iterator_type outit(generated);
141             r = karma::generate_delimited(outit, ast_grammar, space, ast);
142 
143             if (r)
144             {
145                 std::cout << "Got AST:" << std::endl << generated
146                           << std::endl;
147                 std::cout << "-------------------------\n";
148             }
149             else
150             {
151                 std::cout << "-------------------------\n";
152                 std::cout << "Generating failed\n";
153                 std::cout << "-------------------------\n";
154             }
155         }
156         else
157         {
158             std::string rest(iter, end);
159             std::cout << "-------------------------\n";
160             std::cout << "Parsing failed\n";
161             std::cout << "stopped at: \": " << rest << "\"\n";
162             std::cout << "-------------------------\n";
163         }
164     }
165 
166     std::cout << "Bye... :-) \n\n";
167     return 0;
168 }
169 
170 
171