require 'set'
require 'lib/grammar'
module Mapper
class Validator
def Validator.analyze_all grammar
Validator.analyze_recursivity grammar
Validator.analyze_sn_altering grammar
Validator.analyze_arity grammar
Validator.analyze_min_depth grammar
grammar
end
def Validator.check_unused grammar
defs = grammar.symbols
grammar.each_value do |rule|
rule.each do |alt|
alt.each do |token|
next unless token.type == :symbol
next unless defs.include? token.data
defs.delete token.data
end
end
end
defs
end
def Validator.check_undefined grammar
undefs = []
defs = grammar.symbols
grammar.each_value do |rule|
rule.each do |alt|
alt.each do |token|
next unless token.type == :symbol
next if defs.include? token.data
undefs.push token.data
end
end
end
undefs
end
def Validator.analyze_recursivity gram
raise 'Validator: cannot analyze_recursivity of undefined symbols' unless Validator.check_undefined( gram ).empty?
gram.each_value do |rule|
rule.recursivity = :infinite
rule.each { |alt| alt.recursivity = :infinite }
end
changed = true
while changed
changed = false
gram.each_value do |rule|
rule.each do |alt|
references = alt.find_all { |token| token.type == :symbol }
res = recursivity_over( references.map {|token| gram[token.data] } )
now = if res.include? :infinite
:infinite
elsif res.include? :cyclic
:cyclic
else
:terminating
end
changed = true if alt.recursivity != now
alt.recursivity = now
end
res = recursivity_over rule
now = (res.size == 1) ? res.first : :cyclic
changed = true if rule.recursivity != now
rule.recursivity = now
end
end
gram
end
def Validator.analyze_sn_altering grammar
grammar.each_value do |rule|
rule.sn_altering = :nodal
subsyms = nil
rule.each do |alts|
sub = alts.find_all {|token| token.type == :symbol }
subsyms = sub if subsyms.nil?
next if subsyms == sub
rule.sn_altering = :structural
break
end
end
grammar
end
def Validator.analyze_arity grammar
grammar.each_value do |rule|
rule.each do |alt|
alt.arity = ( alt.find_all { |token| token.type == :symbol } ).size
end
end
grammar
end
def Validator.analyze_min_depth grammar
raise 'Validator: cannot analyze_min_depth of undefined symbols' unless Validator.check_undefined( grammar ).empty?
grammar.each_value do |rule|
rule.min_depth = nil
rule.each { |alt| alt.min_depth = nil }
end
changed = true
while changed
changed = false
grammar.each_value do |rule|
symbol_depth = nil
rule.each do |alt|
next unless alt.min_depth.nil?
alt_depth = nil
alt.each do |token|
depth = (token.type == :symbol) ? grammar[token.data].min_depth : 1
if depth.nil?
alt_depth = nil
break
end
alt_depth = depth if alt_depth.nil? or alt_depth < depth
end
next if alt_depth.nil?
changed = true if alt.min_depth != alt_depth
alt.min_depth = alt_depth
symbol_depth = alt_depth if symbol_depth.nil? or symbol_depth > alt_depth
end
next if symbol_depth.nil?
next unless rule.min_depth.nil? rule.min_depth = symbol_depth + 1
changed = true
end end
grammar
end
protected
def Validator.recursivity_over container
result = Set.new
container.each { |item| result.add( item.recursivity ) }
result.to_a
end
end
end