Module: EBNF::BNF

Included in:
Base
Defined in:
lib/ebnf/bnf.rb

Instance Method Summary collapse

Instance Method Details

#make_bnfENBF

Transform EBNF Rule set to BNF:

* Add rule [0] (_empty rule (seq))
* Transform each rule into a set of rules that are just BNF, using {Rule#to_bnf}.

Returns:

  • (ENBF)

    self



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/ebnf/bnf.rb', line 9

def make_bnf
  progress("make_bnf") {"Start: #{@ast.length} rules"}
  new_ast = [Rule.new(:_empty, "0", [:seq], :kind => :rule)]

  ast.each do |rule|
    debug("make_bnf") {"expand from: #{rule.inspect}"}
    new_rules = rule.to_bnf
    debug(" => ") {new_rules.map(&:sym).join(', ')}
    new_ast += new_rules
  end

  # Consolodate equivalent terminal rules
  to_rewrite = {}
  new_ast.select {|r| r.terminal?}.each do |src_rule|
    new_ast.select {|r| r.terminal?}.each do |dst_rule|
      if src_rule.equivalent?(dst_rule) && src_rule != dst_rule
        debug("make_bnf") {"equivalent rules: #{src_rule.inspect} and #{dst_rule.inspect}"}
        (to_rewrite[src_rule] ||= []) << dst_rule
      end
    end
  end

  # Replace references to equivalent rules with canonical rule
  to_rewrite.each do |src_rule, dst_rules|
    dst_rules.each do |dst_rule|
      new_ast.each do |mod_rule|
        debug("make_bnf") {"rewrite #{mod_rule.inspect} from #{dst_rule.sym} to #{src_rule.sym}"}
        mod_rule.rewrite(dst_rule, src_rule)
      end
    end
  end

  # AST now has just rewritten rules
  compacted_ast = new_ast - to_rewrite.values.flatten.compact

  # Sort AST by number
  @ast = compacted_ast
  progress("make_bnf") {"End: #{@ast.length} rules"}
  self
end