Create a gist now

Instantly share code, notes, and snippets.

@LNSEAB /gist:5335399
Last active Dec 15, 2015

What would you like to do?
boostで作ったASTからllvm言語に変換
#include <llvm/IRBuilder.h>
#include <llvm/LLVMContext.h>
#include <llvm/Module.h>
#include <llvm/Support/raw_ostream.h>
#include <stdexcept>
#include <iostream>
#include <memory>
#include <fstream>
#include <functional>
#include <boost/variant.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace ast {
struct add;
struct sub;
struct mul;
struct div;
template <class Op>
struct binary_op;
using expr = boost::variant<
int,
boost::recursive_wrapper< binary_op< add > >,
boost::recursive_wrapper< binary_op< sub > >,
boost::recursive_wrapper< binary_op< mul > >,
boost::recursive_wrapper< binary_op< div > >
>;
template <class Op>
struct binary_op
{
expr lhs;
expr rhs;
binary_op(expr const& lhs_, expr const& rhs_) :
lhs( lhs_ ), rhs( rhs_ )
{ }
};
} // namespace ast
namespace parser {
namespace qi = boost::spirit::qi;
template <class Iterator>
struct arith_grammar :
qi::grammar< Iterator, ast::expr(), qi::ascii::space_type >
{
template <class T>
using rule_t = qi::rule< Iterator, T, qi::ascii::space_type >;
rule_t< ast::expr() > expr;
rule_t< ast::expr() > term;
rule_t< ast::expr() > factor;
arith_grammar() :
arith_grammar::base_type( expr )
{
namespace phx = boost::phoenix;
expr %= term[qi::_val = qi::_1]
>> *(
( '+' >> term[qi::_val = phx::construct< ast::binary_op< ast::add > >( qi::_val, qi::_1 )] )
| ( '-' >> term[qi::_val = phx::construct< ast::binary_op< ast::sub > >( qi::_val, qi::_1 )] )
);
term %= factor[qi::_val = qi::_1]
>> *(
( '*' >> factor[qi::_val = phx::construct< ast::binary_op< ast::mul > >( qi::_val, qi::_1 )] )
| ( '/' >> factor[qi::_val = phx::construct< ast::binary_op< ast::div > >( qi::_val, qi::_1 )] )
);
factor %= qi::int_ | ( '(' >> expr >> ')' )[qi::_val = qi::_1];
}
};
} // namespace parser
class asemmbly :
public boost::static_visitor< llvm::Value* >
{
llvm::IRBuilder<>& builder_;
public:
asemmbly(llvm::IRBuilder<>& builder) :
boost::static_visitor< llvm::Value* >(),
builder_( builder )
{ }
llvm::Value* operator()(int value)
{
return llvm::ConstantInt::get( builder_.getInt32Ty(), value );
}
template <class Op>
llvm::Value* operator()(ast::binary_op< Op > const& op)
{
llvm::Value* lhs = boost::apply_visitor( *this, op.lhs );
llvm::Value* rhs = boost::apply_visitor( *this, op.rhs );
return apply_op( op, lhs, rhs );
}
private:
llvm::Value* apply_op(ast::binary_op< ast::add > const&, llvm::Value* lhs, llvm::Value* rhs)
{
return builder_.CreateAdd( lhs, rhs );
}
llvm::Value* apply_op(ast::binary_op< ast::sub > const&, llvm::Value* lhs, llvm::Value* rhs)
{
return builder_.CreateSub( lhs, rhs );
}
llvm::Value* apply_op(ast::binary_op< ast::mul > const&, llvm::Value* lhs, llvm::Value* rhs)
{
return builder_.CreateMul( lhs, rhs );
}
llvm::Value* apply_op(ast::binary_op< ast::div > const&, llvm::Value* lhs, llvm::Value* rhs)
{
return builder_.CreateSDiv( lhs, rhs );
}
};
std::vector< std::string > read_file(char const* filename)
{
std::ifstream ifs( filename, std::ios::binary );
if( ifs.fail() ) {
return {};
}
std::vector< std::string > result;
for( std::string line; std::getline( ifs, line ); ) {
result.push_back( line );
}
return result;
}
std::string print_llvm_lang(std::unique_ptr< llvm::Module > const& module)
{
std::string result;
llvm::raw_string_ostream stream( result );
module->print( stream, nullptr );
return result;
}
void make_main_func(llvm::LLVMContext& context, std::unique_ptr< llvm::Module >& module, llvm::IRBuilder<>& builder)
{
auto* main_func = llvm::Function::Create(
llvm::FunctionType::get( builder.getInt32Ty(), false ),
llvm::Function::ExternalLinkage,
"main",
module.get()
);
builder.SetInsertPoint( llvm::BasicBlock::Create( context, "entry", main_func ) );
}
llvm::Constant* make_printf(std::unique_ptr< llvm::Module >& module, llvm::IRBuilder<>& builder)
{
std::vector< llvm::Type* > args = {
builder.getInt8Ty()->getPointerTo()
};
return module->getOrInsertFunction(
"printf",
llvm::FunctionType::get( builder.getInt32Ty(), llvm::ArrayRef< llvm::Type* >( args ), true )
);
}
void make_ret_main(llvm::IRBuilder<>& builder)
{
builder.CreateRet( llvm::ConstantInt::get( builder.getInt32Ty(), 0 ) );
}
int main(int argc, char* argv[])
{
try {
if( argc != 2 ) {
throw std::runtime_error( "invalid arguments" );
}
auto const code = read_file( argv[1] );
if( code.empty() ) {
throw std::runtime_error( "cannot read the file" );
}
parser::arith_grammar< std::string::const_iterator > grammar;
std::vector< ast::expr > asts;
int line = 0;
bool err = false;
for( auto const& i : code ) {
ast::expr tree;
++line;
if( !boost::spirit::qi::phrase_parse( i.begin(), i.end(), grammar, boost::spirit::qi::ascii::space, tree ) ) {
std::cerr << argv[1] << ":" << line << ": parse error" << std::endl;
err = true;
continue;
}
asts.push_back( tree );
}
if( err ) {
throw std::runtime_error( "detected errors" );
}
auto& context = llvm::getGlobalContext();
std::unique_ptr< llvm::Module > module( new llvm::Module( "arith", context ) );
llvm::IRBuilder<> builder( context );
make_main_func( context, module, builder );
auto* printf_func = make_printf( module, builder );
auto* format = builder.CreateGlobalStringPtr( "%d\n" );
asemmbly asm_obj( builder );
for( auto const& i : asts ) {
std::vector< llvm::Value* > args = {
format, boost::apply_visitor( asm_obj, i )
};
builder.CreateCall( printf_func, llvm::ArrayRef< llvm::Value* >( args ) );
}
make_ret_main( builder );
std::cout << print_llvm_lang( module );
}
catch( std::exception const& e ) {
std::cerr << e.what() << std::endl;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment