rley 0.4.01 → 0.4.02

Sign up to get free protection for your applications and to get access to all the features.
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