diff options
Diffstat (limited to 'linker.csc')
| -rw-r--r-- | linker.csc | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/linker.csc b/linker.csc new file mode 100644 index 0000000..852ee13 --- /dev/null +++ b/linker.csc @@ -0,0 +1,67 @@ +(define-library (csc linker) + (export link remove-labels make-label-map translate-labels) + (import (scheme base) + (only (csc encoding) encode) + (only (csc format) sprintf) + (only (csc hash-map) + hash-bytevector + insert + lookup + make-map) + (only (csc list) + enumerate + filter) + (only (csc match) match)) + (begin + ; A CSC bytecode program is a list of opcodes. An opcode is a symbol, or a 2 + ; item list of a symbol and an argument. The full list of opcodes can be + ; found in encoding.csc. + + + (define (translate-labels program label-map) + (map + (lambda (x) + (match x + ((i . ((! 'if) label)) + ; Compute offset from the current position. Subtract 1 + ; because the instruction pointer is incremented each + ; time already. + (list 'if (- (lookup label-map label) i 1))) + ((_ . ((! 'call) label)) + (list 'call (lookup label-map label))) + ((_ . opcode) opcode))) + (enumerate program))) + (lambda (i . opcode) + (match opcode + (((! 'if) label) #t) + (_ #f))) + + + (define (hash-string s) + (hash-bytevector (string->utf8 s))) + + + (define (make-label-map program) + (let loop ((m (make-map hash-string string<?)) + (program program) + (i 0)) + (match program + ('() m) + ((((! 'label) name) . tail) + (loop (insert m name i) tail i)) ; N.b.: i instead of (+ 1 i) because we're going to remove the labels later. + ((_ . tail) (loop m tail (+ 1 i)))))) + + + (define (remove-labels program) + (filter + (lambda (opcode) + (match opcode + (((! 'label) _) #f) + (_ #t))) + program)) + + + (define (link . programs) + (let* ((program (apply append programs)) + (label-map (make-label-map program))) + (encode (translate-labels (remove-labels program) label-map)))))) |
