|
1 "{ Package: 'stx:goodies/petitparser/compiler' }" |
|
2 |
|
3 "{ NameSpace: Smalltalk }" |
|
4 |
|
5 Object subclass:#PEGFsa |
|
6 instanceVariableNames:'states startState name distances priorities' |
|
7 classVariableNames:'' |
|
8 poolDictionaries:'' |
|
9 category:'PetitCompiler-FSA' |
|
10 ! |
|
11 |
|
12 !PEGFsa methodsFor:'accessing'! |
|
13 |
|
14 allTransitions |
|
15 ^ self allTransitions: IdentitySet new |
|
16 ! |
|
17 |
|
18 allTransitions: collection |
|
19 self states do: [ :s | collection addAll: s transitions ]. |
|
20 ^ collection |
|
21 ! |
|
22 |
|
23 forwardTransitions |
|
24 | backTransitions | |
|
25 backTransitions := self backTransitions. |
|
26 ^ self allTransitions reject: [ :t | backTransitions includes: t ] |
|
27 ! |
|
28 |
|
29 minPriority |
|
30 "this is the worst estimate" |
|
31 ^ (self states size) negated |
|
32 ! |
|
33 |
|
34 name |
|
35 ^ name |
|
36 ! |
|
37 |
|
38 name: anObject |
|
39 |
|
40 name := anObject |
|
41 ! |
|
42 |
|
43 prefix |
|
44 ^ 'fsa_' |
|
45 ! |
|
46 |
|
47 startState |
|
48 ^ startState |
|
49 ! |
|
50 |
|
51 stateNamed: name |
|
52 ^ states detect: [ :e | e name = name ] |
|
53 ! |
|
54 |
|
55 states |
|
56 ^ states |
|
57 ! |
|
58 |
|
59 suffix |
|
60 ^ '' |
|
61 ! |
|
62 |
|
63 transitionFrom: from to: to |
|
64 ^ from transitions detect: [ :t | t destination = to ] |
|
65 ! |
|
66 |
|
67 transitionsFor: state |
|
68 self assert: (states includes: state). |
|
69 ^ state transitions |
|
70 ! ! |
|
71 |
|
72 !PEGFsa methodsFor:'analysis'! |
|
73 |
|
74 backTransitions |
|
75 | transitionSet | |
|
76 transitionSet := IdentitySet new. |
|
77 self computeDistances. |
|
78 |
|
79 self backTransitionsFrom: startState openSet: IdentitySet new transitionSet: transitionSet. |
|
80 ^ transitionSet |
|
81 ! |
|
82 |
|
83 backTransitionsFrom: state openSet: openSet transitionSet: transitionSet |
|
84 (openSet includes: state) ifTrue: [ |
|
85 ^ self |
|
86 ]. |
|
87 openSet add: state. |
|
88 |
|
89 state transitions do: [ :t | |
|
90 ((openSet includes: t destination) and: [self is: state furtherThan: t destination]) ifTrue: [ |
|
91 transitionSet add: t |
|
92 ]. |
|
93 self backTransitionsFrom: t destination openSet: openSet copy transitionSet: transitionSet |
|
94 ] |
|
95 ! |
|
96 |
|
97 computeDistances |
|
98 | queue openSet | |
|
99 distances := IdentityDictionary new. |
|
100 queue := OrderedCollection with: startState. |
|
101 openSet := IdentitySet new. |
|
102 |
|
103 distances at: startState put: 0. |
|
104 |
|
105 [ queue isEmpty not ] whileTrue: [ |
|
106 | state | |
|
107 state := queue removeFirst. |
|
108 openSet add: state. |
|
109 |
|
110 state transitions do: [ :t | |
|
111 (openSet includes: (t destination)) ifFalse: [ |
|
112 distances at: (t destination ) put: ((distances at: state) + 1). |
|
113 queue addLast: (t destination) |
|
114 ] |
|
115 ] |
|
116 ]. |
|
117 |
|
118 ^ distances |
|
119 ! |
|
120 |
|
121 computePriorities |
|
122 | queue openSet | |
|
123 self flag: 'not working...'. |
|
124 priorities := IdentityDictionary new. |
|
125 queue := OrderedCollection with: startState. |
|
126 openSet := IdentitySet new. |
|
127 |
|
128 priorities at: startState put: (startState priorityIfNone: 0). |
|
129 |
|
130 [ queue isEmpty not ] whileTrue: [ |
|
131 | state | |
|
132 state := queue removeFirst. |
|
133 openSet add: state. |
|
134 |
|
135 state transitions do: [ :t | |
|
136 (openSet includes: (t destination)) ifFalse: [ |
|
137 priorities at: (t destination ) put: ((priorities at: state) + t priority). |
|
138 queue addLast: (t destination) |
|
139 ] |
|
140 ] |
|
141 ]. |
|
142 |
|
143 ^ priorities |
|
144 ! |
|
145 |
|
146 epsilonDestinationsFrom: state |
|
147 | openSet | |
|
148 openSet := IdentitySet new. |
|
149 self epsilonDestinationsFrom: state openSet: openSet. |
|
150 ^ openSet |
|
151 ! |
|
152 |
|
153 epsilonDestinationsFrom: state openSet: openSet |
|
154 (openSet includes: state) ifTrue: [ |
|
155 ^ self |
|
156 ]. |
|
157 |
|
158 openSet add: state. |
|
159 |
|
160 ((self transitionsFor: state) select: [ :t | t isEpsilon ]) do: [ :t | |
|
161 self epsilonDestinationsFrom: t destination openSet: openSet |
|
162 ] |
|
163 |
|
164 ! |
|
165 |
|
166 finalStates |
|
167 ^ self reachableStates select: [ :s | s isFinal ] |
|
168 ! |
|
169 |
|
170 is: state furtherThan: anotherState |
|
171 |
|
172 ^ (distances at: state) >= (distances at: anotherState) |
|
173 ! |
|
174 |
|
175 isBackTransition: t |
|
176 ^ self backTransitions includes: t |
|
177 ! |
|
178 |
|
179 joinPoints |
|
180 ^ self joinTransitions collect: [ :t | t destination ] |
|
181 ! |
|
182 |
|
183 joinTransitions |
|
184 | joinTransitions transitions size | |
|
185 joinTransitions := IdentitySet new. |
|
186 |
|
187 transitions := self allTransitions asOrderedCollection. |
|
188 size := transitions size. |
|
189 |
|
190 |
|
191 (1 to: size - 1) do: [ :index1 | |
|
192 (index1 + 1 to: size) do: [ :index2 | |
|
193 ((transitions at: index1) destination == (transitions at: index2) destination) ifTrue: [ |
|
194 joinTransitions add: (transitions at: index1). |
|
195 joinTransitions add: (transitions at: index2). |
|
196 ] |
|
197 ] |
|
198 ]. |
|
199 |
|
200 ^ joinTransitions |
|
201 ! |
|
202 |
|
203 minimumPriority |
|
204 ! |
|
205 |
|
206 nonFinalStates |
|
207 ^ self states reject: [ :s | s isFinal ] |
|
208 ! |
|
209 |
|
210 reachableStates |
|
211 ^ self statesReachableFrom: startState |
|
212 ! |
|
213 |
|
214 statePairs |
|
215 | pairs ordered | |
|
216 pairs := OrderedCollection new. |
|
217 ordered := self topologicalOrder. |
|
218 1 to: (ordered size - 1) do: [ :index1 | |
|
219 (index1 + 1) to: ordered size do: [ :index2 | |
|
220 pairs add: (PEGFsaPair with: (ordered at: index1) with: (ordered at: index2)) |
|
221 ] |
|
222 ]. |
|
223 |
|
224 self assert: (pairs allSatisfy: [ :e | e class == PEGFsaPair ]). |
|
225 ^ pairs |
|
226 ! |
|
227 |
|
228 statesReachableFrom: state |
|
229 | openSet | |
|
230 self assert: state isNil not. |
|
231 |
|
232 openSet := IdentitySet new. |
|
233 self statesReachableFrom: state openSet: openSet. |
|
234 ^ openSet |
|
235 ! |
|
236 |
|
237 statesReachableFrom: state openSet: openSet |
|
238 (openSet contains: [:e | e == state]) ifTrue: [ |
|
239 ^ self |
|
240 ]. |
|
241 |
|
242 openSet add: state. |
|
243 |
|
244 (self transitionsFor: state) do: [ :t | |
|
245 self statesReachableFrom: t destination openSet: openSet |
|
246 ] |
|
247 |
|
248 ! |
|
249 |
|
250 topologicalOrder |
|
251 | collection | |
|
252 collection := OrderedCollection new. |
|
253 self statesReachableFrom: startState openSet: collection. |
|
254 ^ collection |
|
255 ! ! |
|
256 |
|
257 !PEGFsa methodsFor:'comparing'! |
|
258 |
|
259 = anotherFsa |
|
260 " |
|
261 Please note what the compare does. IMO nothing useful for no. |
|
262 |
|
263 For comparing if two FSA's are equivalent, use isIsomorphicTo: |
|
264 " |
|
265 |
|
266 (self == anotherFsa) ifTrue: [ ^ true ]. |
|
267 (self class == anotherFsa class) ifFalse: [ ^ false ]. |
|
268 |
|
269 (startState = anotherFsa startState) ifFalse: [ ^ false ]. |
|
270 (name = anotherFsa name) ifFalse: [ ^ false ]. |
|
271 |
|
272 (states size = anotherFsa states size) ifFalse: [ ^ false ]. |
|
273 states do: [:s | |
|
274 (anotherFsa states contains: [ :e | e = s ]) ifFalse: [ ^ false ]. |
|
275 ]. |
|
276 ^ true |
|
277 ! |
|
278 |
|
279 hash |
|
280 ^ states hash bitXor: (startState bitXor: name) |
|
281 ! |
|
282 |
|
283 isIsomorphicTo: anotherFsa |
|
284 | topologicalOrder anotherTopologicalOrder | |
|
285 |
|
286 " |
|
287 Please not that this version of comparison is sensitive to the order |
|
288 in which the transitions in state are ordered. |
|
289 " |
|
290 |
|
291 topologicalOrder := self topologicalOrder. |
|
292 anotherTopologicalOrder := anotherFsa topologicalOrder. |
|
293 |
|
294 topologicalOrder size == anotherTopologicalOrder size ifFalse: [ ^ false ]. |
|
295 |
|
296 topologicalOrder with: anotherTopologicalOrder do: [ :s1 :s2 | |
|
297 (s1 canBeIsomorphicTo: s2) ifFalse: [ ^ false ] |
|
298 ]. |
|
299 |
|
300 ^ true |
|
301 " |
|
302 transitions := topologicalOrder flatCollect: [ :s | s transitions ]. |
|
303 anotherTransitions := anotherTopologicalOrder flatCollect: [ :s | s transitions ]. |
|
304 " |
|
305 ! ! |
|
306 |
|
307 !PEGFsa methodsFor:'copying'! |
|
308 |
|
309 postCopy |
|
310 | map | |
|
311 super postCopy. |
|
312 |
|
313 map := IdentityDictionary new. |
|
314 states do: [ :s | |
|
315 map at: s put: s copy. |
|
316 ]. |
|
317 |
|
318 states := map values asIdentitySet. |
|
319 startState := map at: startState. |
|
320 |
|
321 states do: [ :s | |
|
322 s transitions do: [:t | |
|
323 t destination: (map at: t destination) |
|
324 ] |
|
325 ] |
|
326 ! ! |
|
327 |
|
328 !PEGFsa methodsFor:'gt'! |
|
329 |
|
330 gtGraphViewIn: composite |
|
331 <gtInspectorPresentationOrder: 41> |
|
332 composite roassal2 |
|
333 title: 'Graph'; |
|
334 initializeView: [ RTMondrian new ]; |
|
335 painting: [ :view | |
|
336 self viewGraphOn: view. |
|
337 ]. |
|
338 ! |
|
339 |
|
340 gtStringViewIn: composite |
|
341 <gtInspectorPresentationOrder: 40> |
|
342 |
|
343 composite text |
|
344 title: 'Textual Representation'; |
|
345 display: [ :fsa | fsa asString ] |
|
346 ! |
|
347 |
|
348 viewGraphOn: b |
|
349 b shape circle size: 50. |
|
350 b shape color: Color gray muchLighter muchLighter. |
|
351 b shape withText: #gtName. |
|
352 b nodes: (self nonFinalStates). |
|
353 |
|
354 b shape circle size: 50. |
|
355 b shape color: Color gray muchLighter. |
|
356 b shape withText: #gtName. |
|
357 b nodes: (self finalStates). |
|
358 |
|
359 b shape arrowedLine. |
|
360 b edges |
|
361 connectToAll: [ :state | |
|
362 state transitions select: [:t | (self isBackTransition:t) not] |
|
363 thenCollect: #destination ] |
|
364 labelled: [ :t | (self transitionFrom: t key to: t value) gtName ]. |
|
365 |
|
366 b shape arrowedLine. |
|
367 b shape color: Color red. |
|
368 b edges |
|
369 connectToAll: [ :state | |
|
370 state transitions select: [:t | (self isBackTransition: t) ] |
|
371 thenCollect: #destination ] |
|
372 labelled: [ :t | (self transitionFrom: t key to: t value) gtName ]. |
|
373 |
|
374 |
|
375 b layout horizontalTree . |
|
376 b layout layout horizontalGap: 30. |
|
377 |
|
378 ^ b |
|
379 ! ! |
|
380 |
|
381 !PEGFsa methodsFor:'initialization'! |
|
382 |
|
383 initialize |
|
384 states := IdentitySet new. |
|
385 ! ! |
|
386 |
|
387 !PEGFsa methodsFor:'modifications'! |
|
388 |
|
389 addState: state |
|
390 self assert: (states includes: state) not. |
|
391 states add: state |
|
392 ! |
|
393 |
|
394 addTransitionFrom: fromState to: toState |
|
395 ^ self addTransitionFrom: fromState to: toState priority: 0 |
|
396 ! |
|
397 |
|
398 addTransitionFrom: fromState to: toState on: character |
|
399 self addTransitionFrom: fromState to: toState on: character priority: 0 |
|
400 ! |
|
401 |
|
402 addTransitionFrom: fromState to: toState on: character priority: priority |
|
403 | transition | |
|
404 transition := PEGFsaTransition new |
|
405 addCharacter: character; |
|
406 destination: toState; |
|
407 priority: priority; |
|
408 yourself. |
|
409 |
|
410 fromState addTransition: transition |
|
411 ! |
|
412 |
|
413 addTransitionFrom: fromState to: toState onCharacterSet: characterSet |
|
414 self addTransitionFrom: fromState to: toState onCharacterSet: characterSet priority: 0 |
|
415 ! |
|
416 |
|
417 addTransitionFrom: fromState to: toState onCharacterSet: characterSet priority: priority |
|
418 | transition | |
|
419 transition := PEGFsaTransition new |
|
420 characterSet: characterSet; |
|
421 destination: toState; |
|
422 priority: priority; |
|
423 yourself. |
|
424 |
|
425 fromState addTransition: transition |
|
426 ! |
|
427 |
|
428 addTransitionFrom: fromState to: toState priority: priority |
|
429 | transition | |
|
430 self assert: (states includes: fromState). |
|
431 self assert: (states includes: toState). |
|
432 |
|
433 transition := PEGFsaTransition new |
|
434 destination: toState; |
|
435 priority: priority; |
|
436 yourself. |
|
437 |
|
438 fromState addTransition: transition. |
|
439 ! |
|
440 |
|
441 adopt: fsa |
|
442 states addAll: fsa reachableStates. |
|
443 ! |
|
444 |
|
445 finalState: state |
|
446 self assert: state isFinal not. |
|
447 state final: true. |
|
448 ! |
|
449 |
|
450 fixFinalStatePriorities |
|
451 self finalStates do: [ :s | |
|
452 s hasPriority ifFalse: [ s priority: 0 ] |
|
453 ] |
|
454 ! |
|
455 |
|
456 removeState: state |
|
457 self assert: (states includes: state). |
|
458 states remove: state. |
|
459 ! |
|
460 |
|
461 replace: state with: anotherState |
|
462 | transitions | |
|
463 self assert: (state class == PEGFsaState). |
|
464 self assert: (anotherState class == PEGFsaState). |
|
465 |
|
466 transitions := self allTransitions. |
|
467 |
|
468 transitions do: [ :t | |
|
469 (t destination == state) ifTrue: [ |
|
470 t destination: anotherState. |
|
471 ] |
|
472 ]. |
|
473 states := startState reachableStates. |
|
474 ! |
|
475 |
|
476 startState: state |
|
477 self assert: (states includes: state). |
|
478 |
|
479 startState := state |
|
480 ! ! |
|
481 |
|
482 !PEGFsa methodsFor:'printing'! |
|
483 |
|
484 asString |
|
485 | stream | |
|
486 stream := WriteStream on: ''. |
|
487 |
|
488 self topologicalOrder do: [ :state | |
|
489 state printOn: stream. |
|
490 stream nextPutAll: '> '. |
|
491 |
|
492 (self transitionsFor: state) do: [ :transition | |
|
493 stream nextPut: (Character codePoint: 13). |
|
494 stream nextPut: (Character codePoint: 9). |
|
495 transition printOn: stream. |
|
496 ]. |
|
497 stream nextPut: (Character codePoint: 13). |
|
498 ]. |
|
499 |
|
500 " stream nextPutAll: 'finals: '. |
|
501 (states select: [:s | s isFinal ]) do: [:e | e printOn: stream ]. |
|
502 stream nextPut: (Character codePoint: 13). |
|
503 " |
|
504 ^ stream contents. |
|
505 ! ! |
|
506 |
|
507 !PEGFsa methodsFor:'testing'! |
|
508 |
|
509 canHavePPCId |
|
510 ^ true |
|
511 ! |
|
512 |
|
513 checkConsistency |
|
514 self assert: (states includes: startState). |
|
515 states do: [ :s | s transitions do: [ :t | |
|
516 self assert: (states includes: t destination). |
|
517 ] ]. |
|
518 ^ true |
|
519 ! |
|
520 |
|
521 checkFinalStatesPriorities |
|
522 self assert: (self finalStates allSatisfy: #hasPriority) |
|
523 ! |
|
524 |
|
525 checkSanity |
|
526 self checkConsistency. |
|
527 self checkTransitionsIdentity. |
|
528 self checkFinalStatesPriorities. |
|
529 ! |
|
530 |
|
531 checkTransitionsIdentity |
|
532 | bag set | |
|
533 bag := IdentityBag new. |
|
534 set := IdentitySet new. |
|
535 bag := self allTransitions: bag. |
|
536 set := self allTransitions: set. |
|
537 |
|
538 self assert: bag size == set size. |
|
539 ! |
|
540 |
|
541 isDeterministic |
|
542 self reachableStates do: [ :state | |
|
543 state transitionPairs do: [ :pair | |
|
544 ((pair first intersection: pair second) includes: true) ifTrue: [ |
|
545 ^ false |
|
546 ] |
|
547 ] |
|
548 ]. |
|
549 ^ true |
|
550 ! |
|
551 |
|
552 isReachableState: state |
|
553 ^ self reachableStates includes: state |
|
554 ! |
|
555 |
|
556 isStartState: state |
|
557 ^ startState == state |
|
558 ! |
|
559 |
|
560 isWithoutEpsilons |
|
561 self reachableStates do: [ :state | |
|
562 state transitions do: [ :t | |
|
563 t isEpsilon ifTrue: [ ^ false ] |
|
564 ] |
|
565 ]. |
|
566 ^ true |
|
567 ! ! |
|
568 |
|
569 !PEGFsa methodsFor:'transformations'! |
|
570 |
|
571 compact |
|
572 self fixFinalStatePriorities. |
|
573 self determinize. |
|
574 self minimize. |
|
575 |
|
576 self checkSanity. |
|
577 ! |
|
578 |
|
579 determinize |
|
580 | joinDictionary | |
|
581 self removeEpsilons. |
|
582 |
|
583 self removeUnreachableStates. |
|
584 self removeLowPriorityTransitions. |
|
585 self mergeTransitions. |
|
586 |
|
587 joinDictionary := Dictionary new. |
|
588 self topologicalOrder do: [:state | state determinize: joinDictionary ]. |
|
589 |
|
590 states := startState reachableStates. |
|
591 |
|
592 self removeUnreachableStates. |
|
593 self removeLowPriorityTransitions. |
|
594 self mergeTransitions. |
|
595 |
|
596 ! |
|
597 |
|
598 mergeTransitions |
|
599 | toRemove | |
|
600 self reachableStates do: [ :state | |
|
601 toRemove := OrderedCollection new. |
|
602 state transitionPairs do:[ :pair | |
|
603 (pair first destination = pair second destination) ifTrue: [ |
|
604 pair first mergeWith: pair second. |
|
605 toRemove add: pair second. |
|
606 ] |
|
607 ]. |
|
608 toRemove do: [ :t | |
|
609 state removeTransition: t |
|
610 ] |
|
611 ] |
|
612 ! |
|
613 |
|
614 minimize |
|
615 | pair | |
|
616 pair := self statePairs detect: [ :p | p first equals: p second ] ifNone: [ nil ]. |
|
617 [ pair isNil not ] whileTrue: [ |
|
618 "Join priorities, because equivalency of priorities does not imply from the equeality of states" |
|
619 pair first joinPriority: pair second newState: pair first. |
|
620 pair first joinName: pair second newState: pair first. |
|
621 self replace: pair second with: pair first. |
|
622 self mergeTransitions. |
|
623 pair := self statePairs detect: [ :p | p first equals: p second ] ifNone: [ nil ]. |
|
624 ]. |
|
625 ! |
|
626 |
|
627 removeEpsilonTransition: transition source: state |
|
628 ^ self removeEpsilonTransition: transition source: state openSet: IdentitySet new |
|
629 ! |
|
630 |
|
631 removeEpsilonTransition: transition source: source openSet: openSet |
|
632 | destination | |
|
633 (openSet includes: transition) ifTrue: [ self error: 'loop in epsilons?!!' ]. |
|
634 openSet add: transition. |
|
635 |
|
636 destination := transition destination. |
|
637 |
|
638 "First Remove Recursively" |
|
639 ((self transitionsFor: destination ) select: [ :t | t isEpsilon ]) do: [ :t | |
|
640 self removeEpsilonTransition: t source: destination openSet: openSet |
|
641 ]. |
|
642 |
|
643 (transition priority abs) timesRepeat: [ |
|
644 (self statesReachableFrom: destination) do: [ :s | |
|
645 s decreasePriority. |
|
646 s transitions do: [ :t | t decreasePriority ] |
|
647 ] |
|
648 ]. |
|
649 |
|
650 (destination transitions) do: [ :t | |
|
651 source addTransition: (t copy) |
|
652 ]. |
|
653 |
|
654 destination hasPriority ifTrue: [ |
|
655 source hasPriority ifTrue: [ |
|
656 "self assert: source priority == destination priority" |
|
657 self flag: 'I am not 100% sure about this case' |
|
658 ]. |
|
659 source priority: destination priority |
|
660 ]. |
|
661 |
|
662 destination isFinal ifTrue: [ |
|
663 source final: true. |
|
664 source retval: destination retval. |
|
665 ]. |
|
666 |
|
667 source removeTransition: transition. |
|
668 ! |
|
669 |
|
670 removeEpsilons |
|
671 states do: [ :state | |
|
672 self removeEpsilonsFor: state |
|
673 ] |
|
674 ! |
|
675 |
|
676 removeEpsilonsFor: state |
|
677 (self transitionsFor: state) copy do: [ :t | |
|
678 t isEpsilon ifTrue: [ |
|
679 self removeEpsilonTransition: t source: state |
|
680 ] |
|
681 ] |
|
682 ! |
|
683 |
|
684 removeLowPriorityTransitions |
|
685 states do: [ :state | |
|
686 self removeLowPriorityTransitionsFor: state |
|
687 ] |
|
688 ! |
|
689 |
|
690 removeLowPriorityTransitionsFor: state |
|
691 state hasPriority ifFalse: [ ^ self ]. |
|
692 state isFinal ifFalse: [ ^ self ]. |
|
693 |
|
694 state transitions do: [ :t | |
|
695 (t priority < state priority) ifTrue: [ |
|
696 state removeTransition: t |
|
697 ] |
|
698 ] |
|
699 ! |
|
700 |
|
701 removeUnreachableStates |
|
702 | reachable toRemove | |
|
703 reachable := self reachableStates. |
|
704 toRemove := OrderedCollection new. |
|
705 |
|
706 states do: [ :s | |
|
707 (reachable includes: s) ifFalse: [ |
|
708 toRemove add: s |
|
709 ] |
|
710 ]. |
|
711 |
|
712 toRemove do: [ :s | states remove: s ] |
|
713 ! ! |
|
714 |