Skip to content

Commit 74c1b7f

Browse files
authored
Create forth.html
1 parent 10437f4 commit 74c1b7f

File tree

1 file changed

+181
-0
lines changed

1 file changed

+181
-0
lines changed

forth.html

+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
<html>
2+
<head><title>Forth interpreter</title>
3+
<style>
4+
#output {
5+
font-family: monospace;
6+
white-space: pre;
7+
}
8+
9+
input {
10+
margin-top: 20px;
11+
}
12+
</style>
13+
</head>
14+
<body>
15+
16+
<div id=output>
17+
<div>Welcome to FORTH</div>
18+
</div>
19+
20+
21+
<input id="input" size=80>
22+
<button>Run</button>
23+
24+
25+
<script>
26+
27+
let inputEl = document.querySelector('input');
28+
let outputEl = document.querySelector('#output');
29+
let runEl = document.querySelector('button');
30+
31+
function output(s){
32+
let divEl = document.createElement('div');
33+
divEl.innerText = s;
34+
outputEl.appendChild(divEl);
35+
}
36+
37+
let stack = [];
38+
39+
const variables = []; // a list of [name, value]
40+
41+
const builtIns = {
42+
swap: function () {
43+
let a = stack.pop();
44+
let b = stack.pop();
45+
stack.push(a);
46+
stack.push(b);
47+
},
48+
over: function () {
49+
let a = stack.pop();
50+
let b = stack.pop();
51+
stack.push(b);
52+
stack.push(a);
53+
stack.push(b);
54+
},
55+
drop: function() {stack.pop()},
56+
rot: function () {
57+
let a = stack.pop();
58+
let b = stack.pop();
59+
let c = stack.pop();
60+
stack.push(a);
61+
stack.push(c);
62+
stack.push(b);
63+
},
64+
dup: function() {
65+
let a = stack.pop();
66+
stack.push(a);
67+
stack.push(a);
68+
},
69+
cr: function() {output('')},
70+
emit: function() {output(String.fromCharCode(stack.pop()))},
71+
invert: function () {
72+
stack.push(stack.pop() ? 0 : -1)
73+
},
74+
and: function () {
75+
stack.push(stack.pop() && stack.pop() ? -1 : 0)
76+
},
77+
or: function () {
78+
stack.push(stack.pop() || stack.pop() ? -1 : 0)
79+
},
80+
variable: function () {
81+
let name = unprocessedWords.shift();
82+
if (findVariable(name) != null) {
83+
output('Variable ' + name + ' is already defined');
84+
return;
85+
}
86+
variables.push([name, 0]);
87+
}
88+
}
89+
90+
builtIns['.'] = function() {output(stack.pop());};
91+
92+
builtIns['+'] = function() {stack.push(stack.pop() + stack.pop());};
93+
94+
builtIns['-'] = function() {stack.push(stack.pop() - stack.pop());};
95+
96+
builtIns['*'] = function() {stack.push(stack.pop() * stack.pop());};
97+
98+
builtIns['/'] = function() {stack.push(Math.floor(stack.pop() / stack.pop()));};
99+
100+
builtIns['='] = function() {stack.push(stack.pop() == stack.pop() ? -1 : 0);};
101+
102+
builtIns['>'] = function() {stack.push(stack.pop() <= stack.pop() ? -1 : 0);};
103+
104+
builtIns['<'] = function() {stack.push(stack.pop() >= stack.pop() ? -1 : 0);};
105+
106+
builtIns[':'] = function() {
107+
output('user-defined functions are not supported yet');
108+
while (unprocessedWords.length && ';' != unprocessedWords.shift());
109+
};
110+
builtIns['alloc'] = function() {
111+
output('alloc is not supported yet');
112+
};
113+
builtIns['cells'] = function() {
114+
// do nothing because it would multiply by 1.
115+
};
116+
117+
builtIns['@'] = function() {
118+
stack.push(variables[stack.pop()][1]);
119+
}
120+
121+
builtIns['!'] = function() {
122+
variables[stack.pop()][1] = stack.pop();
123+
}
124+
125+
126+
function findVariable(word) {
127+
for (let i = 0; i<variables.length; i++)
128+
if (word == variables[i][0]) {
129+
return i;
130+
}
131+
return null;
132+
}
133+
134+
135+
function execute(word) {
136+
if (!isNaN(word)) {
137+
stack.push(Number(word));
138+
return;
139+
}
140+
let f = builtIns[word];
141+
var addr = findVariable(word);
142+
143+
if (f) {
144+
f.call();
145+
} else if (addr != null) {
146+
stack.push(addr);
147+
} else {
148+
// TODO: user-defined functions
149+
output('unknown word: ' + word);
150+
}
151+
}
152+
153+
let unprocessedWords = [];
154+
155+
function repl(s) {
156+
if (s.length == 0) return;
157+
output('>> ' + s);
158+
unprocessedWords = s.split(' ');
159+
while (w = unprocessedWords.shift()) {
160+
execute(w);
161+
}
162+
output('Stack is: ' + stack.join(' '));
163+
output('ok');
164+
output('');
165+
inputEl.value = '';
166+
}
167+
168+
runEl.addEventListener('click', (e) => {
169+
repl(inputEl.value);
170+
inputEl.value = '';
171+
});
172+
inputEl.addEventListener('keyup', (e) => {
173+
if (e.key === 'Enter' || e.keyCode === 13) {
174+
repl(inputEl.value);
175+
inputEl.value = '';
176+
}
177+
});
178+
179+
</script>
180+
</body>
181+
</html>

0 commit comments

Comments
 (0)