|
|
|
//
|
|
|
|
// brainfuck.hpp
|
|
|
|
//
|
|
|
|
// Created by Joshua Moerman on 05/22/11.
|
|
|
|
// Copyright 2011 Vadovas. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
/*
|
|
|
|
T is the memory-type (normally bytes aka char)
|
|
|
|
OutputIterator is where to write (normally cout)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef BRAINFUCK_HPP
|
|
|
|
#define BRAINFUCK_HPP
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <iterator>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
namespace brainfuck_details {
|
|
|
|
|
|
|
|
// recursive funtion (from http://www.xs4all.nl/~weegen/eelis/geordi/) but templated
|
|
|
|
template <typename T, typename InputIterator, typename OutputIterator>
|
|
|
|
void b(char * c, InputIterator& in, T * & p, OutputIterator out){
|
|
|
|
for(; *c && *c != ']'; ++c) {
|
|
|
|
switch(*c){
|
|
|
|
case '>' : ++p; break;
|
|
|
|
case '<' : --p; break;
|
|
|
|
case '+' : ++*p; break;
|
|
|
|
case '-' : --*p; break;
|
|
|
|
case '.' : *out++ = *p; break;
|
|
|
|
case ',' : *p = *in++; break;
|
|
|
|
case '[' :
|
|
|
|
for(++c; *p;) b(c, in, p, out);
|
|
|
|
for(int d = 0; *c!=']' || d--; ++c) if(*c == '[') d++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// normally we want a comma between values
|
|
|
|
template <typename T>
|
|
|
|
std::ostream_iterator<T> default_ostream_iterator(std::ostream& os = std::cout){
|
|
|
|
return std::ostream_iterator<T>(os, ", ");
|
|
|
|
}
|
|
|
|
|
|
|
|
// except for char's
|
|
|
|
template <>
|
|
|
|
std::ostream_iterator<char> default_ostream_iterator<char>(std::ostream& os){
|
|
|
|
return std::ostream_iterator<char>(os);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Would be better if we used a smarter iterator for p... it is of fixed size now :(
|
|
|
|
template <typename T = char, typename OutputIterator = std::ostream_iterator<T>>
|
|
|
|
void brainfuck(std::string prg, std::basic_string<T> inp = std::basic_string<T>(), OutputIterator it = brainfuck_details::default_ostream_iterator<T>()) {
|
|
|
|
char * c = new char[prg.length() + 1];
|
|
|
|
std::copy(prg.begin(), prg.end(), c);
|
|
|
|
|
|
|
|
T * i = new T[inp.length() + 1];
|
|
|
|
std::copy(inp.begin(), inp.end(), i);
|
|
|
|
|
|
|
|
T * p = new T[512];
|
|
|
|
std::fill_n(p, 512, T(0));
|
|
|
|
|
|
|
|
brainfuck_details::b(c,i,p,it);
|
|
|
|
}
|
|
|
|
|
|
|
|
// we can't put a default on the InputIterator, because that would be ambigious
|
|
|
|
template <typename T = char, typename InputIterator = std::istream_iterator<T>, typename OutputIterator = std::ostream_iterator<T>>
|
|
|
|
void brainfuck(std::string prg, InputIterator inp, OutputIterator it = brainfuck_details::default_ostream_iterator<T>()) {
|
|
|
|
char * c = new char[prg.length() + 1];
|
|
|
|
std::copy(prg.begin(), prg.end(), c);
|
|
|
|
|
|
|
|
T * p = new T[512];
|
|
|
|
std::fill_n(p, 512, T(0));
|
|
|
|
|
|
|
|
brainfuck_details::b(c,inp,p,it);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // BRAINFUCK_HPP
|