]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/example/qi/compiler_tutorial/mini_c/compiler.cpp
1 /*=============================================================================
2 Copyright (c) 2001-2011 Joel de Guzman
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 =============================================================================*/
7 #include "compiler.hpp"
9 #include <boost/foreach.hpp>
10 #include <boost/variant/apply_visitor.hpp>
11 #include <boost/assert.hpp>
12 #include <boost/lexical_cast.hpp>
15 namespace client
{ namespace code_gen
17 void function::op(int a
)
23 void function::op(int a
, int b
)
30 void function::op(int a
, int b
, int c
)
38 int const* function::find_var(std::string
const& name
) const
40 std::map
<std::string
, int>::const_iterator i
= variables
.find(name
);
41 if (i
== variables
.end())
46 void function::add_var(std::string
const& name
)
48 std::size_t n
= variables
.size();
52 void function::link_to(std::string
const& name
, std::size_t address
)
54 function_calls
[address
] = name
;
57 void function::print_assembler() const
59 std::vector
<int>::const_iterator pc
= code
.begin() + address
;
61 std::vector
<std::string
> locals(variables
.size());
62 typedef std::pair
<std::string
, int> pair
;
63 BOOST_FOREACH(pair
const& p
, variables
)
65 locals
[p
.second
] = p
.first
;
66 std::cout
<< " local "
67 << p
.first
<< ", @" << p
.second
<< std::endl
;
70 std::map
<std::size_t, std::string
> lines
;
71 std::set
<std::size_t> jumps
;
73 while (pc
!= (code
.begin() + address
+ size_
))
76 std::size_t address
= pc
- code
.begin();
138 line
+= locals
[*pc
++];
142 line
+= " op_store ";
143 line
+= locals
[*pc
++];
148 line
+= boost::lexical_cast
<std::string
>(*pc
++);
162 std::size_t pos
= (pc
- code
.begin()) + *pc
++;
163 if (pos
== code
.size())
166 line
+= boost::lexical_cast
<std::string
>(pos
);
173 line
+= " op_jump_if ";
174 std::size_t pos
= (pc
- code
.begin()) + *pc
++;
175 if (pos
== code
.size())
178 line
+= boost::lexical_cast
<std::string
>(pos
);
187 std::size_t jump
= *pc
++;
188 line
+= boost::lexical_cast
<std::string
>(nargs
) + ", ";
189 BOOST_ASSERT(function_calls
.find(jump
) != function_calls
.end());
190 line
+= function_calls
.find(jump
)->second
;
195 line
+= " op_stk_adj ";
196 line
+= boost::lexical_cast
<std::string
>(*pc
++);
201 line
+= " op_return";
204 lines
[address
] = line
;
207 std::cout
<< "start:" << std::endl
;
208 typedef std::pair
<std::size_t, std::string
> line_info
;
209 BOOST_FOREACH(line_info
const& l
, lines
)
211 std::size_t pos
= l
.first
;
212 if (jumps
.find(pos
) != jumps
.end())
213 std::cout
<< pos
<< ':' << std::endl
;
214 std::cout
<< l
.second
<< std::endl
;
217 std::cout
<< "end:" << std::endl
<< std::endl
;
220 bool compiler::operator()(unsigned int x
)
222 BOOST_ASSERT(current
!= 0);
223 current
->op(op_int
, x
);
227 bool compiler::operator()(bool x
)
229 BOOST_ASSERT(current
!= 0);
230 current
->op(x
? op_true
: op_false
);
234 bool compiler::operator()(ast::identifier
const& x
)
236 BOOST_ASSERT(current
!= 0);
237 int const* p
= current
->find_var(x
.name
);
240 error_handler(x
.id
, "Undeclared variable: " + x
.name
);
243 current
->op(op_load
, *p
);
247 bool compiler::operator()(ast::operation
const& x
)
249 BOOST_ASSERT(current
!= 0);
250 if (!boost::apply_visitor(*this, x
.operand_
))
254 case ast::op_plus
: current
->op(op_add
); break;
255 case ast::op_minus
: current
->op(op_sub
); break;
256 case ast::op_times
: current
->op(op_mul
); break;
257 case ast::op_divide
: current
->op(op_div
); break;
259 case ast::op_equal
: current
->op(op_eq
); break;
260 case ast::op_not_equal
: current
->op(op_neq
); break;
261 case ast::op_less
: current
->op(op_lt
); break;
262 case ast::op_less_equal
: current
->op(op_lte
); break;
263 case ast::op_greater
: current
->op(op_gt
); break;
264 case ast::op_greater_equal
: current
->op(op_gte
); break;
266 case ast::op_and
: current
->op(op_and
); break;
267 case ast::op_or
: current
->op(op_or
); break;
268 default: BOOST_ASSERT(0); return false;
273 bool compiler::operator()(ast::unary
const& x
)
275 BOOST_ASSERT(current
!= 0);
276 if (!boost::apply_visitor(*this, x
.operand_
))
280 case ast::op_negative
: current
->op(op_neg
); break;
281 case ast::op_not
: current
->op(op_not
); break;
282 case ast::op_positive
: break;
283 default: BOOST_ASSERT(0); return false;
288 bool compiler::operator()(ast::function_call
const& x
)
290 BOOST_ASSERT(current
!= 0);
292 if (functions
.find(x
.function_name
.name
) == functions
.end())
294 error_handler(x
.function_name
.id
, "Function not found: " + x
.function_name
.name
);
298 boost::shared_ptr
<code_gen::function
> p
= functions
[x
.function_name
.name
];
300 if (p
->nargs() != x
.args
.size())
302 error_handler(x
.function_name
.id
, "Wrong number of arguments: " + x
.function_name
.name
);
306 BOOST_FOREACH(ast::expression
const& expr
, x
.args
)
316 current
->link_to(x
.function_name
.name
, p
->get_address());
321 bool compiler::operator()(ast::expression
const& x
)
323 BOOST_ASSERT(current
!= 0);
324 if (!boost::apply_visitor(*this, x
.first
))
326 BOOST_FOREACH(ast::operation
const& oper
, x
.rest
)
334 bool compiler::operator()(ast::assignment
const& x
)
336 BOOST_ASSERT(current
!= 0);
339 int const* p
= current
->find_var(x
.lhs
.name
);
342 error_handler(x
.lhs
.id
, "Undeclared variable: " + x
.lhs
.name
);
345 current
->op(op_store
, *p
);
349 bool compiler::operator()(ast::variable_declaration
const& x
)
351 BOOST_ASSERT(current
!= 0);
352 int const* p
= current
->find_var(x
.lhs
.name
);
355 error_handler(x
.lhs
.id
, "Duplicate variable: " + x
.lhs
.name
);
358 if (x
.rhs
) // if there's an RHS initializer
360 bool r
= (*this)(*x
.rhs
);
361 if (r
) // don't add the variable if the RHS fails
363 current
->add_var(x
.lhs
.name
);
364 current
->op(op_store
, *current
->find_var(x
.lhs
.name
));
370 current
->add_var(x
.lhs
.name
);
375 bool compiler::operator()(ast::statement
const& x
)
377 BOOST_ASSERT(current
!= 0);
378 return boost::apply_visitor(*this, x
);
381 bool compiler::operator()(ast::statement_list
const& x
)
383 BOOST_ASSERT(current
!= 0);
384 BOOST_FOREACH(ast::statement
const& s
, x
)
392 bool compiler::operator()(ast::if_statement
const& x
)
394 BOOST_ASSERT(current
!= 0);
395 if (!(*this)(x
.condition
))
397 current
->op(op_jump_if
, 0); // we shall fill this (0) in later
398 std::size_t skip
= current
->size()-1; // mark its position
399 if (!(*this)(x
.then
))
401 (*current
)[skip
] = current
->size()-skip
; // now we know where to jump to (after the if branch)
403 if (x
.else_
) // We got an else
405 (*current
)[skip
] += 2; // adjust for the "else" jump
406 current
->op(op_jump
, 0); // we shall fill this (0) in later
407 std::size_t exit
= current
->size()-1; // mark its position
408 if (!(*this)(*x
.else_
))
410 (*current
)[exit
] = current
->size()-exit
;// now we know where to jump to (after the else branch)
416 bool compiler::operator()(ast::while_statement
const& x
)
418 BOOST_ASSERT(current
!= 0);
419 std::size_t loop
= current
->size(); // mark our position
420 if (!(*this)(x
.condition
))
422 current
->op(op_jump_if
, 0); // we shall fill this (0) in later
423 std::size_t exit
= current
->size()-1; // mark its position
424 if (!(*this)(x
.body
))
427 int(loop
-1) - int(current
->size())); // loop back
428 (*current
)[exit
] = current
->size()-exit
; // now we know where to jump to (to exit the loop)
432 bool compiler::operator()(ast::return_statement
const& x
)
438 error_handler(x
.id
, "'void' function returning a value: ");
446 error_handler(x
.id
, current_function_name
+ " function must return a value: ");
453 if (!(*this)(*x
.expr
))
456 current
->op(op_return
);
460 bool compiler::operator()(ast::function
const& x
)
462 void_return
= x
.return_type
== "void";
463 if (functions
.find(x
.function_name
.name
) != functions
.end())
465 error_handler(x
.function_name
.id
, "Duplicate function: " + x
.function_name
.name
);
468 boost::shared_ptr
<code_gen::function
>& p
= functions
[x
.function_name
.name
];
469 p
.reset(new code_gen::function(code
, x
.args
.size()));
471 current_function_name
= x
.function_name
.name
;
473 // op_stk_adj 0 for now. we'll know how many variables
474 // we'll have later and add them
475 current
->op(op_stk_adj
, 0);
476 BOOST_FOREACH(ast::identifier
const& arg
, x
.args
)
478 current
->add_var(arg
.name
);
481 if (!(*this)(x
.body
))
483 (*current
)[1] = current
->nvars(); // now store the actual number of variables
484 // this includes the arguments
488 bool compiler::operator()(ast::function_list
const& x
)
490 // Jump to the main function
491 code
.push_back(op_jump
);
492 code
.push_back(0); // we will fill this in later when we finish compiling
493 // and we know where the main function is
495 BOOST_FOREACH(ast::function
const& f
, x
)
503 // find the main function
504 boost::shared_ptr
<code_gen::function
> p
=
505 find_function("main");
507 if (!p
) // main function not found
509 std::cerr
<< "Error: main function not defined" << std::endl
;
512 code
[1] = p
->get_address()-1; // jump to this (main function) address
517 void compiler::print_assembler() const
519 typedef std::pair
<std::string
, boost::shared_ptr
<code_gen::function
> > pair
;
520 BOOST_FOREACH(pair
const& p
, functions
)
522 std::cout
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" << std::endl
;
523 std::cout
<< p
.second
->get_address() << ": function " << p
.first
<< std::endl
;
524 p
.second
->print_assembler();
528 boost::shared_ptr
<code_gen::function
>
529 compiler::find_function(std::string
const& name
) const
531 function_table::const_iterator i
= functions
.find(name
);
532 if (i
== functions
.end())
533 return boost::shared_ptr
<code_gen::function
>();