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 from which we generate
11 // a simple byte code representation being interpreted by a similar virtual
12 // machine.
13 //
14 // [ JDG April 28, 2008 ]
15 // [ HK May 05, 2008 ]
16 //
17 ///////////////////////////////////////////////////////////////////////////////
18 #include <boost/config/warning_disable.hpp>
19
20 #include <iostream>
21 #include <vector>
22 #include <string>
23
24 #include "calc2_ast_vm.hpp"
25
26 #include <boost/spirit/include/qi.hpp>
27 #include <boost/spirit/include/karma.hpp>
28 #include <boost/fusion/include/adapt_struct.hpp>
29
30 using namespace boost::spirit;
31 using namespace boost::spirit::ascii;
32
33 ///////////////////////////////////////////////////////////////////////////////
34 // Our calculator parser grammar
35 ///////////////////////////////////////////////////////////////////////////////
36 template <typename Iterator>
37 struct calculator
38 : qi::grammar<Iterator, expression_ast(), space_type>
39 {
calculatorcalculator40 calculator() : calculator::base_type(expression)
41 {
42 expression =
43 term [_val = _1]
44 >> *( ('+' >> term [_val += _1])
45 | ('-' >> term [_val -= _1])
46 )
47 ;
48
49 term =
50 factor [_val = _1]
51 >> *( ('*' >> factor [_val *= _1])
52 | ('/' >> factor [_val /= _1])
53 )
54 ;
55
56 factor =
57 uint_ [_val = _1]
58 | '(' >> expression [_val = _1] >> ')'
59 | ('-' >> factor [_val = neg(_1)])
60 | ('+' >> factor [_val = pos(_1)])
61 ;
62 }
63
64 qi::rule<Iterator, expression_ast(), space_type> expression, term, factor;
65 };
66
67 ///////////////////////////////////////////////////////////////////////////////
68 // The Virtual Machine
69 ///////////////////////////////////////////////////////////////////////////////
70 class vmachine
71 {
72 public:
73 union element {
74 int code;
75 char bytes[sizeof(int)];
76 };
77
vmachine(unsigned stackSize=4096)78 vmachine(unsigned stackSize = 4096)
79 : stack(stackSize)
80 , stack_ptr(stack.begin())
81 {
82 }
83
top() const84 int top() const { return stack_ptr[-1]; };
85 void execute(std::vector<element> const& code);
86
87 private:
88 std::vector<int> stack;
89 std::vector<int>::iterator stack_ptr;
90 };
91
execute(std::vector<element> const & code)92 void vmachine::execute(std::vector<element> const& code)
93 {
94 std::vector<element>::const_iterator pc = code.begin();
95 stack_ptr = stack.begin();
96
97 while ((*pc).code && pc != code.end())
98 {
99 switch ((*pc++).code)
100 {
101 case op_neg:
102 stack_ptr[-1] = -stack_ptr[-1];
103 break;
104
105 case op_add:
106 --stack_ptr;
107 stack_ptr[-1] += stack_ptr[0];
108 break;
109
110 case op_sub:
111 --stack_ptr;
112 stack_ptr[-1] -= stack_ptr[0];
113 break;
114
115 case op_mul:
116 --stack_ptr;
117 stack_ptr[-1] *= stack_ptr[0];
118 break;
119
120 case op_div:
121 --stack_ptr;
122 stack_ptr[-1] /= stack_ptr[0];
123 break;
124
125 case op_int:
126 *stack_ptr++ = (*pc++).code;
127 break;
128 }
129 }
130 }
131
132 // We need to tell fusion about our binary_op and unary_op structs
133 // to make them a first-class fusion citizen
134 //
135 // Note: we register the members exactly in the same sequence as we need them
136 // in the grammar
137 BOOST_FUSION_ADAPT_STRUCT(
138 binary_op,
139 (expression_ast, left)
140 (expression_ast, right)
141 (int, op)
142 )
143
144 BOOST_FUSION_ADAPT_STRUCT(
145 unary_op,
146 (expression_ast, right)
147 (int, op)
148 )
149
150 ///////////////////////////////////////////////////////////////////////////////
151 // Our AST grammar for the generator, this just dumps the AST as a expression
152 ///////////////////////////////////////////////////////////////////////////////
153 template <typename OuputIterator, typename Delimiter>
154 struct generate_byte_code
155 : karma::grammar<OuputIterator, expression_ast(), Delimiter>
156 {
generate_byte_codegenerate_byte_code157 generate_byte_code() : generate_byte_code::base_type(ast_node)
158 {
159 ast_node %= int_node | binary_node | unary_node;
160 int_node %= dword(op_int) << dword;
161 binary_node %= ast_node << ast_node << byte_;
162 unary_node %= ast_node << byte_;
163 }
164
165 karma::rule<OuputIterator, expression_ast(), Delimiter> ast_node;
166 karma::rule<OuputIterator, int(), Delimiter> int_node;
167 karma::rule<OuputIterator, binary_op(), Delimiter> binary_node;
168 karma::rule<OuputIterator, unary_op(), Delimiter> unary_node;
169 };
170
171 ///////////////////////////////////////////////////////////////////////////////
172 // helper function helping to deduce the delimiter type
173 template <typename Delimiter>
generate_vm_code(expression_ast const & ast,std::vector<vmachine::element> & code,Delimiter const & d)174 bool generate_vm_code(expression_ast const& ast,
175 std::vector<vmachine::element>& code, Delimiter const& d)
176 {
177 // Our generator grammar definitions
178 typedef char* output_iterator_type;
179 typedef generate_byte_code<output_iterator_type, Delimiter> generate_byte_code;
180
181 char* outbuffer = (*code.begin()).bytes;
182 generate_byte_code gen_vm;
183 return karma::generate_delimited(outbuffer, gen_vm, d, ast);
184 }
185
186 ///////////////////////////////////////////////////////////////////////////////
187 // Main program
188 ///////////////////////////////////////////////////////////////////////////////
189 int
main()190 main()
191 {
192 std::cout << "/////////////////////////////////////////////////////////\n\n";
193 std::cout << "Compile simple expressions to bytecode...\n\n";
194 std::cout << "/////////////////////////////////////////////////////////\n\n";
195 std::cout << "Type an expression...or [q or Q] to quit\n\n";
196
197 // Our parser grammar definitions
198 typedef std::string::const_iterator iterator_type;
199 typedef calculator<iterator_type> calculator;
200
201 calculator calc;
202
203 std::string str;
204 while (std::getline(std::cin, str))
205 {
206 if (str.empty() || str[0] == 'q' || str[0] == 'Q')
207 break;
208
209 expression_ast ast;
210 std::string::const_iterator iter = str.begin();
211 std::string::const_iterator end = str.end();
212 bool r = qi::phrase_parse(iter, end, calc, space, ast);
213
214 if (r && iter == end)
215 {
216 // we assume a vm code size of 4096 is sufficient
217 std::vector<vmachine::element> code (4096);
218 r = generate_vm_code(ast, code, pad(4));
219
220 if (r)
221 {
222 vmachine vm;
223 vm.execute(code);
224 std::cout << "\nresult = " << vm.top() << std::endl;
225 std::cout << "-------------------------\n";
226 }
227 else
228 {
229 std::cout << "-------------------------\n";
230 std::cout << "Generating failed\n";
231 std::cout << "-------------------------\n";
232 }
233 }
234 else
235 {
236 std::string rest(iter, end);
237 std::cout << "-------------------------\n";
238 std::cout << "Parsing failed\n";
239 std::cout << "stopped at: \": " << rest << "\"\n";
240 std::cout << "-------------------------\n";
241 }
242 }
243
244 std::cout << "Bye... :-) \n\n";
245 return 0;
246 }
247
248
249