1 /*=============================================================================
2     Copyright (c) 2001-2011 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/foreach.hpp>
10 #include <boost/variant/apply_visitor.hpp>
11 #include <boost/assert.hpp>
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         std::map<std::string, int>::const_iterator 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] = n;
45     }
46 
print_variables(std::vector<int> const & stack) const47     void program::print_variables(std::vector<int> const& stack) const
48     {
49         typedef std::pair<std::string, int> pair;
50         BOOST_FOREACH(pair const& p, variables)
51         {
52             std::cout << "    " << p.first << ": " << stack[p.second] << std::endl;
53         }
54     }
55 
print_assembler() const56     void program::print_assembler() const
57     {
58         std::vector<int>::const_iterator pc = code.begin();
59 
60         std::vector<std::string> locals(variables.size());
61         typedef std::pair<std::string, int> pair;
62         BOOST_FOREACH(pair const& p, variables)
63         {
64             locals[p.second] = p.first;
65             std::cout << "local       "
66                 << p.first << ", @" << p.second << std::endl;
67         }
68 
69         while (pc != code.end())
70         {
71             switch (*pc++)
72             {
73                 case op_neg:
74                     std::cout << "op_neg" << std::endl;
75                     break;
76 
77                 case op_add:
78                     std::cout << "op_add" << std::endl;
79                     break;
80 
81                 case op_sub:
82                     std::cout << "op_sub" << std::endl;
83                     break;
84 
85                 case op_mul:
86                     std::cout << "op_mul" << std::endl;
87                     break;
88 
89                 case op_div:
90                     std::cout << "op_div" << std::endl;
91                     break;
92 
93                 case op_load:
94                     std::cout << "op_load     " << locals[*pc++] << std::endl;
95                     break;
96 
97                 case op_store:
98                     std::cout << "op_store    " << locals[*pc++] << std::endl;
99                     break;
100 
101                 case op_int:
102                     std::cout << "op_int      " << *pc++ << std::endl;
103                     break;
104 
105                 case op_stk_adj:
106                     std::cout << "op_stk_adj  " << *pc++ << std::endl;
107                     break;
108             }
109         }
110     }
111 
operator ()(unsigned int x) const112     bool compiler::operator()(unsigned int x) const
113     {
114         program.op(op_int, x);
115         return true;
116     }
117 
operator ()(ast::variable const & x) const118     bool compiler::operator()(ast::variable const& x) const
119     {
120         int const* p = program.find_var(x.name);
121         if (p == 0)
122         {
123             std::cout << x.id << std::endl;
124             error_handler(x.id, "Undeclared variable: " + x.name);
125             return false;
126         }
127         program.op(op_load, *p);
128         return true;
129     }
130 
operator ()(ast::operation const & x) const131     bool compiler::operator()(ast::operation const& x) const
132     {
133         if (!boost::apply_visitor(*this, x.operand_))
134             return false;
135         switch (x.operator_)
136         {
137             case '+': program.op(op_add); break;
138             case '-': program.op(op_sub); break;
139             case '*': program.op(op_mul); break;
140             case '/': program.op(op_div); break;
141             default: BOOST_ASSERT(0); return false;
142         }
143         return true;
144     }
145 
operator ()(ast::signed_ const & x) const146     bool compiler::operator()(ast::signed_ const& x) const
147     {
148         if (!boost::apply_visitor(*this, x.operand_))
149             return false;
150         switch (x.sign)
151         {
152             case '-': program.op(op_neg); break;
153             case '+': break;
154             default: BOOST_ASSERT(0); return false;
155         }
156         return true;
157     }
158 
operator ()(ast::expression const & x) const159     bool compiler::operator()(ast::expression const& x) const
160     {
161         if (!boost::apply_visitor(*this, x.first))
162             return false;
163         BOOST_FOREACH(ast::operation const& oper, x.rest)
164         {
165             if (!(*this)(oper))
166                 return false;
167         }
168         return true;
169     }
170 
operator ()(ast::assignment const & x) const171     bool compiler::operator()(ast::assignment const& x) const
172     {
173         if (!(*this)(x.rhs))
174             return false;
175         int const* p = program.find_var(x.lhs.name);
176         if (p == 0)
177         {
178             std::cout << x.lhs.id << std::endl;
179             error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name);
180             return false;
181         }
182         program.op(op_store, *p);
183         return true;
184     }
185 
operator ()(ast::variable_declaration const & x) const186     bool compiler::operator()(ast::variable_declaration const& x) const
187     {
188         int const* p = program.find_var(x.assign.lhs.name);
189         if (p != 0)
190         {
191             std::cout << x.assign.lhs.id << std::endl;
192             error_handler(x.assign.lhs.id, "Duplicate variable: " + x.assign.lhs.name);
193             return false;
194         }
195         bool r = (*this)(x.assign.rhs);
196         if (r) // don't add the variable if the RHS fails
197         {
198             program.add_var(x.assign.lhs.name);
199             program.op(op_store, *program.find_var(x.assign.lhs.name));
200         }
201         return r;
202     }
203 
operator ()(ast::statement_list const & x) const204     bool compiler::operator()(ast::statement_list const& x) const
205     {
206         program.clear();
207 
208         // op_stk_adj 0 for now. we'll know how many variables we'll have later
209         program.op(op_stk_adj, 0);
210         BOOST_FOREACH(ast::statement const& s, x)
211         {
212             if (!boost::apply_visitor(*this, s))
213             {
214                 program.clear();
215                 return false;
216             }
217         }
218         program[1] = program.nvars(); // now store the actual number of variables
219         return true;
220     }
221 }}
222 
223