mirror of
https://github.com/remko/waforth
synced 2025-01-18 22:26:39 +01:00
Replace assembler with preprocessor
This commit is contained in:
parent
46cbda1f6a
commit
9c99a927be
6 changed files with 301 additions and 360 deletions
|
@ -17,5 +17,4 @@ addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
- make
|
- make
|
||||||
- racket
|
|
||||||
# - wabt
|
# - wabt
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -16,7 +16,7 @@ dev-server: $(WASM_FILES)
|
||||||
wasm: $(WASM_FILES) src/waforth.assembled.wat src/tools/quadruple.wasm.hex
|
wasm: $(WASM_FILES) src/waforth.assembled.wat src/tools/quadruple.wasm.hex
|
||||||
|
|
||||||
src/waforth.wasm: src/waforth.wat dist
|
src/waforth.wasm: src/waforth.wat dist
|
||||||
racket -f $< > src/waforth.wat.tmp
|
./src/tools/preprocess.js $< > src/waforth.wat.tmp
|
||||||
$(WAT2WASM) $(WAT2WASM_FLAGS) -o $@ src/waforth.wat.tmp
|
$(WAT2WASM) $(WAT2WASM_FLAGS) -o $@ src/waforth.wat.tmp
|
||||||
|
|
||||||
src/waforth.assembled.wat: src/waforth.wasm
|
src/waforth.assembled.wat: src/waforth.wasm
|
||||||
|
|
15
README.md
15
README.md
|
@ -51,23 +51,16 @@ You can also run the tests in Node.JS by running
|
||||||
|
|
||||||
## Design
|
## Design
|
||||||
|
|
||||||
### The Macro Assembler
|
### The Preprocessor
|
||||||
|
|
||||||
The WAForth core is written as [a single
|
The WAForth core is written as [a single
|
||||||
module](https://github.com/remko/waforth/blob/master/src/waforth.wat) in
|
module](https://github.com/remko/waforth/blob/master/src/waforth.wat) in
|
||||||
WebAssembly's [text
|
WebAssembly's [text
|
||||||
format](https://webassembly.github.io/spec/core/text/index.html). The text
|
format](https://webassembly.github.io/spec/core/text/index.html). The text
|
||||||
format isn't really meant for writing code in, so it has no facilities like a
|
format isn't really meant for writing code in, so it has no facilities like a
|
||||||
real assembler (e.g. constant definitions, macro expansion, ...) However, since
|
real assembler (e.g. constant definitions, macro expansion, ...).
|
||||||
the text format uses S-expressions, you can do some small modifications to make
|
To help with maintenance, the WebAssembly file is piped through a simple string
|
||||||
it extensible with Lisp-style macros.
|
preprocessor that replaces constants with defined values.
|
||||||
|
|
||||||
I added some Racket macros to the module definition, and implemented [a mini
|
|
||||||
assembler](https://github.com/remko/waforth/blob/master/src/tools/assembler.rkt)
|
|
||||||
to print out the resulting s-expressions in the right format.
|
|
||||||
|
|
||||||
The result is something that looks like a standard WebAssembly module, but
|
|
||||||
sprinkled with some macros for convenience.
|
|
||||||
|
|
||||||
### The Interpreter
|
### The Interpreter
|
||||||
|
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
#lang racket
|
|
||||||
|
|
||||||
(define (asm-symbol? x)
|
|
||||||
(and (symbol? x) (eq? (string-ref (symbol->string x) 0) #\!)))
|
|
||||||
|
|
||||||
(define (preprocess x)
|
|
||||||
(cond ((list? x)
|
|
||||||
(cond ((null? x) '())
|
|
||||||
((and (list? (car x)) (asm-symbol? (caar x)))
|
|
||||||
(append (eval (car x)) (preprocess (cdr x))))
|
|
||||||
(else
|
|
||||||
(cons (preprocess (car x)) (preprocess (cdr x))))))
|
|
||||||
((asm-symbol? x)
|
|
||||||
(eval x))
|
|
||||||
(else x)))
|
|
||||||
|
|
||||||
(define (byte->hex byte)
|
|
||||||
(define digits "0123456789ABCDEF")
|
|
||||||
(string (string-ref digits (quotient byte 16))
|
|
||||||
(string-ref digits (remainder byte 16))))
|
|
||||||
|
|
||||||
(define (byte->string byte)
|
|
||||||
(cond ((> byte 255) (raise "Illegal byte"))
|
|
||||||
((and (> byte 32) (< byte 127) (not (or (eqv? byte 34) (eqv? byte 92))))
|
|
||||||
(string (integer->char byte)))
|
|
||||||
(else (string-append "\\" (byte->hex byte)))))
|
|
||||||
|
|
||||||
(define (string-escape s)
|
|
||||||
(string-join (map byte->string (map char->integer (string->list s))) ""))
|
|
||||||
|
|
||||||
(define (serialize x)
|
|
||||||
(cond ((list? x)
|
|
||||||
(string-append "(" (string-join (map serialize x) " ") ")"))
|
|
||||||
((string? x)
|
|
||||||
(string-append "\"" (string-escape x) "\""))
|
|
||||||
((symbol? x)
|
|
||||||
(symbol->string x))
|
|
||||||
((number? x)
|
|
||||||
(number->string x))
|
|
||||||
((bytes? x)
|
|
||||||
(string-append
|
|
||||||
"\""
|
|
||||||
(string-join (map byte->string (bytes->list x)) "")
|
|
||||||
"\""))
|
|
||||||
(else (raise (list "Unexpected type" x)))))
|
|
||||||
|
|
||||||
(define (priority x)
|
|
||||||
(cond ((eq? x 'module) 0)
|
|
||||||
((and (list? x) (eq? (car x) 'import)) 1000000)
|
|
||||||
((and (list? x) (eq? (car x) 'memory)) 2000000)
|
|
||||||
((and (list? x) (eq? (car x) 'global)) 3000000)
|
|
||||||
((and (list? x) (eq? (car x) 'data)) (+ 5000000 (car (cdr (car (cdr x))))))
|
|
||||||
(else 100000000)))
|
|
||||||
|
|
||||||
(define (wasm-assemble module)
|
|
||||||
(display
|
|
||||||
(serialize
|
|
||||||
(sort (preprocess module)
|
|
||||||
(lambda (x y) (< (priority x) (priority y)))))))
|
|
||||||
|
|
||||||
(define-syntax module
|
|
||||||
(syntax-rules ()
|
|
||||||
((_ arg ...)
|
|
||||||
(wasm-assemble '(module arg ...)))))
|
|
||||||
|
|
||||||
(provide module)
|
|
30
src/tools/preprocess.js
Executable file
30
src/tools/preprocess.js
Executable file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const process = require("process");
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
function escapeRegExp(string) {
|
||||||
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = process.argv[2];
|
||||||
|
const lines = fs
|
||||||
|
.readFileSync(file)
|
||||||
|
.toString()
|
||||||
|
.split("\n");
|
||||||
|
|
||||||
|
const definitions = {};
|
||||||
|
lines.forEach(line => {
|
||||||
|
Object.keys(definitions).forEach(k => {
|
||||||
|
line = line.replace(
|
||||||
|
new RegExp(escapeRegExp(k) + "(\\s|\\))", "g"),
|
||||||
|
definitions[k] + " (; = " + k + " ;)$1"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const m = line.match(/^;; \(define\s+([^\s]+)\s+([^\s]+)\)/);
|
||||||
|
if (m) {
|
||||||
|
definitions[m[1]] = m[2];
|
||||||
|
} else {
|
||||||
|
console.log(line);
|
||||||
|
}
|
||||||
|
});
|
545
src/waforth.wat
545
src/waforth.wat
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue