Created
September 22, 2011 10:14
-
-
Save kiritsuku/1234474 to your computer and use it in GitHub Desktop.
A brainfuck compiler implemented with TMP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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