rley 0.2.15 → 0.3.00
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/rley/constants.rb +1 -1
- data/lib/rley/gfg/call_edge.rb +30 -0
- data/lib/rley/gfg/edge.rb +4 -0
- data/lib/rley/gfg/end_vertex.rb +1 -1
- data/lib/rley/gfg/epsilon_edge.rb +0 -4
- data/lib/rley/gfg/grm_flow_graph.rb +32 -7
- data/lib/rley/gfg/item_vertex.rb +71 -25
- data/lib/rley/gfg/non_terminal_vertex.rb +10 -1
- data/lib/rley/gfg/return_edge.rb +31 -0
- data/lib/rley/gfg/scan_edge.rb +2 -1
- data/lib/rley/gfg/shortcut_edge.rb +26 -0
- data/lib/rley/gfg/start_vertex.rb +2 -2
- data/lib/rley/gfg/vertex.rb +27 -1
- data/lib/rley/parse_forest_visitor.rb +115 -0
- data/lib/rley/parser/base_parser.rb +27 -0
- data/lib/rley/parser/dotted_item.rb +11 -0
- data/lib/rley/parser/earley_parser.rb +3 -15
- data/lib/rley/parser/gfg_chart.rb +106 -0
- data/lib/rley/parser/gfg_earley_parser.rb +139 -0
- data/lib/rley/parser/gfg_parsing.rb +384 -0
- data/lib/rley/parser/parse_entry.rb +148 -0
- data/lib/rley/parser/parse_entry_set.rb +104 -0
- data/lib/rley/parser/parse_entry_tracker.rb +56 -0
- data/lib/rley/parser/parse_forest_builder.rb +229 -0
- data/lib/rley/parser/parse_forest_factory.rb +54 -0
- data/lib/rley/parser/parse_walker_factory.rb +237 -0
- data/lib/rley/ptree/token_range.rb +14 -1
- data/lib/rley/sppf/alternative_node.rb +34 -0
- data/lib/rley/sppf/composite_node.rb +27 -0
- data/lib/rley/sppf/epsilon_node.rb +27 -0
- data/lib/rley/sppf/leaf_node.rb +12 -0
- data/lib/rley/sppf/non_terminal_node.rb +38 -0
- data/lib/rley/sppf/parse_forest.rb +48 -0
- data/lib/rley/sppf/sppf_node.rb +24 -0
- data/lib/rley/sppf/token_node.rb +29 -0
- data/lib/rley/syntax/grammar_builder.rb +16 -12
- data/lib/rley/syntax/grm_symbol.rb +6 -0
- data/lib/rley/syntax/terminal.rb +5 -0
- data/spec/rley/gfg/call_edge_spec.rb +51 -0
- data/spec/rley/gfg/end_vertex_spec.rb +1 -0
- data/spec/rley/gfg/grm_flow_graph_spec.rb +24 -2
- data/spec/rley/gfg/item_vertex_spec.rb +75 -6
- data/spec/rley/gfg/non_terminal_vertex_spec.rb +14 -0
- data/spec/rley/gfg/return_edge_spec.rb +51 -0
- data/spec/rley/gfg/shortcut_edge_spec.rb +43 -0
- data/spec/rley/gfg/vertex_spec.rb +52 -37
- data/spec/rley/parse_forest_visitor_spec.rb +238 -0
- data/spec/rley/parser/dotted_item_spec.rb +29 -8
- data/spec/rley/parser/gfg_chart_spec.rb +138 -0
- data/spec/rley/parser/gfg_earley_parser_spec.rb +918 -0
- data/spec/rley/parser/gfg_parsing_spec.rb +565 -0
- data/spec/rley/parser/parse_entry_set_spec.rb +179 -0
- data/spec/rley/parser/parse_entry_spec.rb +208 -0
- data/spec/rley/parser/parse_forest_builder_spec.rb +382 -0
- data/spec/rley/parser/parse_forest_factory_spec.rb +81 -0
- data/spec/rley/parser/parse_walker_factory_spec.rb +235 -0
- data/spec/rley/parser/state_set_spec.rb +4 -0
- data/spec/rley/sppf/alternative_node_spec.rb +72 -0
- data/spec/rley/sppf/antecedence_graph.rb +87 -0
- data/spec/rley/sppf/forest_representation.rb +136 -0
- data/spec/rley/sppf/gfg_representation.rb +111 -0
- data/spec/rley/sppf/non_terminal_node_spec.rb +64 -0
- data/spec/rley/support/ambiguous_grammar_helper.rb +36 -36
- data/spec/rley/support/expectation_helper.rb +36 -0
- data/spec/rley/support/grammar_helper.rb +28 -0
- data/spec/rley/support/grammar_sppf_helper.rb +25 -0
- data/spec/rley/syntax/grammar_builder_spec.rb +5 -0
- data/spec/rley/syntax/non_terminal_spec.rb +4 -0
- data/spec/rley/syntax/terminal_spec.rb +4 -0
- metadata +58 -2
@@ -0,0 +1,81 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
require_relative '../../../lib/rley/parser/gfg_earley_parser'
|
4
|
+
|
5
|
+
require_relative '../../../lib/rley/syntax/grammar_builder'
|
6
|
+
require_relative '../support/grammar_helper'
|
7
|
+
require_relative '../support/expectation_helper'
|
8
|
+
|
9
|
+
# Load the class under test
|
10
|
+
require_relative '../../../lib/rley/parser/parse_forest_factory'
|
11
|
+
|
12
|
+
module Rley # Open this namespace to avoid module qualifier prefixes
|
13
|
+
module Parser
|
14
|
+
describe ParseForestFactory do
|
15
|
+
include GrammarHelper # Mix-in with token factory method
|
16
|
+
include ExpectationHelper # Mix-in with expectation on parse entry sets
|
17
|
+
|
18
|
+
let(:sample_grammar) do
|
19
|
+
# Grammar based on paper from Elisabeth Scott
|
20
|
+
# "SPPF=Style Parsing From Earley Recognizers" in
|
21
|
+
# Notes in Theoretical Computer Science 203, (2008), pp. 53-67
|
22
|
+
# contains a hidden left recursion and a cycle
|
23
|
+
builder = Syntax::GrammarBuilder.new
|
24
|
+
builder.add_terminals('a', 'b')
|
25
|
+
builder.add_production('Phi' => %'S')
|
26
|
+
builder.add_production('S' => %w[A T])
|
27
|
+
builder.add_production('S' => %w[a T])
|
28
|
+
builder.add_production('A' => 'a')
|
29
|
+
builder.add_production('A' => %w[B A])
|
30
|
+
builder.add_production('B' => [])
|
31
|
+
builder.add_production('T' => %w( b b b))
|
32
|
+
builder.grammar
|
33
|
+
end
|
34
|
+
|
35
|
+
let(:sample_tokens) do
|
36
|
+
build_token_sequence(%w(a b b b), sample_grammar)
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:sample_result) do
|
40
|
+
parser = Parser::GFGEarleyParser.new(sample_grammar)
|
41
|
+
parser.parse(sample_tokens)
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
subject do
|
46
|
+
ParseForestFactory.new(sample_result)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Emit a text representation of the current path.
|
50
|
+
def path_to_s()
|
51
|
+
text_parts = subject.curr_path.map { |path_element| path_element.to_string(0) }
|
52
|
+
return text_parts.join('/')
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
context 'Initialization:' do
|
57
|
+
it 'should be created with a GFGParsing' do
|
58
|
+
expect { ParseForestFactory.new(sample_result) }.not_to raise_error
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should know the parse result' do
|
62
|
+
expect(subject.parsing).to eq(sample_result)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
=begin
|
66
|
+
context 'Parse forest construction' do
|
67
|
+
it 'should build a parse forest' do
|
68
|
+
forest = subject.build_parse_forest
|
69
|
+
|
70
|
+
require 'yaml'
|
71
|
+
require_relative '../sppf/forest_representation'
|
72
|
+
File.open("forest.yml", "w") { |f| YAML.dump(forest, f) }
|
73
|
+
pen = ForestRepresentation.new
|
74
|
+
pen.generate_graph(forest, File.open("forest.dot", "w"))
|
75
|
+
end
|
76
|
+
end # context
|
77
|
+
=end
|
78
|
+
end # describe
|
79
|
+
end # module
|
80
|
+
end # module
|
81
|
+
# End of file
|
@@ -0,0 +1,235 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
require_relative '../../../lib/rley/syntax/grammar_builder'
|
4
|
+
require_relative '../support/grammar_helper'
|
5
|
+
require_relative '../support/expectation_helper'
|
6
|
+
|
7
|
+
require_relative '../../../lib/rley/parser/gfg_earley_parser'
|
8
|
+
|
9
|
+
# Load the class under test
|
10
|
+
require_relative '../../../lib/rley/parser/parse_walker_factory'
|
11
|
+
|
12
|
+
|
13
|
+
module Rley # Open this namespace to avoid module qualifier prefixes
|
14
|
+
module Parser
|
15
|
+
describe ParseWalkerFactory do
|
16
|
+
include GrammarHelper # Mix-in with token factory method
|
17
|
+
include ExpectationHelper # Mix-in with expectation on parse entry sets
|
18
|
+
|
19
|
+
# Helper method use to check wether a visit event
|
20
|
+
# matches the given expectations
|
21
|
+
# The expectations form an array with the given elements:
|
22
|
+
# [0] => the event symbol (:visit)
|
23
|
+
# [1] => the parse entry being visited
|
24
|
+
# [2] => the index of the parse entry set to which the visitee belongs to
|
25
|
+
def event_expectations(anEvent, expectations)
|
26
|
+
visit_event, entry, index = anEvent
|
27
|
+
expect(visit_event).to eq(expectations[0])
|
28
|
+
if expectations[1].is_a?(String)
|
29
|
+
case entry
|
30
|
+
when Parser::ParseEntry
|
31
|
+
expect(entry.to_s).to eq(expectations[1])
|
32
|
+
when Parser::Token
|
33
|
+
expect(entry.lexeme).to eq(expectations[1])
|
34
|
+
end
|
35
|
+
else
|
36
|
+
expect(entry).to eq(expectations[1])
|
37
|
+
end
|
38
|
+
expect(index).to eq(expectations[2])
|
39
|
+
end
|
40
|
+
|
41
|
+
let(:sample_grammar) do
|
42
|
+
# Grammar based on paper from Elisabeth Scott
|
43
|
+
# "SPPF=Style Parsing From Earley Recognizers" in
|
44
|
+
# Notes in Theoretical Computer Science 203, (2008), pp. 53-67
|
45
|
+
# contains a hidden left recursion and a cycle
|
46
|
+
builder = Syntax::GrammarBuilder.new
|
47
|
+
builder.add_terminals('a', 'b')
|
48
|
+
builder.add_production('Phi' => %'S')
|
49
|
+
builder.add_production('S' => %w[A T])
|
50
|
+
builder.add_production('S' => %w[a T])
|
51
|
+
builder.add_production('A' => 'a')
|
52
|
+
builder.add_production('A' => %w[B A])
|
53
|
+
builder.add_production('B' => [])
|
54
|
+
builder.add_production('T' => %w( b b b))
|
55
|
+
builder.grammar
|
56
|
+
end
|
57
|
+
|
58
|
+
let(:sample_tokens) do
|
59
|
+
build_token_sequence(%w(a b b b), sample_grammar)
|
60
|
+
end
|
61
|
+
|
62
|
+
let(:sample_result) do
|
63
|
+
parser = Parser::GFGEarleyParser.new(sample_grammar)
|
64
|
+
parser.parse(sample_tokens)
|
65
|
+
end
|
66
|
+
|
67
|
+
let(:subject) { ParseWalkerFactory.new }
|
68
|
+
|
69
|
+
|
70
|
+
context 'Initialization:' do
|
71
|
+
it 'should be created without argument' do
|
72
|
+
expect { ParseWalkerFactory.new }.not_to raise_error
|
73
|
+
end
|
74
|
+
end # context
|
75
|
+
|
76
|
+
context 'Parse graph traversal:' do
|
77
|
+
it 'should create an Enumerator as a walker' do
|
78
|
+
expect(subject.build_walker(sample_result)).to be_kind_of(Enumerator)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should return the accepting parse entry in the first place' do
|
82
|
+
walker = subject.build_walker(sample_result)
|
83
|
+
first_event = walker.next
|
84
|
+
expectations = [:visit, sample_result.accepting_entry, 4]
|
85
|
+
event_expectations(first_event, expectations)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should traverse the parse graph backwards' do
|
89
|
+
walker = subject.build_walker(sample_result)
|
90
|
+
event1 = walker.next
|
91
|
+
expectations = [:visit, 'Phi. | 0', 4]
|
92
|
+
event_expectations(event1, expectations)
|
93
|
+
|
94
|
+
event2 = walker.next
|
95
|
+
expectations = [:visit, 'Phi => S . | 0', 4]
|
96
|
+
event_expectations(event2, expectations)
|
97
|
+
|
98
|
+
event3 = walker.next
|
99
|
+
expectations = [:visit, 'S. | 0', 4]
|
100
|
+
event_expectations(event3, expectations)
|
101
|
+
|
102
|
+
# Backtrack created: first alternative selected
|
103
|
+
event4 = walker.next
|
104
|
+
expectations = [:visit, 'S => a T . | 0', 4]
|
105
|
+
event_expectations(event4, expectations)
|
106
|
+
|
107
|
+
event5 = walker.next
|
108
|
+
expectations = [:visit, 'T. | 1', 4]
|
109
|
+
event_expectations(event5, expectations)
|
110
|
+
|
111
|
+
event6 = walker.next
|
112
|
+
expectations = [:visit, 'T => b b b . | 1', 4]
|
113
|
+
event_expectations(event6, expectations)
|
114
|
+
|
115
|
+
event7 = walker.next
|
116
|
+
expectations = [:visit, 'T => b b . b | 1', 3]
|
117
|
+
event_expectations(event7, expectations)
|
118
|
+
|
119
|
+
event8 = walker.next
|
120
|
+
expectations = [:visit, 'T => b . b b | 1', 2]
|
121
|
+
event_expectations(event8, expectations)
|
122
|
+
|
123
|
+
event9 = walker.next
|
124
|
+
expectations = [:visit, 'T => . b b b | 1', 1]
|
125
|
+
event_expectations(event9, expectations)
|
126
|
+
|
127
|
+
event10 = walker.next
|
128
|
+
expectations = [:visit, '.T | 1', 1]
|
129
|
+
event_expectations(event10, expectations)
|
130
|
+
|
131
|
+
event11 = walker.next
|
132
|
+
expectations = [:visit, 'S => a . T | 0', 1]
|
133
|
+
event_expectations(event11, expectations)
|
134
|
+
|
135
|
+
event12 = walker.next
|
136
|
+
expectations = [:visit, 'S => . a T | 0', 0]
|
137
|
+
event_expectations(event12, expectations)
|
138
|
+
|
139
|
+
event13 = walker.next
|
140
|
+
expectations = [:visit, '.S | 0', 0]
|
141
|
+
event_expectations(event13, expectations)
|
142
|
+
|
143
|
+
event14 = walker.next
|
144
|
+
expectations = [:visit, 'Phi => . S | 0', 0]
|
145
|
+
event_expectations(event14, expectations)
|
146
|
+
|
147
|
+
event15 = walker.next
|
148
|
+
expectations = [:visit, '.Phi | 0', 0]
|
149
|
+
event_expectations(event15, expectations)
|
150
|
+
|
151
|
+
# Backtracking is occurring
|
152
|
+
event16 = walker.next
|
153
|
+
expectations = [:backtrack, 'S. | 0', 4]
|
154
|
+
event_expectations(event16, expectations)
|
155
|
+
|
156
|
+
event18 = walker.next
|
157
|
+
expectations = [:visit, 'S => A T . | 0', 4]
|
158
|
+
event_expectations(event18, expectations)
|
159
|
+
|
160
|
+
event19 = walker.next
|
161
|
+
expectations = [:revisit, 'T. | 1', 4]
|
162
|
+
event_expectations(event19, expectations)
|
163
|
+
|
164
|
+
# Multiple visit occurred: jump to antecedent of start entry
|
165
|
+
event20 = walker.next
|
166
|
+
expectations = [:visit, 'S => A . T | 0', 1]
|
167
|
+
event_expectations(event20, expectations)
|
168
|
+
|
169
|
+
event21 = walker.next
|
170
|
+
expectations = [:visit, 'A. | 0', 1]
|
171
|
+
event_expectations(event21, expectations)
|
172
|
+
|
173
|
+
# Backtrack created: first alternative selected
|
174
|
+
event22 = walker.next
|
175
|
+
expectations = [:visit, 'A => a . | 0', 1]
|
176
|
+
event_expectations(event22, expectations)
|
177
|
+
|
178
|
+
event23 = walker.next
|
179
|
+
expectations = [:visit, 'A => . a | 0', 0]
|
180
|
+
event_expectations(event23, expectations)
|
181
|
+
|
182
|
+
event24 = walker.next
|
183
|
+
expectations = [:visit, '.A | 0', 0]
|
184
|
+
event_expectations(event24, expectations)
|
185
|
+
|
186
|
+
event25 = walker.next
|
187
|
+
expectations = [:visit, 'S => . A T | 0', 0]
|
188
|
+
event_expectations(event25, expectations)
|
189
|
+
|
190
|
+
# Backtracking is occurring
|
191
|
+
event26 = walker.next
|
192
|
+
expectations = [:backtrack, 'A. | 0', 1]
|
193
|
+
event_expectations(event26, expectations)
|
194
|
+
|
195
|
+
event27 = walker.next
|
196
|
+
expectations = [:visit, 'A => B A . | 0', 1]
|
197
|
+
event_expectations(event27, expectations)
|
198
|
+
|
199
|
+
event28 = walker.next
|
200
|
+
expectations = [:revisit, 'A. | 0', 1]
|
201
|
+
event_expectations(event28, expectations)
|
202
|
+
|
203
|
+
event29 = walker.next
|
204
|
+
expectations = [:visit, 'A => B . A | 0', 0]
|
205
|
+
event_expectations(event29, expectations)
|
206
|
+
|
207
|
+
event30 = walker.next
|
208
|
+
expectations = [:visit, 'B. | 0', 0]
|
209
|
+
event_expectations(event30, expectations)
|
210
|
+
|
211
|
+
event31 = walker.next
|
212
|
+
expectations = [:visit, 'B => . | 0', 0]
|
213
|
+
event_expectations(event31, expectations)
|
214
|
+
|
215
|
+
event32 = walker.next
|
216
|
+
expectations = [:visit, '.B | 0', 0]
|
217
|
+
event_expectations(event32, expectations)
|
218
|
+
|
219
|
+
event33 = walker.next
|
220
|
+
expectations = [:visit, 'A => . B A | 0', 0]
|
221
|
+
event_expectations(event33, expectations)
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'should raise an exception at end of visit' do
|
225
|
+
walker = subject.build_walker(sample_result)
|
226
|
+
32.times { walker.next }
|
227
|
+
|
228
|
+
expect{ walker.next }.to raise_error(StopIteration)
|
229
|
+
end
|
230
|
+
|
231
|
+
end # context
|
232
|
+
end # describe
|
233
|
+
end # module
|
234
|
+
end # module
|
235
|
+
# End of file
|
@@ -17,6 +17,10 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
17
17
|
it 'should be created without argument' do
|
18
18
|
expect { StateSet.new }.not_to raise_error
|
19
19
|
end
|
20
|
+
|
21
|
+
it 'should be empty at creation' do
|
22
|
+
expect(subject.states).to be_empty
|
23
|
+
end
|
20
24
|
end # context
|
21
25
|
|
22
26
|
context 'Provided services:' do
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require_relative '../../spec_helper'
|
3
|
+
|
4
|
+
require_relative '../../../lib/rley/gfg/item_vertex'
|
5
|
+
require_relative '../../../lib/rley/syntax/terminal'
|
6
|
+
require_relative '../../../lib/rley/syntax/production'
|
7
|
+
require_relative '../../../lib/rley/ptree/token_range'
|
8
|
+
require_relative '../../../lib/rley/parser/dotted_item'
|
9
|
+
|
10
|
+
# Load the class under test
|
11
|
+
require_relative '../../../lib/rley/sppf/alternative_node'
|
12
|
+
|
13
|
+
module Rley # Open this namespace to avoid module qualifier prefixes
|
14
|
+
module SPPF # Open this namespace to avoid module qualifier prefixes
|
15
|
+
describe AlternativeNode do
|
16
|
+
# Factory method. Generate a range from its boundary values.
|
17
|
+
def range(low, high)
|
18
|
+
return PTree::TokenRange.new(low: low, high: high)
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:t_a) { Syntax::Terminal.new('A') }
|
22
|
+
let(:t_b) { Syntax::Terminal.new('B') }
|
23
|
+
let(:t_c) { Syntax::Terminal.new('C') }
|
24
|
+
let(:nt_sentence) { Syntax::NonTerminal.new('sentence') }
|
25
|
+
let(:sample_prod) do
|
26
|
+
Syntax::Production.new(nt_sentence, [t_a, t_b, t_c])
|
27
|
+
end
|
28
|
+
let(:sample_item) { Parser::DottedItem.new(sample_prod, 3) }
|
29
|
+
let(:sample_vertex) { GFG::ItemVertex.new(sample_item) }
|
30
|
+
let(:sample_range) { range(0, 3) }
|
31
|
+
|
32
|
+
subject { AlternativeNode.new(sample_vertex, sample_range) }
|
33
|
+
|
34
|
+
context 'Construction:' do
|
35
|
+
it 'should be created with a item vertex and a token range' do
|
36
|
+
expect { AlternativeNode.new(sample_vertex, sample_range) }.not_to raise_error
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'Initialization:' do
|
41
|
+
it 'should know its token range' do
|
42
|
+
expect(subject.range).to eq(sample_range)
|
43
|
+
expect(subject.origin).to eq(sample_range.low)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "shouldn't have children yet" do
|
47
|
+
expect(subject.subnodes).to be_empty
|
48
|
+
end
|
49
|
+
end # context
|
50
|
+
|
51
|
+
context 'Provided services:' do
|
52
|
+
it 'should accept the addition of subnodes' do
|
53
|
+
subnode1 = double('first_subnode')
|
54
|
+
subnode2 = double('second_subnode')
|
55
|
+
subnode3 = double('third_subnode')
|
56
|
+
expect { subject.add_subnode(subnode1) }.not_to raise_error
|
57
|
+
subject.add_subnode(subnode2)
|
58
|
+
subject.add_subnode(subnode3)
|
59
|
+
expect(subject.subnodes).to eq([subnode3, subnode2, subnode1])
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
it 'should have a string representation' do
|
64
|
+
expect(subject.to_string(0)).to eq('Alt(sentence => A B C .)[0, 3]')
|
65
|
+
end
|
66
|
+
end # context
|
67
|
+
|
68
|
+
end # describe
|
69
|
+
end # module
|
70
|
+
end # module
|
71
|
+
|
72
|
+
# End of file
|
@@ -0,0 +1,87 @@
|
|
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
|