Class: Ast::BNF::Definition

Inherits:
Object
  • Object
show all
Defined in:
lib/ast_ast/bnf.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, rules, klass) ⇒ Definition

Returns a new instance of Definition.



28
29
30
31
32
# File 'lib/ast_ast/bnf.rb', line 28

def initialize(name, rules, klass)
  @name = name
  @rules = rules.map {|i| i.is_a?(Array) ? i : [i] }
  @klass = klass
end

Instance Attribute Details

#nameObject

Returns the value of attribute name.



26
27
28
# File 'lib/ast_ast/bnf.rb', line 26

def name
  @name
end

#rulesObject

Returns the value of attribute rules.



26
27
28
# File 'lib/ast_ast/bnf.rb', line 26

def rules
  @rules
end

Instance Method Details

#inspectObject



123
# File 'lib/ast_ast/bnf.rb', line 123

def inspect; "#<Ast::BNF::Definition #{@name}>"; end

#orderInteger

Gets the order of the Definition, this does require access to the other definitions. Here’s why:

The order of a definition is basically how many (max) times would you have to loop thorugh to get to a terminal rule. So from the example below,

<LETTER> ::= a|b|c|d|...|X|Y|Z       #=> terminal
<WORD>   ::= <WORD><LETTER>|<LETTER> #=> 1st order
<STRING> ::= '<WORD>'                #=> 2nd order

Here it is easy to see that <LETTER> is terminal, no other rule will have to be looked at to determine if something is a <LETTER>. For a <WORD> you have to look at the <LETTER> definition, so this is 1st order. And for <STRING>, you need to look at <WORD> which in turn looks at <LETTER>, so you are going back 2 steps.

Returns:

  • (Integer)

    order of definition



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/ast_ast/bnf.rb', line 54

def order
  if terminal?
    0
  elsif self_referential?
    1
  else
    r = 0
    @rules.each do |rule|
      # Only interested in rule with recursion
      if rule.size > 1
        rule.each do |elem|
          # Only interested in references
          if elem.is_a? String
            b = @klass.defs.find_all {|i| i.name == elem}[0].order + 1
            r = b if b > r # swap if higher
          end
        end
      end
    end
    r
  end
end

#self_referential?Boolean

A Definition is self referential if the only refernce to another rule is to itself or if the other references are to terminal rule.

This is not a perfect definition of what “self referential” really means but it does help when finding the order!

Returns:

  • (Boolean)

    whether the definition is self referential



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/ast_ast/bnf.rb', line 104

def self_referential?
  r = false
  @rules.each do |rule|
    rule.each do |elem|
      if elem == @name
        r = true
      else
        k = @klass.defs.find_all{|i| i.name == elem}[0]
        if k && k.terminal?
          r = true
        else
          return false  
        end
      end
    end
  end
  r
end

#terminal?Boolean

A terminal defintion does not reference any other definitions. This is largely irrelevent as Ast::Tokeniser should take care of this but it may be useful in some cases.

Returns:

  • (Boolean)

    whether contains just terminal elements



84
85
86
87
88
89
90
91
92
93
# File 'lib/ast_ast/bnf.rb', line 84

def terminal?
  @rules.each do |r|
    if r.is_a? Array
      r.each do |i|
       return false if i.is_a? String
      end
    end
  end
  true
end