spirit/example/x3/calc/calc8/compiler.cpp
2017-12-17 20:14:56 +03:00

218 lines
5.9 KiB
C++

/*=============================================================================
Copyright (c) 2001-2014 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/variant/apply_visitor.hpp>
#include <boost/assert.hpp>
#include <iostream>
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
{
auto 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] = int(n);
}
void program::print_variables(std::vector<int> const& stack) const
{
for (auto const& p : variables)
{
std::cout << " " << p.first << ": " << stack[p.second] << std::endl;
}
}
void program::print_assembler() const
{
auto pc = code.begin();
std::vector<std::string> locals(variables.size());
typedef std::pair<std::string, int> pair;
for (pair const& p : variables)
{
locals[p.second] = p.first;
std::cout << "local "
<< p.first << ", @" << p.second << std::endl;
}
while (pc != code.end())
{
switch (*pc++)
{
case op_neg:
std::cout << "op_neg" << std::endl;
break;
case op_add:
std::cout << "op_add" << std::endl;
break;
case op_sub:
std::cout << "op_sub" << std::endl;
break;
case op_mul:
std::cout << "op_mul" << std::endl;
break;
case op_div:
std::cout << "op_div" << std::endl;
break;
case op_load:
std::cout << "op_load " << locals[*pc++] << std::endl;
break;
case op_store:
std::cout << "op_store " << locals[*pc++] << std::endl;
break;
case op_int:
std::cout << "op_int " << *pc++ << std::endl;
break;
case op_stk_adj:
std::cout << "op_stk_adj " << *pc++ << std::endl;
break;
}
}
}
bool compiler::operator()(unsigned int x) const
{
program.op(op_int, x);
return true;
}
bool compiler::operator()(ast::variable const& x) const
{
int const* p = program.find_var(x.name);
if (p == 0)
{
error_handler(x, "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 '+': program.op(op_add); break;
case '-': program.op(op_sub); break;
case '*': program.op(op_mul); break;
case '/': program.op(op_div); break;
default: BOOST_ASSERT(0); return false;
}
return true;
}
bool compiler::operator()(ast::signed_ const& x) const
{
if (!boost::apply_visitor(*this, x.operand_))
return false;
switch (x.sign)
{
case '-': program.op(op_neg); break;
case '+': 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;
for (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)
{
error_handler(x.lhs, "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)
{
error_handler(x.assign.lhs, "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_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);
for (ast::statement const& s : x)
{
if (!boost::apply_visitor(*this, s))
{
program.clear();
return false;
}
}
program[1] = int(program.nvars()); // now store the actual number of variables
return true;
}
}}