mirror of
https://github.com/remko/waforth
synced 2025-01-17 18:11: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:
|
||||
packages:
|
||||
- make
|
||||
- racket
|
||||
# - 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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
### The Macro Assembler
|
||||
### The Preprocessor
|
||||
|
||||
The WAForth core is written as [a single
|
||||
module](https://github.com/remko/waforth/blob/master/src/waforth.wat) in
|
||||
WebAssembly's [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
|
||||
real assembler (e.g. constant definitions, macro expansion, ...) However, since
|
||||
the text format uses S-expressions, you can do some small modifications to make
|
||||
it extensible with Lisp-style macros.
|
||||
|
||||
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.
|
||||
real assembler (e.g. constant definitions, macro expansion, ...).
|
||||
To help with maintenance, the WebAssembly file is piped through a simple string
|
||||
preprocessor that replaces constants with defined values.
|
||||
|
||||
### 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);
|
||||
}
|
||||
});
|
547
src/waforth.wat
547
src/waforth.wat
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue