Skip to content

Instantly share code, notes, and snippets.

@kiritsuku
Created September 22, 2011 10:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kiritsuku/1234474 to your computer and use it in GitHub Desktop.
Save kiritsuku/1234474 to your computer and use it in GitHub Desktop.
A brainfuck compiler implemented with TMP
/*
* TMP brainfuck compiler
*
* compile with: g++ -std=c++0x -Wall -Wextra -ftemplate-depth=2000 <file>.cpp
* compile version: g++ >= 4.6.1
*/
#include <cstddef>
#include <cstdio>
#include <utility>
#include <type_traits>
#include <boost/mpl/at.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/has_key.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/map.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/vector.hpp>
using boost::mpl::at;
using boost::mpl::if_;
using boost::mpl::if_c;
using boost::mpl::front;
using boost::mpl::has_key;
using boost::mpl::identity;
using boost::mpl::map;
using boost::mpl::pair;
using boost::mpl::pop_front;
using boost::mpl::push_front;
using boost::mpl::vector;
constexpr char source[] = // Hello world von wikipedia
"+++++ +++++ initialize counter (cell #0) to 10"
"[ use loop to set the next four cells to 70/100/30/10"
" > +++++ ++ add 7 to cell #1"
" > +++++ +++++ add 10 to cell #2"
" > +++ add 3 to cell #3"
" > + add 1 to cell #4"
" <<<< - decrement counter (cell #0)"
"]"
"> ++ . print 'H'"
"> + . print 'e'"
"+++++ ++ . print 'l'"
". print 'l'"
"+++ . print 'o'"
"> ++ . print ' '"
"<< +++++ +++++ +++++ . print 'W'"
"> . print 'o'"
"+++ . print 'r'"
"----- - . print 'l'"
"----- --- . print 'd'"
"> + . print '!'"
"> . print '\n'";
template <std::ptrdiff_t N> struct mod_ptr_cmd { template <typename Env> static void run(Env& env) { env.ptr += N; } };
template <unsigned char N> struct mod_data_cmd { template <typename Env> static void run(Env& env) { *env.ptr += N; } };
struct get_cmd { template <typename Env> static void run(Env& env) { *env.ptr = std::getchar(); } };
struct put_cmd { template <typename Env> static void run(Env& env) { std::putchar( *env.ptr ); } };
struct block_begin { template <typename Env> static void run(Env&) {} };
struct block_end { template <typename Env> static void run(Env&) {} };
typedef map<
pair<std::integral_constant<char, '>'>, mod_ptr_cmd<1>>,
pair<std::integral_constant<char, '<'>, mod_ptr_cmd<-1>>,
pair<std::integral_constant<char, '+'>, mod_data_cmd<1>>,
pair<std::integral_constant<char, '-'>, mod_data_cmd<-1>>,
pair<std::integral_constant<char, ','>, get_cmd>,
pair<std::integral_constant<char, '.'>, put_cmd>,
pair<std::integral_constant<char, '['>, block_begin>,
pair<std::integral_constant<char, ']'>, block_end>> commands;
template <typename Command, char... Tail> struct fuse;
template <typename Command, typename Next, char... Tail> struct compile
: compile<Next, void, Tail...>
{
template <typename Env> static void run(Env& env)
{
Command::run( env );
compile<Next, void, Tail...>::run( env );
}
};
template <typename Command, char... Tail> struct compile<Command, void, Tail...>
: fuse<Command, Tail...> {};
template <char... Tail> struct compile<block_begin, void, Tail...>
{
typedef compile<void, void, Tail...> base;
typedef typename front<typename base::tails>::type this_tail;
typedef typename pop_front<typename base::tails>::type tails;
template <typename Env> static void run(Env& env)
{
while ( *env.ptr != 0 )
{
base::run( env );
}
this_tail::run( env );
}
};
template <char... Tail> struct compile<block_end, void, Tail...>
{
typedef compile<void, void, Tail...> base;
typedef typename push_front<typename base::tails, base>::type tails;
template <typename Env> static void run(Env&) {}
};
template <typename T, typename U> struct fuse_command
: pair<T, U> {};
template <std::ptrdiff_t a, std::ptrdiff_t b> struct fuse_command<mod_ptr_cmd<a>, mod_ptr_cmd<b>>
: pair<mod_ptr_cmd<a+b>, void> {};
template <unsigned char a, unsigned char b> struct fuse_command<mod_data_cmd<a>, mod_data_cmd<b>>
: pair<mod_data_cmd<a+b>, void> {};
template <typename U> struct fuse_command<void, U>
: pair<U, void> {};
template <typename Command, char c, char... Tail> struct fuse<Command, c, Tail...>
: compile<
typename fuse_command<Command, typename if_<has_key<commands, std::integral_constant<char, c>>, typename at<commands, std::integral_constant<char, c>>::type, void>::type>::first,
typename fuse_command<Command, typename if_<has_key<commands, std::integral_constant<char, c>>, typename at<commands, std::integral_constant<char, c>>::type, void>::type>::second,
Tail...> {};
template <typename Command> struct fuse<Command>
{
typedef vector<> tails;
template <typename Env> static void run(Env& env) { Command::run( env ); }
};
template <> struct fuse<void>
{
typedef vector<> tails;
template <typename Env> static void run(Env&) {}
};
template <char... src> struct program
{
template <typename Env> static void run(Env& env) { compile<void, void, src...>::run( env ); }
};
template <std::size_t... i> struct indexes
: identity<indexes<i...>> {};
template <typename T, typename U> struct concat
: concat<typename T::type, typename U::type> {};
template <std::size_t... i, std::size_t... j> struct concat<indexes<i...>, indexes<j...>>
: indexes<i..., ( j + sizeof... i )...> {};
template <typename T> struct twice
: concat<T, T> {};
template <std::size_t N> struct make_indexes
: concat<twice<make_indexes<(N / 2)>>, if_c<(N % 2 == 1), indexes<0>, indexes<>>> {};
template <> struct make_indexes<0>
: indexes<> {};
template <typename = typename make_indexes<sizeof source - 1>::type> struct source_to_program;
template <std::size_t... i> struct source_to_program<indexes<i...>>
: identity<program<source[ i ]...>> {};
struct Environment
{
unsigned char data[32768];
unsigned char* ptr;
};
int main()
{
Environment env = { {}, env.data };
source_to_program<>::type p;
p.run( env );
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment