Created
October 4, 2013 00:31
-
-
Save poizan42/6819243 to your computer and use it in GitHub Desktop.
Brainfuck intepreter written in JavaScript (and HTML)
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
<!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