Skip to content

Instantly share code, notes, and snippets.

@indivisible
Created April 2, 2021 09:44
Show Gist options
  • Save indivisible/5a9223374b2030fb7595c6ee4e3d6fce to your computer and use it in GitHub Desktop.
Save indivisible/5a9223374b2030fb7595c6ee4e3d6fce to your computer and use it in GitHub Desktop.
Python Brainfuck interpreter in a generator expression
#!/usr/bin/env python3
'''brainfuck interpreter in a single generator expression
im sorry'''
def bf(code):
all(
# we need to yield *something*
1
# modify this for smaller / larger "memory"
for cells_size in [30000]
# what to do on input past end-of-file:
# None: do not change value of cell
# <any other value>: write this value into the cell
for eof_indicator in [-1]
for imp in [__import__]
for itertools in [imp('itertools')]
for count in [lambda src, pc, offset, ch: src[pc:pc+offset].count(ch)]
for get_skip_size in [imp('functools').lru_cache(None)(lambda src, pc: len(list(itertools.takewhile(lambda offset: count(src, pc, offset, '[') - count(src, pc, offset, ']'), range(1, len(src[pc:]))))))]
for skip_forward in [lambda s: s._replace(pc=s.pc + 1 + get_skip_size(s.src, s.pc))]
for ord_or_default in [lambda ch: (list(ch) + [eof_indicator])[0]]
for os in [imp('os')]
for stdin in [os.fdopen(os.dup(imp('sys').stdin.fileno()), 'rb', buffering=0)]
for getch in [lambda: ord_or_default(stdin.read(1))]
for input_maybe_store in [lambda s, ch: ch is not None and s.mem.__setitem__(s.idx, ch % 256)]
for ops in [{
'+': lambda s: s.mem.__setitem__(s.idx, (s.mem[s.idx]+1) % 256) or s._replace(pc=s.pc+1),
'-': lambda s: s.mem.__setitem__(s.idx, (s.mem[s.idx]-1) % 256) or s._replace(pc=s.pc+1),
'>': lambda s: s._replace(pc=s.pc+1, idx=(s.idx+1) % len(s.mem)),
'<': lambda s: s._replace(pc=s.pc+1, idx=(s.idx-1) % len(s.mem)),
'.': lambda s: print(chr(s.mem[s.idx]), end='') or s._replace(pc=s.pc+1),
',': lambda s: input_maybe_store(s, getch()) or s._replace(pc=s.pc+1),
'[': lambda s: (s.mem[s.idx] and s._replace(pc=s.pc+1, stack=(s.pc,)+s.stack)) or skip_forward(s),
']': lambda s: s._replace(pc=s.stack[0], stack=s.stack[1:])
}]
# ignore not valid operation characters in input
for valid_code in [tuple(c for c in code if c in ops)]
for state in [imp('collections').namedtuple('State', ('src', 'mem', 'pc', 'idx', 'stack'))(valid_code, [0]*cells_size, 0, 0, tuple())]
# loop until the program counter reaches the end of the program
for _ in itertools.takewhile(lambda _: state.pc < len(state.src), itertools.cycle([0]))
# perform the next operation
for state in [ops[state.src[state.pc]](state)]
)
badhello = '+[-[<<[+[--->]-[<<<]]]>>>-]>-.---.>..>.<<<<-.<+.>>>>>.>.<<.<-.'
# shift = ',[+.,]'
rot13 = '''+[,+[-[>+>+<<-]>[<+>-]+>>++++++++[<-------->-]<-[<[-]>>>+[<+<+>>-]<[>+<-]<[<++>
>>+[<+<->>-]<[>+<-]]>[<]<]>>[-]<<<[[-]<[>>+>+<<<-]>>[<<+>>-]>>++++++++[<-------
->-]<->>++++[<++++++++>-]<-<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<<<<+>>>>++++[<++++++++
>-]>-]<<-<-]>[<<<<[-]>>>>[<<<<->>>>-]]<<++++[<<++++++++>>-]<<-[>>+>+<<<-]>>[<<+
>>-]+>>+++++[<----->-]<-[<[-]>>>+[<+<->>-]<[>+<-]<[<++>>>+[<+<+>>-]<[>+<-]]>[<]
<]>>[-]<<<[[-]<<[>>+>+<<<-]>>[<<+>>-]+>------------[<[-]>>>+[<+<->>-]<[>+<-]<[<
++>>>+[<+<+>>-]<[>+<-]]>[<]<]>>[-]<<<<<------------->>[[-]+++++[<<+++++>>-]<<+>
>]<[>++++[<<++++++++>>-]<-]>]<[-]++++++++[<++++++++>-]<+>]<.[-]+>>+<]>[[-]<]<]'''
if __name__ == '__main__':
hello = '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++..'
test_programs = [hello, badhello, rot13]
for prog in test_programs:
bf(prog)
print()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment