/*============================================================================= 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 #include #include #include #include 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::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 const& stack) const { typedef std::pair pair; BOOST_FOREACH(pair const& p, variables) { std::cout << " " << p.first << ": " << stack[p.second] << std::endl; } } void program::print_assembler() const { std::vector::const_iterator pc = code.begin(); std::vector locals(variables.size()); typedef std::pair pair; BOOST_FOREACH(pair const& p, variables) { locals[p.second] = p.first; std::cout << " local " << p.first << ", @" << p.second << std::endl; } std::map lines; std::set 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 += boost::lexical_cast(locals[*pc++]); break; case op_store: line += " op_store "; line += boost::lexical_cast(locals[*pc++]); break; case op_int: line += " op_int "; line += boost::lexical_cast(*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(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(pos); jumps.insert(pos); } break; case op_stk_adj: line += " op_stk_adj "; line += boost::lexical_cast(*pc++); break; } lines[address] = line; } std::cout << "start:" << std::endl; typedef std::pair 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; } }}