Created
April 2, 2021 09:44
-
-
Save indivisible/5a9223374b2030fb7595c6ee4e3d6fce to your computer and use it in GitHub Desktop.
Python Brainfuck interpreter in a generator expression
This file contains 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
#!/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