Class Relation
Relations with 3 Components Example 1 label a b i.e., organized triples b at: at: containing a Dictionary Dictionary label OrderedCollection A Example 2 a b i.e., organized triples b at: at: containing a Dictionary Dictionary A OrderedCollection a is in allFrom b is in allTo Assumes a and b can be compared using =
A dictionary of dictionaries of collections The Relation Class A dictionary of dictionaries of collections items key a key label collection with b label label a b or a b Use 1 label or label Use 2 a b a b clear resetting allFrom, alTo, allToFor: items querying addItem: a via: label toItem: b adding do: [:a :label :b | ...] simple looping for: fromItems byLabelsDo: [:label :toItems | ...]” Most important smart looping
Easy To Implement Items is a dictionary of dictionaries of collections label label label Like right, left, or up where a b a b a b Items is a dictionary of dictionaries of collections key a key label {b1, b2, ...} clear items := Dictionary new addItem: a via: label toItem: b ((items at: a ifAbsentPut: [Dictionary new]) at: label ifAbsentPut: [OrderedCollection new]) addIfAbsent: b Assumes a = b is implemented
Easy To Implement Items is a dictionary of dictionaries of collections allFrom ^items keys key a key label {b1, b2, ...} allTo ^self allToFor: self allFrom allToFor: fromItems | all emptyDictionary | all := OrderedCollection new. emptyDictionary := Dictionary new. fromItems do: [:a | “Note that the labels are ignored” (items at: a ifAbsent: [emptyDictionary]) values do: [:toItems | all addAllIfAbsent: toItems]]. ^all Assumes a = b is implemented
Items is a dictionary of dictionaries of collections Simple Looping Items is a dictionary of dictionaries of collections key a key symbol {b1, b2, ...} do: aBlock "aRelation do: [:a :label :b | ...]" items keysAndValuesDo: [:a :dictionary | dictionary keysAndValuesDo: [:label :orderedCollection | orderedCollection do: [:b | aBlock value: a value: label value: b]]]
Items is a dictionary of dictionaries of collections looping Items is a dictionary of dictionaries of collections key a key symbol {b1, b2, ...} for: fromItems byLabelsDo: aBlock "aBlock expects [:label :toItems | ...]" | labelledItems emptyDictionary | labelledItems := Dictionary new. emptyDictionary := Dictionary new. fromItems do: [:a | (items at: a ifAbsent: [emptyDictionary]) keysAndValuesDo: [:label :toItems | (labelledItems at: label ifAbsentPut: [OrderedCollection new]) addAllIfAbsent: toItems]]. labelledItems keysAndValues do: aBlock
Three Observations
From an augmented grammar Observations 1 From an augmented grammar We created 3 relations: Global up: e.g., Global left: e.g., Temporary right; e.g., Simpler right; e.g., Grammar G -> c 6 5 A A -> a 8 7 b 4 1 2 '|-' 3 G {EndOfFile} G' -> G 511 211 A 711 511 '|-'11 211 111 G12 312 211 211 3 G 511 A 6 2 3 G 5 A 6
BUT WE CAN'T TELL which a's and b's belong together. Observations 2 From right for: fromItems byLabelsDo: [:label :toItems | ...]” we know that many a's are in fromItems many b's are in toItems BUT WE CAN'T TELL which a's and b's belong together.
Enough to ensure, if 2 names are equal, their hashes must be equal Observations 3 Relations use items for which we had to make sure that = was implemented for transition name because it's used as a key in the relation's dictionary BUT THAT'S NOT ENOUGH You also have to implement hash ^symbol hash + attributes hash + action hash Enough to ensure, if 2 names are equal, their hashes must be equal
where rightSubset is a relation Note: toItems is rightSubset allTo Consequently We want to define a better variation. Instead of right for: fromItems byLabelsDo: [:label :toItems | ...]” let's have right for: fromItems byLabelRelationsDo: [:label :rightSubset | ...]” where rightSubset is a relation Note: toItems is rightSubset allTo
Review of Algorithm
Define your global relations Algorithm Define your global relations up := Relation new. left := Relation new. Build initial readahead state Create a readahead state and to the unclosured items, add the initial state of the grammar's extra production. Build successor readahead states See next slide
Build Successor states (requires iteration) states do: [:state| Define your temporary right relation right := Relation new. Perform the closure A Using as a guide, set up closured items add items to global up See next slide for details This requires a loop on closured items Set up right M Using the grammar, the closured items and as a guide, set up temporary right See AFTER next slide for details Build successor readahead states from right See next slide This requires a loop on states
Applying the Closure to a Readahead State and Extending Up Given current readaheadState Ra with unclosureItems Let closureItems := unclosureItems shallowCopy Using the grammar and the following as a guide = {(p,r) such that there is a production right part of the form and } ? -> … p … q A The down relation A -> … r where r is an initial state A closureItems do: [:p | For each initial state r, add r to the closuredItems IF NOT ALREADY THERE. up addItem: <r,Ra> via: A toItem: <p,Ra>
closureItems do: [:p | Using the grammar and the following as a guide Extending Right Given readaheadState with closureItems all computed. Using the grammar and the following as a guide X X The right relation A -> … p q … closureItems do: [:p | for each X-successor q of p. right addItem: p via: X toItem: q
Computing Successors and Extending Left It’s easy to build successors of currentState right for: closuredItems byLabelsDo: [:name :successorItems | state := ReadaheadState new unclosuredItems: successorItems. index := states indexOf: state. successorState := index = 0 ifTrue: ["Not there" states add: state. state] ifFalse: ["Already there" states at: index]] when current and successor states are available We can now build left left := Relation new. right do: [:a :label :b | pairA := Array with: a with: currentState. pairB := Array with: b with: successorState. pairLabel := TransitionName new name: label; state: successorState left addItem: pairB via: pairLabel toItem: pairA] How do we go about combining these 2 code fragments? Oops: NOT SO EASY
Computing Successors and Extending Left Assuming was set up earlier. left := Relation new. right for: closuredItems byLabelRelationsDo: [:name :rightSubset | successorItems := rightSubset allTo. state := ReadaheadState new unclosuredItems: successorItems. index := states indexOf: state. successorState := index = 0 ifTrue: ["Not there" states add: state. state] ifFalse: ["Already there" states at: index]. rightSubset do: [:a :label :b | pairA := Array with: a with: currentState. pairB := Array with: b with: successorState. pairLabel := TransitionName new name: label; state: successorState left addItem: pairB via: pairLabel toItem: pairA]] assumes = is implemented for readahead states
Converting to for:byLabelRelationsDo: Items is a dictionary of dictionaries of collections key a key symbol {b1, b2, ...} for: fromItems byLabelsDo: aBlock "aBlock expects [:label :toItems | ...]" | labelledItems emptyDictionary | labelledItems := Dictionary new. emptyDictionary := Dictionary new. fromItems do: [:a | (items at: a ifAbsent: [emptyDictionary]) keysAndValuesDo: [:label :toItems | (labelledItems at: label ifAbsentPut: [OrderedCollection new]) addAllIfAbsent: toItems]]. labelledItems keysAndValues do: aBlock BLUE: What we need to change RED: The relation data
Converting to for:byLabelsRelationsDo: Items is a dictionary of dictionaries of collections key a key symbol {b1, b2, ...} for: fromItems byLabelRelationsDo: aBlock "aBlock expects [:label :rightSubset| ...]" | labelledItems emptyDictionary | labelledItems := Dictionary new. emptyDictionary := Dictionary new. fromItems do: [:a | (items at: a ifAbsent: [emptyDictionary]) keysAndValuesDo: [:label :toItems | (labelledItems at: label ifAbsentPut: [Relation new]) addItem: a via: label toAllItems: toItems]]. labelledItems keysAndValues do: aBlock BLUE: What we need to change RED: The relation data Helper method Better name?
The new Looping Construct Items is a dictionary of dictionaries of collections key a key symbol {b1, b2, ...} for: fromItems byLabelRelationsDo: aBlock "aBlock expects [:label :rightSubset| ...]" | labelledItems emptyDictionary | labelledRelations := Dictionary new. emptyDictionary := Dictionary new. fromItems do: [:a | (items at: a ifAbsent: [emptyDictionary]) keysAndValuesDo: [:label :toItems | (labelledRelations at: label ifAbsentPut: [Relation new]) addItem: a via: label toAllItems: toItems]]. labelledRelations keysAndValues do: aBlock
The Simple Helper Function So we can avoid having to loop ourselves addItem: a via: label toAllItems: bCollection bCollection do: [:b | self addItem: a via: label toItem: b]
What about Readback States?
What’s Different for Readback FSMs The items are (rightPartState, readaheadState) pairs. For each readahead state, we use the closured items and compute initial readback states on a per nonterminal basis, each containing items (pairs) built from the right part states that are final items. We have a readback state with unclosure items. We already have relations for left and up. Why don’t we extend class Relation to help us?
How do we tell if a label is dealing with an Invisible? Ask the label... label isInvisible label isVisible See previous notes in building readback FSMs for details. Summary: It's invisible if it's a semantic action or a look transition.
Using Relation Left invisibleLeftClosureOf: fromItems using: left "Returns a collection of items." | allLefts | allLefts := fromItems shallowCopy. allLefts do: [:a | left for: (Array with: a) byLabelsDo: [:label :toItems | label isInvisible ifTrue: [ allLefts addAllIfAbsent: toItems]]] ^allLefts A Relation class method It is possible to make it an instance method (with receiver left) but it's purpose is too specific to be a general method
Using Relation Left forVisibleLeftOf: fromItems using: left byLabelRelationsDo : aBlock "aBlock expects [:label :leftSubset | ...]" left for: fromItems byLabelRelationsDo : [:label :leftSubset | label isVisible ifTrue: [aBlock value: label value: leftSubset]] Can be used for building successor readback states (similar to the approach used for building successor readahead states but has to distinguish visibles from invisibles] A Relation class method
What about Lookback?
Recall R * Mp ( | ) What does it mean? F -> a #indent C C -> B B -> A A -> w R * invisibles Mp ( | ) Example grammar What does it mean? In readback state R, you are at the left end of the handle say w to be reduced to say A Then you are where the dot is… A -> w Up 1 B -> A Up C -> B Up F -> a #indent C Invisible Left F -> a #indent C Visible a is lookback
Computing Lookback lookbackFor: fromItems using: left and: up "Returns a collection of labels (not items)." | toItems toLabels | "Perform one up..." toItems := up allToFor: fromItems. "Perform many invisible lefts and ups." toItems do: [:a | left for: (Array with: a) byLabelsDo: [:label :labelSuccessors | label isInvisible ifTrue: [toItems addAllIfAbsent: labelSuccessors]]. toItems addAllIfAbsent: (up allToFor: (Array with: a))]. "Finally, pick up the visible labels..." toLabels := OrderedCollection new. self forVisibleLeftOf: toItems using: left byLabelsDo: [:label :labelSuccessors | toLabels addIfAbsent: label]. ^toLabels Class method
Note See "Detailed Summary So Far: Building Readback States" in "ReadbackFSMsForGrammars" for slightly more detailed steps to building readback states.
Done