]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/example/qi/compiler_tutorial/conjure2/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 =============================================================================*/
8 #include "compiler.hpp"
10 #include <boost/foreach.hpp>
11 #include <boost/variant/apply_visitor.hpp>
12 #include <boost/assert.hpp>
13 #include <boost/lexical_cast.hpp>
16 namespace client
{ namespace code_gen
18 void function::op(int a
)
24 void function::op(int a
, int b
)
31 void function::op(int a
, int b
, int c
)
39 int const* function::find_var(std::string
const& name
) const
41 std::map
<std::string
, int>::const_iterator i
= variables
.find(name
);
42 if (i
== variables
.end())
47 void function::add_var(std::string
const& name
)
49 std::size_t n
= variables
.size();
53 void function::link_to(std::string
const& name
, std::size_t address
)
55 function_calls
[address
] = name
;
58 void function::print_assembler() const
60 std::vector
<int>::const_iterator pc
= code
.begin() + address
;
62 std::vector
<std::string
> locals(variables
.size());
63 typedef std::pair
<std::string
, int> pair
;
64 BOOST_FOREACH(pair
const& p
, variables
)
66 locals
[p
.second
] = p
.first
;
67 std::cout
<< " local "
68 << p
.first
<< ", @" << p
.second
<< std::endl
;
71 std::map
<std::size_t, std::string
> lines
;
72 std::set
<std::size_t> jumps
;
74 while (pc
!= (code
.begin() + address
+ size_
))
77 std::size_t address
= pc
- code
.begin();
139 line
+= boost::lexical_cast
<std::string
>(locals
[*pc
++]);
143 line
+= " op_store ";
144 line
+= boost::lexical_cast
<std::string
>(locals
[*pc
++]);
149 line
+= boost::lexical_cast
<std::string
>(*pc
++);
163 std::size_t pos
= (pc
- code
.begin()) + *pc
++;
164 if (pos
== code
.size())
167 line
+= boost::lexical_cast
<std::string
>(pos
);
174 line
+= " op_jump_if ";
175 std::size_t pos
= (pc
- code
.begin()) + *pc
++;
176 if (pos
== code
.size())
179 line
+= boost::lexical_cast
<std::string
>(pos
);
188 std::size_t jump
= *pc
++;
189 line
+= boost::lexical_cast
<std::string
>(nargs
) + ", ";
190 BOOST_ASSERT(function_calls
.find(jump
) != function_calls
.end());
191 line
+= function_calls
.find(jump
)->second
;
196 line
+= " op_stk_adj ";
197 line
+= boost::lexical_cast
<std::string
>(*pc
++);
202 line
+= " op_return";
205 lines
[address
] = line
;
208 std::cout
<< "start:" << std::endl
;
209 typedef std::pair
<std::size_t, std::string
> line_info
;
210 BOOST_FOREACH(line_info
const& l
, lines
)
212 std::size_t pos
= l
.first
;
213 if (jumps
.find(pos
) != jumps
.end())
214 std::cout
<< pos
<< ':' << std::endl
;
215 std::cout
<< l
.second
<< std::endl
;
218 std::cout
<< "end:" << std::endl
<< std::endl
;
221 bool compiler::operator()(unsigned int x
)
223 BOOST_ASSERT(current
!= 0);
224 current
->op(op_int
, x
);
228 bool compiler::operator()(bool x
)
230 BOOST_ASSERT(current
!= 0);
231 current
->op(x
? op_true
: op_false
);
235 bool compiler::operator()(ast::identifier
const& x
)
237 BOOST_ASSERT(current
!= 0);
238 int const* p
= current
->find_var(x
.name
);
241 error_handler(x
.id
, "Undeclared variable: " + x
.name
);
244 current
->op(op_load
, *p
);
248 bool compiler::operator()(token_ids::type
const& x
)
250 BOOST_ASSERT(current
!= 0);
253 case token_ids::plus
: current
->op(op_add
); break;
254 case token_ids::minus
: current
->op(op_sub
); break;
255 case token_ids::times
: current
->op(op_mul
); break;
256 case token_ids::divide
: current
->op(op_div
); break;
258 case token_ids::equal
: current
->op(op_eq
); break;
259 case token_ids::not_equal
: current
->op(op_neq
); break;
260 case token_ids::less
: current
->op(op_lt
); break;
261 case token_ids::less_equal
: current
->op(op_lte
); break;
262 case token_ids::greater
: current
->op(op_gt
); break;
263 case token_ids::greater_equal
: current
->op(op_gte
); break;
265 case token_ids::logical_or
: current
->op(op_or
); break;
266 case token_ids::logical_and
: current
->op(op_and
); break;
267 default: BOOST_ASSERT(0); return false;
272 bool compiler::operator()(ast::unary
const& x
)
274 BOOST_ASSERT(current
!= 0);
275 if (!boost::apply_visitor(*this, x
.operand_
))
279 case token_ids::minus
: current
->op(op_neg
); break;
280 case token_ids::not_
: current
->op(op_not
); break;
281 case token_ids::plus
: break;
282 default: BOOST_ASSERT(0); return false;
287 bool compiler::operator()(ast::function_call
const& x
)
289 BOOST_ASSERT(current
!= 0);
291 if (functions
.find(x
.function_name
.name
) == functions
.end())
293 error_handler(x
.function_name
.id
, "Function not found: " + x
.function_name
.name
);
297 boost::shared_ptr
<code_gen::function
> p
= functions
[x
.function_name
.name
];
299 if (p
->nargs() != x
.args
.size())
301 error_handler(x
.function_name
.id
, "Wrong number of arguments: " + x
.function_name
.name
);
305 BOOST_FOREACH(ast::expression
const& expr
, x
.args
)
315 current
->link_to(x
.function_name
.name
, p
->get_address());
329 2, // op_minus_assign
330 2, // op_times_assign
331 2, // op_divide_assign
333 2, // op_bit_and_assign
334 2, // op_bit_xor_assign
335 2, // op_bitor_assign
336 2, // op_shift_left_assign
337 2, // op_shift_right_assign
362 9, // op_greater_equal
366 10, // op_shift_right
379 inline int precedence_of(token_ids::type op
)
381 return precedence
[op
& 0xFF];
384 // The Shunting-yard algorithm
385 bool compiler::compile_expression(
387 std::list
<ast::operation
>::const_iterator
& rbegin
,
388 std::list
<ast::operation
>::const_iterator rend
)
390 while ((rbegin
!= rend
) && (precedence_of(rbegin
->operator_
) >= min_precedence
))
392 token_ids::type op
= rbegin
->operator_
;
393 if (!boost::apply_visitor(*this, rbegin
->operand_
))
397 while ((rbegin
!= rend
) && (precedence_of(rbegin
->operator_
) > precedence_of(op
)))
399 token_ids::type next_op
= rbegin
->operator_
;
400 compile_expression(precedence_of(next_op
), rbegin
, rend
);
407 bool compiler::operator()(ast::expression
const& x
)
409 BOOST_ASSERT(current
!= 0);
410 if (!boost::apply_visitor(*this, x
.first
))
412 std::list
<ast::operation
>::const_iterator rbegin
= x
.rest
.begin();
413 if (!compile_expression(0, rbegin
, x
.rest
.end()))
418 bool compiler::operator()(ast::assignment
const& x
)
420 BOOST_ASSERT(current
!= 0);
423 int const* p
= current
->find_var(x
.lhs
.name
);
426 error_handler(x
.lhs
.id
, "Undeclared variable: " + x
.lhs
.name
);
429 current
->op(op_store
, *p
);
433 bool compiler::operator()(ast::variable_declaration
const& x
)
435 BOOST_ASSERT(current
!= 0);
436 int const* p
= current
->find_var(x
.lhs
.name
);
439 error_handler(x
.lhs
.id
, "Duplicate variable: " + x
.lhs
.name
);
442 if (x
.rhs
) // if there's an RHS initializer
444 bool r
= (*this)(*x
.rhs
);
445 if (r
) // don't add the variable if the RHS fails
447 current
->add_var(x
.lhs
.name
);
448 current
->op(op_store
, *current
->find_var(x
.lhs
.name
));
454 current
->add_var(x
.lhs
.name
);
459 bool compiler::operator()(ast::statement
const& x
)
461 BOOST_ASSERT(current
!= 0);
462 return boost::apply_visitor(*this, x
);
465 bool compiler::operator()(ast::statement_list
const& x
)
467 BOOST_ASSERT(current
!= 0);
468 BOOST_FOREACH(ast::statement
const& s
, x
)
476 bool compiler::operator()(ast::if_statement
const& x
)
478 BOOST_ASSERT(current
!= 0);
479 if (!(*this)(x
.condition
))
481 current
->op(op_jump_if
, 0); // we shall fill this (0) in later
482 std::size_t skip
= current
->size()-1; // mark its position
483 if (!(*this)(x
.then
))
485 (*current
)[skip
] = current
->size()-skip
; // now we know where to jump to (after the if branch)
487 if (x
.else_
) // We got an alse
489 (*current
)[skip
] += 2; // adjust for the "else" jump
490 current
->op(op_jump
, 0); // we shall fill this (0) in later
491 std::size_t exit
= current
->size()-1; // mark its position
492 if (!(*this)(*x
.else_
))
494 (*current
)[exit
] = current
->size()-exit
;// now we know where to jump to (after the else branch)
500 bool compiler::operator()(ast::while_statement
const& x
)
502 BOOST_ASSERT(current
!= 0);
503 std::size_t loop
= current
->size(); // mark our position
504 if (!(*this)(x
.condition
))
506 current
->op(op_jump_if
, 0); // we shall fill this (0) in later
507 std::size_t exit
= current
->size()-1; // mark its position
508 if (!(*this)(x
.body
))
511 int(loop
-1) - int(current
->size())); // loop back
512 (*current
)[exit
] = current
->size()-exit
; // now we know where to jump to (to exit the loop)
516 bool compiler::operator()(ast::return_statement
const& x
)
522 error_handler(x
.id
, "'void' function returning a value: ");
530 error_handler(x
.id
, current_function_name
+ " function must return a value: ");
537 if (!(*this)(*x
.expr
))
540 current
->op(op_return
);
544 bool compiler::operator()(ast::function
const& x
)
546 void_return
= x
.return_type
== "void";
547 if (functions
.find(x
.function_name
.name
) != functions
.end())
549 error_handler(x
.function_name
.id
, "Duplicate function: " + x
.function_name
.name
);
552 boost::shared_ptr
<code_gen::function
>& p
= functions
[x
.function_name
.name
];
553 p
.reset(new code_gen::function(code
, x
.args
.size()));
555 current_function_name
= x
.function_name
.name
;
557 // op_stk_adj 0 for now. we'll know how many variables
558 // we'll have later and add them
559 current
->op(op_stk_adj
, 0);
560 BOOST_FOREACH(ast::identifier
const& arg
, x
.args
)
562 current
->add_var(arg
.name
);
565 if (!(*this)(x
.body
))
567 (*current
)[1] = current
->nvars(); // now store the actual number of variables
568 // this includes the arguments
572 bool compiler::operator()(ast::function_list
const& x
)
574 // Jump to the main function
575 code
.push_back(op_jump
);
576 code
.push_back(0); // we will fill this in later when we finish compiling
577 // and we know where the main function is
579 BOOST_FOREACH(ast::function
const& f
, x
)
587 // find the main function
588 boost::shared_ptr
<code_gen::function
> p
=
589 find_function("main");
591 if (!p
) // main function not found
593 std::cerr
<< "Error: main function not defined" << std::endl
;
596 code
[1] = p
->get_address()-1; // jump to this (main function) address
601 void compiler::print_assembler() const
603 typedef std::pair
<std::string
, boost::shared_ptr
<code_gen::function
> > pair
;
604 BOOST_FOREACH(pair
const& p
, functions
)
606 std::cout
<< ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;" << std::endl
;
607 std::cout
<< p
.second
->get_address() << ": function " << p
.first
<< std::endl
;
608 p
.second
->print_assembler();
612 boost::shared_ptr
<code_gen::function
>
613 compiler::find_function(std::string
const& name
) const
615 function_table::const_iterator i
= functions
.find(name
);
616 if (i
== functions
.end())
617 return boost::shared_ptr
<code_gen::function
>();