Class: Ast::BNF::Definition
- Inherits:
-
Object
- Object
- Ast::BNF::Definition
- Defined in:
- lib/ast_ast/bnf.rb
Instance Attribute Summary collapse
-
#name ⇒ Object
Returns the value of attribute name.
-
#rules ⇒ Object
Returns the value of attribute rules.
Instance Method Summary collapse
-
#initialize(name, rules, klass) ⇒ Definition
constructor
A new instance of Definition.
- #inspect ⇒ Object
-
#order ⇒ Integer
Gets the order of the Definition, this does require access to the other definitions.
-
#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.
-
#terminal? ⇒ Boolean
A terminal defintion does not reference any other definitions.
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
#name ⇒ Object
Returns the value of attribute name.
26 27 28 |
# File 'lib/ast_ast/bnf.rb', line 26 def name @name end |
#rules ⇒ Object
Returns the value of attribute rules.
26 27 28 |
# File 'lib/ast_ast/bnf.rb', line 26 def rules @rules end |
Instance Method Details
#inspect ⇒ Object
123 |
# File 'lib/ast_ast/bnf.rb', line 123 def inspect; "#<Ast::BNF::Definition #{@name}>"; end |
#order ⇒ Integer
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.
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!
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.
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 |