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