1 /*============================================================================= 2 Copyright (c) 2001-2014 Joel de Guzman 3 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" 8 #include "vm.hpp" 9 #include <boost/variant/apply_visitor.hpp> 10 #include <boost/assert.hpp> 11 #include <iostream> 12 13 namespace client { namespace code_gen 14 { op(int a)15 void program::op(int a) 16 { 17 code.push_back(a); 18 } 19 op(int a,int b)20 void program::op(int a, int b) 21 { 22 code.push_back(a); 23 code.push_back(b); 24 } 25 op(int a,int b,int c)26 void program::op(int a, int b, int c) 27 { 28 code.push_back(a); 29 code.push_back(b); 30 code.push_back(c); 31 } 32 find_var(std::string const & name) const33 int const* program::find_var(std::string const& name) const 34 { 35 auto i = variables.find(name); 36 if (i == variables.end()) 37 return 0; 38 return &i->second; 39 } 40 add_var(std::string const & name)41 void program::add_var(std::string const& name) 42 { 43 std::size_t n = variables.size(); 44 variables[name] = int(n); 45 } 46 print_variables(std::vector<int> const & stack) const47 void program::print_variables(std::vector<int> const& stack) const 48 { 49 for (auto const& p : variables) 50 { 51 std::cout << " " << p.first << ": " << stack[p.second] << std::endl; 52 } 53 } 54 print_assembler() const55 void program::print_assembler() const 56 { 57 auto pc = code.begin(); 58 59 std::vector<std::string> locals(variables.size()); 60 typedef std::pair<std::string, int> pair; 61 for (pair const& p : variables) 62 { 63 locals[p.second] = p.first; 64 std::cout << "local " 65 << p.first << ", @" << p.second << std::endl; 66 } 67 68 while (pc != code.end()) 69 { 70 switch (*pc++) 71 { 72 case op_neg: 73 std::cout << "op_neg" << std::endl; 74 break; 75 76 case op_add: 77 std::cout << "op_add" << std::endl; 78 break; 79 80 case op_sub: 81 std::cout << "op_sub" << std::endl; 82 break; 83 84 case op_mul: 85 std::cout << "op_mul" << std::endl; 86 break; 87 88 case op_div: 89 std::cout << "op_div" << std::endl; 90 break; 91 92 case op_load: 93 std::cout << "op_load " << locals[*pc++] << std::endl; 94 break; 95 96 case op_store: 97 std::cout << "op_store " << locals[*pc++] << std::endl; 98 break; 99 100 case op_int: 101 std::cout << "op_int " << *pc++ << std::endl; 102 break; 103 104 case op_stk_adj: 105 std::cout << "op_stk_adj " << *pc++ << std::endl; 106 break; 107 } 108 } 109 } 110 operator ()(unsigned int x) const111 bool compiler::operator()(unsigned int x) const 112 { 113 program.op(op_int, x); 114 return true; 115 } 116 operator ()(ast::variable const & x) const117 bool compiler::operator()(ast::variable const& x) const 118 { 119 int const* p = program.find_var(x.name); 120 if (p == 0) 121 { 122 error_handler(x, "Undeclared variable: " + x.name); 123 return false; 124 } 125 program.op(op_load, *p); 126 return true; 127 } 128 operator ()(ast::operation const & x) const129 bool compiler::operator()(ast::operation const& x) const 130 { 131 if (!boost::apply_visitor(*this, x.operand_)) 132 return false; 133 switch (x.operator_) 134 { 135 case '+': program.op(op_add); break; 136 case '-': program.op(op_sub); break; 137 case '*': program.op(op_mul); break; 138 case '/': program.op(op_div); break; 139 default: BOOST_ASSERT(0); return false; 140 } 141 return true; 142 } 143 operator ()(ast::signed_ const & x) const144 bool compiler::operator()(ast::signed_ const& x) const 145 { 146 if (!boost::apply_visitor(*this, x.operand_)) 147 return false; 148 switch (x.sign) 149 { 150 case '-': program.op(op_neg); break; 151 case '+': break; 152 default: BOOST_ASSERT(0); return false; 153 } 154 return true; 155 } 156 operator ()(ast::expression const & x) const157 bool compiler::operator()(ast::expression const& x) const 158 { 159 if (!boost::apply_visitor(*this, x.first)) 160 return false; 161 for (ast::operation const& oper : x.rest) 162 { 163 if (!(*this)(oper)) 164 return false; 165 } 166 return true; 167 } 168 operator ()(ast::assignment const & x) const169 bool compiler::operator()(ast::assignment const& x) const 170 { 171 if (!(*this)(x.rhs)) 172 return false; 173 int const* p = program.find_var(x.lhs.name); 174 if (p == 0) 175 { 176 error_handler(x.lhs, "Undeclared variable: " + x.lhs.name); 177 return false; 178 } 179 program.op(op_store, *p); 180 return true; 181 } 182 operator ()(ast::variable_declaration const & x) const183 bool compiler::operator()(ast::variable_declaration const& x) const 184 { 185 int const* p = program.find_var(x.assign.lhs.name); 186 if (p != 0) 187 { 188 error_handler(x.assign.lhs, "Duplicate variable: " + x.assign.lhs.name); 189 return false; 190 } 191 bool r = (*this)(x.assign.rhs); 192 if (r) // don't add the variable if the RHS fails 193 { 194 program.add_var(x.assign.lhs.name); 195 program.op(op_store, *program.find_var(x.assign.lhs.name)); 196 } 197 return r; 198 } 199 operator ()(ast::statement_list const & x) const200 bool compiler::operator()(ast::statement_list const& x) const 201 { 202 program.clear(); 203 204 // op_stk_adj 0 for now. we'll know how many variables we'll have later 205 program.op(op_stk_adj, 0); 206 for (ast::statement const& s : x) 207 { 208 if (!boost::apply_visitor(*this, s)) 209 { 210 program.clear(); 211 return false; 212 } 213 } 214 program[1] = int(program.nvars()); // now store the actual number of variables 215 return true; 216 } 217 }} 218