|
8 | 8 | racket/match
|
9 | 9 | racket/set
|
10 | 10 | racket/promise
|
11 |
| - "build-nt-property.rkt" |
12 | 11 | "lang-struct.rkt"
|
13 | 12 | "match-a-pattern.rkt")
|
14 | 13 |
|
|
44 | 43 | (set-member? cyclic-nts (nt-name nt)))
|
45 | 44 | lang))
|
46 | 45 | ;; topological sort
|
47 |
| - (define sorted-left |
| 46 | + (define sorted-finite |
48 | 47 | (topo-sort non-cyclic
|
49 | 48 | (filter-edges edges non-cyclic)))
|
50 | 49 | ;; rhs sort
|
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))) |
| 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))) |
59 | 55 |
|
60 | 56 | ;; find-edges : lang -> (hash[symbol] -o> (setof (listof symbol)))
|
61 | 57 | (define (find-edges lang)
|
|
105 | 101 | (hash)
|
106 | 102 | lang))
|
107 | 103 |
|
108 |
| -;; find-cycles : (hash[symbol] -o> (setof symbol)) -> (setof symbol) |
| 104 | +;; find-cycles : (hash[symbol] -o> (setof symbol)]) -> (setof symbol) |
109 | 105 | (define (find-cycles edges)
|
110 | 106 | (foldl
|
111 | 107 | (λ (v s)
|
|
190 | 186 | lang))
|
191 | 187 |
|
192 | 188 |
|
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)))]))) |
| 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)) |
228 | 257 |
|
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)) |
| 258 | +;; A NTName is a symbol representing the name of a non-terminal |
248 | 259 |
|
249 | 260 | ;; directly-used-nts : pat -> (setof symbol)
|
250 | 261 | (define (directly-used-nts pat)
|
|
347 | 358 | (my-max current-max
|
348 | 359 | (let () . defs+exprs))))]))
|
349 | 360 |
|
350 |
| - |
351 |
| -(define (build-cant-enumerate-table lang edges) |
| 361 | +(define (build-cant-enumerate-table lang edges unsolvables) |
352 | 362 | ;; cant-enumerate-table : hash[sym[nt] -o> boolean]
|
353 | 363 | (define cant-enumerate-table (make-hash))
|
354 | 364 |
|
|
381 | 391 | ;; fill in the entire table
|
382 | 392 | (for ([nt (in-list lang)])
|
383 | 393 | (cant-enumerate-nt/fill-table (nt-name nt)))
|
384 |
| - |
| 394 | + (for ([name (in-list unsolvables)]) |
| 395 | + (hash-set! cant-enumerate-table name #t)) |
385 | 396 | cant-enumerate-table)
|
386 | 397 |
|
387 | 398 | ;; can-enumerate? : any/c hash[sym -o> any[boolean]] (promise hash[sym -o> any[boolean]])
|
|
0 commit comments