Skip to content

Instantly share code, notes, and snippets.

@erikroyall
Last active November 11, 2016 23:22
Show Gist options
  • Save erikroyall/a8c54f806c9b6bbafcbef9ce5a60e650 to your computer and use it in GitHub Desktop.
Save erikroyall/a8c54f806c9b6bbafcbef9ce5a60e650 to your computer and use it in GitHub Desktop.
function parse(code) {
const flow = [];
const state = {
expectingNextLine: false
};
// Remove blank lines and generate an array containing
// each line of code
const xcode =
code
.split("\n")
.map(line => line.trim())
.filter(line => line !== "");
for (let cur = 0; cur < xcode.length; cur++) {
const line = xcode[cur];
const xline =
line
.split(" ")
.map(op => op.trim())
.filter(op => op !== "");
// Check for labels
if (xline[0].split(":").length === 2) {
// Check if previous statement was a LabelExpression
if (state.expectingNextLine) {
console.error("Expected a FunctionApplication, encountered a LabelExpression");
break;
}
// Check if this is the last line of code
if (cur + 1 === xcode.length) {
console.error("Expected a FunctionApplication, reached end of input");
break;
}
flow.push({
line: cur,
type: "LabelExpression",
code: xline[0],
name: xline[0].split(":")[0],
pointsTo: cur + 1
});
// If it's a label, next label must be a FunctionApplication
state.expectingNextLine = true;
continue;
}
flow.push({
line: cur,
type: "FunctionApplication",
code: xline.join(" "),
name: xline[0],
args: xline.slice(1)
});
state.expectingNextLine = false;
}
return flow;
}
var handlers = {
add: function addHandler (args) {
return args.reduce((acc,cur) => +acc + +cur, 0);
},
sub: function subHandler (args) {
return args.reduce((acc,cur) => +acc - +cur, 0);
},
mul: function mulHandler (args) {
return args.reduce((acc,cur) => +acc * +cur, 0);
},
div: function divHandler (args) {
return args.reduce((acc,cur) => +acc / +cur, 0);
},
print: function printHandler (args, state) {
let out = "";
if (args.length === 0) {
out += "\n";
return 0;
}
args.forEach(function (arg) {
if (arg[0] === ":") {
out += state.vars[arg.slice(1)] + " ";
} else if (arg[0] === "%") {
out += state.data[arg.slice(1)] + " ";
} else {
out += arg + " ";
}
});
state.output += out;
return 0;
},
let: function letHandler (arg, state, code) {
if (arg.length !== 2) {
console.error("let() takes 2 parameters, " + arg.length + " passed");
console.error(code);
console.error(" ^");
return -1;
}
else if (arg[1][0] === ":") {
state.vars[arg[0]] = state.vars[arg[1].slice(1)];
} else if (arg[1][0] === "%") {
state.vars[arg[0]] = state.data[arg[1].slice(1)];
} else {
state.vars[arg[0]] = arg[1];
}
return 0;
}
};
function evaluate(tree) {
const labelTable = {};
const state = {
output: "",
vars: {}, // Program-defined variables
data: {
retval: null
}
};
// Populate the label table
for (let cur = 0; cur < tree.length; cur++) {
let ins = tree[cur];
if (ins.type === "LabelExpression") {
labelTable[ins.name] = ins.pointsTo;
}
}
for (let cur = 0; cur < tree.length; cur++) {
let ins = tree[cur];
if (ins.type === "FunctionApplication") {
// handle goto
if (ins.name === "goto") {
cur = labelTable[ins.args[0]] - 1;
continue;
}
// call the handler
state.data.retval = handlers[ins.name](ins.args, state, ins.code);
}
}
return state.output;
}
let out = evaluate(parse(`
let god pootis
let name :god
goto main
ignored
main:
print hello :name
print %ln
print 1 + 1 =
add 1 1
print %retval
`));
console.log(out);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment