rley 0.3.04 → 0.3.05

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -3
  3. data/CHANGELOG.md +3 -0
  4. data/Rakefile +30 -30
  5. data/examples/parsers/parsing_L0.rb +1 -1
  6. data/examples/parsers/parsing_L1.rb +1 -1
  7. data/examples/parsers/parsing_abc.rb +1 -1
  8. data/examples/parsers/parsing_ambig.rb +1 -1
  9. data/examples/parsers/parsing_another.rb +1 -1
  10. data/examples/parsers/parsing_b_expr.rb +1 -1
  11. data/examples/parsers/parsing_err_expr.rb +1 -1
  12. data/examples/parsers/parsing_groucho.rb +1 -1
  13. data/examples/parsers/parsing_right_recursive.rb +1 -1
  14. data/examples/parsers/parsing_tricky.rb +1 -1
  15. data/lib/rley/constants.rb +2 -2
  16. data/lib/rley/formatter/base_formatter.rb +0 -2
  17. data/lib/rley/formatter/debug.rb +0 -2
  18. data/lib/rley/formatter/json.rb +1 -3
  19. data/lib/rley/gfg/call_edge.rb +31 -30
  20. data/lib/rley/gfg/edge.rb +22 -23
  21. data/lib/rley/gfg/end_vertex.rb +22 -24
  22. data/lib/rley/gfg/epsilon_edge.rb +20 -21
  23. data/lib/rley/gfg/grm_flow_graph.rb +39 -39
  24. data/lib/rley/gfg/item_vertex.rb +16 -17
  25. data/lib/rley/gfg/non_terminal_vertex.rb +3 -4
  26. data/lib/rley/gfg/return_edge.rb +32 -31
  27. data/lib/rley/gfg/scan_edge.rb +25 -26
  28. data/lib/rley/gfg/shortcut_edge.rb +25 -26
  29. data/lib/rley/gfg/start_vertex.rb +0 -2
  30. data/lib/rley/gfg/vertex.rb +8 -8
  31. data/lib/rley/parse_forest_visitor.rb +113 -115
  32. data/lib/rley/parse_tree_visitor.rb +0 -2
  33. data/lib/rley/parser/base_parser.rb +27 -27
  34. data/lib/rley/parser/chart.rb +14 -14
  35. data/lib/rley/parser/dotted_item.rb +33 -33
  36. data/lib/rley/parser/earley_parser.rb +6 -6
  37. data/lib/rley/parser/gfg_chart.rb +8 -15
  38. data/lib/rley/parser/gfg_earley_parser.rb +15 -13
  39. data/lib/rley/parser/gfg_parsing.rb +26 -22
  40. data/lib/rley/parser/grm_items_builder.rb +3 -2
  41. data/lib/rley/parser/parse_entry.rb +3 -9
  42. data/lib/rley/parser/parse_entry_set.rb +14 -19
  43. data/lib/rley/parser/parse_entry_tracker.rb +56 -56
  44. data/lib/rley/parser/parse_forest_builder.rb +215 -214
  45. data/lib/rley/parser/parse_forest_factory.rb +57 -56
  46. data/lib/rley/parser/parse_state.rb +8 -11
  47. data/lib/rley/parser/parse_state_tracker.rb +56 -56
  48. data/lib/rley/parser/parse_tracer.rb +3 -3
  49. data/lib/rley/parser/parse_tree_builder.rb +10 -10
  50. data/lib/rley/parser/parse_walker_factory.rb +30 -33
  51. data/lib/rley/parser/parsing.rb +8 -8
  52. data/lib/rley/parser/state_set.rb +23 -26
  53. data/lib/rley/ptree/non_terminal_node.rb +1 -1
  54. data/lib/rley/ptree/token_range.rb +2 -2
  55. data/lib/rley/sppf/alternative_node.rb +32 -34
  56. data/lib/rley/sppf/composite_node.rb +27 -27
  57. data/lib/rley/sppf/epsilon_node.rb +26 -27
  58. data/lib/rley/sppf/leaf_node.rb +11 -12
  59. data/lib/rley/sppf/non_terminal_node.rb +37 -38
  60. data/lib/rley/sppf/sppf_node.rb +1 -1
  61. data/lib/rley/sppf/token_node.rb +29 -29
  62. data/lib/rley/syntax/grammar.rb +1 -3
  63. data/lib/rley/syntax/grammar_builder.rb +8 -8
  64. data/lib/rley/syntax/non_terminal.rb +2 -4
  65. data/lib/rley/syntax/production.rb +3 -3
  66. data/lib/rley/syntax/symbol_seq.rb +1 -1
  67. data/spec/rley/gfg/call_edge_spec.rb +50 -51
  68. data/spec/rley/gfg/edge_spec.rb +33 -33
  69. data/spec/rley/gfg/end_vertex_spec.rb +26 -27
  70. data/spec/rley/gfg/epsilon_edge_spec.rb +25 -25
  71. data/spec/rley/gfg/grm_flow_graph_spec.rb +1 -1
  72. data/spec/rley/gfg/item_vertex_spec.rb +3 -4
  73. data/spec/rley/gfg/return_edge_spec.rb +51 -51
  74. data/spec/rley/gfg/scan_edge_spec.rb +32 -30
  75. data/spec/rley/gfg/shortcut_edge_spec.rb +1 -1
  76. data/spec/rley/gfg/vertex_spec.rb +3 -3
  77. data/spec/rley/parse_forest_visitor_spec.rb +239 -238
  78. data/spec/rley/parser/dotted_item_spec.rb +1 -1
  79. data/spec/rley/parser/earley_parser_spec.rb +16 -16
  80. data/spec/rley/parser/gfg_earley_parser_spec.rb +30 -31
  81. data/spec/rley/parser/gfg_parsing_spec.rb +11 -10
  82. data/spec/rley/parser/grm_items_builder_spec.rb +2 -2
  83. data/spec/rley/parser/parse_entry_set_spec.rb +4 -4
  84. data/spec/rley/parser/parse_entry_spec.rb +0 -2
  85. data/spec/rley/parser/parse_forest_builder_spec.rb +82 -57
  86. data/spec/rley/parser/parse_forest_factory_spec.rb +84 -82
  87. data/spec/rley/parser/parse_walker_factory_spec.rb +10 -9
  88. data/spec/rley/parser/parsing_spec.rb +0 -1
  89. data/spec/rley/sppf/alternative_node_spec.rb +2 -2
  90. data/spec/rley/sppf/non_terminal_node_spec.rb +0 -1
  91. data/spec/rley/support/ambiguous_grammar_helper.rb +1 -1
  92. data/spec/rley/support/expectation_helper.rb +37 -36
  93. data/spec/rley/support/grammar_abc_helper.rb +17 -17
  94. data/spec/rley/support/grammar_b_expr_helper.rb +40 -39
  95. data/spec/rley/support/grammar_helper.rb +2 -1
  96. data/spec/rley/support/{grammar_L0_helper.rb → grammar_l0_helper.rb} +82 -81
  97. data/spec/rley/support/grammar_sppf_helper.rb +24 -25
  98. data/spec/rley/syntax/grammar_spec.rb +1 -1
  99. metadata +2 -2
@@ -1,214 +1,215 @@
1
- require_relative '../syntax/terminal'
2
- require_relative '../syntax/non_terminal'
3
- require_relative '../gfg/end_vertex'
4
- require_relative '../gfg/item_vertex'
5
- require_relative '../gfg/start_vertex'
6
- require_relative '../sppf/epsilon_node'
7
- require_relative '../sppf/non_terminal_node'
8
- require_relative '../sppf/alternative_node'
9
- require_relative '../sppf/parse_forest'
10
-
11
- module Rley # This module is used as a namespace
12
- module Parser # This module is used as a namespace
13
- # Builder GoF pattern. Builder pattern builds a complex object
14
- # (say, a parse forest) from simpler objects (terminal and non-terminal
15
- # nodes) and using a step by step approach.
16
- class ParseForestBuilder
17
- # The sequence of input tokens
18
- attr_reader(:tokens)
19
-
20
- # Link to forest object
21
- attr_reader(:forest)
22
-
23
- # Link to current path
24
- attr_reader(:curr_path)
25
-
26
- # The last parse entry visited
27
- attr_reader(:last_visitee)
28
-
29
- # A hash with pairs of the form: visited parse entry => forest node
30
- attr_reader(:entry2node)
31
-
32
- # A hash with pairs of the form: parent end entry => path to alternative node
33
- # This is needed for synchronizing backtracking
34
- attr_reader(:entry2path_to_alt)
35
-
36
- def initialize(theTokens)
37
- @tokens = theTokens
38
- @curr_path = []
39
- @entry2node = {}
40
- @entry2path_to_alt = {}
41
- end
42
-
43
- def receive_event(anEvent, anEntry, anIndex)
44
- # puts "Event: #{anEvent} #{anEntry} #{anIndex}"
45
- if anEntry.dotted_entry?
46
- process_item_entry(anEvent, anEntry, anIndex)
47
- elsif anEntry.start_entry?
48
- process_start_entry(anEvent, anEntry, anIndex)
49
- elsif anEntry.end_entry?
50
- process_end_entry(anEvent, anEntry, anIndex)
51
- else
52
- fail NotImplementedError
53
- end
54
-
55
- @last_visitee = anEntry
56
- end
57
-
58
- # Return the current_parent node
59
- def curr_parent()
60
- return self.curr_path.last
61
- end
62
-
63
- private
64
-
65
- def process_start_entry(anEvent, anEntry, anIndex)
66
- self.curr_path.pop
67
- end
68
-
69
- def process_end_entry(anEvent, anEntry, anIndex)
70
- case anEvent
71
- when :visit
72
- # create a node with the non-terminal
73
- # with same right extent as curr_entry_set_index
74
- # add the new node as first child of current_parent
75
- # append the new node to the curr_path
76
- range = { low: anEntry.origin, high: anIndex }
77
- non_terminal = anEntry.vertex.non_terminal
78
- create_non_terminal_node(anEntry, range, non_terminal)
79
- @forest = create_forest(curr_parent) unless @last_visitee
80
-
81
- when :backtrack
82
- # Restore path
83
- @curr_path = self.entry2path_to_alt[anEntry].dup
84
- # puts "Restore path #{curr_path.join(', ')}]"
85
- antecedent_index = curr_parent.subnodes.size
86
- # puts "Current parent #{curr_parent.to_string(0)}"
87
- # puts "Antecedent index #{antecedent_index}"
88
-
89
-
90
- when :revisit
91
- # Retrieve the already existing node corresponding to re-visited entry
92
- popular = @entry2node[anEntry]
93
-
94
- # Share with parent
95
- curr_parent.add_subnode(popular)
96
-
97
- else
98
- fail NotImplementedError
99
- end
100
- end
101
-
102
-
103
- def process_item_entry(anEvent, anEntry, anIndex)
104
- if anEntry.exit_entry?
105
- # Previous entry was an end entry (X. pattern)
106
- # Does the previous entry have multiple antecedent?
107
- if last_visitee.end_entry? && last_visitee.antecedents.size > 1
108
- # Store current path for later backtracking
109
- # puts "Store backtrack context #{last_visitee}"
110
- # puts "path [#{curr_path.join(', ')}]"
111
- self.entry2path_to_alt[last_visitee] = curr_path.dup
112
- curr_parent.refinement = :or
113
-
114
- create_alternative_node(anEntry)
115
- end
116
- end
117
-
118
- # Retrieve the grammar symbol before the dot (if any)
119
- prev_symbol = anEntry.prev_symbol
120
- case prev_symbol
121
- when Syntax::Terminal
122
- # Add node without changing current path
123
- create_token_node(anEntry, anIndex)
124
-
125
- when Syntax::NonTerminal
126
- # Do nothing
127
-
128
- when NilClass # Dot at the beginning of production
129
- if anEntry.vertex.dotted_item.production.empty?
130
- # Empty rhs => create an epsilon node ...
131
- # ... without changing current path
132
- create_epsilon_node(anEntry, anIndex)
133
- end
134
- self.curr_path.pop if curr_parent.kind_of?(SPPF::AlternativeNode)
135
- end
136
- end
137
-
138
- # Create an empty parse forest
139
- def create_forest(aRootNode)
140
- return Rley::SPPF::ParseForest.new(aRootNode)
141
- end
142
-
143
-
144
- # Factory method. Build and return an SPPF non-terminal node.
145
- def create_non_terminal_node(anEntry, aRange, nonTSymb = nil)
146
- non_terminal = nonTSymb.nil? ? anEntry.vertex.non_terminal : nonTSymb
147
- new_node = Rley::SPPF::NonTerminalNode.new(non_terminal, aRange)
148
- entry2node[anEntry] = new_node
149
- # puts "FOREST ADD #{curr_parent.key if curr_parent}/#{new_node.key}"
150
- add_subnode(new_node)
151
-
152
- return new_node
153
- end
154
-
155
-
156
- # Add an alternative node to the forest
157
- def create_alternative_node(anEntry)
158
- alternative = Rley::SPPF::AlternativeNode.new(anEntry.vertex, curr_parent.range)
159
- add_subnode(alternative)
160
- # puts "FOREST ADD #{alternative.key}"
161
-
162
- return alternative
163
- end
164
-
165
- # create a token node,
166
- # with same origin as token,
167
- # with same right extent = origin + 1
168
- # add the new node as first child of current_parent
169
- def create_token_node(anEntry, anIndex)
170
- token_position = anIndex - 1
171
- curr_token = tokens[token_position]
172
- new_node = SPPF::TokenNode.new(curr_token, token_position)
173
- candidate = add_node_to_forest(new_node)
174
- entry2node[anEntry] = candidate
175
-
176
- return candidate
177
- end
178
-
179
-
180
- def create_epsilon_node(anEntry, anIndex)
181
- new_node = SPPF::EpsilonNode.new(anIndex)
182
- candidate = add_node_to_forest(new_node)
183
- entry2node[anEntry] = candidate
184
-
185
- return candidate
186
- end
187
-
188
- # Add the given node if not yet present in parse forest
189
- def add_node_to_forest(aNode)
190
- key_node = aNode.key
191
- if forest.include?(key_node)
192
- new_node = forest.key2node[key_node]
193
- else
194
- new_node = aNode
195
- forest.key2node[key_node] = new_node
196
- # puts "FOREST ADD #{key_node}"
197
- end
198
- add_subnode(new_node, false)
199
-
200
- return new_node
201
- end
202
-
203
-
204
- # Add the given node as sub-node of current parent node
205
- # Optionally add the node to the current path
206
- def add_subnode(aNode, addToPath = true)
207
- curr_parent.add_subnode(aNode) unless curr_path.empty?
208
- self.curr_path << aNode if addToPath
209
- end
210
- end # class
211
- end # module
212
- end # module
213
-
214
- # End of file
1
+ require_relative '../syntax/terminal'
2
+ require_relative '../syntax/non_terminal'
3
+ require_relative '../gfg/end_vertex'
4
+ require_relative '../gfg/item_vertex'
5
+ require_relative '../gfg/start_vertex'
6
+ require_relative '../sppf/epsilon_node'
7
+ require_relative '../sppf/non_terminal_node'
8
+ require_relative '../sppf/alternative_node'
9
+ require_relative '../sppf/parse_forest'
10
+
11
+ module Rley # This module is used as a namespace
12
+ module Parser # This module is used as a namespace
13
+ # Builder GoF pattern. Builder pattern builds a complex object
14
+ # (say, a parse forest) from simpler objects (terminal and non-terminal
15
+ # nodes) and using a step by step approach.
16
+ class ParseForestBuilder
17
+ # The sequence of input tokens
18
+ attr_reader(:tokens)
19
+
20
+ # Link to forest object
21
+ attr_reader(:forest)
22
+
23
+ # Link to current path
24
+ attr_reader(:curr_path)
25
+
26
+ # The last parse entry visited
27
+ attr_reader(:last_visitee)
28
+
29
+ # A hash with pairs of the form: visited parse entry => forest node
30
+ attr_reader(:entry2node)
31
+
32
+ # A hash with pairs of the form:
33
+ # parent end entry => path to alternative node
34
+ # This is needed for synchronizing backtracking
35
+ attr_reader(:entry2path_to_alt)
36
+
37
+ def initialize(theTokens)
38
+ @tokens = theTokens
39
+ @curr_path = []
40
+ @entry2node = {}
41
+ @entry2path_to_alt = {}
42
+ end
43
+
44
+ def receive_event(anEvent, anEntry, anIndex)
45
+ # puts "Event: #{anEvent} #{anEntry} #{anIndex}"
46
+ if anEntry.dotted_entry?
47
+ process_item_entry(anEvent, anEntry, anIndex)
48
+ elsif anEntry.start_entry?
49
+ process_start_entry(anEvent, anEntry, anIndex)
50
+ elsif anEntry.end_entry?
51
+ process_end_entry(anEvent, anEntry, anIndex)
52
+ else
53
+ raise NotImplementedError
54
+ end
55
+
56
+ @last_visitee = anEntry
57
+ end
58
+
59
+ # Return the current_parent node
60
+ def curr_parent()
61
+ return curr_path.last
62
+ end
63
+
64
+ private
65
+
66
+ def process_start_entry(_anEvent, _anEntry, _anIndex)
67
+ curr_path.pop
68
+ end
69
+
70
+ def process_end_entry(anEvent, anEntry, anIndex)
71
+ case anEvent
72
+ when :visit
73
+ # create a node with the non-terminal
74
+ # with same right extent as curr_entry_set_index
75
+ # add the new node as first child of current_parent
76
+ # append the new node to the curr_path
77
+ range = { low: anEntry.origin, high: anIndex }
78
+ non_terminal = anEntry.vertex.non_terminal
79
+ create_non_terminal_node(anEntry, range, non_terminal)
80
+ @forest = create_forest(curr_parent) unless @last_visitee
81
+
82
+ when :backtrack
83
+ # Restore path
84
+ @curr_path = entry2path_to_alt[anEntry].dup
85
+ # puts "Restore path #{curr_path.join(', ')}]"
86
+ antecedent_index = curr_parent.subnodes.size
87
+ # puts "Current parent #{curr_parent.to_string(0)}"
88
+ # puts "Antecedent index #{antecedent_index}"
89
+
90
+
91
+ when :revisit
92
+ # Retrieve the already existing node corresponding
93
+ # to re-visited entry
94
+ popular = @entry2node[anEntry]
95
+
96
+ # Share with parent
97
+ curr_parent.add_subnode(popular)
98
+
99
+ else
100
+ raise NotImplementedError
101
+ end
102
+ end
103
+
104
+
105
+ def process_item_entry(_anEvent, anEntry, anIndex)
106
+ if anEntry.exit_entry?
107
+ # Previous entry was an end entry (X. pattern)
108
+ # Does the previous entry have multiple antecedent?
109
+ if last_visitee.end_entry? && last_visitee.antecedents.size > 1
110
+ # Store current path for later backtracking
111
+ # puts "Store backtrack context #{last_visitee}"
112
+ # puts "path [#{curr_path.join(', ')}]"
113
+ entry2path_to_alt[last_visitee] = curr_path.dup
114
+ curr_parent.refinement = :or
115
+
116
+ create_alternative_node(anEntry)
117
+ end
118
+ end
119
+
120
+ # Retrieve the grammar symbol before the dot (if any)
121
+ prev_symbol = anEntry.prev_symbol
122
+ case prev_symbol
123
+ when Syntax::Terminal
124
+ # Add node without changing current path
125
+ create_token_node(anEntry, anIndex)
126
+
127
+ when NilClass # Dot at the beginning of production
128
+ if anEntry.vertex.dotted_item.production.empty?
129
+ # Empty rhs => create an epsilon node ...
130
+ # ... without changing current path
131
+ create_epsilon_node(anEntry, anIndex)
132
+ end
133
+ curr_path.pop if curr_parent.kind_of?(SPPF::AlternativeNode)
134
+ end
135
+ end
136
+
137
+ # Create an empty parse forest
138
+ def create_forest(aRootNode)
139
+ return Rley::SPPF::ParseForest.new(aRootNode)
140
+ end
141
+
142
+
143
+ # Factory method. Build and return an SPPF non-terminal node.
144
+ def create_non_terminal_node(anEntry, aRange, nonTSymb = nil)
145
+ non_terminal = nonTSymb.nil? ? anEntry.vertex.non_terminal : nonTSymb
146
+ new_node = Rley::SPPF::NonTerminalNode.new(non_terminal, aRange)
147
+ entry2node[anEntry] = new_node
148
+ # puts "FOREST ADD #{curr_parent.key if curr_parent}/#{new_node.key}"
149
+ add_subnode(new_node)
150
+
151
+ return new_node
152
+ end
153
+
154
+
155
+ # Add an alternative node to the forest
156
+ def create_alternative_node(anEntry)
157
+ vertex = anEntry.vertex
158
+ range = curr_parent.range
159
+ alternative = Rley::SPPF::AlternativeNode.new(vertex, range)
160
+ add_subnode(alternative)
161
+ # puts "FOREST ADD #{alternative.key}"
162
+
163
+ return alternative
164
+ end
165
+
166
+ # create a token node,
167
+ # with same origin as token,
168
+ # with same right extent = origin + 1
169
+ # add the new node as first child of current_parent
170
+ def create_token_node(anEntry, anIndex)
171
+ token_position = anIndex - 1
172
+ curr_token = tokens[token_position]
173
+ new_node = SPPF::TokenNode.new(curr_token, token_position)
174
+ candidate = add_node_to_forest(new_node)
175
+ entry2node[anEntry] = candidate
176
+
177
+ return candidate
178
+ end
179
+
180
+
181
+ def create_epsilon_node(anEntry, anIndex)
182
+ new_node = SPPF::EpsilonNode.new(anIndex)
183
+ candidate = add_node_to_forest(new_node)
184
+ entry2node[anEntry] = candidate
185
+
186
+ return candidate
187
+ end
188
+
189
+ # Add the given node if not yet present in parse forest
190
+ def add_node_to_forest(aNode)
191
+ key_node = aNode.key
192
+ if forest.include?(key_node)
193
+ new_node = forest.key2node[key_node]
194
+ else
195
+ new_node = aNode
196
+ forest.key2node[key_node] = new_node
197
+ # puts "FOREST ADD #{key_node}"
198
+ end
199
+ add_subnode(new_node, false)
200
+
201
+ return new_node
202
+ end
203
+
204
+
205
+ # Add the given node as sub-node of current parent node
206
+ # Optionally add the node to the current path
207
+ def add_subnode(aNode, addToPath = true)
208
+ curr_parent.add_subnode(aNode) unless curr_path.empty?
209
+ curr_path << aNode if addToPath
210
+ end
211
+ end # class
212
+ end # module
213
+ end # module
214
+
215
+ # End of file
@@ -1,56 +1,57 @@
1
- require_relative 'parse_walker_factory'
2
- require_relative 'parse_forest_builder'
3
-
4
- module Rley # This module is used as a namespace
5
- module Parser # This module is used as a namespace
6
- # Utility class that helps to create a ParseForest from
7
- # a given Parsing object.
8
- class ParseForestFactory
9
- # Link to Parsing object (= results of recognizer)
10
- attr_reader(:parsing)
11
-
12
-
13
- def initialize(aParsingResult)
14
- @parsing = aParsingResult
15
- end
16
-
17
- # Factory that produces the parse forest
18
- def build_parse_forest()
19
- a_walker = walker(parsing)
20
- a_builder = builder(parsing)
21
-
22
- begin
23
- loop do
24
- event = a_walker.next
25
- # puts "EVENT #{event[0]} #{event[1]}"
26
- a_builder.receive_event(*event)
27
- end
28
- rescue StopIteration
29
- # Do nothing
30
- end
31
-
32
- return a_builder.forest
33
- end
34
-
35
-
36
- private
37
- # Create a Parsing walker, that is, an object
38
- # that will iterate over the relevant nodes (= parsing entries)
39
- # of a GFGParsing
40
- def walker(aParseResult)
41
- walker_factory = ParseWalkerFactory.new
42
- accept_entry = aParseResult.accepting_entry
43
- accept_index = aParseResult.chart.last_index
44
- walker = walker_factory.build_walker(accept_entry, accept_index)
45
- end
46
-
47
- # Create a Builder, that is, an object
48
- # that will create piece by piece the forest
49
- def builder(aParseResult)
50
- ParseForestBuilder.new(aParseResult.tokens)
51
- end
52
- end # class
53
- end # module
54
- end # module
55
-
56
- # End of file
1
+ require_relative 'parse_walker_factory'
2
+ require_relative 'parse_forest_builder'
3
+
4
+ module Rley # This module is used as a namespace
5
+ module Parser # This module is used as a namespace
6
+ # Utility class that helps to create a ParseForest from
7
+ # a given Parsing object.
8
+ class ParseForestFactory
9
+ # Link to Parsing object (= results of recognizer)
10
+ attr_reader(:parsing)
11
+
12
+
13
+ def initialize(aParsingResult)
14
+ @parsing = aParsingResult
15
+ end
16
+
17
+ # Factory that produces the parse forest
18
+ def build_parse_forest()
19
+ a_walker = walker(parsing)
20
+ a_builder = builder(parsing)
21
+
22
+ begin
23
+ loop do
24
+ event = a_walker.next
25
+ # puts "EVENT #{event[0]} #{event[1]}"
26
+ a_builder.receive_event(*event)
27
+ end
28
+ rescue StopIteration
29
+ # Do nothing
30
+ end
31
+
32
+ return a_builder.forest
33
+ end
34
+
35
+
36
+ private
37
+
38
+ # Create a Parsing walker, that is, an object
39
+ # that will iterate over the relevant nodes (= parsing entries)
40
+ # of a GFGParsing
41
+ def walker(aParseResult)
42
+ walker_factory = ParseWalkerFactory.new
43
+ accept_entry = aParseResult.accepting_entry
44
+ accept_index = aParseResult.chart.last_index
45
+ walker_factory.build_walker(accept_entry, accept_index)
46
+ end
47
+
48
+ # Create a Builder, that is, an object
49
+ # that will create piece by piece the forest
50
+ def builder(aParseResult)
51
+ ParseForestBuilder.new(aParseResult.tokens)
52
+ end
53
+ end # class
54
+ end # module
55
+ end # module
56
+
57
+ # End of file