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.
- checksums.yaml +4 -4
- data/.rubocop.yml +7 -3
- data/CHANGELOG.md +3 -0
- data/Rakefile +30 -30
- data/examples/parsers/parsing_L0.rb +1 -1
- data/examples/parsers/parsing_L1.rb +1 -1
- data/examples/parsers/parsing_abc.rb +1 -1
- data/examples/parsers/parsing_ambig.rb +1 -1
- data/examples/parsers/parsing_another.rb +1 -1
- data/examples/parsers/parsing_b_expr.rb +1 -1
- data/examples/parsers/parsing_err_expr.rb +1 -1
- data/examples/parsers/parsing_groucho.rb +1 -1
- data/examples/parsers/parsing_right_recursive.rb +1 -1
- data/examples/parsers/parsing_tricky.rb +1 -1
- data/lib/rley/constants.rb +2 -2
- data/lib/rley/formatter/base_formatter.rb +0 -2
- data/lib/rley/formatter/debug.rb +0 -2
- data/lib/rley/formatter/json.rb +1 -3
- data/lib/rley/gfg/call_edge.rb +31 -30
- data/lib/rley/gfg/edge.rb +22 -23
- data/lib/rley/gfg/end_vertex.rb +22 -24
- data/lib/rley/gfg/epsilon_edge.rb +20 -21
- data/lib/rley/gfg/grm_flow_graph.rb +39 -39
- data/lib/rley/gfg/item_vertex.rb +16 -17
- data/lib/rley/gfg/non_terminal_vertex.rb +3 -4
- data/lib/rley/gfg/return_edge.rb +32 -31
- data/lib/rley/gfg/scan_edge.rb +25 -26
- data/lib/rley/gfg/shortcut_edge.rb +25 -26
- data/lib/rley/gfg/start_vertex.rb +0 -2
- data/lib/rley/gfg/vertex.rb +8 -8
- data/lib/rley/parse_forest_visitor.rb +113 -115
- data/lib/rley/parse_tree_visitor.rb +0 -2
- data/lib/rley/parser/base_parser.rb +27 -27
- data/lib/rley/parser/chart.rb +14 -14
- data/lib/rley/parser/dotted_item.rb +33 -33
- data/lib/rley/parser/earley_parser.rb +6 -6
- data/lib/rley/parser/gfg_chart.rb +8 -15
- data/lib/rley/parser/gfg_earley_parser.rb +15 -13
- data/lib/rley/parser/gfg_parsing.rb +26 -22
- data/lib/rley/parser/grm_items_builder.rb +3 -2
- data/lib/rley/parser/parse_entry.rb +3 -9
- data/lib/rley/parser/parse_entry_set.rb +14 -19
- data/lib/rley/parser/parse_entry_tracker.rb +56 -56
- data/lib/rley/parser/parse_forest_builder.rb +215 -214
- data/lib/rley/parser/parse_forest_factory.rb +57 -56
- data/lib/rley/parser/parse_state.rb +8 -11
- data/lib/rley/parser/parse_state_tracker.rb +56 -56
- data/lib/rley/parser/parse_tracer.rb +3 -3
- data/lib/rley/parser/parse_tree_builder.rb +10 -10
- data/lib/rley/parser/parse_walker_factory.rb +30 -33
- data/lib/rley/parser/parsing.rb +8 -8
- data/lib/rley/parser/state_set.rb +23 -26
- data/lib/rley/ptree/non_terminal_node.rb +1 -1
- data/lib/rley/ptree/token_range.rb +2 -2
- data/lib/rley/sppf/alternative_node.rb +32 -34
- data/lib/rley/sppf/composite_node.rb +27 -27
- data/lib/rley/sppf/epsilon_node.rb +26 -27
- data/lib/rley/sppf/leaf_node.rb +11 -12
- data/lib/rley/sppf/non_terminal_node.rb +37 -38
- data/lib/rley/sppf/sppf_node.rb +1 -1
- data/lib/rley/sppf/token_node.rb +29 -29
- data/lib/rley/syntax/grammar.rb +1 -3
- data/lib/rley/syntax/grammar_builder.rb +8 -8
- data/lib/rley/syntax/non_terminal.rb +2 -4
- data/lib/rley/syntax/production.rb +3 -3
- data/lib/rley/syntax/symbol_seq.rb +1 -1
- data/spec/rley/gfg/call_edge_spec.rb +50 -51
- data/spec/rley/gfg/edge_spec.rb +33 -33
- data/spec/rley/gfg/end_vertex_spec.rb +26 -27
- data/spec/rley/gfg/epsilon_edge_spec.rb +25 -25
- data/spec/rley/gfg/grm_flow_graph_spec.rb +1 -1
- data/spec/rley/gfg/item_vertex_spec.rb +3 -4
- data/spec/rley/gfg/return_edge_spec.rb +51 -51
- data/spec/rley/gfg/scan_edge_spec.rb +32 -30
- data/spec/rley/gfg/shortcut_edge_spec.rb +1 -1
- data/spec/rley/gfg/vertex_spec.rb +3 -3
- data/spec/rley/parse_forest_visitor_spec.rb +239 -238
- data/spec/rley/parser/dotted_item_spec.rb +1 -1
- data/spec/rley/parser/earley_parser_spec.rb +16 -16
- data/spec/rley/parser/gfg_earley_parser_spec.rb +30 -31
- data/spec/rley/parser/gfg_parsing_spec.rb +11 -10
- data/spec/rley/parser/grm_items_builder_spec.rb +2 -2
- data/spec/rley/parser/parse_entry_set_spec.rb +4 -4
- data/spec/rley/parser/parse_entry_spec.rb +0 -2
- data/spec/rley/parser/parse_forest_builder_spec.rb +82 -57
- data/spec/rley/parser/parse_forest_factory_spec.rb +84 -82
- data/spec/rley/parser/parse_walker_factory_spec.rb +10 -9
- data/spec/rley/parser/parsing_spec.rb +0 -1
- data/spec/rley/sppf/alternative_node_spec.rb +2 -2
- data/spec/rley/sppf/non_terminal_node_spec.rb +0 -1
- data/spec/rley/support/ambiguous_grammar_helper.rb +1 -1
- data/spec/rley/support/expectation_helper.rb +37 -36
- data/spec/rley/support/grammar_abc_helper.rb +17 -17
- data/spec/rley/support/grammar_b_expr_helper.rb +40 -39
- data/spec/rley/support/grammar_helper.rb +2 -1
- data/spec/rley/support/{grammar_L0_helper.rb → grammar_l0_helper.rb} +82 -81
- data/spec/rley/support/grammar_sppf_helper.rb +24 -25
- data/spec/rley/syntax/grammar_spec.rb +1 -1
- metadata +2 -2
@@ -16,11 +16,8 @@ module Rley # This module is used as a namespace
|
|
16
16
|
def ==(other)
|
17
17
|
return true if object_id == other.object_id
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
else
|
22
|
-
result = false
|
23
|
-
end
|
19
|
+
result = (dotted_rule == other.dotted_rule) &&
|
20
|
+
(origin == other.origin)
|
24
21
|
|
25
22
|
return result
|
26
23
|
end
|
@@ -50,11 +47,11 @@ module Rley # This module is used as a namespace
|
|
50
47
|
return false unless dotted_rule.production == other_production
|
51
48
|
|
52
49
|
prev_position = other.dotted_rule.prev_position
|
53
|
-
if prev_position.nil?
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
50
|
+
result = if prev_position.nil?
|
51
|
+
false
|
52
|
+
else
|
53
|
+
dotted_rule.position == prev_position
|
54
|
+
end
|
58
55
|
|
59
56
|
return result
|
60
57
|
end
|
@@ -72,7 +69,7 @@ module Rley # This module is used as a namespace
|
|
72
69
|
|
73
70
|
# Return the validated dotted item(rule)
|
74
71
|
def valid_dotted_rule(aDottedRule)
|
75
|
-
|
72
|
+
raise StandardError, 'Dotted item cannot be nil' if aDottedRule.nil?
|
76
73
|
|
77
74
|
return aDottedRule
|
78
75
|
end
|
@@ -1,56 +1,56 @@
|
|
1
|
-
module Rley # This module is used as a namespace
|
2
|
-
module Parser # This module is used as a namespace
|
3
|
-
# Helper class that keeps track of the parse states used
|
4
|
-
# while a Parsing instance is constructing a parse tree.
|
5
|
-
class ParseStateTracker
|
6
|
-
# The index of the current state set
|
7
|
-
attr_reader(:state_set_index)
|
8
|
-
|
9
|
-
# The current parse state
|
10
|
-
attr_reader(:parse_state)
|
11
|
-
|
12
|
-
# The already processed states from current state set
|
13
|
-
attr_reader(:processed_states)
|
14
|
-
|
15
|
-
# Constructor. Refined variant of the inherited constructor.
|
16
|
-
def initialize(aStateSetIndex)
|
17
|
-
self.state_set_index = aStateSetIndex
|
18
|
-
end
|
19
|
-
|
20
|
-
# Write accessor. Sets the value of the state set index
|
21
|
-
def state_set_index=(anIndex)
|
22
|
-
@state_set_index = anIndex
|
23
|
-
@processed_states = {}
|
24
|
-
end
|
25
|
-
|
26
|
-
# Write accessor. Set the given parse state as the current one.
|
27
|
-
def parse_state=(aParseState)
|
28
|
-
|
29
|
-
@parse_state = aParseState
|
30
|
-
processed_states[parse_state] = true
|
31
|
-
end
|
32
|
-
|
33
|
-
# Take the first provided state that wasn't processed yet.
|
34
|
-
def select_state(theStates)
|
35
|
-
a_state = theStates.find { |st| !processed_states.include?(st) }
|
36
|
-
self.parse_state = a_state
|
37
|
-
end
|
38
|
-
|
39
|
-
# The dotted item for the current parse state.
|
40
|
-
def curr_dotted_item()
|
41
|
-
parse_state.dotted_rule
|
42
|
-
end
|
43
|
-
|
44
|
-
def symbol_on_left()
|
45
|
-
return curr_dotted_item.prev_symbol
|
46
|
-
end
|
47
|
-
|
48
|
-
# Notification that one begins with the previous state set
|
49
|
-
def to_prev_state_set()
|
50
|
-
self.state_set_index = state_set_index - 1
|
51
|
-
end
|
52
|
-
end # class
|
53
|
-
end # module
|
54
|
-
end # module
|
55
|
-
|
56
|
-
# End of file
|
1
|
+
module Rley # This module is used as a namespace
|
2
|
+
module Parser # This module is used as a namespace
|
3
|
+
# Helper class that keeps track of the parse states used
|
4
|
+
# while a Parsing instance is constructing a parse tree.
|
5
|
+
class ParseStateTracker
|
6
|
+
# The index of the current state set
|
7
|
+
attr_reader(:state_set_index)
|
8
|
+
|
9
|
+
# The current parse state
|
10
|
+
attr_reader(:parse_state)
|
11
|
+
|
12
|
+
# The already processed states from current state set
|
13
|
+
attr_reader(:processed_states)
|
14
|
+
|
15
|
+
# Constructor. Refined variant of the inherited constructor.
|
16
|
+
def initialize(aStateSetIndex)
|
17
|
+
self.state_set_index = aStateSetIndex
|
18
|
+
end
|
19
|
+
|
20
|
+
# Write accessor. Sets the value of the state set index
|
21
|
+
def state_set_index=(anIndex)
|
22
|
+
@state_set_index = anIndex
|
23
|
+
@processed_states = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
# Write accessor. Set the given parse state as the current one.
|
27
|
+
def parse_state=(aParseState)
|
28
|
+
raise StandardError, 'Nil parse state' if aParseState.nil?
|
29
|
+
@parse_state = aParseState
|
30
|
+
processed_states[parse_state] = true
|
31
|
+
end
|
32
|
+
|
33
|
+
# Take the first provided state that wasn't processed yet.
|
34
|
+
def select_state(theStates)
|
35
|
+
a_state = theStates.find { |st| !processed_states.include?(st) }
|
36
|
+
self.parse_state = a_state
|
37
|
+
end
|
38
|
+
|
39
|
+
# The dotted item for the current parse state.
|
40
|
+
def curr_dotted_item()
|
41
|
+
parse_state.dotted_rule
|
42
|
+
end
|
43
|
+
|
44
|
+
def symbol_on_left()
|
45
|
+
return curr_dotted_item.prev_symbol
|
46
|
+
end
|
47
|
+
|
48
|
+
# Notification that one begins with the previous state set
|
49
|
+
def to_prev_state_set()
|
50
|
+
self.state_set_index = state_set_index - 1
|
51
|
+
end
|
52
|
+
end # class
|
53
|
+
end # module
|
54
|
+
end # module
|
55
|
+
|
56
|
+
# End of file
|
@@ -49,7 +49,7 @@ module Rley # This module is used as a namespace
|
|
49
49
|
def trace_completion(aStatesetIndex, aParseState)
|
50
50
|
return unless level
|
51
51
|
|
52
|
-
if aStatesetIndex == lexemes.size && aParseState.origin
|
52
|
+
if aStatesetIndex == lexemes.size && aParseState.origin.zero? &&
|
53
53
|
aParseState.complete?
|
54
54
|
picture = '=' * (col_width * lexemes.size - 1)
|
55
55
|
else
|
@@ -70,13 +70,13 @@ module Rley # This module is used as a namespace
|
|
70
70
|
def emit_heading()
|
71
71
|
longest = lexemes.map(&:length).max
|
72
72
|
@col_width = longest + 3
|
73
|
-
headers = lexemes.map { |l|
|
73
|
+
headers = lexemes.map { |l| l.center(col_width - 1, ' ').to_s }
|
74
74
|
print_if 1, '|.' + headers.join('.') + ".|\n"
|
75
75
|
end
|
76
76
|
|
77
77
|
def padding(aStatesetIndex, aParseState, aPicture)
|
78
78
|
l_pad_pattern = '.' + ' ' * (col_width - 1)
|
79
|
-
left_padding = l_pad_pattern *
|
79
|
+
left_padding = l_pad_pattern * [0, aParseState.origin].max
|
80
80
|
r_pad_pattern = ' ' * (col_width - 1) + '.'
|
81
81
|
right_padding = r_pad_pattern * (lexemes.size - aStatesetIndex)
|
82
82
|
return left_padding + aPicture + right_padding
|
@@ -49,7 +49,7 @@ module Rley # This module is used as a namespace
|
|
49
49
|
curr_node = current_node
|
50
50
|
unless curr_node.is_a?(PTree::NonTerminalNode)
|
51
51
|
msg = "Current node isn't a non-terminal node #{curr_node.class}"
|
52
|
-
|
52
|
+
raise StandardError, msg
|
53
53
|
end
|
54
54
|
children = curr_node.children
|
55
55
|
path_increment = [children.size - 1, children.last]
|
@@ -122,7 +122,7 @@ module Rley # This module is used as a namespace
|
|
122
122
|
if curr_node.symbol != prod.lhs
|
123
123
|
snapshot = root.to_string(0)
|
124
124
|
msg = "Current node is a #{curr_node.symbol} instead of #{prod.lhs}."
|
125
|
-
|
125
|
+
raise StandardError, msg + "\n" + snapshot
|
126
126
|
end
|
127
127
|
self.range = aRange
|
128
128
|
prod.rhs.each { |symb| add_node(symb, {}) }
|
@@ -153,20 +153,20 @@ module Rley # This module is used as a namespace
|
|
153
153
|
|
154
154
|
def low_bound(aRange)
|
155
155
|
result = case aRange
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
156
|
+
when Integer then aRange
|
157
|
+
when Hash then aRange[:low]
|
158
|
+
when PTree::TokenRange then aRange.low
|
159
|
+
end
|
160
160
|
|
161
161
|
return { low: result }
|
162
162
|
end
|
163
163
|
|
164
164
|
def high_bound(aRange)
|
165
165
|
result = case aRange
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
166
|
+
when Integer then aRange
|
167
|
+
when Hash then aRange[:high]
|
168
|
+
when PTree::TokenRange then aRange.high
|
169
|
+
end
|
170
170
|
|
171
171
|
return { high: result }
|
172
172
|
end
|
@@ -9,16 +9,16 @@ require_relative '../gfg/start_vertex'
|
|
9
9
|
module Rley # This module is used as a namespace
|
10
10
|
module Parser # This module is used as a namespace
|
11
11
|
ParseWalkerContext = Struct.new(
|
12
|
-
:curr_entry,
|
13
|
-
:entry_set_index,
|
14
|
-
:visitees,
|
12
|
+
:curr_entry, # Parse entry currently being visited
|
13
|
+
:entry_set_index, # Sigma set index of current parse entry
|
14
|
+
:visitees, # The set of already visited parse entries
|
15
15
|
:nterm2start, # A Hash non-terminal symbol => start entry
|
16
16
|
:return_stack, # A stack of parse entries
|
17
17
|
:backtrack_points
|
18
18
|
)
|
19
19
|
|
20
20
|
WalkerBacktrackpoint = Struct.new(
|
21
|
-
:entry_set_index,
|
21
|
+
:entry_set_index, # Sigma set index of current parse entry
|
22
22
|
:return_stack, # A stack of parse entries
|
23
23
|
:visitee, # The parse entry being visited
|
24
24
|
:antecedent_index
|
@@ -31,11 +31,11 @@ module Rley # This module is used as a namespace
|
|
31
31
|
# Terminology warning: this class implements an external iterator
|
32
32
|
# for a given GFGParsing object. In other words, its instances are objects
|
33
33
|
# distinct for the GFGParsing.
|
34
|
-
# This is different from the internal iterators, usually implemented
|
35
|
-
# with an each method.
|
34
|
+
# This is different from the internal iterators, usually implemented
|
35
|
+
# in Ruby with an :each method.
|
36
36
|
# Allows to perform a backwards traversal over the relevant parse entries.
|
37
|
-
# backwards traversal means that the traversal starts from the
|
38
|
-
# parse entries and goes to the initial parse entry.
|
37
|
+
# backwards traversal means that the traversal starts from the
|
38
|
+
# accepting (final) parse entries and goes to the initial parse entry.
|
39
39
|
# Relevant parse entries are parse entries that "count" in the parse
|
40
40
|
# (i.e. they belong to a path that leads to the accepting parse entry)
|
41
41
|
class ParseWalkerFactory
|
@@ -53,16 +53,13 @@ module Rley # This module is used as a namespace
|
|
53
53
|
receiver << event unless event.nil?
|
54
54
|
|
55
55
|
if ctx.curr_entry.orphan? # No antecedent?...
|
56
|
-
if ctx.backtrack_points.empty?
|
57
|
-
|
58
|
-
|
59
|
-
receiver << use_backtrack_point(ctx)
|
60
|
-
receiver << visit_entry(ctx.curr_entry, ctx)
|
61
|
-
end
|
56
|
+
break if ctx.backtrack_points.empty?
|
57
|
+
receiver << use_backtrack_point(ctx)
|
58
|
+
receiver << visit_entry(ctx.curr_entry, ctx)
|
62
59
|
end
|
63
60
|
|
64
61
|
result = jump_to_antecedent(ctx)
|
65
|
-
# Emit detection of scan edge if any...
|
62
|
+
# Emit detection of scan edge if any...
|
66
63
|
receiver << result[0] if result.size > 1
|
67
64
|
ctx.curr_entry = result.last
|
68
65
|
end
|
@@ -71,7 +68,8 @@ module Rley # This module is used as a namespace
|
|
71
68
|
return walker
|
72
69
|
end
|
73
70
|
|
74
|
-
private
|
71
|
+
private
|
72
|
+
|
75
73
|
# Context factory method
|
76
74
|
def init_context(acceptingEntry, maxIndex)
|
77
75
|
context = ParseWalkerContext.new
|
@@ -108,8 +106,8 @@ private
|
|
108
106
|
when GFG::ItemVertex
|
109
107
|
# Skip item entries while revisiting
|
110
108
|
event = nil
|
111
|
-
|
112
|
-
|
109
|
+
else
|
110
|
+
raise NotImplementedError
|
113
111
|
end
|
114
112
|
else
|
115
113
|
# first time visit
|
@@ -120,7 +118,7 @@ private
|
|
120
118
|
return event
|
121
119
|
end
|
122
120
|
|
123
|
-
def detect_scan_edge(
|
121
|
+
def detect_scan_edge(_ctx)
|
124
122
|
return nil unless aContext.curr_entry.dotted_entry?
|
125
123
|
end
|
126
124
|
|
@@ -131,12 +129,12 @@ private
|
|
131
129
|
def jump_to_antecedent(aContext)
|
132
130
|
entries = []
|
133
131
|
return entries if aContext.curr_entry.orphan?
|
134
|
-
|
135
|
-
if aContext.curr_entry.antecedents.size == 1
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
132
|
+
|
133
|
+
entries = if aContext.curr_entry.antecedents.size == 1
|
134
|
+
antecedent_of(aContext)
|
135
|
+
else
|
136
|
+
select_antecedent(aContext)
|
137
|
+
end
|
140
138
|
|
141
139
|
return entries
|
142
140
|
end
|
@@ -153,15 +151,15 @@ private
|
|
153
151
|
aContext.return_stack << aContext.curr_entry
|
154
152
|
elsif traversed_edge.kind_of?(GFG::CallEdge)
|
155
153
|
# Pop top of stack
|
156
|
-
|
154
|
+
aContext.return_stack.pop
|
157
155
|
# puts "Pop from return stack matching entry #{new_entry}"
|
158
|
-
elsif traversed_edge.kind_of?(GFG::ScanEdge)
|
156
|
+
elsif traversed_edge.kind_of?(GFG::ScanEdge)
|
159
157
|
# Scan edge encountered, decrease sigma set index
|
160
158
|
aContext.entry_set_index -= 1
|
161
159
|
elsif traversed_edge.kind_of?(GFG::EpsilonEdge)
|
162
160
|
# Do nothing
|
163
161
|
else
|
164
|
-
|
162
|
+
raise NotImplementedError, "edge is a #{traversed_edge.class}"
|
165
163
|
end
|
166
164
|
|
167
165
|
return events
|
@@ -180,7 +178,7 @@ private
|
|
180
178
|
when GFG::StartVertex
|
181
179
|
new_entry = select_calling_entry(aContext)
|
182
180
|
else
|
183
|
-
|
181
|
+
raise StandardError, 'Internal error'
|
184
182
|
end
|
185
183
|
|
186
184
|
return [ new_entry ]
|
@@ -213,7 +211,7 @@ private
|
|
213
211
|
aContext.backtrack_points.pop
|
214
212
|
end
|
215
213
|
# puts "Backtracking to #{bp.visitee}"
|
216
|
-
|
214
|
+
|
217
215
|
# Emit a backtrack event
|
218
216
|
return [:backtrack, bp.visitee, aContext.entry_set_index]
|
219
217
|
end
|
@@ -233,8 +231,7 @@ private
|
|
233
231
|
item = antecd.vertex.dotted_item
|
234
232
|
(antecd.origin == tos.origin) && tos_dotted_item.successor_of?(item)
|
235
233
|
end
|
236
|
-
|
237
|
-
# TODO: double-check validity of next line
|
234
|
+
|
238
235
|
new_entry = aContext.curr_entry unless new_entry
|
239
236
|
|
240
237
|
# puts "Pop from return stack matching entry #{new_entry}"
|
@@ -242,4 +239,4 @@ private
|
|
242
239
|
end
|
243
240
|
end # class
|
244
241
|
end # module
|
245
|
-
end # module
|
242
|
+
end # module
|
data/lib/rley/parser/parsing.rb
CHANGED
@@ -32,7 +32,7 @@ module Rley # This module is used as a namespace
|
|
32
32
|
|
33
33
|
# Retrieve all the complete states with start symbol in lhs
|
34
34
|
end_states = last_chart_entry.states_rewriting(start_symbol)
|
35
|
-
success_states = end_states.select { |st| st.origin
|
35
|
+
success_states = end_states.select { |st| st.origin.zero? }
|
36
36
|
|
37
37
|
return !success_states.empty?
|
38
38
|
end
|
@@ -41,7 +41,7 @@ module Rley # This module is used as a namespace
|
|
41
41
|
# for the same lhs and same origin in any state set.
|
42
42
|
def ambiguous?()
|
43
43
|
found = chart.state_sets.find { |set| !set.ambiguities.empty? }
|
44
|
-
return !
|
44
|
+
return !found.nil?
|
45
45
|
end
|
46
46
|
|
47
47
|
# Factory method. Builds a ParseTree from the parse result.
|
@@ -74,7 +74,7 @@ module Rley # This module is used as a namespace
|
|
74
74
|
# Push a parse state (dotted item + origin) to the
|
75
75
|
# chart entry with given index if it isn't yet in the chart entry.
|
76
76
|
def push_state(aDottedItem, anOrigin, aChartIndex, aReason)
|
77
|
-
|
77
|
+
raise StandardError, 'Dotted item may not be nil' if aDottedItem.nil?
|
78
78
|
chart.push_state(aDottedItem, anOrigin, aChartIndex, aReason)
|
79
79
|
end
|
80
80
|
|
@@ -93,13 +93,13 @@ module Rley # This module is used as a namespace
|
|
93
93
|
# @param aPosition [Fixnum] position in the input token sequence.
|
94
94
|
# @param nextMapping [Proc or Lambda] code to evaluate in order to
|
95
95
|
# determine the "next" dotted rule for a given one.
|
96
|
-
def scanning(aTerminal, aPosition, &
|
96
|
+
def scanning(aTerminal, aPosition, &_nextMapping)
|
97
97
|
curr_token = tokens[aPosition]
|
98
98
|
return unless curr_token.terminal == aTerminal
|
99
99
|
|
100
100
|
states = states_expecting(aTerminal, aPosition, false)
|
101
101
|
states.each do |s|
|
102
|
-
next_item =
|
102
|
+
next_item = yield s.dotted_rule
|
103
103
|
push_state(next_item, s.origin, aPosition + 1, :scanning)
|
104
104
|
end
|
105
105
|
end
|
@@ -115,12 +115,12 @@ module Rley # This module is used as a namespace
|
|
115
115
|
# In other words, rules that predicted the non-terminal X.
|
116
116
|
# For each s, add to chart[aPosition] a state of the form
|
117
117
|
# { dotted_rule: Y → α X • β, origin: i})
|
118
|
-
def completion(aState, aPosition, &
|
118
|
+
def completion(aState, aPosition, &_nextMapping)
|
119
119
|
curr_origin = aState.origin
|
120
120
|
curr_lhs = aState.dotted_rule.lhs
|
121
121
|
states = states_expecting(curr_lhs, curr_origin, false)
|
122
122
|
states.each do |s|
|
123
|
-
next_item =
|
123
|
+
next_item = yield s.dotted_rule
|
124
124
|
push_state(next_item, s.origin, aPosition, :completion)
|
125
125
|
end
|
126
126
|
end
|
@@ -207,7 +207,7 @@ module Rley # This module is used as a namespace
|
|
207
207
|
aTreeBuilder.current_node.range = { low: index, high: index + 1 }
|
208
208
|
link_node_to_token(aTreeBuilder, aStateTracker.state_set_index)
|
209
209
|
unless aTreeBuilder.current_node.is_a?(PTree::TerminalNode)
|
210
|
-
|
210
|
+
raise StandardError, 'Expected terminal node'
|
211
211
|
end
|
212
212
|
aTreeBuilder.move_back
|
213
213
|
state_set = chart[aStateTracker.state_set_index]
|
@@ -9,7 +9,6 @@ module Rley # This module is used as a namespace
|
|
9
9
|
# The set of parse states
|
10
10
|
attr_reader(:states)
|
11
11
|
|
12
|
-
|
13
12
|
def initialize()
|
14
13
|
@states = []
|
15
14
|
end
|
@@ -22,72 +21,70 @@ module Rley # This module is used as a namespace
|
|
22
21
|
if include?(aState)
|
23
22
|
result = false
|
24
23
|
else
|
25
|
-
@states << aState
|
24
|
+
@states << aState
|
26
25
|
result = true
|
27
26
|
end
|
28
|
-
|
27
|
+
|
29
28
|
return result
|
30
29
|
end
|
31
30
|
|
32
31
|
# The list of ParseState that expect the given symbol.
|
33
|
-
# @param aSymbol [GrmSymbol] the expected symbol
|
32
|
+
# @param aSymbol [GrmSymbol] the expected symbol
|
34
33
|
# (=on the right of the dot)
|
35
34
|
def states_expecting(aSymbol)
|
36
35
|
return states.select { |s| s.dotted_rule.next_symbol == aSymbol }
|
37
36
|
end
|
38
|
-
|
39
37
|
|
40
|
-
|
38
|
+
|
39
|
+
# The list of complete ParseState that have the given non-terminal
|
41
40
|
# symbol as the lhs of their production.
|
42
41
|
def states_rewriting(aNonTerm)
|
43
|
-
return states.select do |s|
|
42
|
+
return states.select do |s|
|
44
43
|
(s.dotted_rule.production.lhs == aNonTerm) && s.complete?
|
45
44
|
end
|
46
45
|
end
|
47
|
-
|
46
|
+
|
48
47
|
# The list of ParseState that involve the given production
|
49
48
|
def states_for(aProduction)
|
50
49
|
return states.select { |s| s.dotted_rule.production == aProduction }
|
51
50
|
end
|
52
|
-
|
51
|
+
|
53
52
|
# Retrieve the parse state that is the predecessor of the given one.
|
54
|
-
def predecessor_state(
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
|
53
|
+
def predecessor_state(aPState)
|
54
|
+
dotted_rule = aPState.dotted_rule
|
55
|
+
raise StandardError, aPState.to_s unless dotted_rule.prev_position
|
56
|
+
|
57
|
+
candidate = states.find { |s| s.precedes?(aPState) }
|
61
58
|
return candidate
|
62
59
|
end
|
63
|
-
|
60
|
+
|
64
61
|
# The list of distinct expected terminal symbols. An expected symbol
|
65
62
|
# is on the left of a dot in a parse state of the parse set.
|
66
63
|
def expected_terminals()
|
67
|
-
expecting_terminals = states.select do |s|
|
68
|
-
s.dotted_rule.next_symbol.kind_of?(Rley::Syntax::Terminal)
|
64
|
+
expecting_terminals = states.select do |s|
|
65
|
+
s.dotted_rule.next_symbol.kind_of?(Rley::Syntax::Terminal)
|
69
66
|
end
|
70
|
-
|
67
|
+
|
71
68
|
terminals = expecting_terminals.map { |s| s.dotted_rule.next_symbol }
|
72
69
|
return terminals.uniq
|
73
70
|
end
|
74
|
-
|
71
|
+
|
75
72
|
# Return an Array of Arrays of ambiguous parse states.
|
76
73
|
def ambiguities()
|
77
|
-
complete_states = states.select
|
74
|
+
complete_states = states.select(&:complete?)
|
78
75
|
return [] if complete_states.size <= 1
|
79
|
-
|
76
|
+
|
80
77
|
# Group parse state by lhs symbol and origin
|
81
78
|
groupings = complete_states.group_by do |st|
|
82
|
-
|
79
|
+
st.dotted_rule.lhs.object_id.to_s
|
83
80
|
end
|
84
|
-
|
81
|
+
|
85
82
|
# Retain the groups having more than one element.
|
86
83
|
ambiguous_groups = []
|
87
84
|
groupings.each_value do |a_group|
|
88
85
|
ambiguous_groups << a_group if a_group.size > 1
|
89
86
|
end
|
90
|
-
|
87
|
+
|
91
88
|
return ambiguous_groups
|
92
89
|
end
|
93
90
|
|