; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*- ; This is file assem.scm. ;;;; Disassembler and assembler (define (disassemble tem) (newline) (really-disassemble (cond ((number? tem) (extract (if (($ vm closure?) tem) (($ vm closure-template) tem) tem))) ((and (pair? tem) (eq? (car tem) 'lambda)) (compile-lambda tem (environment->cenv system-environment) nil)) ((template? tem) tem) ((closure? tem) (closure-template tem)) (else (error "not coercable to a template" tem))) 1) 'done) (define (really-disassemble tem level) (display "(%LAP ") ;field reserved for template name (if (template-name tem) (write (template-name tem)) (display "#F")) (let loop ((pc 0)) (if (< pc (code-vector-length (template-code tem))) (loop (write-instruction tem pc level)) (write-char #\) )))) (define (newline-indent n) (newline) (do ((i n (- i 1))) ((= i 0)) (write-char #\space))) (define (write-instruction tem pc level) (let* ((code (template-code tem)) (const tem) ;constants vector (opcode (code-vector-ref code pc)) (pc+1 (+ pc 1)) (lit (lambda () (vector-ref const (code-vector-ref code pc+1)))) (pc+2 (+ pc 2))) (newline-indent (* level 2)) (if (< pc 10) (display " ")) (write pc) (display " (") (write (enumerand->name opcode op)) (let ((new-pc (cond ((= opcode op/literal) (write-string " '") (write (lit)) pc+2) ((= opcode op/native) (write-char #\space) (write (code-vector-ref code pc+1)) (write-string " '") (write (vector-ref const (code-vector-ref code pc+2))) (+ pc 3)) ((or (= opcode op/global) (= opcode op/set-global!)) (write-char #\space) (write `(cell ,(cell-name (lit)))) pc+2) ((= opcode op/make-closure) (write-char #\space) (really-disassemble (lit) (+ level 1)) pc+2) ((or (= opcode op/local) (= opcode op/set-local!)) (write-char #\space) (write (code-vector-ref code pc+1)) (write-char #\space) (write (code-vector-ref code pc+2)) (+ pc 3)) ((or (= opcode op/check-nargs=) (= opcode op/check-nargs>=) (= opcode op/make-env) (= opcode op/make-rest-list) (= opcode op/call) (= opcode op/spread-args) (= opcode op/open-port)) (write-char #\space) (write (code-vector-ref code pc+1)) pc+2) ((or (= opcode op/jump-if-false) (= opcode op/jump) (= opcode op/make-cont)) (write-char #\space) (write `(-> ,(+ pc (code-vector-ref code pc+1) 2))) pc+2) ((or (= opcode op/make-d-vector) (= opcode op/stob-of-type?) (= opcode op/d-vector-ref) (= opcode op/d-vector-set!) (= opcode op/d-vector-length) (= opcode op/make-b-vector) (= opcode op/b-vector-ref) (= opcode op/b-vector-set!) (= opcode op/b-vector-length)) (write-char #\space) (write `(e stob ,(enumerand->name (code-vector-ref code pc+1) stob))) pc+2) ((= opcode op/d-vector) (write-char #\space) (write `(e stob ,(enumerand->name (code-vector-ref code pc+1) stob))) (write-char #\space) (write (code-vector-ref code pc+2)) (+ pc 3)) (else pc+1)))) (write-char #\)) new-pc))) ; The rudiments of an assembler. (define-compilator '%lap (lambda (exp cenv cont state) (sequentially (emit op/make-closure (get-literal state (compile-lap (cadr exp) (cddr exp)))) (dispose-of-val cont)))) (define (compile-lap name instruction-list) name ;ignored for now (compiling (lambda (state) (assemble instruction-list state)))) (define (assemble instruction-list state) (do ((l instruction-list (cdr l)) (seg empty-segment (if (pair? (car l)) (sequentially seg (assemble-instruction (car l) state)) seg))) ;Ignore labels. ((null? l) seg))) (define (assemble-instruction instr state) (do ((os (cdr instr) (cdr os)) (seg (emit (name->enumerand (car instr) op)) (sequentially seg (assemble-operand (car os) state)))) ((null? os) seg))) (define (assemble-operand opcode state) (cond ((integer? opcode) (emit opcode)) ((eq? (car opcode) 'quote) (emit (get-literal state (cadr opcode)))) ((eq? (car opcode) 'e) (emit (name->enumerand (caddr opcode) (case (cadr opcode) ((stob) stob) (else (error "losing" opcode)))))) ((eq? (car opcode) '->) (error "not yet implemented" opcode)) (else (error "unknown operand type" opcode)))) ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*- ; This is file basic.scm. ;;;; Fundamental definitions ; The value returned by SET! is unspecified. (define unspecified (let ((x 0)) (set! x 1))) ; Booleans (define t (= 0 0)) (define nil (= 0 1)) (define (not x) (if x nil t)) (define (boolean? x) (or (eq? x t) (eq? x nil))) ; Equality (define eqv? eq?) (define (equal? obj1 obj2) (cond ((eqv? obj1 obj2) t) ((pair? obj1) (and (pair? obj2) (equal? (car obj1) (car obj2)) (equal? (cdr obj1) (cdr obj2)))) ((string? obj1) (and (string? obj2) (string=? obj1 obj2))) ((vector? obj1) (and (vector? obj2) (let ((z (vector-length obj1))) (and (= z (vector-length obj2)) (let loop ((i 0)) (cond ((= i z) t) ((equal? (vector-ref obj1 i) (vector-ref obj2 i)) (loop (+ i 1))) (else nil))))))) (else nil))) ; Numbers ; How to modularize for VM's like Maclisp that have generic arithmetic ; built-in? (define integer? fixnum?) ;Fix later (define rational? integer?) ;Fix later (define real? number?) ;Fix later (define complex? number?) ;Fix later (define (zero? x) (= x 0)) (define (positive? x) (< 0 x)) (define (negative? x) (< x 0)) (define (even? n) (= 0 (remainder n 2))) (define (odd? n) (not (even? n))) (define (exact? n) t) ;? (define (inexact? n) nil) (define (> x y) (< y x)) (define (<= x y) (not (< y x))) (define (>= x y) (not (< x y))) (define (max x y) (if (< x y) y x)) (define (min x y) (if (< x y) x y)) (define (/ x y) (if (= (remainder x y) 0) (quotient x y) (error "ratios not yet implemented" `(/ x y)))) (define (abs n) (if (< n 0) (- 0 n) n)) (define (expt n p) ;losing algorithm, fix later (do ((a 1 (* a n)) (p p (- p 1))) ((<= p 0) a))) ; Lists [primitive: pair? cons car cdr set-car! set-cdr!] (define (caar x) (car (car x))) (define (cadr x) (car (cdr x))) (define (cdar x) (cdr (car x))) (define (cddr x) (cdr (cdr x))) (define (caaar x) (car (caar x))) (define (caadr x) (car (cadr x))) (define (cadar x) (car (cdar x))) (define (caddr x) (car (cddr x))) (define (cdaar x) (cdr (caar x))) (define (cdadr x) (cdr (cadr x))) (define (cddar x) (cdr (cdar x))) (define (cdddr x) (cdr (cddr x))) (define (caaaar x) (car (caaar x))) (define (caaadr x) (car (caadr x))) (define (caadar x) (car (cadar x))) (define (caaddr x) (car (caddr x))) (define (cadaar x) (car (cdaar x))) (define (cadadr x) (car (cdadr x))) (define (caddar x) (car (cddar x))) (define (cadddr x) (car (cdddr x))) (define (cdaaar x) (cdr (caaar x))) (define (cdaadr x) (cdr (caadr x))) (define (cdadar x) (cdr (cadar x))) (define (cdaddr x) (cdr (caddr x))) (define (cddaar x) (cdr (cdaar x))) (define (cddadr x) (cdr (cdadr x))) (define (cdddar x) (cdr (cddar x))) (define (cddddr x) (cdr (cdddr x))) (define (null? x) (eq? x '())) (define (list . l) l) (define (length l) (do ((l l (cdr l)) (i 0 (+ i 1))) ((null? l) i))) (define (append . lists) (letrec ((append2 (lambda (l1 l2) (if (null? l1) l2 (cons (car l1) (append2 (cdr l1) l2)))))) (cond ((null? lists) '()) ((null? (cdr lists)) (car lists)) ((null? (cddr lists)) (append2 (car lists) (cadr lists))) (else (append2 (car lists) (apply append (cdr lists))))))) (define (reverse list) (letrec ((append-reverse (lambda (list seed) (if (null? list) seed (append-reverse (cdr list) (cons (car list) seed)))))) (append-reverse list '()))) (define (list-tail l index) (let loop ((l l) (i index)) (cond ((= i 0) l) (else (loop (cdr l) (- i 1)))))) (define (list-ref l k) (car (list-tail l k))) (define (last-pair l) (let loop ((l l)) (if (not (pair? (cdr l))) l (loop (cdr l))))) (define (mem pred) (lambda (obj l) (let loop ((l l)) (cond ((null? l) nil) ((pred obj (car l)) l) (else (loop (cdr l))))))) (define memq (mem eq?)) (define memv (mem eqv?)) (define member (mem equal?)) (define (ass pred) (lambda (obj l) (let loop ((l l)) (cond ((null? l) nil) ((pred obj (caar l)) (car l)) (else (loop (cdr l))))))) (define assq (ass eq?)) (define assv (ass eqv?)) (define assoc (ass equal?)) (define (delq obj l) (cond ((null? l) l) ((eq? obj (car l)) (delq obj (cdr l))) (else (cons (car l) (delq obj (cdr l)))))) ; Characters [primitive: char? char->ascii ascii->char char=? char] (define (char>? x y) (char y x)) (define (char>=? x y) (not (char x y))) (define (char<=? x y) (not (char y x))) (define char->integer char->ascii) (define integer->char ascii->char) (define ay (char->integer #\a)) (define zed (char->integer #\z)) (define cap-ay (char->integer #\A)) (define cap-zed (char->integer #\Z)) (define zero (char->integer #\0)) (define nine (char->integer #\9)) (define (char-whitespace? c) (or (char=? c #\space) (char=? c #\newline) (char=? c #\tab) (char=? c #\page))) (define (char-lower-case? c) (let ((c (char->ascii c))) (and (>= c ay) (<= c zed)))) (define (char-upper-case? c) (let ((c (char->ascii c))) (and (>= c cap-ay) (<= c cap-zed)))) (define (char-numeric? c) (let ((c (char->ascii c))) (and (>= c zero) (<= c nine)))) (define (char-alphabetic? c) (or (char-upper-case? c) (char-lower-case? c))) (define (char-upcase c) (if (char-lower-case? c) (ascii->char (- (char->ascii c) (- ay cap-ay))) c)) (define (char-downcase c) (if (char-upper-case? c) (ascii->char (+ (char->ascii c) (- ay cap-ay))) c)) ; Strings (define (substring s start end) (let ((new-string (make-string (- end start)))) (do ((i start (+ i 1)) (j 0 (+ j 1))) ((= i end) new-string) (string-set! new-string j (string-ref s i))))) (define (string-append s1 s2) ;Wants to be n-ary (let ((l1 (string-length s1)) (l2 (string-length s2))) (let ((new-string (make-string (+ l1 l2)))) (do ((i 0 (+ i 1))) ((= i l1) (do ((i i (+ i 1)) (j 0 (+ j 1))) ((= j l2) new-string) (string-set! new-string i (string-ref s2 j)))) (string-set! new-string i (string-ref s1 i)))))) (define (string->list v) (let ((z (string-length v))) (do ((i (- z 1) (- i 1)) (l '() (cons (string-ref v i) l))) ((< i 0) l)))) (define (list->string l) (let ((v (make-string (length l)))) (do ((i 0 (+ i 1)) (l l (cdr l))) ((null? l) v) (string-set! v i (car l))))) (define (string s1 s2) (let ((l1 (string-length s1)) (l2 (string-length s2))) (let ((z (min l1 l2))) (let loop ((i 0)) (cond ((= i z) (< l1 l2)) ((char (string-ref s1 i) (string-ref s2 i)) t) (else (loop (+ i 1)))))))) (define (string>? s1 s2) (string s2 s1)) (define (string<=? s1 s2) (not (string>? s1 s2))) (define (string>=? s1 s2) (not (string s1 s2))) (define (string->symbol string) (intern string the-symbol-table)) ;(define (reverse-list->string l n) ;In microcode? ; (do ((l l (cdr l)) ; (i (- n 1) (- i 1))) ; ((< i 0) (return obj)) ; (string-set! obj i (car l)))) (define (string-find-if pred string) (let loop ((i 0)) (cond ((>= i (string-length string)) nil) ((pred (string-ref string i)) i) (else (loop (+ i 1)))))) ; Vectors (define (vector . l) (list->vector l)) (define (vector->list v) (let ((z (vector-length v))) (do ((i (- z 1) (- i 1)) (l '() (cons (vector-ref v i) l))) ((< i 0) l)))) (define (list->vector l) (let ((v (make-vector (length l) nil))) (do ((i 0 (+ i 1)) (l l (cdr l))) ((null? l) v) (vector-set! v i (car l))))) (define (vector-fill! v x) ;Not essential, but useful (let ((z (vector-length v))) (do ((i 0 (+ i 1))) ((= i z) unspecified) (vector-set! v i x)))) (define (vector-posq thing v) ;Useful (let loop ((i 0)) (cond ((>= i (vector-length v)) nil) ((eq? thing (vector-ref v i)) i) (else (loop (+ i 1)))))) ; Control features (define procedure? closure?) (define (map proc l) (if (null? l) '() (cons (proc (car l)) (map proc (cdr l))))) (define (for-each proc l) (if (null? l) unspecified (begin (proc (car l)) (for-each proc (cdr l))))) (define (make-promise thunk) (let ((already-run? nil) (result nil)) (lambda () (cond ((not already-run?) (set! result (thunk)) (set! already-run? t))) result))) (define (force promise) (promise)) ; Tables (not a standard Scheme feature, but a handy one) (define (make-table) (list 'table)) (define (table-ref table key) (let ((probe (assq key (cdr table)))) (if probe (cdr probe) nil))) (define (table-set! table key val) (let ((probe (assq key (cdr table)))) (if probe (set-cdr! probe val) (set-cdr! table (cons (cons key val) (cdr table)))))) ; Macro auxiliaries (define (or-aux p else-thunk) (if p p (else-thunk))) (define (and-aux p then-thunk) (if p (then-thunk) p)) (define (=>-aux p proc-thunk else-thunk) (if p ((proc-thunk) p) (else-thunk))) (define (case-aux key key-lists else-thunk . thunks) (let loop ((k key-lists) (t thunks)) (cond ((null? k) (else-thunk)) ((memv key (car k)) ((car thunks))) (else (loop (cdr k) (cdr t)))))) ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*- ; This is file comp.scm. ;;;; The compiler ; Opimizations are marked with +++, and may be flushed. ; COMPILE-TOP (define (compile-top l-exp env name) (compile-lambda l-exp (environment->cenv env) name)) (define (compile-lambda exp cenv name) (compiling (lambda (state) (let* ((args (cadr exp)) (body (cddr exp)) (nargs (number-of-required-args args))) (sequentially (if (n-ary? args) (sequentially (if (pair? args) (emit op/check-nargs>= nargs) empty-segment) ;+++ (emit op/make-rest-list nargs) (emit op/make-env (+ nargs 1))) (sequentially (emit op/check-nargs= nargs) (if (null? args) empty-segment ;+++ (emit op/make-env nargs)))) (compile (process-body body) (if (null? args) cenv ;+++ (bind-vars (normalize-formals args) cenv)) '(return) state)))) name)) (define (number-of-required-args formals) (do ((l formals (cdr l)) (i 0 (+ i 1))) ((not (pair? l)) i))) (define (n-ary? formals) (not (null? (if (pair? formals) (cdr (last-pair formals)) formals)))) (define (normalize-formals formals) (cond ((null? formals) '()) ((pair? formals) (cons (car formals) (normalize-formals (cdr formals)))) (else (list formals)))) (define (reverse-list->vector l i) i (list->vector (reverse l))) (define (compile exp cenv cont state) (cond ((symbol? exp) (compile-variable exp cenv cont state)) ((or (number? exp) (char? exp) (string? exp) (boolean? exp)) (compile-literal exp cont state)) ((not (pair? exp)) (error "invalid expression" exp)) ((eq? (car exp) system-ref-marker) (compile (cadr exp) (environment->cenv system-environment) cont state)) ((not (symbol? (car exp))) (compile-unknown-call exp cenv cont state)) (else (let ((probe (table-ref compilators (car exp)))) (if probe (probe exp cenv cont state) (let ((probe (get-macro-expander (car exp)))) (if probe (compile (probe exp) cenv cont state) (compile-var-call exp cenv cont state)))))))) (define (compile-variable exp cenv cont state) (sequentially (let ((info (clookup cenv exp))) (case (car info) ((local) (emit op/local (cadr info) (caddr info))) ((global primitive) (emit op/global (get-literal state (cadr info)))))) (dispose-of-val cont))) (define compilators (make-table)) (define (define-compilator name proc) (table-set! compilators name proc)) (define-compilator 'quote (lambda (exp cenv cont state) cenv ;ignored (compile-literal (cadr exp) cont state))) (define-compilator 'lambda (lambda (exp cenv cont state) (let ((name (if (eq? (car cont) 'set!) (cadr cont) nil))) (sequentially (emit op/make-closure (get-literal state (compile-lambda exp cenv name))) (dispose-of-val cont))))) (define-compilator 'set! (lambda (exp cenv cont state) (let ((var (cadr exp)) (val (caddr exp))) (sequentially (compile val cenv `(set! ,var) state) (let ((info (clookup cenv var))) (case (car info) ((local) (emit op/set-local! (cadr info) (caddr info))) ((global) (emit op/set-global! (get-literal state (cadr info)))) ((primitive) (warn "assigning a primitive" var) (emit op/set-global! (get-literal state (cadr info)))))) (dispose-of-val cont))))) (define-compilator 'if (lambda (exp cenv cont state) (let* ((alt-segment (compile (cadddr exp) cenv cont state)) (con-segment (sequentially (compile (caddr exp) cenv cont state) ;; If (segment-size alt-segment) is too big, we ought to ;; shrink it somehow (e.g. by eta-converting: e => ;; ((lambda () e))). All three of the EMIT-OFFSET's have ;; this problem. Deal with this later... (if (eq? (car cont) 'return) ;Eliminate dead code. empty-segment ;+++ (emit-offset op/jump (segment-size alt-segment)))))) (sequentially (compile (cadr exp) cenv '(val) state) (emit-offset op/jump-if-false (segment-size con-segment)) con-segment alt-segment)))) (define-compilator 'begin (lambda (exp cenv cont state) (compile-begin (cdr exp) cenv cont state))) (define-compilator 'letrec (lambda (exp cenv cont state) (compile (rewrite-letrec exp) cenv cont state))) (define (rewrite-letrec exp) (let ((specs (car exp)) (body (cdr exp))) `((lambda ,(map car specs) ,@(map (lambda (spec) `(set! ,@spec)) specs) ,@body) ,@(map (lambda (spec) spec ;ignored `(,(make-system-ref 'unassigned))) specs)))) (define (compile-literal obj cont state) (sequentially (emit op/literal (get-literal state obj)) (dispose-of-val cont))) (define (compile-begin exp-list cenv cont state) (cond ((null? (cdr exp-list)) (compile (car exp-list) cenv cont state)) (else (sequentially (compile (car exp-list) cenv '(val) state) (compile-begin (cdr exp-list) cenv cont state))))) (define (compile-var-call exp cenv cont state) (let ((info (clookup cenv (car exp)))) (case (car info) ((primitive) (compile-primitive-call (caddr info) (cdr exp) cenv cont state)) (else (compile-unknown-call exp cenv cont state))))) ; Compile a call to an unknown procedure (define (compile-unknown-call exp cenv cont state) (maybe-push-continuation (sequentially (push-all (cdr exp) cenv state) (compile (car exp) cenv '(val) state) (emit op/call (length (cdr exp)))) cont)) (define (maybe-push-continuation code cont) (if (eq? (car cont) 'return) code (sequentially (emit-offset op/make-cont (segment-size code)) code))) (define (push-all exp-list cenv state) (if (null? exp-list) empty-segment ;; Sort of a kludge. Push all but last, then push last. (sequentially (push-all-but-last exp-list cenv state) (emit op/push)))) (define (push-all-but-last exp-list cenv state) (let loop ((l exp-list) (code empty-segment)) (if (null? (cdr l)) (sequentially code (compile (car l) cenv '(val) state)) (loop (cdr l) (sequentially code (compile (car l) cenv '(val) state) (emit op/push)))))) (define (dispose-of-val cont) (case (car cont) ((return) (emit op/return)) (else empty-segment))) ; CLOOKUP returns one of ; (LOCAL back over) ; (GLOBAL cell) ; (PRIMITIVE cell primitive) (define (clookup cenv var) (cenv var 0)) (define (environment->cenv env) (let ((cenv (lambda (var back) back ;ignored (list 'global (lookup env var))))) (if (eq? env system-environment) (add-usual-integrations cenv) cenv))) (define (add-usual-integrations cenv) (lambda (var back) back ;ignored (let ((info (clookup cenv var)) (probe (table-ref primitives var))) (if probe (list 'primitive (cadr info) probe) info)))) ; Local environment management (define (bind-vars vars cenv) (lambda (var back) (let loop ((rib vars) (over 1)) (cond ((null? rib) (cenv var (+ back 1))) ;Not here, try outer env. ((eq? var (car rib)) (list 'local back over)) (else (loop (cdr rib) (+ over 1))))))) (define (compiling proc name) ;; Has type (proc ((proc (state) segment)) template) (let* ((state (make-state)) (segment (proc state))) (make-template segment state name))) ; Literal management (define (make-template segment state name) (list->vector (cons (segment->code-vector segment) (cons name (reverse (state-literals state)))))) (define (make-state) (list '() 2)) (define state-literals car) (define state-literals-index cadr) (define (set-state-literals! state val) (set-car! state val)) (define (set-state-literals-index! state val) (set-car! (cdr state) val)) (define (get-literal state thing) ;; Potential optimization: eliminate duplicate entries. (let ((index (state-literals-index state))) (if (>= index byte-limit) (error "code too complicated for this system" (state-literals state))) (set-state-literals! state (cons thing (state-literals state))) (set-state-literals-index! state (+ index 1)) index)) ; Code emission utilities (define (sequentially . segments) (make-segment (lambda (cv pc) (let loop ((pc pc) (s segments)) (if (null? s) pc (loop (emit-segment! cv pc (car s)) (cdr s))))) (let loop ((size 0) (s segments)) (if (null? s) size (loop (+ size (segment-size (car s))) (cdr s)))))) (define (emit opcode . operands) (for-each (lambda (byte) (if (>= byte byte-limit) (error "byte too big (probably due to complicated code)" opcode operands))) operands) (make-segment (lambda (cv pc) (do ((l operands (cdr l)) (pc (emit-byte! cv pc opcode) (emit-byte! cv pc (car l)))) ((null? l) pc))) (+ 1 (length operands)))) (define (emit-offset opcode offset) (emit opcode offset)) (define (emit-byte! cv pc byte) (code-vector-set! cv pc byte) (+ pc 1)) (define make-segment cons) (define segment-size cdr) (define (emit-segment! cv pc segment) ((car segment) cv pc)) (define empty-segment (sequentially)) (define (segment->code-vector segment) (let ((cv (make-code-vector (segment-size segment)))) (emit-segment! cv 0 segment) cv)) ; Print a warning message (define (warn msg . things) (newline) (display "** Warning: ") (display msg) (let ((o (current-output-port))) (for-each (lambda (thing) (write-char #\space o) (write thing o)) things))) ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*- ; This is file cprim.scm. ;;;; Compiling primitives (define (definitions-for-all-compiler-primitives) ;yuck (map (lambda (name) (let* ((prim (table-ref primitives name)) (nargs (primitive-nargs prim)) (some-names (reverse '(a b c d e f g h i j k l))) (args (list-tail some-names (- (length some-names) nargs)))) ;; Note that if (primitive-n-ary? prim) then we are losing! ;; Fix later, somehow. `(define (,name ,@args) (call-primitively ,(primitive-name prim) ,@args)))) (reverse *primitive-names*))) (define (make-primitive name nargs n-ary? proc) (list name nargs n-ary? proc)) (define primitive-name car) (define primitive-nargs cadr) (define primitive-n-ary? caddr) (define primitive-compilator cadddr) (define-compilator 'call-primitively (lambda (exp cenv cont state) (let ((exp (cdr exp))) (let ((probe (table-ref primitives (car exp)))) (if probe (compile-primitive-call probe (cdr exp) cenv cont state) (begin (warn "procedure in CALL-PRIMITIVELY isn't primitive" exp) (compile-unknown-call exp cenv cont state))))))) (define (compile-primitive-call primitive args cenv cont state) (let ((name (primitive-name primitive))) (if ((if (primitive-n-ary? primitive) >= =) (length args) (primitive-nargs primitive)) ((primitive-compilator primitive) args cenv cont state) (begin (warn "wrong number of arguments to primitive" (cons name args)) (compile-unknown-call (cons (make-system-ref name) args) cenv cont state))))) (define primitives (make-table)) (define *primitive-names* '()) ; "dp" stands for "define-compiler-primitive". ; It wants a short name so that definitions can fit on a single line. (define (dp name nargs n-ary? proc) (table-set! primitives name (make-primitive name nargs n-ary? proc)) (if (not (memq name *primitive-names*)) (set! *primitive-names* (cons name *primitive-names*))) name) (dp 'primitive-catch 1 #f ;(primitive-catch (lambda (cont) ...)) (lambda (args cenv cont state) (maybe-push-continuation (sequentially (emit op/push-cont) (compile (car args) cenv '(val) state) (emit op/call 1)) cont))) (dp 'primitive-throw 2 #f ;(primitive-throw cont val) (lambda (args cenv cont state) cont ;ignored (sequentially (compile (car args) cenv '(val) state) (emit op/push) (compile (cadr args) cenv '(val) state) (emit op/pop-cont) (emit op/return)))) ; APPLY wants to first spread the list, then load the procedure. (dp 'apply 2 #f (lambda (args cenv cont state) (maybe-push-continuation (sequentially (push-all (cdr args) cenv state) (emit op/spread-args (length (cdr args))) (compile (car args) cenv '(val) state) ;procedure arg (emit op/n-call)) ;pops nargs cont))) ; Easy miscellaneous primitives (define (trivial name) (lambda (args cenv cont state) (sequentially (if (null? args) empty-segment (push-all-but-last args cenv state)) (emit (name->enumerand name op)) (dispose-of-val cont)))) ; Synchronize this list with ARCH.SCM and PRIM.SCM ; THIS IS RIDICULOUS. The list should appear in only one place. (for-each (lambda (z) (dp (car z) (cadr z) #f (trivial (car z)))) '(;; Scalar (eq? 2) (fixnum? 1) (number? 1) (+ 2) ;or n-ary (- 2) ;or n-ary (* 2) ;or n-ary (= 2) ;or n-ary (< 2) ;or n-ary (quotient 2) (remainder 2) (char? 1) (char=? 2) (char 2) (char->ascii 1) (ascii->char 1) (eof-object? 1) ;; Stored (pair? 1) (cons 2) (car 1) (cdr 1) (set-car! 2) (set-cdr! 2) (symbol? 1) (make-symbol 1) (symbol->string 1) (cell? 1) (make-cell 2) (cell-name 1) (contents 1) (set-contents! 2) (closure? 1) (make-closure 2) (closure-env 1) (closure-template 1) (code-vector? 1) (make-code-vector 2) (code-vector-length 1) (code-vector-ref 2) (code-vector-set! 3) (string? 1) (make-string 2) ;or 1 (string-length 1) (string-ref 2) (string-set! 3) (vector? 1) (make-vector 2) ;or 1 (vector-length 1) (vector-ref 2) (vector-set! 3) ;; I/O (input-port? 1) (output-port? 1) (open-port 2) (close-port 1) (read-char 1) ;or 0 (peek-char 1) ;or 0 (write-char 2) ;or 1 (write-string 2) ;; Misc (unassigned 0) (halt 1) (set-enabled-interrupts! 1) (return-from-handler 1) (write-image 1) ;; Unnecessary (reverse-list->string 2) (string=? 2) (intern 2) (lookup 2))) ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*- ; This is file defprim.scm. ;;;; Macros for defining primitives (define expand-define-primitive (make-expander (lambda (close opcode input-types action . returner-option) (let ((places (reverse (shorten `(*val* *arg2* *arg3* *arg4*) input-types))) (nargs (length input-types))) (close ;Cheat `(define-opcode ,opcode (lambda () ,@(if (>= nargs 2) `((set! *arg2* (pop))) `()) ,@(if (>= nargs 3) `((set! *arg3* (pop))) `()) ,@(if (>= nargs 4) `((set! *arg4* (pop))) `()) (if (and ,@(map (lambda (in place) `((input-type-predicate ,in) ,place)) input-types places)) ,(let ((yow `(,action ,@(map (lambda (in place) `((input-type-coercion ,in) ,place)) input-types places)))) (if (null? returner-option) yow `(,(car returner-option) ,yow))) (goto wrong-type-argument))))))))) (define expand-define-primitive-structure-type (make-expander (lambda (close type make . body) (let* ((type-> (concatenate-symbol type '->)) (type? (concatenate-symbol type '?)) (size (concatenate-symbol type '-size)) (op/ (lambda (name) (concatenate-symbol 'op/ name))) (vars (shorten `(a b c d e f g) body))) (close ;Cheat `(let ((,type-> (input-type ,type? no-coercion))) (define-primitive ,(op/ type?) (any->) ,type? ->boolean) (define-primitive ,(op/ make) ,(map (lambda (var) var `any->) vars) (lambda ,vars (ensure-space ,size (lambda () (return (,make ,@vars)))))) ,@(apply append (map (lambda (slot) (let ((get (car slot))) `((define-primitive ,(op/ get) (,type->) ,get return) ,@(if (null? (cdr slot)) `() (let ((set (cadr slot))) `((define-primitive ,(op/ set) (,type-> any->) ,set ->unspecified))))))) body)))))))) (define expand-define-vector-type (make-expander (lambda (close type) (let* ((type-> (concatenate-symbol type '->)) (type? (concatenate-symbol type '?)) (size (concatenate-symbol type '-size)) (make (concatenate-symbol 'make- type)) (length (concatenate-symbol type '-length)) (ref (concatenate-symbol type '-ref)) (set (concatenate-symbol type '-set!)) (op/ (lambda (name) (concatenate-symbol 'op/ name)))) (close ;Cheat `(let ((,type-> (input-type ,type? no-coercion))) (define-primitive ,(op/ type?) (any->) ,type? ->boolean) (define-primitive ,(op/ length) (,type->) ,length ->fixnum) (define-primitive ,(op/ make) (fixnum-> any->) (vector-maker ,size ,make ,set)) (define-primitive ,(op/ ref) (,type-> fixnum->) (vector-referencer ,length ,ref)) (define-primitive ,(op/ set) (,type-> fixnum-> any->) (vector-setter ,length ,set)) )))))) (define (shorten l1 l2) (map (lambda (x1 x2) x2 x1) l1 l2)) (define defprim-sig (make-signature 'defprim-sig `((define-primitive ,(make-macro-alphatizer expand-define-primitive)) (define-primitive-structure-type ,(make-macro-alphatizer expand-define-primitive-structure-type)) (define-vector-type ,(make-macro-alphatizer define-vector-type))) ;;+++ KLUDGE '() '())) ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*- ; This is file derive.scm. ;;;; Macro expanders for standard derived expression types ;+++ Some day, update this module to implement Alan Bawden's proposal. (define rewriters (make-table)) (define (get-macro-expander sym) (table-ref rewriters sym)) ; The output of PARSE-TOP-LEVEL-FORM is a