scm-to-vm/scmvm/assembler.scm
2025-06-09 09:02:20 -05:00

67 lines
2.0 KiB
Scheme

(define-module (scmvm assembler)
#:use-module (srfi srfi-1)
#:use-module (scmvm vm)
#:use-module (rnrs bytevectors)
#:use-module (rnrs io ports)
#:use-module ((scheme base)
#:select (write-u8 write-bytevector))
#:export (assemble assemble-file))
(define (lookup-instruction inst)
(define inst-obj (assq inst *instruction-set*))
(if inst-obj
inst-obj
(error (format #f "could not find instruction ~a" inst))))
(define label? (compose not pair?))
(define (variable? x)
(and (pair? x) (eq? (car x) 'variable)))
(define (instruction? x)
(and (not (label? x))
(not (variable? x))))
(define (find-labels inst-seq n)
(cond
[(null? inst-seq) '()]
[(label? (car inst-seq))
(acons (car inst-seq) n (find-labels (cdr inst-seq) n))]
[(variable? (car inst-seq))
(acons (cadar inst-seq) n (find-labels (cdr inst-seq) (+ n 4)))]
[else
(find-labels (cdr inst-seq) (if (eq? (caar inst-seq) 'push) (+ n 5) (+ n 1)))]))
(define (write-word word)
(define bv (make-bytevector 4))
(bytevector-s32-native-set! bv 0 word)
(write-bytevector bv))
(define (assemble inst-seq port)
(with-output-to-port port
(lambda ()
(define labels (find-labels inst-seq 1))
(let loop ([seq inst-seq])
(cond
[(null? seq) '()]
[(label? (car seq)) (loop (cdr seq))]
[(variable? (car seq))
(write-word (caddar seq))
(loop (cdr seq))]
[else
(let* [(inst (car seq))
(inst-obj (lookup-instruction (car inst)))]
(write-u8 (instruction-code inst-obj))
(when (eq? (car inst) 'push)
(if (number? (cadr inst))
(write-word (cadr inst))
(write-word (assq-ref labels (cadr inst)))))
(loop (cdr seq)))])))))
(define (assemble-file file out)
(call-with-input-file file
(lambda (in)
(define (read-all next)
(if (eof-object? next)
'()
(cons next (read-all (read in)))))
(assemble (read-all (read in)) out))))