Skip to content

Instantly share code, notes, and snippets.

@H2CO3
Last active August 29, 2015 13:56
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 H2CO3/9306268 to your computer and use it in GitHub Desktop.
Save H2CO3/9306268 to your computer and use it in GitHub Desktop.
//
// bf.spn
// a Brainfuck parser and interpreter in Sparkling
//
// by Arpad Goretity (H2CO3)
// The "zeroise" optimization is based on the idea of Daniel Silverstone
// run as: spn bf.spn foo.bf
//
global ins_incrmt = 0,
ins_decrmt = 1,
ins_forward = 2,
ins_back = 3,
ins_putc = 4,
ins_getc = 5,
ins_while = 6;
global insMap = {
'+': {
"code": ins_incrmt,
"name": "increment",
"func": function(env) {
var byte = zeroise(env);
if ++byte == 256 {
byte = 0;
}
env.tape[env.pointer] = byte;
}
},
'-': {
"code": ins_decrmt,
"name": "decrement",
"func": function(env) {
var byte = zeroise(env);
if byte == 0 {
byte = 256;
}
env.tape[env.pointer] = --byte;
}
},
'>': {
"code": ins_forward,
"name": "forward",
"func": function(env) { env.pointer++; }
},
'<': {
"code": ins_back,
"name": "back",
"func": function(env) { env.pointer--; }
},
'.': {
"code": ins_putc,
"name": "putc",
"func": function(env) {
printf("%c", zeroise(env));
}
},
',': {
"code": ins_getc,
"name": "getc",
"func": function(env) { env.tape[env.pointer] = getc(); }
},
'[': {
"code": ins_while,
"name": "while",
"func": function(env, ast) {
while zeroise(env) != 0 {
interpretInstructionList(env, ast);
}
}
}
};
function parseInstructionList(parser)
{
var insList = {};
while parser.idx < sizeof parser.src && parser.src[parser.idx] != ']' {
var ch = parser.src[parser.idx];
if insMap[ch] == nil {
// comment
parser.idx++;
continue;
}
var ins = insMap[ch].code;
if ins == ins_while {
parser.idx++; // skip '['
insList[sizeof insList] = parseInstructionList(parser);
parser.idx++; // skip ']'
} else {
insList[sizeof insList] = ch;
parser.idx++;
}
}
return insList;
}
function parseString(src)
{
return parseInstructionList({ "src": src, "idx": 0});
}
function printInstructionList(list, indent)
{
if indent == nil {
indent = 0;
}
for var i = 0; i < sizeof list; i++ {
if typeof list[i] == "array" {
for var j = 0; j < indent; j++ {
printf("\t");
}
printf("loop {\n");
printInstructionList(list[i], indent + 1);
for var j = 0; j < indent; j++ {
printf("\t");
}
printf("}");
} else {
for var j = 0; j < indent; j++ {
printf("\t");
}
printf("%s", insMap[list[i]].name);
// printf("%c", list[i]);
}
print(i < sizeof list - 1 ? "," : "");
}
}
function zeroise(env)
{
var byte = env.tape[env.pointer];
return byte == nil ? 0 : byte;
}
function interpretInstructionList(env, ast)
{
for var i = 0; i < sizeof ast; i++ {
if typeof ast[i] == "array" {
insMap['['].func(env, ast[i]);
} else {
insMap[ast[i]].func(env);
}
}
}
function interpret(ast)
{
interpretInstructionList({ "tape": {}, "pointer": 0 }, ast);
}
function readFile(fname)
{
var f = fopen(fname, "rb");
fseek(f, 0, "end");
var len = ftell(f);
fseek(f, 0, "set");
var data = fread(f, len);
fclose(f);
return data;
}
global getc_state = { "buf": "", "idx": 0 };
function getc()
{
if getc_state.idx >= sizeof getc_state.buf {
getc_state.idx = 0;
getc_state.buf = getline();
}
return getc_state.buf[getc_state.idx++];
}
var data = readFile(argv[1]);
var ast = parseString(data);
// printInstructionList(ast);
interpret(ast);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment