compiler/PEGFsaMinimizator.st
changeset 515 b5316ef15274
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/compiler/PEGFsaMinimizator.st	Mon Aug 17 12:13:16 2015 +0100
@@ -0,0 +1,105 @@
+"{ Package: 'stx:goodies/petitparser/compiler' }"
+
+"{ NameSpace: Smalltalk }"
+
+Object subclass:#PEGFsaMinimizator
+	instanceVariableNames:'fsa joinDictionary'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'PetitCompiler-FSA'
+!
+
+!PEGFsaMinimizator methodsFor:'comparison'!
+
+info: info equals: anotherInfo
+    (info == anotherInfo) ifTrue: [ ^ true ].
+    (info class == anotherInfo class) ifFalse: [ ^ false ].
+
+    "	
+        I suppose I don't if someone does not have the priority set.
+        Please note that equals is used for minimization, so I try to
+        be as liberal as possible to get as small automaton as possible.
+    "
+    (info hasPriority and: [anotherInfo hasPriority]) ifTrue: [ 	
+        (info priority == anotherInfo priority) ifFalse: [ ^ false ].
+    ].
+
+    (info isFinal == anotherInfo isFinal) ifFalse: [ ^ false ].
+    (info isFsaFailure == anotherInfo isFsaFailure) ifFalse: [ ^ false ].
+
+    ^ true
+!
+
+state: state equals: anotherState
+    (state == anotherState) ifTrue: [ ^ true ].
+    (state class == anotherState class) ifFalse: [ ^ false ].
+    
+    (state isFinal = anotherState isFinal) ifFalse: [ ^ false ].
+
+    (state stateInfos size == anotherState stateInfos size) ifFalse: [ ^ false ].
+    state retvals do: [:retval |
+        (self info: (state infoFor: retval) equals: (anotherState infoFor: retval ifAbsent: [ ^ false ])) ifFalse: [ ^ false ]
+    ].
+
+
+    (state transitions size == anotherState transitions size) ifFalse: [ ^ false ].
+    anotherState transitions do: [ :anotherStateT | 
+        (state transitions contains: [ :stateT | 
+            (anotherStateT equals: stateT) or: [
+                "this is condition for self reference" 
+                (anotherStateT destination == anotherState) and: [ stateT destination == state ]	
+            ] ] ) ifFalse: [ ^ false ]
+    ].
+    
+    ^ true
+! !
+
+!PEGFsaMinimizator methodsFor:'joining'!
+
+joinInfo: state with: anotherState
+    self assert: state stateInfos size == anotherState stateInfos size.
+
+    state stateInfos do: [ :si1 | 
+        self assert: (anotherState stateInfos contains: [ :si2 | 
+            si1 isFinal == si2 isFinal and: [ si1 isFsaFailure == si2 isFsaFailure  ]
+        ])
+    ]
+!
+
+joinName: state with: anotherState
+    state name: state name asString, '+', anotherState name asString.
+!
+
+joinState: state with: anotherState
+    self assert: state hasZeroPriorityOnly.
+    self assert: anotherState hasZeroPriorityOnly.
+
+    self joinName: state with: anotherState.
+    self joinInfo: state with: anotherState.
+    
+! !
+
+!PEGFsaMinimizator methodsFor:'minimization'!
+
+minimize
+    | pair |
+    pair := fsa statePairs detect:  [ :p | self state: p first equals: p second ] ifNone: [ nil ].
+
+    [ pair isNil not ] whileTrue: [ 
+        "Join priorities, because equivalency of priorities does not follow from the `equals:` of states"
+        self joinState: pair first with: pair second.
+        fsa replace: pair second with: pair first.
+        fsa mergeTransitions.
+
+        pair := fsa statePairs detect: [ :p | self state: p first equals: p second ] ifNone: [ nil ].
+ 	].
+!
+
+minimize: anFsa
+    fsa := anFsa.
+
+    self minimize.
+    fsa checkSanity.
+    ^ fsa
+! !
+