From 24272d599e1886a8fb47e3e47d33a0aa7dd74e22 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 30 May 2023 18:23:54 -0400 Subject: feat: web version also uses c code, compiled to wasm --- forth.c | 61 +++++++++++++++---------- forth.js | 150 +++++++++++-------------------------------------------------- index.html | 1 + makefile | 3 +- optable.c | 32 ++++++++----- optable.h | 6 +-- 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 -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 = `

@@ -149,31 +63,17 @@ if (typeof window !== 'undefined') { // browser UI
         
       
     
` - 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 @@
+ 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; -- cgit v1.2.3