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