summaryrefslogtreecommitdiff
path: root/module/language/sassy/parse.scm
blob: 1301fc915556951dcccef18f540bd87d931aaba9 (plain)
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
; parse.scm - Sassy's top level parser
; Copyright (C) 2005 Jonathan Kraut

; This library is free software; you can redistribute it and/or
; modify it under the terms of the GNU Lesser General Public
; License as published by the Free Software Foundation; either
; version 2.1 of the License, or (at your option) any later version.

; This library is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
; Lesser General Public License for more details.

; You should have received a copy of the GNU Lesser General Public
; License along with this library; if not, write to the Free Software
; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

; Contact:
; Jonathan Kraut
; 4130 43 ST #C2
; Sunnyside, NY 11104
; jak76@columbia.edu

; see file COPYING in the top of Sassy's distribution directory


; module parse
; import macros api text numbers opcodes push-stacks operands intern
; import-syntax meta-lambda
; export all

(define parse-directives
  
  (let ()

    (define (process-bits int output)
      (if (or (= 16 int) (= 32 int))
	  (sassy-bits-set! output int)
	  (error "sassy: bad bits" int)))
    
    (define (process-org text-base output)
      (if (and (integer? text-base)
	       (zero? (sassy-text-size output))
	       (positive? text-base))
	  (sassy-text-org-set!  output text-base)
	  (error "sassy: bad org" text-base)))
    
    (define (process-entry entry-label output)
      (if (symbol? entry-label)
	  (begin (sassy-symbol-set! output entry-label '(scope export))
		 (sassy-entry-point-set! output entry-label))
	  (error "sassy: bad entry" entry-label)))

    (define (process-include include-list output)
      (for-each
       (lambda (x)
	 (cond ((string? x) (parse-directives (read-file x) output))
	       ((symbol? x) (parse-directives (eval x
						    (interaction-environment))
					      output))
	       (else (error "sassy: bad include" x))))
       include-list))
  
    (define (process-scopes scope-list scope output)
      (for-each (lambda (x)
		  (if (eq? 'import scope)
		      (sassy-symbol-def-error output x))
		  (if (symbol? x)
		      (sassy-symbol-set! output x `(scope ,scope))
		      (error "sassy: bad scope" scope x)))
		scope-list))

    (define (align-to count align)
      (let ((diff (modulo count align)))
	(if (zero? diff)
	    0
	    (- align diff))))

    (define aligner
      (let ((power-of-2 (lambda (x)
			  (and (integer? x) (positive? x)
			       (zero? (logand x (- x 1)))
			       x))))
	(meta-lambda
	 (and 'align power-of-2))))

    (define (process-heap heap-list output)
      (letrec
	  ((heap-sizer
	    (meta-lambda
	     (or (and 'bytes  u-dword)
		 (and 'words  u-dword (lambda (units) (* units 2)))
		 (and 'dwords u-dword (lambda (units) (* units 4)))
		 (and 'qwords u-dword (lambda (units) (* units 8))))))
	   (heap-item
	    (meta-lambda
	     (or
	      (and ,@aligner (lambda (align)
			       (let ((size (sassy-heap-size output)))
				 (sassy-heap-size-set!
				  output (+ size (align-to size align)))
				 (when (> align (sassy-heap-align output))
				       (sassy-heap-align-set! output align)))))
	      (and ,@heap-sizer (lambda (sizer)
				  (sassy-heap-size-set!
				   output (+ sizer (sassy-heap-size output)))))
	      (and 'label valid-label __
		   (lambda (label . rst)
		     (let ((current-size (sassy-heap-size output)))
		       (sassy-symbol-def-error output label)
		       (sassy-symbol-set! output label '(section heap)
					  `(offset ,current-size) '(size 0))
		       (for-each heap-item rst)
		       (sassy-symbol-set! output label
					  `(size ,(- (sassy-heap-size output)
						     current-size))))))
	      (and 'begin (* heap-item))
	      (else (lambda (h) (error "sassy: bad heap item" h)))))))
	(for-each heap-item heap-list)))

    (define (process-text text-list output)
      (letrec ((text-item
		(meta-lambda
		 (or
		  (and ,@aligner (lambda (align)
				   (push-stack-align (sassy-text-stack output)
						     align #x90
						     (sassy-text-org output))
				   (if (> align (sassy-text-align output))
				       (sassy-text-align-set! output align))))
 		  (and 'label valid-label __
		       (lambda (label . opcodes-or-prims)
			 (sassy-symbol-def-error output label)
			 (sassy-symbol-set!
			  output label
			  '(section text)
			  `(offset ,(+ (sassy-text-org output)
				       (sassy-text-size output))))
			 (sassy-symbol-set!
			  output label
			  `(size ,(handle-text-block `(begin ,@opcodes-or-prims)
				   output (t-make))))))
		  (else (lambda (opcode-or-prim)
			  (handle-text-block opcode-or-prim output
					     (t-make))))))))
	(for-each text-item text-list)))

    (define (sassy-reloc-set! output name section offset type patcher)
      (sassy-reloc-list-set!
       output (cons (make-sassy-reloc name section offset type patcher)
		    (sassy-reloc-list output))))

    (define (process-data data-list output)
      (letrec
	  ((current-byte-size (/ (sassy-bits output) 8))
	   (char/str/num
	    (lambda (item size)
	      (let ((data-stack (sassy-data-stack output)))
		(cond ((char? item)
		       (push-stack-push data-stack (char->integer item))
		       (push-stack-align data-stack size 0))
		      ((string? item)
		       (push-stack-push data-stack
					(map char->integer (string->list item)))
		       (push-stack-align data-stack size 0))
		      ((number? item)
		       (push-stack-push data-stack
					(number->byte-list item size)))
		      (else (lambda (i) (error "sassy: bad data" i)))))))
	   
	   (handle-data-symbol
	    (lambda (type target value)
	      (when (eqv? 'rel type)
		    (error "no rel relocations in data section right now"
			   (list 'reloc type target value)))
	      (when (eqv? '$here target)
		    (set! target (sassy-data-size output)))
	      (let* ((offset (sassy-data-size output))
		     (target-value (cond ((sassy-symbol-exists-env?
					   output target)
					  => 
					  (lambda (x) (sassy-symbol-offset x)))
					 (else target)))
		     (a-reloc (make-sassy-reloc
			       (get-reloc-target target output)
			       'data offset type #f value current-byte-size))
		     (patcher (let ((p (push-stack-push->patcher
					(sassy-data-stack output)
					(number->byte-list value
							   current-byte-size))))
				(lambda (new)
				  (p (number->byte-list new current-byte-size))
				  (sassy-reloc-value-set! a-reloc new)))))
		(sassy-reloc-patcher-set! a-reloc patcher)
		(sassy-reloc-list-set! output
				       (cons a-reloc (sassy-reloc-list output)))
		(if (number? target-value)
		    (patcher (+ target-value value))
		    (sassy-symbol-set!
		     output target
		     `(unres ,(lambda (n) (patcher (+ n value)))))))))
	   (data4
	    (meta-lambda
	     (or
	      (and ,@symbol? (lambda (label)
			       (check-label-size 4 current-byte-size 'dwords
						 label)
			       (handle-data-symbol 'abs label 0)))
	      (and ,@custom-reloc (lambda (a-reloc)
				    (check-label-size 4 current-byte-size
						      'dwords a-reloc)
				    (apply handle-data-symbol (cdr a-reloc))))
	      (else (lambda (data) (char/str/num data 4))))))
	   (data2
	    (meta-lambda
	     (or
	      (and ,@symbol? (lambda (label)
			       (check-label-size 2 current-byte-size 'words
						 label)
			       (handle-data-symbol 'abs label 0)))
	      (and ,@custom-reloc (lambda (a-reloc)
				    (check-label-size 2 current-byte-size
						      'words a-reloc)
				    (apply handle-data-symbol (cdr a-reloc))))
	      (else (lambda (data) (char/str/num data 2))))))
	   (data-item
	    (meta-lambda
	     (or
	      (and ,@aligner (lambda (align)
			       (push-stack-align (sassy-data-stack output)
						 align 0)
			       (if (> align (sassy-data-align output))
				   (sassy-data-align-set! output align))))
	      (and 'label valid-label __
		   (lambda (label . things)
		     (sassy-symbol-def-error output label)
		     (let ((offset (sassy-data-size output)))
		       (sassy-symbol-set! output label '(section data)
					  `(offset ,offset))
		       (for-each data-item things)
		       (sassy-symbol-set! output label
					  `(size ,(- (sassy-data-size output)
						     offset))))))
	      (and 'locals pair? __
		   (lambda (locals . body)
		     (let ((reset! (setup-locals locals output #f)))
		       (for-each data-item body)
		       (reset!))))
	      (and 'dwords __ (lambda datas (for-each data4 datas)))
	      (and 'bytes  __ (lambda datas (for-each
					     (lambda (x) (char/str/num x 1))
					     datas)))
	      (and 'words  __ (lambda datas (for-each data2 datas)))
	      (and 'qwords __ (lambda datas (for-each
					     (lambda (x) (char/str/num x 8))
					     datas)))
	      (and 'begin (* data-item))
	      (else (lambda (i) (error "sassy: bad data items" i)))))))
	(for-each data-item data-list)))

    (lambda (directives-list output)
      (letrec
	  ((parse-expand (lambda (itm) (parse (sassy-expand itm))))
	   (parse
	     (meta-lambda
	      (or
	       ,@'void
	       (and 'text    __ (lambda lst (process-text lst output)))
	       (and 'heap    __ (lambda lst (process-heap lst output)))
	       (and 'data    __ (lambda lst (process-data lst output)))
	       (and 'import  __ (lambda lst (process-scopes
					     lst 'import output)))
	       (and 'export  __ (lambda lst (process-scopes
					     lst 'export output)))
	       (and 'include __ (lambda lst (process-include lst output)))
;	       (and 'direcs  __ (lambda lst (parse-directives lst output)))
	       (and 'entry    ? (lambda (symb) (process-entry symb output)))
	       (and 'org      ? (lambda (int ) (process-org int output)))
	       (and 'bits     ? (lambda (int ) (process-bits int output)))
	       (and 'begin (* parse-expand))
	       (else (lambda (err) (error "sassy: bad directive" err)))))))
	(for-each parse-expand directives-list)))))