analyzer/extensions.st
changeset 382 1825151d6455
parent 381 0bbbcf5da2d4
equal deleted inserted replaced
381:0bbbcf5da2d4 382:1825151d6455
    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 ] ].
    68 ! !
    68 ! !
    69 
    69 
    70 !PPNotParser methodsFor:'*petitanalyzer-private'!
    70 !PPNotParser methodsFor:'*petitanalyzer-private'!
    71 
    71 
    72 firstSets: aFirstDictionary into: aSet
    72 firstSets: aFirstDictionary into: aSet
    73 	
    73 
    74 ! !
    74 ! !
    75 
    75 
    76 !PPNotParser methodsFor:'*petitanalyzer-testing'!
    76 !PPNotParser methodsFor:'*petitanalyzer-testing'!
    77 
    77 
    78 isFirstSetTerminal
    78 isFirstSetTerminal
    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: [
   287 
   287 
   288 !PPParser methodsFor:'*petitanalyzer-testing'!
   288 !PPParser methodsFor:'*petitanalyzer-testing'!
   289 
   289 
   290 isNullable
   290 isNullable
   291 	"Answer true if the receiver is a nullable parser, e.g. it can successfully parse nothing."
   291 	"Answer true if the receiver is a nullable parser, e.g. it can successfully parse nothing."
   292 	
   292 
   293 	^ false
   293 	^ false
   294 ! !
   294 ! !
   295 
   295 
   296 !PPParser methodsFor:'*petitanalyzer-testing'!
   296 !PPParser methodsFor:'*petitanalyzer-testing'!
   297 
   297 
   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