39 aSeenDictionary at: self ifPresent: [ :value | ^ value ]. |
39 aSeenDictionary at: self ifPresent: [ :value | ^ value ]. |
40 copy := aSeenDictionary at: self put: self copy. |
40 copy := aSeenDictionary at: self put: self copy. |
41 copies := OrderedCollection new. |
41 copies := OrderedCollection new. |
42 parsers do: [ :each | |
42 parsers do: [ :each | |
43 | result | |
43 | result | |
44 result := each |
44 result := each |
45 copyInContext: aDictionary |
45 copyInContext: aDictionary |
46 seen: aSeenDictionary. |
46 seen: aSeenDictionary. |
47 result isCollection |
47 result isCollection |
48 ifTrue: [ copies addAll: result ] |
48 ifTrue: [ copies addAll: result ] |
49 ifFalse: [ copies add: result ] ]. |
49 ifFalse: [ copies add: result ] ]. |
99 !PPParser methodsFor:'*petitanalyzer-named'! |
99 !PPParser methodsFor:'*petitanalyzer-named'! |
100 |
100 |
101 allNamedParsersDo: aBlock |
101 allNamedParsersDo: aBlock |
102 "Iterate over all the named parse nodes of the receiver." |
102 "Iterate over all the named parse nodes of the receiver." |
103 |
103 |
104 self allParsersDo: [ :each | |
104 self allParsersDo: [ :each | |
105 each name notNil |
105 each name notNil |
106 ifTrue: [ aBlock value: each ] ] |
106 ifTrue: [ aBlock value: each ] ] |
107 ! ! |
107 ! ! |
108 |
108 |
109 !PPParser methodsFor:'*petitanalyzer-matching'! |
109 !PPParser methodsFor:'*petitanalyzer-matching'! |
114 |
114 |
115 !PPParser methodsFor:'*petitanalyzer-matching'! |
115 !PPParser methodsFor:'*petitanalyzer-matching'! |
116 |
116 |
117 copyInContext: aDictionary seen: aSeenDictionary |
117 copyInContext: aDictionary seen: aSeenDictionary |
118 | copy | |
118 | copy | |
119 aSeenDictionary |
119 aSeenDictionary |
120 at: self |
120 at: self |
121 ifPresent: [ :value | ^ value ]. |
121 ifPresent: [ :value | ^ value ]. |
122 copy := aSeenDictionary |
122 copy := aSeenDictionary |
123 at: self |
123 at: self |
124 put: self copy. |
124 put: self copy. |
125 copy children do: [ :each | |
125 copy children do: [ :each | |
131 |
131 |
132 !PPParser methodsFor:'*petitanalyzer-querying'! |
132 !PPParser methodsFor:'*petitanalyzer-querying'! |
133 |
133 |
134 cycleSet |
134 cycleSet |
135 "Answer a set of all nodes that are within one or more cycles of left-recursion. This is generally not a problem if at least one of the nodes is memoized, but it might make the grammar very inefficient and should be avoided if possible." |
135 "Answer a set of all nodes that are within one or more cycles of left-recursion. This is generally not a problem if at least one of the nodes is memoized, but it might make the grammar very inefficient and should be avoided if possible." |
136 |
136 |
137 | cycles | |
137 | cycles | |
138 cycles := IdentitySet new. |
138 cycles := IdentitySet new. |
139 self cycleSet: OrderedCollection new firstSets: self firstSets into: cycles. |
139 self cycleSet: OrderedCollection new firstSets: self firstSets into: cycles. |
140 ^ cycles |
140 ^ cycles |
141 ! ! |
141 ! ! |
153 cycleSet: aStack firstSets: aDictionary into: aSet |
153 cycleSet: aStack firstSets: aDictionary into: aSet |
154 "PRIVATE: Try to find a cycle, where aStack contains the previously visited parsers. The method returns quickly when the receiver is a terminal, terminals cannot be part of a cycle. If aStack already contains the receiver, then we are in a cycle. In this case we don't process the children further and add the nodes to aSet." |
154 "PRIVATE: Try to find a cycle, where aStack contains the previously visited parsers. The method returns quickly when the receiver is a terminal, terminals cannot be part of a cycle. If aStack already contains the receiver, then we are in a cycle. In this case we don't process the children further and add the nodes to aSet." |
155 |
155 |
156 | index | |
156 | index | |
157 self isTerminal |
157 self isTerminal |
158 ifTrue: [ ^ self ]. |
158 ifTrue: [ ^ self ]. |
159 (index := aStack indexOf: self) > 0 |
159 (index := aStack indexOf: self) > 0 |
160 ifTrue: [ ^ aSet addAll: (aStack copyFrom: index to: aStack size) ]. |
160 ifTrue: [ ^ aSet addAll: (aStack copyFrom: index to: aStack size) ]. |
161 aStack addLast: self. |
161 aStack addLast: self. |
162 (self cycleSet: aDictionary) |
162 (self cycleSet: aDictionary) |
163 do: [ :each | each cycleSet: aStack firstSets: aDictionary into: aSet ]. |
163 do: [ :each | each cycleSet: aStack firstSets: aDictionary into: aSet ]. |
166 |
166 |
167 !PPParser methodsFor:'*petitanalyzer-querying'! |
167 !PPParser methodsFor:'*petitanalyzer-querying'! |
168 |
168 |
169 firstSet |
169 firstSet |
170 "Answer the first-set of the receiver. Note, this implementation is inefficient when called on different receivers of the same grammar, instead use #firstSets to calculate the first-sets at once." |
170 "Answer the first-set of the receiver. Note, this implementation is inefficient when called on different receivers of the same grammar, instead use #firstSets to calculate the first-sets at once." |
171 |
171 |
172 ^ self firstSets at: self |
172 ^ self firstSets at: self |
173 ! ! |
173 ! ! |
174 |
174 |
175 !PPParser methodsFor:'*petitanalyzer-querying'! |
175 !PPParser methodsFor:'*petitanalyzer-querying'! |
176 |
176 |
177 firstSets |
177 firstSets |
178 "Answer a dictionary with all the parsers reachable from the receiver as key and their first-set as value. The first-set of a parser is the list of terminal parsers that begin the parser derivable from that parser." |
178 "Answer a dictionary with all the parsers reachable from the receiver as key and their first-set as value. The first-set of a parser is the list of terminal parsers that begin the parser derivable from that parser." |
179 |
179 |
180 | firstSets | |
180 | firstSets | |
181 firstSets := IdentityDictionary new. |
181 firstSets := IdentityDictionary new. |
182 self allParsersDo: [ :each | |
182 self allParsersDo: [ :each | |
183 firstSets at: each put: (each isFirstSetTerminal |
183 firstSets at: each put: (each isFirstSetTerminal |
184 ifTrue: [ IdentitySet with: each ] |
184 ifTrue: [ IdentitySet with: each ] |
213 |
213 |
214 !PPParser methodsFor:'*petitanalyzer-querying'! |
214 !PPParser methodsFor:'*petitanalyzer-querying'! |
215 |
215 |
216 followSets |
216 followSets |
217 "Answer a dictionary with all the parsers reachable from the receiver as key and their follow-set as value. The follow-set of a parser is the list of terminal parsers that can appear immediately to the right of that parser." |
217 "Answer a dictionary with all the parsers reachable from the receiver as key and their follow-set as value. The follow-set of a parser is the list of terminal parsers that can appear immediately to the right of that parser." |
218 |
218 |
219 | current previous continue firstSets followSets | |
219 | current previous continue firstSets followSets | |
220 current := previous := 0. |
220 current := previous := 0. |
221 firstSets := self firstSets. |
221 firstSets := self firstSets. |
222 followSets := IdentityDictionary new. |
222 followSets := IdentityDictionary new. |
223 self allParsersDo: [ :each | followSets at: each put: IdentitySet new ]. |
223 self allParsersDo: [ :each | followSets at: each put: IdentitySet new ]. |
224 (followSets at: self) add: PPSentinel instance. |
224 (followSets at: self) add: PPSentinel instance. |
225 [ followSets keysAndValuesDo: [ :parser :follow | |
225 [ followSets keysAndValuesDo: [ :parser :follow | |
226 parser |
226 parser |
227 followSets: followSets |
227 followSets: followSets |
228 firstSets: firstSets |
228 firstSets: firstSets |
229 into: follow ]. |
229 into: follow ]. |
230 current := followSets |
230 current := followSets |
231 inject: 0 |
231 inject: 0 |
238 |
238 |
239 !PPParser methodsFor:'*petitanalyzer-private'! |
239 !PPParser methodsFor:'*petitanalyzer-private'! |
240 |
240 |
241 followSets: aFollowDictionary firstSets: aFirstDictionary into: aSet |
241 followSets: aFollowDictionary firstSets: aFirstDictionary into: aSet |
242 "PRIVATE: Try to add additional elements to the follow-set aSet of the receiver, use the incomplete aFollowDictionary and the complete aFirstDictionary." |
242 "PRIVATE: Try to add additional elements to the follow-set aSet of the receiver, use the incomplete aFollowDictionary and the complete aFirstDictionary." |
243 |
243 |
244 self children do: [ :parser | (aFollowDictionary at: parser) addAll: aSet ] |
244 self children do: [ :parser | (aFollowDictionary at: parser) addAll: aSet ] |
245 ! ! |
245 ! ! |
246 |
246 |
247 !PPParser methodsFor:'*petitanalyzer-named'! |
247 !PPParser methodsFor:'*petitanalyzer-named'! |
248 |
248 |
265 |
265 |
266 !PPParser methodsFor:'*petitanalyzer-named'! |
266 !PPParser methodsFor:'*petitanalyzer-named'! |
267 |
267 |
268 innerChildrenDo: aBlock seen: aSet |
268 innerChildrenDo: aBlock seen: aSet |
269 "Iterate over the inner children of the receiver." |
269 "Iterate over the inner children of the receiver." |
270 |
270 |
271 self children do: [ :each | |
271 self children do: [ :each | |
272 (aSet includes: each) |
272 (aSet includes: each) |
273 ifTrue: [ ^ self ]. |
273 ifTrue: [ ^ self ]. |
274 aSet add: each. |
274 aSet add: each. |
275 each name isNil ifTrue: [ |
275 each name isNil ifTrue: [ |
333 parser := matchList at: matchIndex. |
333 parser := matchList at: matchIndex. |
334 parser class = PPListPattern ifTrue: [ |
334 parser class = PPListPattern ifTrue: [ |
335 currentIndex := parserIndex - 1. |
335 currentIndex := parserIndex - 1. |
336 [ currentDictionary := aDictionary copy. |
336 [ currentDictionary := aDictionary copy. |
337 currentSeen := aSet copy. |
337 currentSeen := aSet copy. |
338 parserList size < currentIndex or: [ |
338 parserList size < currentIndex or: [ |
339 parsers := parserList copyFrom: parserIndex to: currentIndex. |
339 parsers := parserList copyFrom: parserIndex to: currentIndex. |
340 (currentDictionary at: parser ifAbsentPut: [ parsers ]) = parsers and: [ |
340 (currentDictionary at: parser ifAbsentPut: [ parsers ]) = parsers and: [ |
341 (self |
341 (self |
342 matchList: matchList |
342 matchList: matchList |
343 index: matchIndex + 1 |
343 index: matchIndex + 1 |
344 against: parserList |
344 against: parserList |
345 index: currentIndex + 1 |
345 index: currentIndex + 1 |
346 inContext: currentDictionary |
346 inContext: currentDictionary |
347 seen: currentSeen) |
347 seen: currentSeen) |
348 ifTrue: [ |
348 ifTrue: [ |
349 currentDictionary keysAndValuesDo: [ :key :value | aDictionary at: key put: value ]. |
349 currentDictionary keysAndValuesDo: [ :key :value | aDictionary at: key put: value ]. |
350 ^ true ]. |
350 ^ true ]. |
351 false ] ] ] whileFalse: [ currentIndex := currentIndex + 1 ]. |
351 false ] ] ] whileFalse: [ currentIndex := currentIndex + 1 ]. |
352 ^ false ]. |
352 ^ false ]. |
353 parserList size < parserIndex |
353 parserList size < parserIndex |
384 |
384 |
385 !PPParser methodsFor:'*petitanalyzer-named'! |
385 !PPParser methodsFor:'*petitanalyzer-named'! |
386 |
386 |
387 namedChildrenDo: aBlock seen: aSet |
387 namedChildrenDo: aBlock seen: aSet |
388 "Iterate over the named children of the receiver." |
388 "Iterate over the named children of the receiver." |
389 |
389 |
390 self children do: [ :each | |
390 self children do: [ :each | |
391 (aSet includes: each) |
391 (aSet includes: each) |
392 ifTrue: [ ^ self ]. |
392 ifTrue: [ ^ self ]. |
393 aSet add: each. |
393 aSet add: each. |
394 each name isNil |
394 each name isNil |
446 !PPRepeatingParser methodsFor:'*petitanalyzer-private'! |
446 !PPRepeatingParser methodsFor:'*petitanalyzer-private'! |
447 |
447 |
448 followSets: aFollowDictionary firstSets: aFirstDictionary into: aSet |
448 followSets: aFollowDictionary firstSets: aFirstDictionary into: aSet |
449 | firstSet | |
449 | firstSet | |
450 super followSets: aFollowDictionary firstSets: aFirstDictionary into: aSet. |
450 super followSets: aFollowDictionary firstSets: aFirstDictionary into: aSet. |
451 |
451 |
452 firstSet := aFirstDictionary at: self. |
452 firstSet := aFirstDictionary at: self. |
453 self children do: [:p | (aFollowDictionary at: p) addAll: (firstSet reject: [:each | each isNullable]) ] |
453 self children do: [:p | (aFollowDictionary at: p) addAll: (firstSet reject: [:each | each isNullable]) ] |
454 ! ! |
454 ! ! |
455 |
455 |
456 !PPRepeatingParser methodsFor:'*petitanalyzer-testing'! |
456 !PPRepeatingParser methodsFor:'*petitanalyzer-testing'! |
498 | followSet firstSet | |
498 | followSet firstSet | |
499 followSet := aFollowDictionary at: parser. |
499 followSet := aFollowDictionary at: parser. |
500 index = parsers size |
500 index = parsers size |
501 ifTrue: [ followSet addAll: aSet ] |
501 ifTrue: [ followSet addAll: aSet ] |
502 ifFalse: [ |
502 ifFalse: [ |
503 (self class withAll: (parsers |
503 (self class withAll: (parsers |
504 copyFrom: index + 1 to: parsers size)) |
504 copyFrom: index + 1 to: parsers size)) |
505 firstSets: aFirstDictionary |
505 firstSets: aFirstDictionary |
506 into: (firstSet := IdentitySet new). |
506 into: (firstSet := IdentitySet new). |
507 (firstSet anySatisfy: [ :each | each isNullable ]) |
507 (firstSet anySatisfy: [ :each | each isNullable ]) |
508 ifTrue: [ followSet addAll: aSet ]. |
508 ifTrue: [ followSet addAll: aSet ]. |
509 followSet addAll: (firstSet |
509 followSet addAll: (firstSet |
510 reject: [ :each | each isNullable ]) ] ] |
510 reject: [ :each | each isNullable ]) ] ] |
511 ! ! |
511 ! ! |
512 |
512 |
513 !PPTokenParser methodsFor:'*petitanalyzer-matching'! |
513 !PPTokenParser methodsFor:'*petitanalyzer-matching'! |
514 |
514 |