#include <iostream>
#include <cstring>
#include <fstream>
#include <sstream>

class brainfuck
{
    private:
        size_t _size;
        size_t _dp;
        char* _data;
        
        void check_size(){
            if (_dp >= _size)
            {
                char* tmp = new char[_size * 2];
                std::memset(tmp, 0, _size * 2);
                std::memcpy(tmp, _data, _size);
                _size = _size * 2;
                delete[] _data;
                _data = tmp;
            }
        }
    public:
        brainfuck(): _size(30000), _dp(0), _data(new char[_size])
        {
            std::memset(_data, 0, _size);
        }
        
        void increment_dp()
        {
            _dp++;
        }
        
        void decrement_dp()
        {
            if (_dp != 0)
                _dp--;
        }
        
        void increment()
        {
            check_size();
            _data[_dp]++;
        }
        
        void decrement(){
            check_size();
            _data[_dp]--;
        }
        
        void print(){
            std::cout << _data[_dp];
        }
        
        void read(){
            std::cin >> _data[_dp];
        }
        
        char is(){
            return _data[_dp];
        }
};

template<typename functor>
void match(functor f, int sp, size_t& index, const std::string& program){
    
    while (f(index) < program.size()){
        if (program[index] == '[')
            sp++;
        if (program[index] == ']')
            sp--;
        if (sp == 0)
            break;
    }
}

int main()
{
    std::ifstream bf("../bf.bf");
    std::stringstream buffer;
    buffer << bf.rdbuf();
    auto program = buffer.str();
    
    brainfuck fuck;
    
    size_t index = 0;
    while (index < program.size()){
        auto c = program[index];
        switch (c){
            case '>':
                fuck.increment_dp();
                break;
            case '<':
                fuck.decrement_dp();
                break;
            case '+':
                fuck.increment();
                break;
            case '-':
                fuck.decrement();
                break;
            case '.':
                fuck.print();
                break;
            case ',':
                fuck.read();
                break;
            case '[':
                if (fuck.is() == 0)
                    match([](size_t& idx){return ++idx;}, 1, index, program);
                break;
            case ']':
                if (fuck.is() != 0)
                    match([](size_t& idx){return --idx;}, -1, index, program);
                break;
            default:
                break;
        }
        index++;
    }
    
    return 0;
}