Created
March 15, 2016 17:09
-
-
Save Danappelxx/86031868034f6a5306ea to your computer and use it in GitHub Desktop.
A simple recursive Brainfuck parser & interpreter (`,` not supported).
This file contains hidden or 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
extension String { | |
subscript(safe index: String.CharacterView.Index) -> Character? { | |
guard index < endIndex else { return nil } | |
return self[index] | |
} | |
} | |
public final class Brainfuck { | |
public enum Token { | |
case IncrementPointer | |
case DecrementPointer | |
case IncrementByte | |
case DecrementByte | |
case Print | |
case Loop([Token]) | |
public var description: String { | |
switch self { | |
case .IncrementPointer: return ">" | |
case .DecrementPointer: return "<" | |
case .IncrementByte: return "+" | |
case .DecrementByte: return"-" | |
case .Print: return "." | |
case .Loop(let tokens): return "[" + tokens.map { $0.description }.reduce("", combine: +) + "]" | |
} | |
} | |
} | |
public private(set) var pointer = 0 | |
public private(set) var cells = [Int](count: 100, repeatedValue: 0) | |
let tokens: [Token] | |
public init(tokens: [Token]) { | |
self.tokens = tokens | |
} | |
public convenience init(input: String) { | |
self.init(tokens: Brainfuck.parse(input)) | |
} | |
public func evaluate() -> [Int] { | |
return self.evaluate(tokens: self.tokens) | |
} | |
private func evaluate(tokens tokens: [Token]) -> [Int] { | |
var output = [Int]() | |
for token in tokens { | |
switch token { | |
case .IncrementPointer: pointer += 1 | |
case .DecrementPointer: pointer -= 1 | |
case .IncrementByte: cells[pointer] += 1 | |
case .DecrementByte: cells[pointer] -= 1 | |
case .Print: output.append(cells[pointer]) | |
case .Loop(let loop): | |
while cells[pointer] != 0 { | |
evaluate(tokens: loop) | |
} | |
} | |
} | |
return output | |
} | |
static func parse(input: String) -> [Token] { | |
var index = input.startIndex | |
var tokens = [Token]() | |
while let char = input[safe: index] { | |
switch char { | |
case ".": tokens.append(.Print) | |
case ">": tokens.append(.IncrementPointer) | |
case "<": tokens.append(.DecrementPointer) | |
case "+": tokens.append(.IncrementByte) | |
case "-": tokens.append(.DecrementByte) | |
case "[": | |
let startIndex = index.successor() | |
let endIndex: String.CharacterView.Index = { | |
var i = startIndex | |
var opened = 1 | |
while opened > 0 { | |
i = i.successor() | |
if input[i] == "[" { | |
opened += 1 | |
} | |
if input[i] == "]" { | |
opened -= 1 | |
} | |
} | |
return i | |
}() | |
let loop = parse(input[startIndex...endIndex]) | |
tokens.append(.Loop(loop)) | |
index = endIndex | |
case "]": break // ignore, above case should handle it | |
default: break // ignore all other characters | |
} | |
index = index.successor() | |
} | |
return tokens | |
} | |
} | |
let addTwo = "+++>++++<[->+<]>." | |
let helloWorld = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++." | |
let brainfuck = Brainfuck(input: helloWorld) | |
let output = brainfuck.evaluate() | |
let outputString = output.map { String(Character(UnicodeScalar($0))) } // -> Hello World!\n |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment