rley 0.4.01 → 0.4.02

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/LICENSE.txt +2 -2
  4. data/README.md +3 -3
  5. data/examples/NLP/mini_en_demo.rb +1 -1
  6. data/examples/data_formats/JSON/JSON_demo.rb +1 -0
  7. data/examples/data_formats/JSON/JSON_lexer.rb +4 -4
  8. data/examples/general/calc/calc_lexer.rb +2 -2
  9. data/lib/rley.rb +1 -1
  10. data/lib/rley/constants.rb +1 -1
  11. data/lib/rley/formatter/debug.rb +2 -2
  12. data/lib/rley/formatter/json.rb +4 -4
  13. data/lib/rley/parse_tree_visitor.rb +9 -9
  14. data/lib/rley/parser/base_parser.rb +1 -1
  15. data/lib/rley/parser/gfg_parsing.rb +9 -0
  16. data/lib/rley/parser/parse_tree_builder.rb +176 -126
  17. data/lib/rley/parser/parse_tree_factory.rb +57 -0
  18. data/lib/rley/ptree/non_terminal_node.rb +10 -9
  19. data/lib/rley/ptree/parse_tree_node.rb +10 -5
  20. data/lib/rley/ptree/terminal_node.rb +14 -6
  21. data/lib/rley/sppf/sppf_node.rb +2 -2
  22. data/lib/rley/{parser → tokens}/token.rb +1 -4
  23. data/lib/rley/{ptree → tokens}/token_range.rb +1 -1
  24. data/spec/rley/formatter/debug_spec.rb +16 -16
  25. data/spec/rley/formatter/json_spec.rb +8 -8
  26. data/spec/rley/parse_forest_visitor_spec.rb +1 -1
  27. data/spec/rley/parse_tree_visitor_spec.rb +28 -28
  28. data/spec/rley/parser/error_reason_spec.rb +3 -3
  29. data/spec/rley/parser/gfg_chart_spec.rb +2 -2
  30. data/spec/rley/parser/gfg_earley_parser_spec.rb +2 -2
  31. data/spec/rley/parser/gfg_parsing_spec.rb +2 -2
  32. data/spec/rley/parser/groucho_spec.rb +1 -1
  33. data/spec/rley/parser/parse_tracer_spec.rb +2 -2
  34. data/spec/rley/parser/parse_tree_builder_spec.rb +213 -140
  35. data/spec/rley/parser/parse_tree_factory_spec.rb +85 -0
  36. data/spec/rley/parser/parse_walker_factory_spec.rb +11 -10
  37. data/spec/rley/ptree/non_terminal_node_spec.rb +23 -20
  38. data/spec/rley/ptree/terminal_node_spec.rb +7 -12
  39. data/spec/rley/sppf/alternative_node_spec.rb +2 -2
  40. data/spec/rley/sppf/non_terminal_node_spec.rb +2 -2
  41. data/spec/rley/support/ambiguous_grammar_helper.rb +2 -2
  42. data/spec/rley/support/expectation_helper.rb +1 -1
  43. data/spec/rley/support/grammar_ambig01_helper.rb +2 -2
  44. data/spec/rley/support/grammar_b_expr_helper.rb +2 -2
  45. data/spec/rley/support/grammar_helper.rb +3 -3
  46. data/spec/rley/support/grammar_l0_helper.rb +2 -2
  47. data/spec/rley/support/grammar_pb_helper.rb +2 -2
  48. data/spec/rley/{ptree → tokens}/token_range_spec.rb +2 -2
  49. data/spec/rley/{parser → tokens}/token_spec.rb +2 -2
  50. metadata +11 -17
  51. data/lib/rley/parser/chart.rb +0 -82
  52. data/lib/rley/parser/earley_parser.rb +0 -203
  53. data/lib/rley/parser/parsing.rb +0 -265
  54. data/spec/rley/parser/chart_spec.rb +0 -120
  55. data/spec/rley/parser/earley_parser_spec.rb +0 -710
  56. data/spec/rley/parser/parsing_spec.rb +0 -408
@@ -1,82 +0,0 @@
1
- require_relative 'state_set'
2
- require_relative 'parse_state'
3
-
4
- module Rley # This module is used as a namespace
5
- module Parser # This module is used as a namespace
6
- # Also called a parse table
7
- # A one-dimensional array with n + 1 entries (n = number of input tokens).
8
- class Chart
9
- # An array of state sets (one per input token + 1)
10
- attr_reader(:state_sets)
11
-
12
- # The level of trace details reported on stdout during the parse.
13
- # The possible values are:
14
- # 0: No trace output (default case)
15
- # 1: Show trace of scanning and completion rules
16
- # 2: Same as of 1 with the addition of the prediction rules
17
- attr_reader(:tracer)
18
-
19
- # @param startItems [Array] A non-empty Array of dotted items for
20
- # the start symbol.
21
- # @param tokenCount [Fixnum] The number of lexemes in the input to parse.
22
- # @param aTracer [ParseTracer] A tracer object.
23
- def initialize(startItems, tokenCount, aTracer)
24
- @tracer = aTracer
25
- @state_sets = Array.new(tokenCount + 1) { |_| StateSet.new }
26
- startItems.each do |startDottedItem|
27
- push_state(startDottedItem, 0, 0, :start_rule)
28
- end
29
- end
30
-
31
- # The dotted item/rule used to seed the parse chart.
32
- # It corresponds to the start production and a dot placed
33
- # at the beginning of the rhs
34
- def start_dotted_rule()
35
- return self[0].states.first.dotted_rule
36
- end
37
-
38
- # Return the start (non-terminal) symbol of the grammar.
39
- def start_symbol()
40
- return state_sets.first.states[0].dotted_rule.lhs
41
- end
42
-
43
- # Access the state set at given position
44
- def [](index)
45
- return state_sets[index]
46
- end
47
-
48
- # Return the index value of the last non-empty state set.
49
- def last_index()
50
- first_empty = state_sets.find_index(&:empty?)
51
- index = if first_empty.nil?
52
- state_sets.size - 1
53
- else
54
- first_empty.zero? ? 0 : first_empty - 1
55
- end
56
-
57
- return index
58
- end
59
-
60
- # Push a parse state for the chart entry with given index
61
- def push_state(aDottedItem, anOrigin, anIndex, aReason)
62
- new_state = ParseState.new(aDottedItem, anOrigin)
63
- pushed = self[anIndex].push_state(new_state)
64
- return unless pushed && tracer.level > 0
65
- case aReason
66
- when :start_rule, :prediction
67
- tracer.trace_prediction(anIndex, new_state)
68
-
69
- when :scanning
70
- tracer.trace_scanning(anIndex, new_state)
71
-
72
- when :completion
73
- tracer.trace_completion(anIndex, new_state)
74
- else
75
- raise NotImplementedError, "Unknown push_state mode #{aReason}"
76
- end
77
- end
78
- end # class
79
- end # module
80
- end # module
81
-
82
- # End of file
@@ -1,203 +0,0 @@
1
- require_relative 'base_parser'
2
-
3
- module Rley # This module is used as a namespace
4
- module Parser # This module is used as a namespace
5
- # Implementation of a parser that uses the Earley parsing algorithm.
6
- class EarleyParser < BaseParser
7
- # A Hash that defines the mapping: non-terminal => [start dotted items]
8
- attr_reader(:start_mapping)
9
-
10
- # A Hash that defines the mapping: dotted item => next dotted item
11
- # In other words, the 'next_mapping' allows to find the dotted item
12
- # after "advancing" the dot
13
- attr_reader(:next_mapping)
14
-
15
- def initialize(aGrammar)
16
- super(aGrammar)
17
- @start_mapping = build_start_mapping(dotted_items)
18
- @next_mapping = build_next_mapping(dotted_items)
19
- end
20
-
21
- # Parse a sequence of input tokens.
22
- # @param aTokenSequence [Array] Array of Tokens objects returned by a
23
- # tokenizer/scanner/lexer.
24
- # @param aTraceLevel [Fixnum] The specified trace level.
25
- # The possible values are:
26
- # 0: No trace output (default case)
27
- # 1: Show trace of scanning and completion rules
28
- # 2: Same as of 1 with the addition of the prediction rules
29
- # @return [Parsing] an object that embeds the parse results.
30
- def parse(aTokenSequence, aTraceLevel = 0)
31
- tracer = ParseTracer.new(aTraceLevel, $stdout, aTokenSequence)
32
- result = Parsing.new(start_dotted_items, aTokenSequence, tracer)
33
- last_token_index = aTokenSequence.size
34
- (0..last_token_index).each do |i|
35
- handle_error(result) if result.chart[i].empty?
36
- predicted = Set.new
37
- result.chart[i].each do |state|
38
- if state.complete? # End of production reached?
39
- completion(result, state, i, tracer)
40
- else
41
- next_symbol = state.next_symbol
42
- if next_symbol.kind_of?(Syntax::NonTerminal)
43
- unless predicted.include? next_symbol
44
- prediction(result, state, next_symbol, i, tracer)
45
- predicted << next_symbol # Avoid repeated predictions
46
- end
47
- elsif i < last_token_index
48
- # Expecting a terminal symbol
49
- scanning(result, next_symbol, i, tracer)
50
- end
51
- end
52
- end
53
- end
54
-
55
- return result
56
- end
57
-
58
- private
59
-
60
- # Create a Hash with pairs of the kind:
61
- # non-terminal => [start dotted items]
62
- def build_start_mapping(theDottedItems)
63
- mapping = {}
64
- theDottedItems.each do |item|
65
- next unless item.at_start?
66
-
67
- lhs_symbol = item.lhs
68
- map_entry = mapping.fetch(lhs_symbol, [])
69
- map_entry << item
70
- mapping[lhs_symbol] = map_entry
71
- end
72
-
73
- return mapping
74
- end
75
-
76
- # Create a Hash with pairs of the kind:
77
- # dotted item => next dotted item
78
- # next dotted item uses same production and the dot
79
- # position is advanced by one symbol
80
- def build_next_mapping(theDottedItems)
81
- mapping = {}
82
- theDottedItems.each_cons(2) do |(item1, item2)|
83
- next if item1.production != item2.production
84
- mapping[item1] = item2
85
- end
86
-
87
- return mapping
88
- end
89
-
90
- # The dotted item for the start production and
91
- # with the dot at the beginning of the rhs
92
- def start_dotted_items()
93
- start_symbol = grammar.start_symbol
94
- start_items = dotted_items.select do |anItem|
95
- (anItem.lhs == start_symbol) && anItem.at_start?
96
- end
97
-
98
- return start_items
99
- end
100
-
101
-
102
- # This method is called when a parse state for chart entry at position
103
- # 'pos' expects as next symbol a non-terminal.
104
- # Given a predicted non-terminal 'nt' and a current token position
105
- # 'pos':
106
- # For each production with 'nt' as lhs, retrieve their corresponding
107
- # initial dotted rules nt -> . xxxx
108
- # For retrieved dotted rule, add a parse state to the chart entry
109
- # at 'pos': <initial dotted rule, pos, pos>
110
- # In short, one adds states to chart[pos], one per production that
111
- # specifies how to reduce some input into the predicted nt (non-terminal)
112
- # A prediction corresponds to a potential expansion of a nonterminal
113
- # in a left-most derivation.
114
- # @param aParsing [Parsing] the object that encapsulates the results
115
- # result of the parsing process
116
- # @param aState [ParseState] current parse state being processed
117
- # @param aNonTerminal [NonTerminal] a non-terminal symbol that
118
- # immediately follows a dot
119
- # (= is expected/predicted by the production rule)
120
- # @param aPosition [Fixnum] position in the input token sequence.
121
- def prediction(aParsing, aState, aNonTerminal, aPosition, aTracer)
122
- if aTracer.level > 1
123
- puts "Chart[#{aPosition}] Prediction(s) from #{aState}:"
124
- end
125
- # Retrieve all start dotted items for productions
126
- # with aNonTerminal as its lhs
127
- items = start_mapping[aNonTerminal]
128
- items.each do |an_item|
129
- aParsing.push_state(an_item, aPosition, aPosition, :prediction)
130
- end
131
-
132
- return unless aNonTerminal.nullable?
133
- # Ayock-Horspool trick for nullable rules
134
- next_item = next_mapping[aState.dotted_rule]
135
- aParsing.push_state(next_item, aState.origin, aPosition, :prediction)
136
- end
137
-
138
- # This method is called when a parse state for chart entry at position
139
- # 'pos' expects a terminal as next symbol.
140
- # If the input token matches the terminal symbol then:
141
- # Retrieve all parse states for chart entry at 'aPosition'
142
- # that have the given terminal as next symbol.
143
- # For each s of the above states, push to chart entry aPosition + 1
144
- # a new state like: <next dotted rule, s.origin, aPosition + 1>
145
- # In other words, we place the dotted rules in the next state set
146
- # such that the dot appears after terminal.
147
- # @param aParsing [Parsing] the object that encapsulates the results
148
- # result of the parsing process
149
- # @param aTerminal [Terminal] a terminal symbol that
150
- # immediately follows a dot
151
- # @param aPosition [Fixnum] position in the input token sequence.
152
- def scanning(aParsing, aTerminal, aPosition, aTracer)
153
- if aTracer.level > 1
154
- prefix = "Chart[#{aPosition}] Scanning of terminal "
155
- suffix = "#{aTerminal.name}:"
156
- puts prefix + suffix
157
- end
158
- aParsing.scanning(aTerminal, aPosition) do |item|
159
- next_mapping[item]
160
- end
161
- end
162
-
163
- # This method is called when a parse state at chart entry reaches
164
- # the end of a production.
165
- # For every state in chart[aPosition] that is
166
- # complete (i.e. of the form: { dotted_rule: X -> γ •, origin: j}),
167
- # Find states s in chart[j] of the
168
- # form { dotted_rule: Y -> α • X β, origin: i}
169
- # In other words, rules that predicted the non-terminal X.
170
- # For each s, add to chart[aPosition] a state of the form
171
- # { dotted_rule: Y → α X • β, origin: i})
172
- def completion(aParsing, aState, aPosition, aTracer)
173
- if aTracer.level > 1
174
- puts "Chart[#{aPosition}] Completion of state #{aState}:"
175
- end
176
- aParsing.completion(aState, aPosition) do |item|
177
- next_mapping[item]
178
- end
179
- end
180
-
181
- # Raise an exception to indicate a syntax error.
182
- def handle_error(aParsing)
183
- # Retrieve the first empty state set
184
- pos = aParsing.chart.state_sets.find_index(&:empty?)
185
- lexeme_at_pos = aParsing.tokens[pos - 1].lexeme
186
-
187
- terminals = aParsing.chart.state_sets[pos - 1].expected_terminals
188
- term_names = terminals.map(&:name)
189
- err_msg = "Syntax error at or near token #{pos}"
190
- err_msg << ">>>#{lexeme_at_pos}<<<:\nExpected "
191
- err_msg << if terminals.size > 1
192
- "one of: ['#{term_names.join("', '")}'],"
193
- else
194
- ": #{term_names[0]},"
195
- end
196
- err_msg << " found a '#{aParsing.tokens[pos - 1].terminal.name}'"
197
- raise StandardError, err_msg + ' instead.'
198
- end
199
- end # class
200
- end # module
201
- end # module
202
-
203
- # End of file
@@ -1,265 +0,0 @@
1
- require_relative 'chart'
2
- require_relative 'parse_state_tracker'
3
- require_relative 'parse_tree_builder'
4
-
5
-
6
- module Rley # This module is used as a namespace
7
- module Parser # This module is used as a namespace
8
- class Parsing
9
- attr_reader(:chart)
10
-
11
- # The sequence of input token to parse
12
- attr_reader(:tokens)
13
-
14
- # @param aTracer [ParseTracer] An object that traces the parsing.
15
- # The possible values are:
16
- # 0: No trace output (default case)
17
- # 1: Show trace of scanning and completion rules
18
- # 2: Same as of 1 with the addition of the prediction rules
19
- def initialize(startDottedRules, theTokens, aTracer)
20
- @tokens = theTokens.dup
21
- @chart = Chart.new(startDottedRules, tokens.size, aTracer)
22
- end
23
-
24
- # Return true if the parse was successful (= input tokens
25
- # followed the syntax specified by the grammar)
26
- def success?()
27
- # Success can be detected as follows:
28
- # The last chart entry has at least one complete parse state
29
- # for the start symbol with an origin == 0
30
- last_chart_entry = chart.state_sets[-1]
31
- start_symbol = chart.start_symbol
32
-
33
- # Retrieve all the complete states with start symbol in lhs
34
- end_states = last_chart_entry.states_rewriting(start_symbol)
35
- success_states = end_states.select { |st| st.origin.zero? }
36
-
37
- return !success_states.empty?
38
- end
39
-
40
- # Return true if there are more than one complete state
41
- # for the same lhs and same origin in any state set.
42
- def ambiguous?()
43
- found = chart.state_sets.find { |set| !set.ambiguities.empty? }
44
- return !found.nil?
45
- end
46
-
47
- # Factory method. Builds a ParseTree from the parse result.
48
- # @return [ParseTree]
49
- # Algorithm:
50
- # set state_set_index = index of last state set in chart
51
- # Search the completed parse state that corresponds to the full parse
52
- def parse_tree()
53
- state_tracker = new_state_tracker
54
- builder = tree_builder(state_tracker.state_set_index)
55
-
56
- loop do
57
- state_tracker.symbol_on_left
58
- # match_symbol = state_tracker.symbol_on_left
59
- # puts '--------------------'
60
- # puts "Active parse state: #{state_tracker.parse_state}"
61
- # puts "Matching symbol: #{match_symbol}"
62
- # puts 'Parse tree:'
63
- # puts builder.root.to_string(0)
64
-
65
- # Place the symbol on left of the dot in the parse tree
66
- done = insert_matched_symbol(state_tracker, builder)
67
- break if done
68
- end
69
-
70
- return builder.parse_tree
71
- end
72
-
73
-
74
- # Push a parse state (dotted item + origin) to the
75
- # chart entry with given index if it isn't yet in the chart entry.
76
- def push_state(aDottedItem, anOrigin, aChartIndex, aReason)
77
- raise StandardError, 'Dotted item may not be nil' if aDottedItem.nil?
78
- chart.push_state(aDottedItem, anOrigin, aChartIndex, aReason)
79
- end
80
-
81
-
82
- # This method is called when a parse state for chart entry at position
83
- # 'pos' expects a terminal as next symbol.
84
- # If the input token matches the terminal symbol then:
85
- # Retrieve all parse states for chart entry at 'aPosition'
86
- # that have the given terminal as next symbol.
87
- # For each s of the above states, push to chart entry aPosition + 1
88
- # a new state like: <next dotted rule, s.origin, aPosition + 1>
89
- # In other words, we place the dotted rules in the next state set
90
- # such that the dot appears after terminal.
91
- # @param aTerminal [Terminal] a terminal symbol that
92
- # immediately follows a dot
93
- # @param aPosition [Fixnum] position in the input token sequence.
94
- # @param nextMapping [Proc or Lambda] code to evaluate in order to
95
- # determine the "next" dotted rule for a given one.
96
- def scanning(aTerminal, aPosition, &_nextMapping)
97
- curr_token = tokens[aPosition]
98
- return unless curr_token.terminal == aTerminal
99
-
100
- states = states_expecting(aTerminal, aPosition, false)
101
- states.each do |s|
102
- next_item = yield s.dotted_rule
103
- push_state(next_item, s.origin, aPosition + 1, :scanning)
104
- end
105
- end
106
-
107
-
108
-
109
- # This method is called when a parse state at chart entry reaches the end
110
- # of a production.
111
- # For every state in chart[aPosition] that is complete
112
- # (i.e. of the form: { dotted_rule: X -> γ •, origin: j}),
113
- # Find states s in chart[j] of the form
114
- # {dotted_rule: Y -> α • X β, origin: i}
115
- # In other words, rules that predicted the non-terminal X.
116
- # For each s, add to chart[aPosition] a state of the form
117
- # { dotted_rule: Y → α X • β, origin: i})
118
- def completion(aState, aPosition, &_nextMapping)
119
- curr_origin = aState.origin
120
- curr_lhs = aState.dotted_rule.lhs
121
- states = states_expecting(curr_lhs, curr_origin, false)
122
- states.each do |s|
123
- next_item = yield s.dotted_rule
124
- push_state(next_item, s.origin, aPosition, :completion)
125
- end
126
- end
127
-
128
-
129
- # The list of ParseState from the chart entry at given position
130
- # that expect the given terminal
131
- def states_expecting(aTerminal, aPosition, toSort)
132
- expecting = chart[aPosition].states_expecting(aTerminal)
133
- return expecting if !toSort || expecting.size < 2
134
-
135
- # Put predicted states ahead
136
- (predicted, others) = expecting.partition(&:predicted?)
137
-
138
- # Sort state in reverse order of their origin value
139
- [predicted, others].each do |set|
140
- set.sort! { |a, b| b.origin <=> a.origin }
141
- end
142
-
143
- return predicted + others
144
- end
145
-
146
- # Retrieve the parse state(s) that represents a complete, successful parse
147
- # After a successful parse, the last chart entry
148
- # has a parse state that involves the start symbol and
149
- # has a dot positioned at the end of its rhs.
150
- def end_parse_states()
151
- last_chart_entry = chart.state_sets[-1]
152
- start_symbol = chart.start_symbol
153
-
154
- # Retrieve all the complete states with origin at 0
155
- end_states = last_chart_entry.states_rewriting(start_symbol)
156
-
157
- return end_states
158
- end
159
-
160
-
161
- # Insert in a parse tree the symbol on the left of the
162
- # current dotted rule.
163
- def insert_matched_symbol(aStateTracker, aBuilder)
164
- # Retrieve symbol before the dot in active parse state
165
- match_symbol = aStateTracker.symbol_on_left
166
-
167
- # Retrieve tree node being processed
168
- tree_node = aBuilder.current_node
169
-
170
- done = false
171
- case [match_symbol.class, tree_node.class]
172
- when [Syntax::Terminal, PTree::TerminalNode]
173
- aStateTracker.to_prev_state_set
174
- predecessor_state_terminal(match_symbol, aStateTracker, aBuilder)
175
-
176
- when [NilClass, Rley::PTree::TerminalNode],
177
- [NilClass, PTree::NonTerminalNode]
178
- # Retrieve all parse states that expect the lhs
179
- new_states = states_expecting_lhs(aStateTracker, aBuilder)
180
- done = true if new_states.empty?
181
- # Select an unused parse state
182
- aStateTracker.select_state(new_states)
183
-
184
- when [Syntax::NonTerminal, PTree::NonTerminalNode]
185
- completed_state_for(match_symbol, aStateTracker, aBuilder)
186
- end
187
-
188
- done ||= aBuilder.root == aBuilder.current_node
189
- return done
190
- end
191
-
192
- private
193
-
194
- # Factory method. Creates and initializes a ParseStateTracker instance.
195
- def new_state_tracker()
196
- instance = ParseStateTracker.new(chart.last_index)
197
- instance.parse_state = end_parse_states.first
198
-
199
- return instance
200
- end
201
-
202
-
203
- # A terminal symbol is on the left of dot.
204
- # Go to the predecessor state for the given terminal
205
- def predecessor_state_terminal(_a_symb, aStateTracker, aTreeBuilder)
206
- index = aStateTracker.state_set_index
207
- aTreeBuilder.current_node.range = { low: index, high: index + 1 }
208
- link_node_to_token(aTreeBuilder, aStateTracker.state_set_index)
209
- unless aTreeBuilder.current_node.is_a?(PTree::TerminalNode)
210
- raise StandardError, 'Expected terminal node'
211
- end
212
- aTreeBuilder.move_back
213
- state_set = chart[aStateTracker.state_set_index]
214
- previous_state = state_set.predecessor_state(aStateTracker.parse_state)
215
- aStateTracker.parse_state = previous_state
216
- end
217
-
218
-
219
- # Retrieve a complete state with given terminal symbol as lhs.
220
- def completed_state_for(a_symb, aTracker, aTreeBuilder)
221
- new_states = chart[aTracker.state_set_index].states_rewriting(a_symb)
222
- aTracker.select_state(new_states)
223
- aTreeBuilder.range = { high: aTracker.state_set_index }
224
- aTreeBuilder.use_complete_state(aTracker.parse_state)
225
- link_node_to_token(aTreeBuilder, aTracker.state_set_index - 1)
226
- aTreeBuilder.move_down
227
- end
228
-
229
-
230
- def states_expecting_lhs(aStateTracker, aTreeBuilder)
231
- lhs = aStateTracker.curr_dotted_item.production.lhs
232
- new_states = states_expecting(lhs, aStateTracker.state_set_index, true)
233
- new_states.reject! { |st| st == aStateTracker.parse_state }
234
- # Filter out parse states with incompatible range
235
- if new_states.size > 1
236
- previous_node = aTreeBuilder.current_path[-3]
237
- new_states.select! do |parse_state|
238
- parse_state.dotted_rule.production.lhs == previous_node.symbol
239
- end
240
- end
241
-
242
- return new_states
243
- end
244
-
245
- # If the current node is a terminal node
246
- # then link the token to that node
247
- def link_node_to_token(aTreeBuilder, aStateSetIndex)
248
- return unless aTreeBuilder.current_node.is_a?(PTree::TerminalNode)
249
- return unless aTreeBuilder.current_node.token.nil?
250
-
251
- a_node = aTreeBuilder.current_node
252
- a_node.token = tokens[aStateSetIndex] unless a_node.token
253
- end
254
-
255
- # Factory method. Initializes a ParseTreeBuilder object
256
- def tree_builder(anIndex)
257
- full_range = { low: 0, high: anIndex }
258
- start_production = chart.start_dotted_rule.production
259
- return ParseTreeBuilder.new(start_production, full_range)
260
- end
261
- end # class
262
- end # module
263
- end # module
264
-
265
- # End of file