rley 0.3.01 → 0.3.04
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/CHANGELOG.md +17 -3
- data/Gemfile +1 -1
- data/examples/parsers/parsing_groucho.rb +1 -3
- data/lib/rley/constants.rb +1 -1
- data/lib/rley/parser/gfg_parsing.rb +5 -179
- data/lib/rley/parser/parse_forest_builder.rb +62 -77
- data/lib/rley/parser/parse_walker_factory.rb +26 -17
- data/lib/rley.rb +1 -0
- data/spec/rley/gfg/end_vertex_spec.rb +1 -1
- data/spec/rley/gfg/shortcut_edge_spec.rb +6 -6
- data/spec/rley/gfg/start_vertex_spec.rb +1 -1
- data/spec/rley/parse_forest_visitor_spec.rb +1 -1
- data/spec/rley/parse_tree_visitor_spec.rb +1 -1
- data/spec/rley/parser/gfg_parsing_spec.rb +3 -6
- data/spec/rley/parser/parse_entry_set_spec.rb +19 -19
- data/spec/rley/parser/parse_entry_spec.rb +6 -6
- data/spec/rley/parser/parse_forest_builder_spec.rb +374 -79
- data/spec/rley/parser/parse_forest_factory_spec.rb +1 -1
- data/spec/rley/parser/parse_walker_factory_spec.rb +60 -40
- data/spec/rley/parser/state_set_spec.rb +8 -8
- data/spec/rley/support/grammar_L0_helper.rb +81 -0
- metadata +11 -13
- data/spec/rley/sppf/antecedence_graph.rb +0 -87
- data/spec/rley/sppf/forest_representation.rb +0 -136
- data/spec/rley/sppf/gfg_representation.rb +0 -111
@@ -63,7 +63,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
63
63
|
parser = Parser::GFGEarleyParser.new(sample_grammar)
|
64
64
|
parser.parse(sample_tokens)
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
let(:accept_entry) { sample_result.accepting_entry }
|
68
68
|
let(:accept_index) { sample_result.chart.last_index }
|
69
69
|
subject { ParseWalkerFactory.new }
|
@@ -100,7 +100,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
100
100
|
event3 = walker.next
|
101
101
|
expectations = [:visit, 'S. | 0', 4]
|
102
102
|
event_expectations(event3, expectations)
|
103
|
-
|
103
|
+
|
104
104
|
# Backtrack created: first alternative selected
|
105
105
|
event4 = walker.next
|
106
106
|
expectations = [:visit, 'S => a T . | 0', 4]
|
@@ -112,16 +112,16 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
112
112
|
|
113
113
|
event6 = walker.next
|
114
114
|
expectations = [:visit, 'T => b b b . | 1', 4]
|
115
|
-
event_expectations(event6, expectations)
|
116
|
-
|
115
|
+
event_expectations(event6, expectations)
|
116
|
+
|
117
117
|
event7 = walker.next
|
118
118
|
expectations = [:visit, 'T => b b . b | 1', 3]
|
119
|
-
event_expectations(event7, expectations)
|
119
|
+
event_expectations(event7, expectations)
|
120
120
|
|
121
121
|
event8 = walker.next
|
122
122
|
expectations = [:visit, 'T => b . b b | 1', 2]
|
123
|
-
event_expectations(event8, expectations)
|
124
|
-
|
123
|
+
event_expectations(event8, expectations)
|
124
|
+
|
125
125
|
event9 = walker.next
|
126
126
|
expectations = [:visit, 'T => . b b b | 1', 1]
|
127
127
|
event_expectations(event9, expectations)
|
@@ -144,7 +144,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
144
144
|
|
145
145
|
event14 = walker.next
|
146
146
|
expectations = [:visit, 'Phi => . S | 0', 0]
|
147
|
-
event_expectations(event14, expectations)
|
147
|
+
event_expectations(event14, expectations)
|
148
148
|
|
149
149
|
event15 = walker.next
|
150
150
|
expectations = [:visit, '.Phi | 0', 0]
|
@@ -153,80 +153,100 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
153
153
|
# Backtracking is occurring
|
154
154
|
event16 = walker.next
|
155
155
|
expectations = [:backtrack, 'S. | 0', 4]
|
156
|
-
event_expectations(event16, expectations)
|
157
|
-
|
158
|
-
|
156
|
+
event_expectations(event16, expectations)
|
157
|
+
|
158
|
+
event17 = walker.next
|
159
159
|
expectations = [:visit, 'S => A T . | 0', 4]
|
160
|
+
event_expectations(event17, expectations)
|
161
|
+
|
162
|
+
event18 = walker.next
|
163
|
+
expectations = [:revisit, 'T. | 1', 4]
|
160
164
|
event_expectations(event18, expectations)
|
161
165
|
|
166
|
+
# Multiple visit occurred: jump to antecedent of start entry
|
162
167
|
event19 = walker.next
|
163
|
-
expectations = [:
|
168
|
+
expectations = [:visit, 'S => A . T | 0', 1]
|
164
169
|
event_expectations(event19, expectations)
|
165
170
|
|
166
|
-
# Multiple visit occurred: jump to antecedent of start entry
|
167
171
|
event20 = walker.next
|
168
|
-
expectations = [:visit, '
|
172
|
+
expectations = [:visit, 'A. | 0', 1]
|
169
173
|
event_expectations(event20, expectations)
|
170
174
|
|
175
|
+
# Backtrack created: first alternative selected
|
171
176
|
event21 = walker.next
|
172
|
-
expectations = [:visit, 'A. | 0', 1]
|
177
|
+
expectations = [:visit, 'A => a . | 0', 1]
|
173
178
|
event_expectations(event21, expectations)
|
174
|
-
|
175
|
-
# Backtrack created: first alternative selected
|
179
|
+
|
176
180
|
event22 = walker.next
|
177
|
-
expectations = [:visit, 'A => a . | 0', 1]
|
178
|
-
event_expectations(event22, expectations)
|
179
|
-
|
180
|
-
event23 = walker.next
|
181
181
|
expectations = [:visit, 'A => . a | 0', 0]
|
182
|
+
event_expectations(event22, expectations)
|
183
|
+
|
184
|
+
event23 = walker.next
|
185
|
+
expectations = [:visit, '.A | 0', 0]
|
182
186
|
event_expectations(event23, expectations)
|
183
187
|
|
184
188
|
event24 = walker.next
|
185
|
-
expectations = [:visit, '.A | 0', 0]
|
189
|
+
expectations = [:visit, 'S => . A T | 0', 0]
|
186
190
|
event_expectations(event24, expectations)
|
187
191
|
|
188
192
|
event25 = walker.next
|
189
|
-
expectations = [:
|
193
|
+
expectations = [:revisit, '.S | 0', 0]
|
190
194
|
event_expectations(event25, expectations)
|
191
195
|
|
192
|
-
# Backtracking is occurring
|
193
196
|
event26 = walker.next
|
194
|
-
expectations = [:
|
195
|
-
event_expectations(event26, expectations)
|
196
|
-
|
197
|
+
expectations = [:revisit, '.Phi | 0', 0]
|
198
|
+
event_expectations(event26, expectations)
|
199
|
+
|
200
|
+
# Backtracking is occurring
|
197
201
|
event27 = walker.next
|
198
|
-
expectations = [:
|
202
|
+
expectations = [:backtrack, 'A. | 0', 1]
|
199
203
|
event_expectations(event27, expectations)
|
200
|
-
|
204
|
+
|
201
205
|
event28 = walker.next
|
202
|
-
expectations = [:
|
206
|
+
expectations = [:visit, 'A => B A . | 0', 1]
|
203
207
|
event_expectations(event28, expectations)
|
204
208
|
|
205
209
|
event29 = walker.next
|
206
|
-
expectations = [:
|
207
|
-
event_expectations(event29, expectations)
|
210
|
+
expectations = [:revisit, 'A. | 0', 1]
|
211
|
+
event_expectations(event29, expectations)
|
208
212
|
|
209
213
|
event30 = walker.next
|
210
|
-
expectations = [:visit, 'B. | 0', 0]
|
214
|
+
expectations = [:visit, 'A => B . A | 0', 0]
|
211
215
|
event_expectations(event30, expectations)
|
212
216
|
|
213
217
|
event31 = walker.next
|
214
|
-
expectations = [:visit, 'B
|
218
|
+
expectations = [:visit, 'B. | 0', 0]
|
215
219
|
event_expectations(event31, expectations)
|
216
220
|
|
217
221
|
event32 = walker.next
|
218
|
-
expectations = [:visit, '
|
219
|
-
event_expectations(event32, expectations)
|
222
|
+
expectations = [:visit, 'B => . | 0', 0]
|
223
|
+
event_expectations(event32, expectations)
|
220
224
|
|
221
225
|
event33 = walker.next
|
226
|
+
expectations = [:visit, '.B | 0', 0]
|
227
|
+
event_expectations(event33, expectations)
|
228
|
+
|
229
|
+
event34 = walker.next
|
222
230
|
expectations = [:visit, 'A => . B A | 0', 0]
|
223
|
-
event_expectations(
|
231
|
+
event_expectations(event34, expectations)
|
232
|
+
|
233
|
+
event35 = walker.next
|
234
|
+
expectations = [:revisit, '.A | 0', 0]
|
235
|
+
event_expectations(event35, expectations)
|
236
|
+
|
237
|
+
event36 = walker.next
|
238
|
+
expectations = [:revisit, '.S | 0', 0]
|
239
|
+
event_expectations(event36, expectations)
|
240
|
+
|
241
|
+
event37 = walker.next
|
242
|
+
expectations = [:revisit, '.Phi | 0', 0]
|
243
|
+
event_expectations(event37, expectations)
|
224
244
|
end
|
225
|
-
|
245
|
+
|
226
246
|
it 'should raise an exception at end of visit' do
|
227
247
|
walker = subject.build_walker(accept_entry, accept_index)
|
228
|
-
|
229
|
-
|
248
|
+
37.times { walker.next }
|
249
|
+
|
230
250
|
expect{ walker.next }.to raise_error(StopIteration)
|
231
251
|
end
|
232
252
|
|
@@ -54,8 +54,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
54
54
|
# Adding states
|
55
55
|
subject.push_state(state1)
|
56
56
|
subject.push_state(state2)
|
57
|
-
|
58
|
-
|
57
|
+
expect(dotted_rule1).to receive(:production).and_return(:dummy)
|
58
|
+
expect(dotted_rule2).to receive(:production).and_return(a_prod)
|
59
59
|
expect(subject.states_for(a_prod)).to eq([state2])
|
60
60
|
end
|
61
61
|
|
@@ -67,11 +67,11 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
67
67
|
# Adding states
|
68
68
|
subject.push_state(state1)
|
69
69
|
subject.push_state(state2)
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
70
|
+
expect(dotted_rule1).to receive(:production).and_return(prod1)
|
71
|
+
expect(prod1).to receive(:lhs).and_return(:dummy)
|
72
|
+
expect(dotted_rule2).to receive(:production).and_return(prod2)
|
73
|
+
expect(dotted_rule2).to receive(:reduce_item?).and_return(true)
|
74
|
+
expect(prod2).to receive(:lhs).and_return(non_term)
|
75
75
|
expect(subject.states_rewriting(non_term)).to eq([state2])
|
76
76
|
end
|
77
77
|
|
@@ -103,7 +103,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
103
103
|
it 'should complain when impossible predecessor of parse state' do
|
104
104
|
subject.push_state(state1)
|
105
105
|
subject.push_state(state2)
|
106
|
-
|
106
|
+
expect(dotted_rule1).to receive(:prev_position).and_return(nil)
|
107
107
|
err = StandardError
|
108
108
|
expect { subject.predecessor_state(state1) }.to raise_error(err)
|
109
109
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Load the builder class
|
2
|
+
require_relative '../../../lib/rley/syntax/grammar_builder'
|
3
|
+
require_relative '../../../lib/rley/parser/token'
|
4
|
+
|
5
|
+
|
6
|
+
module GrammarL0Helper
|
7
|
+
########################################
|
8
|
+
# Factory method. Define a grammar for a micro English-like language
|
9
|
+
# based on Jurafky & Martin L0 language (chapter 12 of the book).
|
10
|
+
# It defines the syntax of a sentence in a language with a
|
11
|
+
# very limited syntax and lexicon in the context of airline reservation.
|
12
|
+
def grammar_L0_builder()
|
13
|
+
builder = Rley::Syntax::GrammarBuilder.new
|
14
|
+
builder.add_terminals('Noun', 'Verb', 'Pronoun', 'Proper-Noun')
|
15
|
+
builder.add_terminals('Determiner', 'Preposition', )
|
16
|
+
builder.add_production('S' => %w[NP VP])
|
17
|
+
builder.add_production('NP' => 'Pronoun')
|
18
|
+
builder.add_production('NP' => 'Proper-Noun')
|
19
|
+
builder.add_production('NP' => %w[Determiner Nominal])
|
20
|
+
builder.add_production('Nominal' => %w[Nominal Noun])
|
21
|
+
builder.add_production('Nominal' => 'Noun')
|
22
|
+
builder.add_production('VP' => 'Verb')
|
23
|
+
builder.add_production('VP' => %w[Verb NP])
|
24
|
+
builder.add_production('VP' => %w[Verb NP PP])
|
25
|
+
builder.add_production('VP' => %w[Verb PP])
|
26
|
+
builder.add_production('PP' => %w[Preposition PP])
|
27
|
+
builder
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return the language lexicon.
|
31
|
+
# A lexicon is just a Hash with pairs of the form:
|
32
|
+
# word => terminal symbol name
|
33
|
+
def lexicon_L0()
|
34
|
+
lexicon = {
|
35
|
+
'flight' => 'Noun',
|
36
|
+
'breeze' => 'Noun',
|
37
|
+
'trip' => 'Noun',
|
38
|
+
'morning' => 'Noun',
|
39
|
+
'is' => 'Verb',
|
40
|
+
'prefer' => 'Verb',
|
41
|
+
'like' => 'Verb',
|
42
|
+
'need' => 'Verb',
|
43
|
+
'want' => 'Verb',
|
44
|
+
'fly' => 'Verb',
|
45
|
+
'me' => 'Pronoun',
|
46
|
+
'I' => 'Pronoun',
|
47
|
+
'you' => 'Pronoun',
|
48
|
+
'it' => 'Pronoun',
|
49
|
+
'Alaska' => 'Proper-Noun',
|
50
|
+
'Baltimore' => 'Proper-Noun',
|
51
|
+
'Chicago' => 'Proper-Noun',
|
52
|
+
'United' => 'Proper-Noun',
|
53
|
+
'American' => 'Proper-Noun',
|
54
|
+
'the' => 'Determiner',
|
55
|
+
'a' => 'Determiner',
|
56
|
+
'an' => 'Determiner',
|
57
|
+
'this' => 'Determiner',
|
58
|
+
'these' => 'Determiner',
|
59
|
+
'that' => 'Determiner',
|
60
|
+
'from' => 'Preposition',
|
61
|
+
'to' => 'Preposition',
|
62
|
+
'on' => 'Preposition',
|
63
|
+
'near' => 'Preposition'
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# Highly simplified tokenizer implementation.
|
69
|
+
def tokenizer_L0(aText, aGrammar)
|
70
|
+
tokens = aText.scan(/\S+/).map do |word|
|
71
|
+
term_name = lexicon_L0[word]
|
72
|
+
if term_name.nil?
|
73
|
+
fail StandardError, "Word '#{word}' not found in lexicon"
|
74
|
+
end
|
75
|
+
terminal = aGrammar.name2symbol[term_name]
|
76
|
+
Rley::Parser::Token.new(word, terminal)
|
77
|
+
end
|
78
|
+
|
79
|
+
return tokens
|
80
|
+
end
|
81
|
+
end # module
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rley
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.04
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -36,40 +36,40 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '3.
|
39
|
+
version: '3.5'
|
40
40
|
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: 3.
|
42
|
+
version: 3.5.0
|
43
43
|
type: :development
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
47
|
- - "~>"
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version: '3.
|
49
|
+
version: '3.5'
|
50
50
|
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: 3.
|
52
|
+
version: 3.5.0
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: simplecov
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
57
|
- - "~>"
|
58
58
|
- !ruby/object:Gem::Version
|
59
|
-
version: '0.
|
59
|
+
version: '0.1'
|
60
60
|
- - ">="
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: 0.
|
62
|
+
version: 0.1.0
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: '0.
|
69
|
+
version: '0.1'
|
70
70
|
- - ">="
|
71
71
|
- !ruby/object:Gem::Version
|
72
|
-
version: 0.
|
72
|
+
version: 0.1.0
|
73
73
|
- !ruby/object:Gem::Dependency
|
74
74
|
name: coveralls
|
75
75
|
requirement: !ruby/object:Gem::Requirement
|
@@ -249,12 +249,10 @@ files:
|
|
249
249
|
- spec/rley/ptree/terminal_node_spec.rb
|
250
250
|
- spec/rley/ptree/token_range_spec.rb
|
251
251
|
- spec/rley/sppf/alternative_node_spec.rb
|
252
|
-
- spec/rley/sppf/antecedence_graph.rb
|
253
|
-
- spec/rley/sppf/forest_representation.rb
|
254
|
-
- spec/rley/sppf/gfg_representation.rb
|
255
252
|
- spec/rley/sppf/non_terminal_node_spec.rb
|
256
253
|
- spec/rley/support/ambiguous_grammar_helper.rb
|
257
254
|
- spec/rley/support/expectation_helper.rb
|
255
|
+
- spec/rley/support/grammar_L0_helper.rb
|
258
256
|
- spec/rley/support/grammar_abc_helper.rb
|
259
257
|
- spec/rley/support/grammar_b_expr_helper.rb
|
260
258
|
- spec/rley/support/grammar_helper.rb
|
@@ -1,87 +0,0 @@
|
|
1
|
-
# Mix-in module that generates a Graphviz's DOT file
|
2
|
-
# that represents the precedence graph of parse entries.
|
3
|
-
module AntecedenceGraph
|
4
|
-
|
5
|
-
def generate_graph(aParsing, aFile)
|
6
|
-
heading = build_heading()
|
7
|
-
aFile.puts(heading)
|
8
|
-
|
9
|
-
fill_graph(aParsing, aFile)
|
10
|
-
|
11
|
-
trailing = build_trailing()
|
12
|
-
aFile.puts(trailing)
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def build_heading()
|
18
|
-
text = <<-END_STRING
|
19
|
-
digraph entries {
|
20
|
-
size = "7,9.5";
|
21
|
-
page = "8.5,11";
|
22
|
-
ratio = fill;
|
23
|
-
rankdir = "BT"; // Draw arrows from bottom to top
|
24
|
-
END_STRING
|
25
|
-
|
26
|
-
return text
|
27
|
-
end
|
28
|
-
|
29
|
-
def build_trailing()
|
30
|
-
return '}'
|
31
|
-
end
|
32
|
-
|
33
|
-
def fill_graph(aParsing, aFile)
|
34
|
-
# Associate to each parse entry a node id
|
35
|
-
oid2node_id = build_nodes_id(aParsing)
|
36
|
-
aParsing.chart.sets.each_with_index do |entry_set, chart_index|
|
37
|
-
# Create the graph nodes
|
38
|
-
aFile.puts ''
|
39
|
-
aFile.puts(cluster_heading(chart_index))
|
40
|
-
|
41
|
-
entry_set.entries.each do |entry|
|
42
|
-
aFile.puts %Q( #{oid2node_id[entry]}[label="#{entry}"];)
|
43
|
-
end
|
44
|
-
aFile.puts ' }' # Close cluster
|
45
|
-
|
46
|
-
# Create the edges
|
47
|
-
aFile.puts ''
|
48
|
-
entry_set.entries.each do |entry|
|
49
|
-
antecedents = aParsing.antecedence[entry]
|
50
|
-
antecedents.each do |antec|
|
51
|
-
aFile.puts " #{oid2node_id[antec]} -> #{oid2node_id[entry]};"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
# For each parse entry, associate a graph node id
|
58
|
-
def build_nodes_id(aParsing)
|
59
|
-
# Create a Hash with pairs of the form: object id => node id
|
60
|
-
oid2node_id = {}
|
61
|
-
|
62
|
-
aParsing.chart.sets.each_with_index do |entry_set, chart_index|
|
63
|
-
entry_set.entries.each_with_index do |entry, entry_index|
|
64
|
-
oid2node_id[entry] = "node_#{chart_index}_#{entry_index}"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
return oid2node_id
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
|
-
def cluster_heading(anIndex)
|
73
|
-
text = <<-END_STRING
|
74
|
-
subgraph cluster_chart_#{anIndex} {
|
75
|
-
style = rounded;
|
76
|
-
color = blue;
|
77
|
-
fontsize = 24.0;
|
78
|
-
labeljust = "r";
|
79
|
-
label="chart[#{anIndex}]";
|
80
|
-
END_STRING
|
81
|
-
|
82
|
-
return text
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end # module
|
@@ -1,136 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
|
-
# Mix-in module that generates a Graphviz's DOT file
|
4
|
-
# that represents a parse forest.
|
5
|
-
class ForestRepresentation
|
6
|
-
|
7
|
-
def generate_graph(aPForest, aFile)
|
8
|
-
heading = build_heading()
|
9
|
-
aFile.puts(heading)
|
10
|
-
|
11
|
-
fill_graph(aPForest, aFile)
|
12
|
-
|
13
|
-
trailing = build_trailing()
|
14
|
-
aFile.puts(trailing)
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def build_heading()
|
20
|
-
text = <<-END_STRING
|
21
|
-
digraph gfg {
|
22
|
-
size="7,9.5";
|
23
|
-
page="8.5,11";
|
24
|
-
ratio = fill;
|
25
|
-
|
26
|
-
END_STRING
|
27
|
-
|
28
|
-
return text
|
29
|
-
end
|
30
|
-
|
31
|
-
def build_trailing()
|
32
|
-
return '}'
|
33
|
-
end
|
34
|
-
|
35
|
-
def fill_graph(aPForest, aFile)
|
36
|
-
visitees = Set.new
|
37
|
-
visit_node(aPForest.root, aFile, visitees)
|
38
|
-
end
|
39
|
-
|
40
|
-
def visit_node(aNode, aFile, visitees)
|
41
|
-
return if visitees.include?(aNode)
|
42
|
-
visitees << aNode
|
43
|
-
aFile.puts %Q( node_#{aNode.object_id}[shape=box, fontsize=18.0, label="#{aNode.to_string(0)}"];)
|
44
|
-
|
45
|
-
if aNode.kind_of?(Rley::SPPF::CompositeNode)
|
46
|
-
aNode.subnodes.each do |snode|
|
47
|
-
# puts snode.to_string(0)
|
48
|
-
next unless snode
|
49
|
-
visit_node(snode, aFile, visitees)
|
50
|
-
aFile.puts %Q( node_#{aNode.object_id} -> node_#{snode.object_id};)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
=begin
|
56
|
-
def fill_graph(aGFGraph, aFile)
|
57
|
-
all_vertices = aGFGraph.vertices.dup
|
58
|
-
(itemized, endpoints) = all_vertices.partition do |vertex|
|
59
|
-
vertex.is_a?(Rley::GFG::ItemVertex)
|
60
|
-
end
|
61
|
-
|
62
|
-
# Group start/end nodes by non-terminal symbol
|
63
|
-
group_endings = endpoints.group_by { |endpoint| endpoint.non_terminal }
|
64
|
-
|
65
|
-
# Group item vertices by lhs non-terminal symbol
|
66
|
-
group_items = itemized.group_by { |vertex| vertex.lhs }
|
67
|
-
|
68
|
-
aFile.puts ''
|
69
|
-
group_endings.each_pair do |nonterm, nodes|
|
70
|
-
text = <<-END_STRING
|
71
|
-
subgraph cluster_#{nonterm} {
|
72
|
-
color = transparent;
|
73
|
-
END_STRING
|
74
|
-
aFile.puts text
|
75
|
-
aFile.puts ' // Define the start and end nodes'
|
76
|
-
nodes.each do |vertex|
|
77
|
-
# Emit the start/end nodes
|
78
|
-
aFile.puts %Q( node_#{vertex.object_id}[shape=box, fontsize=18.0, label="#{vertex.label}"];)
|
79
|
-
end
|
80
|
-
|
81
|
-
# Create sub-clusters by production
|
82
|
-
subnodes = group_items[nonterm]
|
83
|
-
subclusters = subnodes.group_by { |vertex| vertex.dotted_item.production }
|
84
|
-
subclusters.each_pair do |prod, vertices|
|
85
|
-
aFile.puts ''
|
86
|
-
aFile.puts cluster_heading(prod)
|
87
|
-
vertices.each do |vertex|
|
88
|
-
aFile.puts %Q( node_#{vertex.object_id}[label="#{vertex.label}"];)
|
89
|
-
end
|
90
|
-
aFile.puts cluster_trailing(prod)
|
91
|
-
end
|
92
|
-
aFile.puts ' }'
|
93
|
-
end
|
94
|
-
|
95
|
-
aFile.puts ''
|
96
|
-
aFile.puts ' // Draw the edges'
|
97
|
-
aGFGraph.vertices.each do |from_vertex|
|
98
|
-
from_vertex.edges.each do |anEdge|
|
99
|
-
if from_vertex.is_a?(Rley::GFG::EndVertex)
|
100
|
-
to_dotted_item = anEdge.successor.dotted_item
|
101
|
-
label = "RET_#{to_dotted_item.production.object_id}_#{to_dotted_item.prev_position}"
|
102
|
-
aFile.puts " node_#{from_vertex.object_id}->node_#{anEdge.successor.object_id}[color=red, style=dashed, arrowhead=onormal,label=#{label}];"
|
103
|
-
else
|
104
|
-
if anEdge.is_a?(Rley::GFG::ScanEdge)
|
105
|
-
aFile.puts %Q( node_#{from_vertex.object_id}->node_#{anEdge.successor.object_id}[fontsize=18.0, label="#{anEdge.terminal}"];)
|
106
|
-
else
|
107
|
-
if anEdge.successor.is_a?(Rley::GFG::StartVertex)
|
108
|
-
from_dotted_item = from_vertex.dotted_item
|
109
|
-
label = "CALL_#{from_dotted_item.production.object_id}_#{from_dotted_item.position}"
|
110
|
-
aFile.puts " node_#{from_vertex.object_id}->node_#{anEdge.successor.object_id}[color=green, label=#{label}];"
|
111
|
-
else
|
112
|
-
aFile.puts " node_#{from_vertex.object_id}->node_#{anEdge.successor.object_id};"
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
|
121
|
-
def cluster_heading(anObject)
|
122
|
-
text = <<-END_STRING
|
123
|
-
subgraph cluster_#{anObject.object_id} {
|
124
|
-
style = rounded;
|
125
|
-
color = blue;
|
126
|
-
END_STRING
|
127
|
-
|
128
|
-
return text
|
129
|
-
end
|
130
|
-
|
131
|
-
def cluster_trailing(anObject)
|
132
|
-
return ' }'
|
133
|
-
end
|
134
|
-
=end
|
135
|
-
|
136
|
-
end # class
|