|
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 |
| - clang-all-ht/f)) |
54 |
| - |
55 |
| - (values sorted-left |
56 |
| - sorted-right |
57 |
| - (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))) |
58 | 55 |
|
59 | 56 | ;; find-edges : lang -> (hash[symbol] -o> (setof (listof symbol)))
|
60 | 57 | (define (find-edges lang)
|
|
192 | 189 | ;; Problem: we need to find an ordering of the productions of each of
|
193 | 190 | ;; the metavariables such that the graph induced by the first
|
194 | 191 | ;; productions in each case has no cycles.
|
195 |
| -;; |
196 |
| -;; We use a fairly simple algorithm. We start with an empty set of |
197 |
| -;; sinks. An out-edge is an edge all of whose targets are sinks |
198 |
| -;; (note that this includes the empty set). |
199 |
| -;; |
200 |
| -;; Go through each vertex. If it contains an out-edge, pick it, and |
201 |
| -;; add the vertex to the list of sinks. Repeat until all vertices |
202 |
| -;; are sinks. |
203 |
| -;; |
204 |
| -;; For now, diverges if it's impossible :(. |
205 |
| -;; To fix: if a round completes without any vertices becoming a |
206 |
| -;; sink the jig is up |
207 |
| - |
| 192 | +;; spanning-tree : HyperGraph -> (Listof (List Index (Setof NTName))) (Listof NTName) |
208 | 193 | (define (spanning-tree hg)
|
209 |
| - (let loop ([hg hg] |
210 |
| - [sinks (set)] |
| 194 | + (define init-vertices (hash-keys hg)) |
| 195 | + (let loop ([sinks (set)] |
211 | 196 | [edges (hash)]
|
212 |
| - [vertices (hash-keys hg)]) |
213 |
| - (match vertices |
214 |
| - ['() edges] |
215 |
| - [(cons v vs) |
| 197 | + [vertices init-vertices] |
| 198 | + [time (length init-vertices)]) |
| 199 | + (cond |
| 200 | + [(zero? time) |
| 201 | + (values edges vertices)] |
| 202 | + [else |
| 203 | + (match-define (cons v vs) vertices) |
216 | 204 | (define good-edge
|
217 | 205 | (findf (λ (e) (andmap (λ (v) (set-member? sinks v)) (set->list (second e))))
|
218 | 206 | (hash-ref hg v)))
|
219 | 207 | (cond [good-edge
|
220 |
| - (loop hg |
221 |
| - (set-add sinks v) |
| 208 | + (loop (set-add sinks v) |
222 | 209 | (hash-set edges v good-edge)
|
223 |
| - vs)] |
| 210 | + vs |
| 211 | + (sub1 time))] |
224 | 212 | [else
|
225 |
| - (loop hg sinks edges (append vs (list v)))])]))) |
| 213 | + (loop sinks edges (append vs (list v)) (sub1 time))])]))) |
226 | 214 |
|
227 | 215 | ;; A HyperGraph is a Hash NTName (Listof (List Index (Setof NTName)))
|
228 | 216 | ;; associating each non-terminal to a list of out-going edges
|
|
239 | 227 | ;; sorts the language
|
240 | 228 | ;; SIDE EFFECT: if clang-all-ht/f is not #f, sorts it
|
241 | 229 | (define (sort-productions lang clang-all-ht/f)
|
242 |
| - (define spanner (spanning-tree (hypergraph lang))) |
243 |
| - (for/list ([cur-nt (in-list lang)]) |
244 |
| - (match cur-nt |
245 |
| - [(nt name productions) |
246 |
| - (define the-edge (first (hash-ref spanner name))) |
| 230 | + (define-values (spanner unsolvables) (spanning-tree (hypergraph lang))) |
| 231 | + (define sorted |
| 232 | + (for/list ([cur-nt (in-list lang)]) |
| 233 | + (match cur-nt |
| 234 | + [(nt name productions) |
| 235 | + (cond |
| 236 | + [(hash-has-key? spanner name) |
| 237 | + (define the-edge (first (hash-ref spanner name))) |
247 | 238 |
|
248 |
| - ;; less than if the left is the chosen one and the right is not |
249 |
| - (define (less-than? i1 i2) |
250 |
| - (and (equal? i1 the-edge) |
251 |
| - (not (equal? i2 the-edge)))) |
| 239 | + ;; less than if the left is the chosen one and the right is not |
| 240 | + (define (less-than? i1 i2) |
| 241 | + (and (equal? i1 the-edge) |
| 242 | + (not (equal? i2 the-edge)))) |
252 | 243 |
|
253 |
| - (define production-vec (apply vector productions)) |
254 |
| - (define permutation |
255 |
| - (sort (build-list (vector-length production-vec) values) |
256 |
| - less-than? |
257 |
| - #:cache-keys? #t)) |
258 |
| - (when clang-all-ht/f |
259 |
| - (define clang-all-ht-nt-vec (apply vector (hash-ref clang-all-ht/f name))) |
260 |
| - (hash-set! clang-all-ht/f name |
261 |
| - (for/list ([i (in-list permutation)]) |
262 |
| - (vector-ref clang-all-ht-nt-vec i)))) |
263 |
| - (nt name |
264 |
| - (for/list ([i (in-list permutation)]) |
265 |
| - (vector-ref production-vec i)))]))) |
| 244 | + (define production-vec (apply vector productions)) |
| 245 | + (define permutation |
| 246 | + (sort (build-list (vector-length production-vec) values) |
| 247 | + less-than? |
| 248 | + #:cache-keys? #t)) |
| 249 | + (when clang-all-ht/f |
| 250 | + (define clang-all-ht-nt-vec (apply vector (hash-ref clang-all-ht/f name))) |
| 251 | + (hash-set! clang-all-ht/f name |
| 252 | + (for/list ([i (in-list permutation)]) |
| 253 | + (vector-ref clang-all-ht-nt-vec i)))) |
| 254 | + (nt name |
| 255 | + (for/list ([i (in-list permutation)]) |
| 256 | + (vector-ref production-vec i)))] |
| 257 | + [else (nt name productions)])]))) |
| 258 | + (values sorted unsolvables)) |
266 | 259 |
|
267 | 260 | ;; A NTName is a symbol representing the name of a non-terminal
|
268 | 261 |
|
|
367 | 360 | (my-max current-max
|
368 | 361 | (let () . defs+exprs))))]))
|
369 | 362 |
|
370 |
| - |
371 |
| -(define (build-cant-enumerate-table lang edges) |
| 363 | +(define (build-cant-enumerate-table lang edges unsolvables) |
372 | 364 | ;; cant-enumerate-table : hash[sym[nt] -o> boolean]
|
373 | 365 | (define cant-enumerate-table (make-hash))
|
374 | 366 |
|
|
401 | 393 | ;; fill in the entire table
|
402 | 394 | (for ([nt (in-list lang)])
|
403 | 395 | (cant-enumerate-nt/fill-table (nt-name nt)))
|
404 |
| - |
| 396 | + (for ([name (in-list unsolvables)]) |
| 397 | + (hash-set! cant-enumerate-table name #t)) |
405 | 398 | cant-enumerate-table)
|
406 | 399 |
|
407 | 400 | ;; can-enumerate? : any/c hash[sym -o> any[boolean]] (promise hash[sym -o> any[boolean]])
|
|
0 commit comments