aboutsummaryrefslogtreecommitdiffstats
path: root/csc/linker.csc
blob: feec289d4e4325c6849a2e31055b343ebc9a0eab (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
(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)
            insert
            compare-strings
            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 (make-label-map program)
      (let loop ((m (make-map compare-strings))
                 (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))))))