Introduction
Brainfuck is one of the most well-known esoteric programming languages. But it can be hard to understand any code longer that 5 characters. In this kata you have to solve that problem.
Description
In this kata you have to write a function which will do 3 tasks:
Optimize the given Brainfuck code.
Check it for mistakes.
Translate the given Brainfuck programming code into C programming code.
More formally about each of the tasks:
Your function has to remove from the source code all useless command sequences such as: '+-', '<>', '[]'. Also it must erase all characters except +-<>,.[].
Example:
"++--+." -> "+."
"[][+++]" -> "[+++]"
"<>><" -> ""
If the source code contains unpaired braces, your function should return "Error!" string.
Your function must generate a string of the C programming code as follows:
Sequences of the X commands + or - must be replaced by \*p += X;\n or \*p -= X;\n.
Example:
"++++++++++" -> "\*p += 10;\n"
"------" -> "\*p -= 6;\n"
Sequences of the Y commands > or < must be replaced by p += Y;\n or p -= Y;\n.
Example:
">>>>>>>>>>" -> "p += 10;\n"
"<<<<<<" -> "p -= 6;\n"
. command must be replaced by putchar(\*p);\n.
Example:
".." -> "putchar(\*p);\nputchar(\*p);\n"
, command must be replaced by \*p = getchar();\n.
Example:
"," -> "\*p = getchar();\n"
[ command must be replaced by if (\*p) do {\n. ] command must be replaced by } while (\*p);\n.
Example:
"[>>]" ->
if (\*p) do {\n
  p += 2;\n
} while (\*p);\n
Each command in the code block must be shifted 2 spaces to the right accordingly to the previous code block.
Example:
"[>>[<<]]" ->
if (\*p) do {\n
  p += 2;\n
  if (\*p) do {\n
    p -= 2;\n
  } while (\*p);\n
} while (\*p);\n
Examples
Input:
+++++[>++++.<-]
Output:
*p += 5;
if (*p) do {
  p += 1;
  *p += 4;
  putchar(*p);
  p -= 1;
  *p -= 1;
} while (*p);
import re

class Token(object):
    ARITH = 1
    POINTER = 2
    GETCHAR = 3
    PUTCHAR = 4
    OPEN = 5
    CLOSE = 6
    def __init__(self, mode=None, indent=None, value=None):
        self.mode = mode
        self.value = value
        self.indent = indent
    def __str__(self):
        if self.mode == self.ARITH:
            sign = '+' if self.value > 0 else '-'
            return '{}*p {}= {};\n'.format(self.indent, sign, abs(self.value))
        if self.mode == self.POINTER:
            sign = '+' if self.value > 0 else '-'
            return '{}p {}= {};\n'.format(self.indent, sign, abs(self.value))
        if self.mode == self.GETCHAR:
            return self.indent + '*p = getchar();\n'
        if self.mode == self.PUTCHAR:
            return self.indent + 'putchar(*p);\n'
        if self.mode == self.OPEN:
            return self.indent + 'if (*p) do {\n'
        if self.mode == self.CLOSE:
            return self.indent + '} while (*p);\n'
        return ''

class BF(object):
    ARITH = 1
    POINTER = 2
    GETCHAR = 3
    PUTCHAR = 4
    OPEN = 5
    CLOSE = 6
    def __init__(self, source_code):
        self.indent = ''
        self.source_code = source_code
        self.tokens = [Token()]
        self.error = False
        
    def convert_to_c(self):
        try:
            for c in self.source_code:
                self.convert_one_char(c)
        except ValueError:
            return 'Error!'
        if self.indent:
            return 'Error!'
        return ''.join(map(str, self.tokens))
    
    def convert_one_char(self, c):
        if c in '+-':
            if self.tokens[-1].mode != self.ARITH:
                self.tokens.append(Token(self.ARITH, self.indent, 0))
            if c == '+':
                self.tokens[-1].value += 1
            else:
                self.tokens[-1].value -= 1
            if not self.tokens[-1].value:
                del self.tokens[-1]
        elif c in '><':
            if self.tokens[-1].mode != self.POINTER:
                self.tokens.append(Token(self.POINTER, self.indent, 0))
            if c == '>':
                self.tokens[-1].value += 1
            else:
                self.tokens[-1].value -= 1
            if not self.tokens[-1].value:
                del self.tokens[-1]
        elif c == ',':
            self.tokens.append(Token(self.GETCHAR, self.indent, 0))
        elif c == '.':
            self.tokens.append(Token(self.PUTCHAR, self.indent, 0))
        elif c == '[':
            self.tokens.append(Token(self.OPEN, self.indent, 0))
            self.indent += '  '
        elif c == ']':
            if not self.indent:
                raise ValueError
            self.indent = self.indent[:-2]
            if self.tokens[-1].mode == self.OPEN:
                del self.tokens[-1]
            else:
                self.tokens.append(Token(self.CLOSE, self.indent, 0))
    
def brainfuck_to_c(source_code):
    bf = BF(source_code)
    return bf.convert_to_c()
import re

class Token(object):
    ARITH = 1
    POINTER = 2
    GETCHAR = 3
    PUTCHAR = 4
    OPEN = 5
    CLOSE = 6
    def __init__(self, mode=None, indent=None, value=None):
        self.mode = mode
        self.value = value
        self.indent = indent
    def __str__(self):
        if self.mode == self.ARITH:
            sign = '+' if self.value > 0 else '-'
            return '{}*p {}= {};\n'.format(self.indent, sign, abs(self.value))
        if self.mode == self.POINTER:
            sign = '+' if self.value > 0 else '-'
            return '{}p {}= {};\n'.format(self.indent, sign, abs(self.value))
        if self.mode == self.GETCHAR:
            return self.indent + '*p = getchar();\n'
        if self.mode == self.PUTCHAR:
            return self.indent + 'putchar(*p);\n'
        if self.mode == self.OPEN:
            return self.indent + 'if (*p) do {\n'
        if self.mode == self.CLOSE:
            return self.indent + '} while (*p);\n'
        return ''

class BF(object):
    ARITH = 1
    POINTER = 2
    GETCHAR = 3
    PUTCHAR = 4
    OPEN = 5
    CLOSE = 6
    def __init__(self, source_code):
        self.indent = ''
        self.source_code = source_code
        self.tokens = [Token()]
        self.error = False
        
    def convert_to_c(self):
        try:
            for c in self.source_code:
                self.convert_one_char(c)
        except ValueError:
            return 'Error!'
        if self.indent:
            return 'Error!'
        return ''.join(map(str, self.tokens))
    
    def convert_one_char(self, c):
        if c in '+-':
            if self.tokens[-1].mode != self.ARITH:
                self.tokens.append(Token(self.ARITH, self.indent, 0))
            if c == '+':
                self.tokens[-1].value += 1
            else:
                self.tokens[-1].value -= 1
            if not self.tokens[-1].value:
                del self.tokens[-1]
        elif c in '><':
            if self.tokens[-1].mode != self.POINTER:
                self.tokens.append(Token(self.POINTER, self.indent, 0))
            if c == '>':
                self.tokens[-1].value += 1
            else:
                self.tokens[-1].value -= 1
            if not self.tokens[-1].value:
                del self.tokens[-1]
        elif c == ',':
            self.tokens.append(Token(self.GETCHAR, self.indent, 0))
        elif c == '.':
            self.tokens.append(Token(self.PUTCHAR, self.indent, 0))
        elif c == '[':
            self.tokens.append(Token(self.OPEN, self.indent, 0))
            self.indent += '  '
        elif c == ']':
            if not self.indent:
                raise ValueError
            self.indent = self.indent[:-2]
            if self.tokens[-1].mode == self.OPEN:
                del self.tokens[-1]
            else:
                self.tokens.append(Token(self.CLOSE, self.indent, 0))
    
def brainfuck_to_c(source_code):
    bf = BF(source_code)
    return bf.convert_to_c()