-
Notifications
You must be signed in to change notification settings - Fork 4
/
label-sig.rkt
159 lines (127 loc) · 5.87 KB
/
label-sig.rkt
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#lang racket/base
(require racket/unit
"tools/signature-forms.rkt"
"macro.rkt")
(provide label^)
;; FLAT TARGET CODE LABELS
;;
;; A collection of Scheme macros to create concatenative target code
;; structure. This fits into the big picture as follows:
;;
;; * Concatenative macros (those defined with `macro:') are
;; represented as compilation state transformers.
;;
;; * Compilation state is layered (similar to stacked Monads). This
;; is to represent different classes of concatenative macros,
;; ranging from those that represent pure stack functions (such as
;; `+'), to those that implement arbitrary target code
;; transformations.
;;
;; * Target code is represented as a control flow graph (CFG), where
;; basic blocks represent straight-line code and (conditional) jump
;; instructions link to other basic blocks.
;;
;; It is important to note that the CFG is less abstract than i.e. a
;; graph of function calls. I.e. it explicitly supports the notion of
;; ``fall through''. This is necessary to implement flexible control
;; structures with direct machine control, without the need for an
;; optimizer to translate i.e. a graph of function calls to a CFG.
;;
;;
;; -------------------------------------------------------------------
;;
;; Implementation note:
;;
;; Because it's not possible to express macros in terms of multiple
;; unit signatures, we take an intermediate step where
;;
;; 1) a signature is defined that exports the macros, and references
;; a separate collection of identifiers in the signature
;;
;; 2) a binding unit label-unit.rkt is defined that exports these
;; identifiers from directly importing them from other signatures.
;;
;; Some renaming using a `label:' prefix is necessary in order to not
;; cause clashes when the original collection of signatures is
;; imported somewhere else, along side the label^ signature.
(define-signature label^
;; Identifiers used in the implementation of the macros.
;; Concatenative macros
(label:exit ;; to implement functions on top of CFGs
label:allot ;; to reserve RAM space
label:org-begin ;; root a CFG segment at a fixed physical address..
label:org-end ;; ..switch back to normal CFG generation.
;; Compiler support code
label:wrap-word ;; Post-process raw concatenative macro code for ..
label:wrap-variable ;; .. target words and variables.
label:wrap-macro
label:append! ;; Append CFG segment to current segment list.
;; Macros
;; FIXME: some of these could be hidden in modules.
;; Common word entry form. Each word identifier is represented by
;; 2 module level identifiers, one in the `target' namespace
;; pointing to the (still empty) CFG node and one in the `macro'
;; namespace to serve as a proxy for inserting target calls or
;; variable references.
;; The code generator body is appended to the global list of code
;; generators. Source code order is preserved to support proper
;; code fall-through operation. The functional composition of this
;; global list of codegens is the global code generator, which
;; builds the whole CFG starting from an empty compiler state.
(define-syntax-rule (word-defs wrap name raw-macro)
(begin
(define-values (label wrapper codegen)
(wrap 'name
#f ;; source location
raw-macro))
;; These 2 expand to `define' unless name is #f.
(word-define (target) name label)
(word-define (macro) name wrapper)
(label:append! codegen)))
(define-syntax word-define
(syntax-rules ()
((_ _ #f _) (begin)) ;; Don't define anonymous words.
((_ (n ...) name expr)
(ns (n ...) (define name expr)))))
;; The most basic form translates a list of (name . code) pairs to
;; flat code with fallthrough.
(define-syntax-rule (word-flat name rpn-code ...)
(begin
(define codegen (macro: rpn-code ...))
(words-def label:wrap-word name codegen)))
(define-syntax-rule (words-flat (name rpn-code ...) ...)
(begin (word-flat name rpn-code ...) ...))
;; To support functions on top of flat words, the `exit' word is
;; appended to the flat rpn code list.
(define-syntax-rule (word name rpn-code ...)
(begin
(define codegen (macro: rpn-code ... ,label:exit))
(word-defs label:wrap-word name codegen)))
(define-syntax-rule (words (name rpn-code ...) ...)
(begin (word name rpn-code ...) ...))
;; Compile code to a fixed address.
(define-syntax-rule (word-org-flat address rpn-code ...)
(begin
(define codegen
(macro: 'address ,label:org-begin ;; Switch to a new chain
rpn-code ... ;; append the code there,
,label:org-end)) ;; and switch back.
(word-defs label:wrap-word #f codegen)))
(define-syntax-rule (words-org-flat (addr rpn-code ...) ...)
(begin (word-org-flat addr rpn-code ...) ...))
;; Variables are based on the `allot' compiler macro which reserves
;; RAM space in the compilation state. The difference between flat
;; variables and non-flat ones is that the former are guaranteed to
;; be allocated in a contiguous area of RAM.
(define-syntax-rule (variable-entry name size)
(begin
(define codegen (macro: size ,label:allot))
(word-defs label:wrap-variable #f codegen)))
(define-syntax-rule (variables-flat v ...) (begin (variable-entry v 1) ...))
(define-syntax-rule (2variables-flat v ...) (begin (variable-entry v 2) ...))
;; Currently, all variables are flat.
(define-syntax-rule (variables . vs) (variables-flat . vs))
(define-syntax-rule (2variables . vs) (2variables-flat . vs))
;; Convenience rule for macros, in the same style:
(define-syntax-rule (macros . defs) (compositions (macro) macro: . defs))
))