Skip to content

Instantly share code, notes, and snippets.

@markusl
Created August 11, 2011 17:31
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markusl/1140246 to your computer and use it in GitHub Desktop.
Save markusl/1140246 to your computer and use it in GitHub Desktop.
Brainfuck interpreter written in F#
// FSharp (F#) interpreter for brainfuck programming language
// Read more from
// - http://www.muppetlabs.com/~breadbox/bf/
// - http://fsharp.net
// (c) 2011 Markus Lindqvist
module brainfuck
open System
let brainfuckMemorySize = 30000
/// Represents the brainfuck program we are executing
type BrainFuck = {
/// Contains the complete programe we are executing
bfcode : string;
/// Contains the current instruction we are executing
bfcodelocation : int;
/// Contains the program's memory, usually of size 30 000
memory : int array;
/// Contains the brainfuck memory pointer
memorypointer : int;
}
/// Construct initial brainfuck state with zero memory and instruction and memory pointers zeroed
with static member Initial code =
{ new BrainFuck
with bfcode = code
and bfcodelocation = 0
and memory = Array.zeroCreate(brainfuckMemorySize)
and memorypointer = 0 }
/// Keep the pointer location within allowed are
let wrapPointer pointerlocation =
if(pointerlocation < 0) then brainfuckMemorySize-1
else if (pointerlocation = brainfuckMemorySize) then 0
else pointerlocation
/// Get next instruction relative to current location
let getInstruction bf nth =
{ bf with bfcodelocation = bf.bfcodelocation + nth }
let nextInstruction bf = getInstruction bf (+1)
let prevInstruction bf = getInstruction bf (-1)
/// Modify memory at current memory pointer and move to next instruction
let modifyMemoryAtPointer bf op =
let mem = bf.memory
mem.[bf.memorypointer] <- mem.[bf.memorypointer] + op
{ nextInstruction bf with memory = mem }
/// Modify memory pointer and move to next instruction
let modifyMemoryPointer bf op =
{nextInstruction bf with memorypointer = wrapPointer (bf.memorypointer + op) }
let findLoopMatch bf (char1:char) (char2:char) jumpInstruction =
let rec findLoopMatchRec bf nestedLoops =
let currentInstruction = bf.bfcode.Chars(bf.bfcodelocation)
if (currentInstruction = char1 && nestedLoops = 1) then bf
else match currentInstruction with
| b when b = char1 -> findLoopMatchRec (jumpInstruction bf) (nestedLoops-1)
| a when a = char2 -> findLoopMatchRec (jumpInstruction bf) (nestedLoops+1)
| _ -> findLoopMatchRec (jumpInstruction bf) (nestedLoops)
findLoopMatchRec bf 0
/// Jump past current loop
let endLoop bf = findLoopMatch bf ']' '[' nextInstruction
///// Start current loop again
let startLoop bf = findLoopMatch bf '[' ']' prevInstruction
/// Build a map of brainfuck instructions
let brainFuckInstructions =
['>', (fun bf -> modifyMemoryPointer bf (+1));
'<', (fun bf -> modifyMemoryPointer bf (-1));
'+', (fun bf -> modifyMemoryAtPointer bf (+1));
'-', (fun bf -> modifyMemoryAtPointer bf (-1));
'[', (fun bf -> if (bf.memory.[bf.memorypointer] = 0) then (endLoop bf) else (nextInstruction bf));
']', (fun bf -> if (bf.memory.[bf.memorypointer] <> 0) then (startLoop bf) else (nextInstruction bf));
'.', (fun bf -> Console.Write(Convert.ToChar(bf.memory.[bf.memorypointer]));(nextInstruction bf));
',', (fun bf -> bf.memory.[bf.memorypointer] <- Console.Read();(nextInstruction bf))] |> Map.ofList
/// Execute a brainfuck program
let processInstructions (bf:BrainFuck) =
let rec processInstructionsRec (bf:BrainFuck) =
// Check that we have some code left
if(bf.bfcodelocation < bf.bfcode.Length) then
// Look up from instruction table
if(brainFuckInstructions.ContainsKey(bf.bfcode.Chars(bf.bfcodelocation))) then
// Execute the given instruction
let instruction = brainFuckInstructions.Item(bf.bfcode.Chars(bf.bfcodelocation))
processInstructionsRec (instruction bf)
else // Just move to next instruction if we have unknown character
processInstructionsRec (nextInstruction bf)
// Start recursively executing instructions
processInstructionsRec bf
let executeBrainFuck (code:string) =
let bf = BrainFuck.Initial code
processInstructions bf
// Prints: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
let bfcode = "+++++++++++>+>>>>++++++++++++++++++++++++++++++++++++++++++++>++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+>+<<<<<<<-]>>>>>>>[<<<<<<<+>>>>>>>-]<[>++++++++++[-<-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<[>>>+<<<-]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<+>>[-]]<<<<<<<]>>>>>[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]++++++++++<[->-<]>++++++++++++++++++++++++++++++++++++++++++++++++.[-]<<<<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<<[-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-]"
// Prints: Hello World!
//let bfcode = " ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."
executeBrainFuck bfcode
Console.ReadKey()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment