#lang scheme/base
(provide
asm/dasm-lambda-tx)
(require
"../op/static.ss"
(for-template
"../op.ss" "operand.ss" scheme/base))
(define (paramclass->asm name)
(case name
((R) #'asm+/pcr) (else #'asm+)))
(define (paramclass->dasm name)
(case name
((R) #'dasm/pcr)
(else #'dasm/unsigned)))
(define (assembler-body opcode-body)
(syntax-case opcode-body ()
(((opcode . opcode-bits) . operands)
(foldl
(lambda (p/b inner)
(syntax-case p/b ()
((param bits)
#`(#,(paramclass->asm (syntax-e #'param))
pc param bits #,inner))))
#'opcode
(syntax->list #'operands)))))
(define (asm-lambda-tx name formals template-list)
#`(let ((#,name
(lambda (address #,@formals)
(let ((pc (+ address #,(length template-list)))) (list #,@(map assembler-body template-list))))))
#,name))
(define (lex-bits str-stx)
(define (char->stx char)
(datum->syntax str-stx ((lambda (string)
(or (string->number string)
(string->symbol string)))
(string char))))
(define (valid-char? char)
(not (equal? char #\space)))
(map
char->stx
(filter valid-char?
(string->list (syntax->datum str-stx)))))
(define (parse-bits stx)
(syntax-case stx ()
((bit ...)
(let down ((stx (for/list ((el (syntax->list #'(bit ...)))) (list el 1))))
(syntax-case stx ()
(((k n) (l m) . rest)
(let ((_n (syntax-e #'n))
(_m (syntax-e #'m))
(_k (syntax-e #'k))
(_l (syntax-e #'l)))
(cond
((and (symbol? _k) (eq? _k _l))
(down #`((k #,(+ _n _m)) . rest)))
((and (number? _k) (number? _l))
(down #`((#,(+ (* 2 _k) _l) #,(+ _n _m)) . rest)))
(else
#`((k n) #,@(down #`((l m) . rest)))))))
(other #'other))))))
(define-syntax-rule (push! stack x) (set! stack (cons x stack)))
(define-syntax-rule (lambda* formals . body) (lambda (a) (apply (lambda formals . body) a)))
(define (generate-temp) (car (generate-temporaries #'(#f))))
(define (dasm-lambda-tx opcode-name formals body-stx)
(define literals '())
(define variables (make-hash))
(define (fix-names! names bits)
(for/list ((n (syntax->list names))
(b (syntax->list bits))
(i (in-naturals)))
(let ((_n (syntax-e n)))
(if (number? _n)
(let ((__n (generate-temp)))
(push! literals (list __n _n))
__n)
(begin
(hash-set! variables _n b)
n)))))
(let ((ws (generate-temporaries body-stx)))
(syntax-case (list ws body-stx) ()
(((w ...) (((name bits) ...) ...))
#`(let ((#,opcode-name
(lambda (assembler) (lambda (address w ...) (let ((pc (+ address #,(length ws)))) (let-values
#,(for/list ((stx (syntax->list #'((w (name ...) (bits ...)) ...))))
(syntax-case stx ()
((w ns bs)
#`(#,(fix-names! #'ns #'bs)
(disassemble/values 'bs w)))))
(and
#,@(map (lambda* (name value)
#`(= #,name #,value))
literals)
(list assembler
#,@(for/list ((f (syntax->list formals)))
(let ((_f (syntax-e f)))
#`(#,(paramclass->dasm _f)
pc
#,f
#,(hash-ref variables _f))))))))))))
#,opcode-name)))))
(define (asm/dasm-lambda-tx stx)
(syntax-case stx ()
((_ name formals . body)
(let ((body-stx
(syntax-case #'body ()
((((param . bits) ...) ...) (syntax->list #'body))
((str ...) (map (compose parse-bits lex-bits)
(syntax->list #'(str ...)))))))
(values
(asm-lambda-tx #'name #'formals body-stx)
(dasm-lambda-tx #'name #'formals body-stx))))))