Created
March 22, 2020 01:13
-
-
Save jyapayne/ab2a0745382481bcdb86977ca7149e11 to your computer and use it in GitHub Desktop.
Working brainfuck interpreter. Helping drguildo3h on nimforum
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
import os | |
import strutils | |
import system | |
import tables | |
var data: array[30_000, byte] | |
# you'll want to use a uint8 here so that a dec() at dataPointer == 0 will | |
# result in dataPointer == 255 instead of -1 with an int type | |
var dataPointer: uint8 = 0 | |
var instructionPointer: int = 0 | |
proc buildBraceMap(code: string): Table[int, int] = | |
# Computes a jump table | |
# | |
# code taken from | |
# https://github.com/pocmo/Python-Brainfuck/blob/master/brainfuck.py | |
result = initTable[int, int]() | |
var tempPosStack: seq[int] | |
var i = 0 | |
for command in code: | |
if command == '[': | |
tempPosStack.add(i) | |
elif command == ']': | |
let start = tempPosStack.pop() | |
result[start] = i | |
result[i] = start | |
i += 1 | |
var braceMap: Table[int, int] | |
proc panic(message: string) = | |
stderr.writeLine("ERROR: " & message) | |
system.quit(-1) | |
proc incrementByte() = | |
inc(data[dataPointer]) | |
proc decrementByte() = | |
dec(data[dataPointer]) | |
proc outputByte() = | |
# Use chr() here to output the character instead of the | |
# number | |
stdout.write(chr(data[dataPointer])) | |
proc incrementDataPointer() = | |
inc(dataPointer) | |
proc decrementDataPointer() = | |
dec(dataPointer) | |
proc conditionalJumpForward() = | |
if data[dataPointer] == 0: | |
instructionPointer = braceMap[instructionPointer] | |
proc conditionalJumpBackwards() = | |
if data[dataPointer] != 0: | |
instructionPointer = braceMap[instructionPointer] | |
proc readByte() = | |
var buf: array[1, byte] | |
let numBytesRead = stdin.readBytes(buf, 0, 1) | |
if numBytesRead != 1: | |
panic("Failed to read byte from stdin.") | |
data[dataPointer] = buf[0] | |
var instructionToProc = { | |
'+': incrementByte, | |
'-': decrementByte, | |
'>': incrementDataPointer, | |
'<': decrementDataPointer, | |
'[': conditionalJumpForward, | |
']': conditionalJumpBackwards, | |
',': readByte, | |
'.': outputByte | |
}.newTable | |
proc main() = | |
# Always put your code in a main proc and call it. It's better style | |
# and it makes the code run faster | |
# Just simplified your code for example. The code you had was fine :) | |
let instructions = paramStr(1).readFile().strip() | |
braceMap = buildBraceMap(instructions) | |
while true: | |
# Code you had here was fine too. This is just a clearer | |
# way to express it | |
if instructionPointer < len(instructions): | |
instructionToProc[instructions[instructionPointer]]() | |
inc(instructionPointer) | |
else: | |
system.quit(0) | |
when isMainModule: | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment