133 lines
3.7 KiB
Scheme
133 lines
3.7 KiB
Scheme
|
; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
|
||
|
; Copyright (c) 1993-1999 by Richard Kelsey and Jonathan Rees. See file COPYING.
|
||
|
|
||
|
|
||
|
; This is file assem.scm.
|
||
|
|
||
|
;;;; Assembler
|
||
|
|
||
|
; Courtesy John Ramsdell.
|
||
|
|
||
|
; LAP syntax is much like that of the output of the disassembler except
|
||
|
; that global and set-global! take a symbol as an argument,
|
||
|
; statements may be labeled, and jump, jump-if-false, and make-cont
|
||
|
; may make a forward reference to a label to give an offset.
|
||
|
;
|
||
|
; Example: a translation of (define (dog) (if x 0 1)).
|
||
|
; (define dog
|
||
|
; (lap dog
|
||
|
; (check-nargs= 0)
|
||
|
; (global x)
|
||
|
; (jump-if-false 8)
|
||
|
; (literal '0)
|
||
|
; 8 (jump out)
|
||
|
; (literal '1)
|
||
|
; out (return)))
|
||
|
|
||
|
(define-compilator '(lap syntax)
|
||
|
(let ((op/closure (enum op closure)))
|
||
|
(lambda (node cenv depth cont)
|
||
|
(let ((exp (node-form node)))
|
||
|
(deliver-value
|
||
|
(instruction-with-template op/closure
|
||
|
(compile-lap (cddr exp) cenv)
|
||
|
(cadr exp))
|
||
|
cont)))))
|
||
|
|
||
|
; Assembler label environments are simply a-lists.
|
||
|
(define assembler-empty-env '())
|
||
|
(define (assembler-extend sym val env) (cons (cons sym val) env))
|
||
|
(define (assembler-lookup sym env)
|
||
|
(let ((val (assv sym env)))
|
||
|
(if (pair? val) (cdr val) #f)))
|
||
|
|
||
|
(define (compile-lap instruction-list cenv)
|
||
|
(assemble instruction-list
|
||
|
assembler-empty-env
|
||
|
cenv))
|
||
|
|
||
|
; ASSEMBLE returns a segment.
|
||
|
|
||
|
(define (assemble instruction-list lenv cenv)
|
||
|
(if (null? instruction-list)
|
||
|
(sequentially)
|
||
|
(let ((instr (car instruction-list))
|
||
|
(instruction-list (cdr instruction-list)))
|
||
|
(cond ((pair? instr) ; Instruction
|
||
|
(sequentially
|
||
|
(assemble-instruction instr lenv cenv)
|
||
|
(assemble instruction-list
|
||
|
lenv
|
||
|
cenv)))
|
||
|
((or (symbol? instr) ; Label
|
||
|
(number? instr))
|
||
|
(let ((label (make-label)))
|
||
|
(attach-label
|
||
|
label
|
||
|
(assemble instruction-list
|
||
|
(assembler-extend instr label lenv)
|
||
|
cenv))))
|
||
|
(else (error "invalid instruction" instr))))))
|
||
|
|
||
|
; ASSEMBLE-INSTRUCTION returns a segment.
|
||
|
|
||
|
(define (assemble-instruction instr lenv cenv)
|
||
|
(let* ((opcode (name->enumerand (car instr) op))
|
||
|
(arg-specs (vector-ref opcode-arg-specs opcode)))
|
||
|
(cond ((or (not (pair? arg-specs))
|
||
|
(not (pair? (cdr instr))))
|
||
|
(instruction opcode))
|
||
|
((eq? (car arg-specs) 'index)
|
||
|
(assemble-instruction-with-index opcode arg-specs (cdr instr) cenv))
|
||
|
((eq? (car arg-specs) 'offset)
|
||
|
(let ((operand (cadr instr)))
|
||
|
(apply instruction-using-label
|
||
|
opcode
|
||
|
(let ((probe (assembler-lookup operand lenv)))
|
||
|
(if probe
|
||
|
probe
|
||
|
(begin
|
||
|
(syntax-error "can't find forward label reference"
|
||
|
operand)
|
||
|
empty-segment)))
|
||
|
(assemble-operands (cddr instr) arg-specs))))
|
||
|
(else
|
||
|
(apply instruction
|
||
|
opcode
|
||
|
(assemble-operands (cdr instr) arg-specs))))))
|
||
|
|
||
|
; <index> ::= (quote <datum>) | (lap <name> <instr>) | <name>
|
||
|
|
||
|
(define (assemble-instruction-with-index opcode arg-specs operands cenv)
|
||
|
(let ((operand (car operands)))
|
||
|
(if (pair? operand)
|
||
|
(case (car operand)
|
||
|
((quote)
|
||
|
(instruction-with-literal opcode
|
||
|
(cadr operand)))
|
||
|
((lap)
|
||
|
(instruction-with-template opcode
|
||
|
(compile-lap (cddr operand))
|
||
|
(cadr operand)))
|
||
|
(else
|
||
|
(syntax-error "invalid index operand" operand)
|
||
|
empty-segment))
|
||
|
;; Top-level variable reference
|
||
|
(instruction-with-location
|
||
|
opcode
|
||
|
(get-location (lookup cenv operand)
|
||
|
cenv
|
||
|
operand
|
||
|
value-type)))))
|
||
|
|
||
|
(define (assemble-operands operands arg-specs)
|
||
|
(map (lambda (operand arg-spec)
|
||
|
(case arg-spec
|
||
|
((stob) (or (name->enumerand operand stob)
|
||
|
(error "unknown stored object type" operand)))
|
||
|
((byte nargs) operand)
|
||
|
(else (error "unknown operand type" operand arg-spec))))
|
||
|
operands
|
||
|
arg-specs))
|
||
|
|