Class: Rley::GFG::GrmFlowGraph
- Inherits:
-
Object
- Object
- Rley::GFG::GrmFlowGraph
- Defined in:
- lib/rley/gfg/grm_flow_graph.rb
Overview
A Grammar Flow Graph (GFG) represents the parsing states of productions rules from a context-free grammar. This representation is based on a directed graph structure. The parsing process can then be re-formulated as a path problem in the graph. The theory behind GFGs can be found in papers. The first article on GFG can be found here: https://apps.cs.utexas.edu/tech_reports/reports/tr/TR-2102.pdf There are three types of vertex in a GFG: start vertex, end vertex and item vertex. For each non-terminal symbol N of the grammar, there is: a start vertex with label '.N' an end vertex with label 'N.' For each production rule of the grammar: N => s1 s2 s3 (...) sk I.e. a rule with k grammar symbols in its right-handed side. For such a rule there will be k + 1 item vertices. By convention, the first item vertex is labelled as 'N => . s1 s2 s3 (...) sk' the second item vertex is labelled as 'N => s1 . s2 s3 (...) sk' the third item vertex is labelled as 'N => s1 s2 . s3 (...) sk' and so on. In other words, the labels are obtained by moving a dot in successive positions in the rhs. The dot represents the parse progress for the production rule. Symbols on the left of the dot represent the symbols that were successfully matched in the input. A GFG has three types of directed edges linking the vertices. call edge, return edge and scan edge.
Defined Under Namespace
Classes: Branching
Instance Attribute Summary collapse
-
#end_vertex_for ⇒ Object
readonly
A Hash with pairs of the form: non-terminal symbol => end node.
-
#start_vertex ⇒ StartVertex
readonly
The vertex marked as start node of the graph.
-
#start_vertex_for ⇒ Object
readonly
A Hash with pairs of the form: non-terminal symbol => start node.
-
#vertices ⇒ Array<Vertex>
readonly
The set of all vertices in the graph.
Instance Method Summary collapse
-
#diagnose ⇒ Object
Perform a diagnosis of the grammar elements (symbols and rules) in order to detect: If one wants to remove useless rules, then do first: elimination of non-generating symbols then elimination of unreachable symbols.
-
#find_vertex(aVertexLabel) ⇒ Vertex
Retrieve the vertex with given vertex label.
-
#initialize(theDottedItems) ⇒ GrmFlowGraph
constructor
Constructor.
-
#inspect ⇒ String
Returns a string containing a human-readable representation of the production.
-
#traverse_df(aStartVertex, &_visitAction) {|last_one| ... } ⇒ Object
Walk over all the vertices of the graph that are reachable from a given start vertex.
Constructor Details
#initialize(theDottedItems) ⇒ GrmFlowGraph
Constructor. of the grammar.
54 55 56 57 58 59 60 |
# File 'lib/rley/gfg/grm_flow_graph.rb', line 54 def initialize(theDottedItems) @vertices = [] @start_vertex_for = {} @end_vertex_for = {} build_graph(theDottedItems) end |
Instance Attribute Details
#end_vertex_for ⇒ Object (readonly)
A Hash with pairs of the form: non-terminal symbol => end node
49 50 51 |
# File 'lib/rley/gfg/grm_flow_graph.rb', line 49 def end_vertex_for @end_vertex_for end |
#start_vertex ⇒ StartVertex (readonly)
The vertex marked as start node of the graph
43 44 45 |
# File 'lib/rley/gfg/grm_flow_graph.rb', line 43 def start_vertex @start_vertex end |
#start_vertex_for ⇒ Object (readonly)
A Hash with pairs of the form: non-terminal symbol => start node
46 47 48 |
# File 'lib/rley/gfg/grm_flow_graph.rb', line 46 def start_vertex_for @start_vertex_for end |
#vertices ⇒ Array<Vertex> (readonly)
Returns The set of all vertices in the graph.
39 40 41 |
# File 'lib/rley/gfg/grm_flow_graph.rb', line 39 def vertices @vertices end |
Instance Method Details
#diagnose ⇒ Object
Perform a diagnosis of the grammar elements (symbols and rules) in order to detect: If one wants to remove useless rules, then do first: elimination of non-generating symbols then elimination of unreachable symbols
93 94 95 |
# File 'lib/rley/gfg/grm_flow_graph.rb', line 93 def diagnose() mark_unreachable_symbols end |
#find_vertex(aVertexLabel) ⇒ Vertex
Retrieve the vertex with given vertex label.
84 85 86 |
# File 'lib/rley/gfg/grm_flow_graph.rb', line 84 def find_vertex(aVertexLabel) vertices.find { |a_vertex| a_vertex.label == aVertexLabel } end |
#inspect ⇒ String
Returns a string containing a human-readable representation of the production.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/rley/gfg/grm_flow_graph.rb', line 65 def inspect() result = "#<#{self.class.name}:#{object_id}" result << ' @vertices=[' list = vertices.map { |v| "#<#{v.selfie}>" } result << list.join(', ') result << '] ' edges = [] vertices.each do |v| edges << v.edges do |e| result << "#{v.object_id} #{e.inspect}" end end result << "edges=[#{edges.join(",\n ")}]>" return result end |
#traverse_df(aStartVertex, &_visitAction) {|last_one| ... } ⇒ Object
Walk over all the vertices of the graph that are reachable from a given start vertex. This is a depth-first graph traversal.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/rley/gfg/grm_flow_graph.rb', line 122 def traverse_df(aStartVertex, &_visitAction) visited = Set.new stack = [] visitee = aStartVertex curr_edge = nil begin # print_vertex( 'Traversing', visitee) first_time = !visited.include?(visitee) if first_time yield(visitee) visited << visitee end case visitee when Rley::GFG::StartVertex if first_time stack.push(Branching.new(visitee, curr_edge)) curr_edge = stack.last.next_edge elsif curr_edge.nil? # Error probably caused by missing terminal symbol object msg = "Undefined grammar symbol #{visitee.label.sub(/^\./, '')}" raise StandardError, msg else # Skip both start and end vertices # Retrieve the corresponding return edge curr_edge = get_matching_return(curr_edge) end when Rley::GFG::EndVertex if stack.last.done? popped = stack.pop break if stack.empty? # puts "Popped!" return_key = popped.in_edge.key.sub(/^CALL/, 'RET') curr_edge = visitee.edges.find { |e| e.key == return_key } else curr_edge = stack.last.next_edge end else # All other vertex types have only one successor curr_edge = visitee.edges[0] end visitee = curr_edge.successor unless curr_edge.nil? end until stack.empty? # Now process the end vertex matching the initial start vertex last_one = end_vertex_for[aStartVertex.non_terminal] yield(last_one) unless visited.include?(last_one) end |