SHOW:
|
|
- or go back to the newest paste.
| 1 | # Brainfox: A brainf*ck interpreter for microbit. | |
| 2 | # (C) 2017 Alynna Trypnotk, GPL3 | |
| 3 | # Be selective here to save RAM | |
| 4 | from microbit import uart, display, button_a, button_b, sleep, Image, reset | |
| 5 | from gc import collect, mem_free | |
| 6 | from os import remove | |
| 7 | collect() # DEFPROG is Hello World. These strings are defined here to get them in flash, not RAM. | |
| 8 | DEFPROG = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++." | |
| 9 | PROGNAME = "prog.bf" | |
| 10 | INPUTNAME = "input.bf" | |
| 11 | PRIMS = "+-<>[],.#|" | |
| 12 | PRAGMA = "FX" # Default PRAGMA and DELAY. | |
| 13 | DELAY = 100 # You can set these freely. | |
| 14 | CELLS = 256 # CELLS available. This is configurabale | |
| 15 | # and will cost its value in bytes. | |
| 16 | def receive(): | |
| 17 | global PRAGMA | |
| 18 | print("* Enter program, [/ ENTER] to submit *")
| |
| 19 | DC = 0 | |
| 20 | getProg = 2 | |
| 21 | while True: | |
| 22 | AC = str(input()) | |
| 23 | if getProg == 2: # Prevents null programs. | |
| 24 | file = open(PROGNAME, "wt") | |
| 25 | getProg = 1 | |
| 26 | if AC[0] == '/': | |
| 27 | PRAGMA = AC[1:].upper() if len(AC)>1 else PRAGMA | |
| 28 | break | |
| 29 | if AC[0] == '_': | |
| 30 | getProg = 0 | |
| 31 | file.close() | |
| 32 | file = open(INPUTNAME, "wt") | |
| 33 | DC = 0 | |
| 34 | continue | |
| 35 | if getProg: AC = ''.join([x for x in AC if x in PRIMS]) | |
| 36 | DC += len(AC) | |
| 37 | file.write(str(AC)) | |
| 38 | print(DC) | |
| 39 | collect() | |
| 40 | file.close() | |
| 41 | if button_a.is_pressed(): | |
| 42 | try: | |
| 43 | remove(PROGNAME) | |
| 44 | remove(INPUTNAME) | |
| 45 | except: pass | |
| 46 | display.show(Image.PACMAN, wait=False) | |
| 47 | receive() | |
| 48 | reset() | |
| 49 | def get_input(): | |
| 50 | if "R" in PRAGMA: | |
| 51 | while not uart.any(): sleep(1) | |
| 52 | return str(uart.read(1),"ascii"); | |
| 53 | else: | |
| 54 | x = file.read(1) | |
| 55 | return '\0' if x == "" else x | |
| 56 | def bfprint(c): | |
| 57 | print(chr(c),sep='',end='') | |
| 58 | if not "T" in PRAGMA: | |
| 59 | display.show(chr(c) if c>32 else " ") | |
| 60 | sleep(DELAY) | |
| 61 | def leppard(): | |
| 62 | try: | |
| 63 | print("CP:",repr(cell[0:CP+8])[11:-1])
| |
| 64 | except: | |
| 65 | print("CP:",repr(cell[CP-8:CP+8])[11:-1])
| |
| 66 | def debug(): | |
| 67 | print("{0}PC={1} CP={2} [CP]={3} LV={4} {5}#{6}: {7}"
| |
| 68 | .format("["*len(stack), PC, CP, cell[CP], LEVEL, repr(stack),
| |
| 69 | len(stack), "END OF LINE" if PC>=len(prog) else prog[PC])) | |
| 70 | if "C" in PRAGMA: leppard() | |
| 71 | def crash(text): | |
| 72 | global CRASHED | |
| 73 | CRASHED = True | |
| 74 | print("\n[ERROR]",text,"... Debugging.")
| |
| 75 | display.show(Image.HEART,wait=False) | |
| 76 | try: | |
| 77 | prog = open(PROGNAME).read() | |
| 78 | except Exception as e: | |
| 79 | prog = DEFPROG | |
| 80 | with open(PROGNAME,"wt") as f: f.write(prog) | |
| 81 | print("{0}. Using Hello World.\n".format(e))
| |
| 82 | reset() | |
| 83 | CRASHED = False # Semaphore indicating an interpreter error. | |
| 84 | LEVEL = 0 # When zero, we are executing primitives. | |
| 85 | # When non-zero, we are seeking our matching ] | |
| 86 | PC = 0 # Program Counter | |
| 87 | CP = 0 # Cell Pointer | |
| 88 | cell = bytearray(CELLS) # Fixed memory of byte sized cells. | |
| 89 | stack = [] # [] stack. Allocate last because it grows and shrinks. | |
| 90 | uart.init(115200) | |
| 91 | print("Brainfox Initalized.")
| |
| 92 | if button_b.is_pressed(): | |
| 93 | PRAGMA = input("Pragmas: ").upper()
| |
| 94 | if not "R" in PRAGMA: | |
| 95 | try: | |
| 96 | file = open(INPUTNAME) | |
| 97 | except: | |
| 98 | PRAGMA += "R" | |
| 99 | DEBUG = "D" in PRAGMA | |
| 100 | if "F" in PRAGMA: DELAY = 0 | |
| 101 | display.show(Image.HAPPY, wait=False) | |
| 102 | collect() | |
| 103 | print("Prog size: {0}; Free: {1}B ({2} stk)".format(len(prog),mem_free(),int(mem_free()/4)))
| |
| 104 | while True: | |
| 105 | if PC >= len(prog): | |
| 106 | if LEVEL: crash("Unbalanced [")
| |
| 107 | break | |
| 108 | if DEBUG or button_a.is_pressed(): debug() | |
| 109 | if "T" in PRAGMA: | |
| 110 | display.show(prog[PC]) | |
| 111 | sleep(DELAY) | |
| 112 | if prog[PC] in "[]": | |
| 113 | if prog[PC] == "[": | |
| 114 | stack += [PC] | |
| 115 | if cell[CP] == 0 and not LEVEL: | |
| 116 | LEVEL = len(stack) | |
| 117 | else: | |
| 118 | if not (cell[CP] == 0) and not LEVEL: | |
| 119 | PC = stack[-1]+1 | |
| 120 | continue | |
| 121 | if stack == []: | |
| 122 | crash("Unbalanced ]")
| |
| 123 | break | |
| 124 | else: | |
| 125 | stack = stack[:-1] | |
| 126 | if len(stack) < LEVEL: LEVEL = 0 | |
| 127 | if DEBUG: debug() | |
| 128 | if not LEVEL: | |
| 129 | if prog[PC] == ">": | |
| 130 | CP +=1 | |
| 131 | if CP+1 >= CELLS: CP = 0 | |
| 132 | elif prog[PC] == "<": | |
| 133 | CP -= 1 | |
| 134 | if CP < 0: CP = CELLS - 1 | |
| 135 | elif prog[PC] == "+": | |
| 136 | cell[CP] = cell[CP] + 1 | |
| 137 | elif prog[PC] == "-": | |
| 138 | cell[CP] = cell[CP] - 1 | |
| 139 | elif prog[PC] == ",": | |
| 140 | cell[CP] = ord(get_input()) | |
| 141 | elif prog[PC] == ".": | |
| 142 | bfprint(cell[CP]) | |
| 143 | elif "X" in PRAGMA and prog[PC] == "#": | |
| 144 | DEBUG = not DEBUG | |
| 145 | elif "X" in PRAGMA and prog[PC] == "|": | |
| 146 | sleep(DELAY) | |
| 147 | if CRASHED or button_b.is_pressed(): | |
| 148 | break | |
| 149 | else: | |
| 150 | PC+=1 | |
| 151 | try: file.close() | |
| 152 | except: pass | |
| 153 | print("\n--")
| |
| 154 | debug() | |
| 155 | leppard() | |
| 156 | print("* Game Over. Hold A to upload or press B to reset *")
| |
| 157 | while not button_a.is_pressed() and not button_b.is_pressed(): sleep(10) | |
| 158 | reset() |