aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordan <[email protected]>2023-05-30 18:23:54 -0400
committerdan <[email protected]>2023-05-30 18:23:54 -0400
commit24272d599e1886a8fb47e3e47d33a0aa7dd74e22 (patch)
tree3105c1638ff0bb909dff1023102a8e0fe809c83c
parent66d61a5546e5e0173f92e941ab489a1c6474473e (diff)
downloadforth-24272d599e1886a8fb47e3e47d33a0aa7dd74e22.tar.gz
forth-24272d599e1886a8fb47e3e47d33a0aa7dd74e22.tar.bz2
forth-24272d599e1886a8fb47e3e47d33a0aa7dd74e22.zip
feat: web version also uses c code, compiled to wasm
-rw-r--r--forth.c61
-rw-r--r--forth.js150
-rw-r--r--index.html1
-rw-r--r--makefile3
-rw-r--r--optable.c32
-rw-r--r--optable.h6
6 files changed, 87 insertions, 166 deletions
diff --git a/forth.c b/forth.c
index 9f4e34f..96141ed 100644
--- a/forth.c
+++ b/forth.c
@@ -79,10 +79,36 @@ void eval(optable* ot, stack* s, int len, char* line) {
}
}
+int initialised = false;
+optable* ot;
+stack* s;
+int lastline = 0;
-#ifndef __EMSCRIPTEN__
+char* buffer_eval(int len, char* line) {
+ if (!initialised) {
+ ot = optable_new();
+ s = stack_new();
+ initialised = true;
+ outputline = 0;
+ }
+ else {
+ free(outputbuffer);
+ }
+ outputbuffer = malloc(sizeof(char) * 1024);
+ eval(ot, s, len, line);
+ if (outputline) {
+ outputline = 0;
+ return outputbuffer;
+ } else {
+ char* v = "foo";
+ char* v2 = "bar";
+ strcat(v, v2);
+ strcat(v, line);
+ return v;
+ }
+}
-int main(int argc, char** argv) {
+void stdin_eval() {
optable* ot = optable_new();
stack* s = stack_new();
char *line = NULL;
@@ -93,32 +119,19 @@ int main(int argc, char** argv) {
}
}
+#ifndef __EMSCRIPTEN__
+
+int main(int argc, char** argv) {
+ if (argc>1) printf("%s", buffer_eval(strlen(argv[1])+1, argv[1]));
+ else stdin_eval();
+}
+
#else
#include <emscripten/emscripten.h>
-int initialised = false;
-optable* ot;
-stack* s;
-int lastline = 0;
-
#define EXTERN
-EXTERN EMSCRIPTEN_KEEPALIVE char* extern_eval(int len, char* line) {
- if (!initialised) {
- ot = optable_new();
- s = stack_new();
- initialised = true;
- outputline = malloc(sizeof(int));
- *outputline = 0;
- // outputtobuffer = true;
- }
- eval(ot, s, len, line);
- if (*outputline != lastline) {
- lastline = *outputline;
- return outputbuffer;
- } else {
- return "";
- }
-
+EXTERN EMSCRIPTEN_KEEPALIVE char* extern_eval(char* line) {
+ return buffer_eval(strlen(line)+1, line);
}
#endif
diff --git a/forth.js b/forth.js
index 5cea76f..c7ff27d 100644
--- a/forth.js
+++ b/forth.js
@@ -1,96 +1,11 @@
-function forth(print = console.log) {
- const s = []; // the stack
- const popNum = () => Number(s.pop());
- const fs = {
- '/' : () => {
- const a2 = popNum();
- const a1 = popNum();
- s.push(a1 / a2);
- },
- '-' : () => {
- const a2 = popNum();
- const a1 = popNum();
- s.push(a1 - a2);
- },
- '+' : () => { s.push(popNum() + popNum()) },
- '*' : () => { s.push(popNum() * popNum()) },
- '=' : () => { s.push(popNum() === popNum()) },
- 'swap' : () => {
- const a1 = s.pop();
- const a2 = s.pop();
- s.push(a1);
- s.push(a2);
- },
- 'drop' : () => {
- s.pop();
- },
- 'over' : () => {
- const a1 = s.pop();
- const a2 = s.pop();
- s.push(a2);
- s.push(a1);
- s.push(a2);
- },
- 'rot' : () => {
- const a1 = s.pop();
- const a2 = s.pop();
- const a3 = s.pop();
- s.push(a2);
- s.push(a1);
- s.push(a3);
- },
- 'then' : () => {/*Doing nothing skips the token*/},
- 'if' : (initialIdx, tokens) => {
- if (!popNum()) {
- let localIdx = initialIdx;
- while (tokens[localIdx] && tokens[localIdx] !== 'then') {localIdx++}
- return localIdx - initialIdx;
- }
- },
- 'not' : () => { s.push(!popNum()) },
- '.' : () => { print(s.pop()) },
- 'peek' : () => { print(s[s.length - 1]) },
- 'dup' : () => {
- const a = s.pop();
- s.push(a);
- s.push(a);
- },
- ':' : (initialIdx, tokens) => {
- let localIdx = initialIdx + 1;
- const fname = tokens[localIdx++];
- const fnContent = [];
- for (;tokens[localIdx] !== ';'; localIdx++) {
- fnContent.push(tokens[localIdx]);
- }
- fs[fname] = () => {
- exec(fnContent);
- }
- return localIdx - initialIdx; // numItemsSkipped
- },
- }
-
- function exec(tokens) {
- for (let tokenIdx = 0; tokenIdx < tokens.length; tokenIdx++) {
- const token = tokens[tokenIdx];
- if (fs[token]) {
- const numItemsSkipped = fs[token](tokenIdx, tokens);
- if (Number.isInteger(numItemsSkipped)) {
- tokenIdx += numItemsSkipped;
- }
- }
- else {
- s.push(token);
- }
- }
- }
- return t =>
- new Promise(
- resolve => {
- exec(t.split(/[ \n\t]+/).filter(x => x !== ''));
- resolve();
- }
- );
+function exec(x) {
+ return Module.ccall(
+ "extern_eval", // name of C function
+ "string", // return type
+ ["string"], // argument types
+ [x] // arguments
+ );
}
/*
@@ -99,14 +14,13 @@ root tag to add to page:
* */
-if (typeof window !== 'undefined') { // browser UI
- const style = document.createElement('style')
- style.innerHTML = `
+const style = document.createElement('style')
+style.innerHTML = `
#forthroot * {
background-color: #42456f;
color: white;
- font-family: monospace;
- font-size: 1.2rem;
+ font-family: monospace;
+ font-size: 1.2rem;
box-sizing: border-box;
}
#forthouter {
@@ -138,8 +52,8 @@ if (typeof window !== 'undefined') { // browser UI
margin-bottom: 0px;
}
`;
- document.head.appendChild(style);
- forthroot.innerHTML = `
+document.head.appendChild(style);
+forthroot.innerHTML = `
<div id="forthouter">
<div id='forthresultsbox'>
<pre id="forthresults"></pre>
@@ -149,31 +63,17 @@ if (typeof window !== 'undefined') { // browser UI
<input id="forthline" type="text" value="" autocomplete="off">
</form>
</div>`
- forthouter.onclick = () => forthline.focus();
- const print = x => {
- forthresults.innerHTML = forthresults.innerHTML + x + '\n' ;
- forthouter.scrollTo(0, forthouter.scrollHeight);
- };
- const m = forth(print);
- forthform.onsubmit = () => {
- const input = forthline.value;
- if (input !== '') {
- print(`> ${input}`);
- m(input);
- forthline.value = '';
- }
- return false;
+forthouter.onclick = () => forthline.focus();
+const print = x => {
+ forthresults.innerHTML = forthresults.innerHTML + x ;
+ forthouter.scrollTo(0, forthouter.scrollHeight);
+};
+forthform.onsubmit = () => {
+ const input = forthline.value;
+ if (input !== '') {
+ print(`> ${input}\n`);
+ print(exec(input));
+ forthline.value = '';
}
-
-} else { // UI if NodeJS
- const readline = require('readline');
- const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
- const prompt = (query) => new Promise((resolve) => rl.question(query, resolve));
- const m = forth();
- (async () => {
- while (true) {
- const input = await prompt("> ");
- m(input)
- }
- })();
+ return false;
}
diff --git a/index.html b/index.html
index 2ab7c6e..36a86bc 100644
--- a/index.html
+++ b/index.html
@@ -7,6 +7,7 @@
</head>
<body>
<div id="forthroot"></div>
+ <script src="forthlib.js"></script>
<script src="forth.js"></script>
</body>
</html>
diff --git a/makefile b/makefile
index db37b0e..d435c7c 100644
--- a/makefile
+++ b/makefile
@@ -4,4 +4,5 @@ run:
./forth
run-rlwrap:
rlwrap -r -f rlwrapcompletions.forth ./forth
-
+build-wasm:
+ emcc forth.c optable.c stack.c -Wall -o forthlib.js -s NO_EXIT_RUNTIME=1 -s "EXPORTED_RUNTIME_METHODS=['ccall']"
diff --git a/optable.c b/optable.c
index efd01e3..de2aab0 100644
--- a/optable.c
+++ b/optable.c
@@ -201,25 +201,33 @@ static void dup(stack *s) {
stack_push(s, x);
}
+//#ifdef __EMSCRIPTEN__
+int outputline = 0;
+char* outputbuffer;
+//#endif
static void popout(stack *s) {
-#ifdef __EMSCRIPTEN__
- sprintf(outputbuffer, "%d\n", stack_pop(s));
- (*outputline)++;
-#else
- printf("%d\n", stack_pop(s));
-#endif
+if (outputbuffer) {
+ char x[WORD_LEN_LIMIT];
+ sprintf(x, "%d\n", stack_pop(s));
+ strcat(outputbuffer, x);
+ outputline++;
+} else {
+ printf("%d\n", stack_pop(s));
+}
}
static void peekout(stack *s) {
int x = stack_pop(s);
stack_push(s, x);
-#ifdef __EMSCRIPTEN__
- sprintf(outputbuffer, "%d\n", x);
- (*outputline)++;
-#else
- printf("%d\n", x);
-#endif
+if (outputbuffer) {
+ char y[WORD_LEN_LIMIT];
+ sprintf(y, "%d\n", x);
+ strcat(outputbuffer, y);
+ outputline++;
+} else {
+ printf("%d\n", x);
+}
}
static void donothing(stack *s) {
diff --git a/optable.h b/optable.h
index 9675678..811da9f 100644
--- a/optable.h
+++ b/optable.h
@@ -15,10 +15,8 @@ typedef struct wordop wordop;
typedef void (*stackop)(stack *);
typedef void (*directiveop)(stack *, int len, char* line, int* i, optable* optable);
-#ifdef __EMSCRIPTEN__
-extern char outputbuffer[1024];
-extern int* outputline;
-#endif
+extern char* outputbuffer;
+extern int outputline;
typedef struct {
bool isliteral;