Skip to content

Instantly share code, notes, and snippets.

@jyapayne
Created March 22, 2020 01:13
Show Gist options
  • Save jyapayne/ab2a0745382481bcdb86977ca7149e11 to your computer and use it in GitHub Desktop.
Save jyapayne/ab2a0745382481bcdb86977ca7149e11 to your computer and use it in GitHub Desktop.
Working brainfuck interpreter. Helping drguildo3h on nimforum
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