Skip to content

Instantly share code, notes, and snippets.

@thomaswilburn
Created November 2, 2017 16:27
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 thomaswilburn/8ebd1668c9b5098498b358ba3e6cb268 to your computer and use it in GitHub Desktop.
Save thomaswilburn/8ebd1668c9b5098498b358ba3e6cb268 to your computer and use it in GitHub Desktop.
Terrible Forth in JS
var testScript = `
[ double dup + ]
[ quadruple double double ]
1 2 + print
double print
quadruple print
2 jmp
3 +
4 +
if 255 print 0 then
if 10 print then
`;
var Forth = function() {
this.stack = [];
this.dictionary = Object.create(Forth.BASE);
this.memory = new Array(100);
this.mode = Forth.modes.READING;
this.pc = 0;
this.code = [];
};
Forth.modes = {
READING: 0,
COMPILING: 1
};
Forth.BASE = {
print: function(self) {
console.log(self.top());
},
jmp: function(self) {
var amount = self.stack.pop();
self.pc += amount;
},
"+": function(self) {
var [a, b] = self.pop(2);
self.stack.push(a + b);
},
"-": function(self) {
var [a, b] = self.pop(2);
self.stack.push(a - b);
},
dup: function(self) {
var val = self.stack.pop();
self.stack.push(val, val);
},
noop: [],
then: [],
if: function(self) {
var then = self.code.indexOf("then", self.pc);
var condition = self.stack[self.stack.length - 1];
if (condition === 0) {
self.pc = then;
}
}
}
Forth.prototype = {
top: function() {
return this.stack[this.stack.length - 1];
},
pop: function(length) {
var vals = [];
for (var i = 0; i < length; i++) {
vals.unshift(this.stack.pop());
}
return vals;
},
run: function(word) {
if (typeof word == "function") {
word(this);
} else if (word instanceof Array) {
word.forEach(w => this.word(w));
} else {
throw word
}
},
word: function(word) {
word = this.cast(word);
var lookup = this.dictionary[word];
if (lookup) {
this.run(lookup);
} else if (this.isLiteral(word)) {
this.stack.push(word);
} else {
throw "Unrecognized word: " + word
}
},
evaluate: function(code) {
this.pc = 0;
this.code = code.trim().split(/\s+/g);
var buffer = [];
for (; this.pc < this.code.length; this.pc++) {
var w = this.code[this.pc];
if (w == "[") {
this.mode = Forth.modes.COMPILING;
} else if (w == "]") {
this.mode = Forth.modes.READING;
if (buffer.length) {
var name = buffer.shift();
this.dictionary[name] = buffer;
buffer = [];
}
} else {
if (this.mode == Forth.modes.COMPILING) {
buffer.push(w);
} else {
this.word(w);
}
}
}
},
isLiteral: function(word) {
return typeof word == "number";
},
cast: function(word) {
if (typeof word == "string") {
word = word.trim();
if (word.match(/^\d+$/)) {
return parseFloat(word);
}
}
return word;
}
};
var f = new Forth();
f.evaluate(testScript);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment