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