|
8 | 8 | racket/match
|
9 | 9 | racket/set
|
10 | 10 | racket/promise
|
| 11 | + "build-nt-property.rkt" |
11 | 12 | "lang-struct.rkt"
|
12 | 13 | "match-a-pattern.rkt")
|
13 | 14 |
|
|
43 | 44 | (set-member? cyclic-nts (nt-name nt)))
|
44 | 45 | lang))
|
45 | 46 | ;; topological sort
|
46 |
| - (define sorted-finite |
| 47 | + (define sorted-left |
47 | 48 | (topo-sort non-cyclic
|
48 | 49 | (filter-edges edges non-cyclic)))
|
49 | 50 | ;; rhs sort
|
50 |
| - (define-values (sorted-cyclic unsolvables) |
51 |
| - (sort-productions cyclic clang-all-ht/f)) |
52 |
| - (values sorted-finite |
53 |
| - sorted-cyclic |
54 |
| - (build-cant-enumerate-table lang edges unsolvables))) |
| 51 | + (define sorted-right |
| 52 | + (sort-productions cyclic |
| 53 | + cyclic-nts |
| 54 | + clang-all-ht/f)) |
| 55 | + |
| 56 | + (values sorted-left |
| 57 | + sorted-right |
| 58 | + (build-cant-enumerate-table lang edges))) |
55 | 59 |
|
56 | 60 | ;; find-edges : lang -> (hash[symbol] -o> (setof (listof symbol)))
|
57 | 61 | (define (find-edges lang)
|
|
101 | 105 | (hash)
|
102 | 106 | lang))
|
103 | 107 |
|
104 |
| -;; find-cycles : (hash[symbol -o> (setof symbol)]) -> (setof symbol) |
| 108 | +;; find-cycles : (hash[symbol] -o> (setof symbol)) -> (setof symbol) |
105 | 109 | (define (find-cycles edges)
|
106 | 110 | (foldl
|
107 | 111 | (λ (v s)
|
|
186 | 190 | lang))
|
187 | 191 |
|
188 | 192 |
|
189 |
| -;; Problem: we need to find an ordering of the productions of each of |
190 |
| -;; the metavariables such that the graph induced by the first |
191 |
| -;; productions in each case has no cycles. |
192 |
| -;; spanning-tree : HyperGraph -> (Listof (List Index (Setof NTName))) (Listof NTName) |
193 |
| -(define (spanning-tree hg) |
194 |
| - (define init-vertices (hash-keys hg)) |
195 |
| - (let loop ([edges (hash)] |
196 |
| - [vertices init-vertices] |
197 |
| - [time (length init-vertices)]) |
198 |
| - (cond |
199 |
| - [(zero? time) |
200 |
| - (values edges vertices)] |
201 |
| - [else |
202 |
| - (match-define (cons v vs) vertices) |
203 |
| - (define good-edge |
204 |
| - (findf (λ (e) (andmap (λ (v2) (not (member v2 vertices))) (set->list (second e)))) |
205 |
| - (hash-ref hg v))) |
206 |
| - (cond [good-edge |
207 |
| - (loop (hash-set edges v good-edge) |
208 |
| - vs |
209 |
| - (length vs))] |
210 |
| - [else |
211 |
| - (loop edges (append vs (list v)) (sub1 time))])]))) |
212 |
| - |
213 |
| -;; A HyperGraph is a Hash NTName (Listof (List Index (Setof NTName))) |
214 |
| -;; associating each non-terminal to a list of out-going edges |
215 |
| -(define (hypergraph lang) |
216 |
| - (for/hash ([nt (in-list lang)]) |
217 |
| - (define out-edges |
218 |
| - (for/list ([i (in-naturals)] |
219 |
| - [rhs (in-list (nt-rhs nt))]) |
220 |
| - (list i (directly-used-nts (rhs-pattern rhs))))) |
221 |
| - (values (nt-name nt) out-edges))) |
222 |
| - |
223 |
| -;; sort-productions : lang (or/c #f (hash[symbol -o> (list/c any)])) |
224 |
| -;; -> lang |
225 |
| -;; sorts the language |
226 |
| -;; SIDE EFFECT: if clang-all-ht/f is not #f, sorts it |
227 |
| -(define (sort-productions lang clang-all-ht/f) |
228 |
| - (define-values (spanner unsolvables) (spanning-tree (hypergraph lang))) |
229 |
| - (define sorted |
230 |
| - (for/list ([cur-nt (in-list lang)]) |
231 |
| - (match cur-nt |
232 |
| - [(nt name productions) |
233 |
| - (cond |
234 |
| - [(hash-has-key? spanner name) |
235 |
| - (define the-edge (first (hash-ref spanner name))) |
236 |
| - |
237 |
| - ;; less than if the left is the chosen one and the right is not |
238 |
| - (define (less-than? i1 i2) |
239 |
| - (and (equal? i1 the-edge) |
240 |
| - (not (equal? i2 the-edge)))) |
241 |
| - |
242 |
| - (define production-vec (apply vector productions)) |
243 |
| - (define permutation |
244 |
| - (sort (build-list (vector-length production-vec) values) |
245 |
| - less-than? |
246 |
| - #:cache-keys? #t)) |
247 |
| - (when clang-all-ht/f |
248 |
| - (define clang-all-ht-nt-vec (apply vector (hash-ref clang-all-ht/f name))) |
249 |
| - (hash-set! clang-all-ht/f name |
250 |
| - (for/list ([i (in-list permutation)]) |
251 |
| - (vector-ref clang-all-ht-nt-vec i)))) |
252 |
| - (nt name |
253 |
| - (for/list ([i (in-list permutation)]) |
254 |
| - (vector-ref production-vec i)))] |
255 |
| - [else (nt name productions)])]))) |
256 |
| - (values sorted unsolvables)) |
| 193 | +;; sort-productions : lang, |
| 194 | +;; (hash[symbol] -o> (setof symbol)) |
| 195 | +;; (or/c #f (hash[symbol -o> (list/c any)])) -> lang |
| 196 | +(define (sort-productions cyclic nts clang-all-ht/f) |
| 197 | + (define table (terminal-distance-table cyclic nts)) |
| 198 | + (for/list ([cur-nt (in-list cyclic)]) |
| 199 | + (match cur-nt |
| 200 | + [(nt name productions) |
| 201 | + (define (max-terminal-distance pat) |
| 202 | + (define referenced-nts (directly-used-nts pat)) |
| 203 | + (define maximum |
| 204 | + (for/max ([cur-name (in-set referenced-nts)]) |
| 205 | + (if (symbol=? cur-name name) |
| 206 | + +inf.0 |
| 207 | + (hash-ref table cur-name 0)))) |
| 208 | + (if (and (negative? maximum) |
| 209 | + (infinite? maximum)) |
| 210 | + 0 |
| 211 | + maximum)) |
| 212 | + (define production-vec (apply vector productions)) |
| 213 | + (define permutation |
| 214 | + (sort (build-list (vector-length production-vec) values) |
| 215 | + < |
| 216 | + #:key (compose max-terminal-distance |
| 217 | + rhs-pattern |
| 218 | + (λ (i) (vector-ref production-vec i))) |
| 219 | + #:cache-keys? #t)) |
| 220 | + (when clang-all-ht/f |
| 221 | + (define clang-all-ht-nt-vec (apply vector (hash-ref clang-all-ht/f name))) |
| 222 | + (hash-set! clang-all-ht/f name |
| 223 | + (for/list ([i (in-list permutation)]) |
| 224 | + (vector-ref clang-all-ht-nt-vec i)))) |
| 225 | + (nt name |
| 226 | + (for/list ([i (in-list permutation)]) |
| 227 | + (vector-ref production-vec i)))]))) |
257 | 228 |
|
258 |
| -;; A NTName is a symbol representing the name of a non-terminal |
| 229 | +;; terminal-distance-table : lang (hash[symbol] -o> symbol) |
| 230 | +;; -> (hash[symbol] -o> (U natural +inf) |
| 231 | +(define (terminal-distance-table cyclic recs) |
| 232 | + (define (terminal-distance pat this-nt-name table) |
| 233 | + (define referenced-nts (directly-used-nts pat)) |
| 234 | + (define maximum |
| 235 | + (for/max ([cur-name (in-set referenced-nts)]) |
| 236 | + (cond [(symbol=? cur-name this-nt-name) |
| 237 | + +inf.0] |
| 238 | + [else |
| 239 | + (hash-ref table cur-name 0)]))) |
| 240 | + (or (and (infinite? maximum) |
| 241 | + (negative? maximum) |
| 242 | + 0) |
| 243 | + (add1 maximum))) |
| 244 | + (build-nt-property/name cyclic |
| 245 | + terminal-distance |
| 246 | + +inf.0 |
| 247 | + min)) |
259 | 248 |
|
260 | 249 | ;; directly-used-nts : pat -> (setof symbol)
|
261 | 250 | (define (directly-used-nts pat)
|
|
358 | 347 | (my-max current-max
|
359 | 348 | (let () . defs+exprs))))]))
|
360 | 349 |
|
361 |
| -(define (build-cant-enumerate-table lang edges unsolvables) |
| 350 | + |
| 351 | +(define (build-cant-enumerate-table lang edges) |
362 | 352 | ;; cant-enumerate-table : hash[sym[nt] -o> boolean]
|
363 | 353 | (define cant-enumerate-table (make-hash))
|
364 | 354 |
|
|
391 | 381 | ;; fill in the entire table
|
392 | 382 | (for ([nt (in-list lang)])
|
393 | 383 | (cant-enumerate-nt/fill-table (nt-name nt)))
|
394 |
| - (for ([name (in-list unsolvables)]) |
395 |
| - (hash-set! cant-enumerate-table name #t)) |
| 384 | + |
396 | 385 | cant-enumerate-table)
|
397 | 386 |
|
398 | 387 | ;; can-enumerate? : any/c hash[sym -o> any[boolean]] (promise hash[sym -o> any[boolean]])
|
|
0 commit comments