123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- /*=============================================================================
- Copyright (c) 2001-2011 Joel de Guzman
- Distributed under the Boost Software License, Version 1.0. (See accompanying
- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- =============================================================================*/
- #include "compiler.hpp"
- #include "vm.hpp"
- #include <boost/foreach.hpp>
- #include <boost/variant/apply_visitor.hpp>
- #include <boost/assert.hpp>
- #include <boost/lexical_cast.hpp>
- #include <set>
- namespace client { namespace code_gen
- {
- void program::op(int a)
- {
- code.push_back(a);
- }
- void program::op(int a, int b)
- {
- code.push_back(a);
- code.push_back(b);
- }
- void program::op(int a, int b, int c)
- {
- code.push_back(a);
- code.push_back(b);
- code.push_back(c);
- }
- int const* program::find_var(std::string const& name) const
- {
- std::map<std::string, int>::const_iterator i = variables.find(name);
- if (i == variables.end())
- return 0;
- return &i->second;
- }
- void program::add_var(std::string const& name)
- {
- std::size_t n = variables.size();
- variables[name] = n;
- }
- void program::print_variables(std::vector<int> const& stack) const
- {
- typedef std::pair<std::string, int> pair;
- BOOST_FOREACH(pair const& p, variables)
- {
- std::cout << " " << p.first << ": " << stack[p.second] << std::endl;
- }
- }
- void program::print_assembler() const
- {
- std::vector<int>::const_iterator pc = code.begin();
- std::vector<std::string> locals(variables.size());
- typedef std::pair<std::string, int> pair;
- BOOST_FOREACH(pair const& p, variables)
- {
- locals[p.second] = p.first;
- std::cout << " local "
- << p.first << ", @" << p.second << std::endl;
- }
- std::map<std::size_t, std::string> lines;
- std::set<std::size_t> jumps;
- while (pc != code.end())
- {
- std::string line;
- std::size_t address = pc - code.begin();
- switch (*pc++)
- {
- case op_neg:
- line += " op_neg";
- break;
- case op_not:
- line += " op_not";
- break;
- case op_add:
- line += " op_add";
- break;
- case op_sub:
- line += " op_sub";
- break;
- case op_mul:
- line += " op_mul";
- break;
- case op_div:
- line += " op_div";
- break;
- case op_eq:
- line += " op_eq";
- break;
- case op_neq:
- line += " op_neq";
- break;
- case op_lt:
- line += " op_lt";
- break;
- case op_lte:
- line += " op_lte";
- break;
- case op_gt:
- line += " op_gt";
- break;
- case op_gte:
- line += " op_gte";
- break;
- case op_and:
- line += " op_and";
- break;
- case op_or:
- line += " op_or";
- break;
- case op_load:
- line += " op_load ";
- line += locals[*pc++];
- break;
- case op_store:
- line += " op_store ";
- line += locals[*pc++];
- break;
- case op_int:
- line += " op_int ";
- line += boost::lexical_cast<std::string>(*pc++);
- break;
- case op_true:
- line += " op_true";
- break;
- case op_false:
- line += " op_false";
- break;
- case op_jump:
- {
- line += " op_jump ";
- std::size_t pos = (pc - code.begin()) + *pc++;
- if (pos == code.size())
- line += "end";
- else
- line += boost::lexical_cast<std::string>(pos);
- jumps.insert(pos);
- }
- break;
- case op_jump_if:
- {
- line += " op_jump_if ";
- std::size_t pos = (pc - code.begin()) + *pc++;
- if (pos == code.size())
- line += "end";
- else
- line += boost::lexical_cast<std::string>(pos);
- jumps.insert(pos);
- }
- break;
- case op_stk_adj:
- line += " op_stk_adj ";
- line += boost::lexical_cast<std::string>(*pc++);
- break;
- }
- lines[address] = line;
- }
- std::cout << "start:" << std::endl;
- typedef std::pair<std::size_t, std::string> line_info;
- BOOST_FOREACH(line_info const& l, lines)
- {
- std::size_t pos = l.first;
- if (jumps.find(pos) != jumps.end())
- std::cout << pos << ':' << std::endl;
- std::cout << l.second << std::endl;
- }
- std::cout << "end:" << std::endl;
- }
- bool compiler::operator()(unsigned int x) const
- {
- program.op(op_int, x);
- return true;
- }
- bool compiler::operator()(bool x) const
- {
- program.op(x ? op_true : op_false);
- return true;
- }
- bool compiler::operator()(ast::variable const& x) const
- {
- int const* p = program.find_var(x.name);
- if (p == 0)
- {
- std::cout << x.id << std::endl;
- error_handler(x.id, "Undeclared variable: " + x.name);
- return false;
- }
- program.op(op_load, *p);
- return true;
- }
- bool compiler::operator()(ast::operation const& x) const
- {
- if (!boost::apply_visitor(*this, x.operand_))
- return false;
- switch (x.operator_)
- {
- case ast::op_plus: program.op(op_add); break;
- case ast::op_minus: program.op(op_sub); break;
- case ast::op_times: program.op(op_mul); break;
- case ast::op_divide: program.op(op_div); break;
- case ast::op_equal: program.op(op_eq); break;
- case ast::op_not_equal: program.op(op_neq); break;
- case ast::op_less: program.op(op_lt); break;
- case ast::op_less_equal: program.op(op_lte); break;
- case ast::op_greater: program.op(op_gt); break;
- case ast::op_greater_equal: program.op(op_gte); break;
- case ast::op_and: program.op(op_and); break;
- case ast::op_or: program.op(op_or); break;
- default: BOOST_ASSERT(0); return false;
- }
- return true;
- }
- bool compiler::operator()(ast::unary const& x) const
- {
- if (!boost::apply_visitor(*this, x.operand_))
- return false;
- switch (x.operator_)
- {
- case ast::op_negative: program.op(op_neg); break;
- case ast::op_not: program.op(op_not); break;
- case ast::op_positive: break;
- default: BOOST_ASSERT(0); return false;
- }
- return true;
- }
- bool compiler::operator()(ast::expression const& x) const
- {
- if (!boost::apply_visitor(*this, x.first))
- return false;
- BOOST_FOREACH(ast::operation const& oper, x.rest)
- {
- if (!(*this)(oper))
- return false;
- }
- return true;
- }
- bool compiler::operator()(ast::assignment const& x) const
- {
- if (!(*this)(x.rhs))
- return false;
- int const* p = program.find_var(x.lhs.name);
- if (p == 0)
- {
- std::cout << x.lhs.id << std::endl;
- error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name);
- return false;
- }
- program.op(op_store, *p);
- return true;
- }
- bool compiler::operator()(ast::variable_declaration const& x) const
- {
- int const* p = program.find_var(x.assign.lhs.name);
- if (p != 0)
- {
- std::cout << x.assign.lhs.id << std::endl;
- error_handler(x.assign.lhs.id, "Duplicate variable: " + x.assign.lhs.name);
- return false;
- }
- bool r = (*this)(x.assign.rhs);
- if (r) // don't add the variable if the RHS fails
- {
- program.add_var(x.assign.lhs.name);
- program.op(op_store, *program.find_var(x.assign.lhs.name));
- }
- return r;
- }
- bool compiler::operator()(ast::statement const& x) const
- {
- return boost::apply_visitor(*this, x);
- }
- bool compiler::operator()(ast::statement_list const& x) const
- {
- BOOST_FOREACH(ast::statement const& s, x)
- {
- if (!(*this)(s))
- return false;
- }
- return true;
- }
- bool compiler::operator()(ast::if_statement const& x) const
- {
- if (!(*this)(x.condition))
- return false;
- program.op(op_jump_if, 0); // we shall fill this (0) in later
- std::size_t skip = program.size()-1; // mark its position
- if (!(*this)(x.then))
- return false;
- program[skip] = program.size()-skip; // now we know where to jump to (after the if branch)
- if (x.else_) // We got an alse
- {
- program[skip] += 2; // adjust for the "else" jump
- program.op(op_jump, 0); // we shall fill this (0) in later
- std::size_t exit = program.size()-1; // mark its position
- if (!(*this)(*x.else_))
- return false;
- program[exit] = program.size()-exit; // now we know where to jump to (after the else branch)
- }
- return true;
- }
- bool compiler::operator()(ast::while_statement const& x) const
- {
- std::size_t loop = program.size(); // mark our position
- if (!(*this)(x.condition))
- return false;
- program.op(op_jump_if, 0); // we shall fill this (0) in later
- std::size_t exit = program.size()-1; // mark its position
- if (!(*this)(x.body))
- return false;
- program.op(op_jump,
- int(loop-1) - int(program.size())); // loop back
- program[exit] = program.size()-exit; // now we know where to jump to (to exit the loop)
- return true;
- }
- bool compiler::start(ast::statement_list const& x) const
- {
- program.clear();
- // op_stk_adj 0 for now. we'll know how many variables we'll have later
- program.op(op_stk_adj, 0);
- if (!(*this)(x))
- {
- program.clear();
- return false;
- }
- program[1] = program.nvars(); // now store the actual number of variables
- return true;
- }
- }}
|