Skip to content

Instantly share code, notes, and snippets.

@poizan42
Created October 4, 2013 00:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save poizan42/6819243 to your computer and use it in GitHub Desktop.
Save poizan42/6819243 to your computer and use it in GitHub Desktop.
Brainfuck intepreter written in JavaScript (and HTML)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!--
Brainfuck interpreter in JavaScript
Made 2009 by Kasper F. Brandt
I hereby release this code (both html and JavaScript) into the public domain
-->
<html>
<head>
<title>Brainfuck interpreter</title>
<script type="text/javascript">
var loopStack;
var loopTime = 100;//time running in ms before we let the browser process events
var cellRange = 256;
var consoleBox, programBox, runBtn, statusLabel, stopBtn, cellRangeBox;
var program;
var pos;
var ptr;
var memory;
var inputBuffer;
var isWaitingForInput;
var isRunning = false;
var timeoutHandle;
function setText(e, t)
{
if (e.innerText)
e.innerText = t;
else
e.textContent = t;
}
function windowload()
{
consoleBox = document.getElementById("consoleBox");
programBox = document.getElementById("programBox");
runBtn = document.getElementById("runBtn");
statusLabel = document.getElementById("statusLabel");
stopBtn = document.getElementById("stopBtn");
cellRangeBox = document.getElementById("cellRangeBox");
runBtn.onclick = start;
stopBtn.onclick = stop;
consoleBox.onkeypress = consolekeypress;
consoleBox.value="";
updateStatus();
}
function input()
{
if (inputBuffer == "")
return undefined;
else
{
c = inputBuffer[0]
inputBuffer = inputBuffer.substr(1);
return c;
}
}
function output(s)
{
consoleBox.value += s;
}
function ensureMemExists(p)
{
if (memory[p] === undefined)
memory[p] = 0;
}
function step()
{
//0=step ended
//1=fell out
//2=waiting for input
ensureMemExists(ptr+1);
ensureMemExists(ptr-1);
switch (program[pos])
{
case '>':
ptr++;
break;
case '<':
ptr--;
break;
case '+':
memory[ptr]++;
if (memory[ptr] >= cellRange)
memory[ptr] = 0;
break;
case '-':
memory[ptr]--;
if (memory[ptr] < 0)
memory[ptr] = cellRange -1;
break;
case '.':
output(String.fromCharCode(memory[ptr]));
break;
case ',':
var a = input();
if (a == undefined)
return 2;
memory[ptr] = a.charCodeAt(0);
break;
case '[':
var oldpos = pos;
if (memory[ptr]==0)
{
var depth = 0;
for (pos++; pos < program.length; pos++)
{
if (program[pos] == '[')
depth++;
else if (program[pos] == ']' && depth > 0)
depth--;
else if (program[pos] == ']')
break;
}
if (pos == program.length)
{
//output("\n<"+oldpos+">at [: unmatched");
return 1;
}
}
if (program[pos] != ']')
{
loopStack.push(pos);
//output("\n<"+pos+">push. length="+loopStack.length+"|");
}
/*else
output("\n<"+oldpos+">moved to "+pos+". length="+loopStack.length+"|");*/
break;
case ']':
if (loopStack.length == 0)
{
output("\n<"+pos+">at ]: unmatched");
return 1;
}
var p = loopStack.pop();
//output("\n<"+pos+">pop. p="+p+". length="+loopStack.length+"|");
if (memory[ptr]!=0)
pos = p-1;
}
pos++;
if (pos >= program.length)
return 1;
return 0;
}
function run()
{
isRunning = true;
updateStatus();
var startTime = (new Date()).getTime();
while ((new Date()).getTime() - startTime <= loopTime)
{
//output("<d>"+pos+"\n");
switch (step())
{
case 0: //next step
continue;
case 1: //end reached (or unmatched [ ])
isRunning = false;
updateStatus();
return;
case 2: //no input available
isWaitingForInput = true;
updateStatus();
return;
}
}
updateStatus();
//give the browser a chance to process events
timeoutHandle = setTimeout('run();', 1);
}
function start()
{
pos = 0;
ptr = 0;
memory = [0];
loopStack = [];
inputBuffer = "";
program = programBox.value;
if (isNaN(cellRangeBox.value*1))
{
alert("Invalid cell size: "+cellRangeBox.value);
return;
}
cellRange = cellRangeBox.value*1;
cellRangeBox.value = cellRange;
consoleBox.value = "";
run();
}
function updateStatus()
{
programBox.readOnly = isRunning;
runBtn.disabled = isRunning;
cellRangeBox.disabled = isRunning;
stopBtn.disabled = !isRunning;
if (isRunning && isWaitingForInput)
setText(statusLabel, "running - waiting for input");
else if (isRunning)
setText(statusLabel, "running");
else
setText(statusLabel, "not running");
}
function consolekeypress(e)
{
if (!e)
var e = window.event;
if (!isRunning)
return;
var c = e.charCode || e.keyCode;
c = String.fromCharCode(c);
inputBuffer += c;
consoleBox.value += c;
if (isWaitingForInput)
{
isWaitingForInput = false;
run();
}
}
function stop()
{
if (isWaitingForInput)
isWaitingForInput = false;
else if (isRunning)
{
clearTimeout(timeoutHandle);
isRunning = false;
}
updateStatus();
}
</script>
</head>
<body onload="windowload()">
<strong>Program</strong><br>
<textarea id="programBox" cols="80" rows="20">
</textarea><br>
Status: <span id="statusLabel">status...</span><br>
Cell size: <input id="cellRangeBox" value="256"><br>
<input type="button" value="run" id="runBtn"><input type="button" value="stop" id="stopBtn" disabled>
<br><hr>
<strong>Console</strong><br>
<textarea id="consoleBox" readonly cols="80" rows="20">
</textarea>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment