Replace assembler with preprocessor

This commit is contained in:
Remko Tronçon 2019-11-08 16:55:34 +01:00
parent 46cbda1f6a
commit 9c99a927be
6 changed files with 301 additions and 360 deletions

View file

@ -17,5 +17,4 @@ addons:
apt: apt:
packages: packages:
- make - make
- racket
# - wabt # - wabt

View file

@ -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

View file

@ -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

View file

@ -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
View 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);
}
});

File diff suppressed because it is too large Load diff