diff options
author | dan <[email protected]> | 2023-05-30 18:23:54 -0400 |
---|---|---|
committer | dan <[email protected]> | 2023-05-30 18:23:54 -0400 |
commit | 24272d599e1886a8fb47e3e47d33a0aa7dd74e22 (patch) | |
tree | 3105c1638ff0bb909dff1023102a8e0fe809c83c | |
parent | 66d61a5546e5e0173f92e941ab489a1c6474473e (diff) | |
download | forth-24272d599e1886a8fb47e3e47d33a0aa7dd74e22.tar.gz forth-24272d599e1886a8fb47e3e47d33a0aa7dd74e22.tar.bz2 forth-24272d599e1886a8fb47e3e47d33a0aa7dd74e22.zip |
feat: web version also uses c code, compiled to wasm
-rw-r--r-- | forth.c | 61 | ||||
-rw-r--r-- | forth.js | 150 | ||||
-rw-r--r-- | index.html | 1 | ||||
-rw-r--r-- | makefile | 3 | ||||
-rw-r--r-- | optable.c | 32 | ||||
-rw-r--r-- | optable.h | 6 |
6 files changed, 87 insertions, 166 deletions
@@ -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 @@ -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; } @@ -7,6 +7,7 @@ </head> <body> <div id="forthroot"></div> + <script src="forthlib.js"></script> <script src="forth.js"></script> </body> </html> @@ -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']" @@ -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) { @@ -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; |