Module: Antelope::Grammar::Productions
- Included in:
- Antelope::Grammar
- Defined in:
- lib/antelope/grammar/productions.rb
Overview
Manages the productions of the grammar.
Instance Method Summary collapse
-
#all_productions ⇒ Array<Production>
Returns all productions for all nonterminals, sorted by id.
-
#default_production ⇒ Production
private
Creates the default production for the grammar.
-
#find_token(value) ⇒ Token
Finds a token based on its corresponding symbol.
-
#generate_production_for(rule, id) ⇒ Production
private
Generates a production for a given compiler rule.
-
#generate_productions ⇒ Hash<(Symbol, Array<Production>)>
private
Actually generates the productions.
-
#productions ⇒ Hash<(Symbol, Array<Production>)>
Returns a hash of all of the productions.
-
#type_for(token) ⇒ Object
private
Returns the defined type for the given token name.
Instance Method Details
#all_productions ⇒ Array<Production>
Returns all productions for all nonterminals, sorted by id.
20 21 22 |
# File 'lib/antelope/grammar/productions.rb', line 20 def all_productions productions.values.flatten.sort_by(&:id) end |
#default_production ⇒ Production (private)
Creates the default production for the grammar. The left
hand side of the production is the :$start
symbol, with
the right hand side being the first rule's left-hand side
and the terminal $
. This production is automagically
given the last precedence, and an id of 0.
146 147 148 149 150 151 |
# File 'lib/antelope/grammar/productions.rb', line 146 def default_production Production.new(Token::Nonterminal.new(:$start), [ Token::Nonterminal.new(@compiler.rules.first[:label]), Token::Terminal.new(:$end) ], "", precedence.last, 0) end |
#find_token(value) ⇒ Token
Finds a token based on its corresponding symbol. First
checks the productions, to see if it's a nonterminal; then,
tries to find it in the terminals; otherwise, if the symbol
is error
, it returns a Token::Error; if the symbol is
nothing
or ε
, it returns a Token::Epsilon; if it's
none of those, it raises an UndefinedTokenError.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/antelope/grammar/productions.rb', line 35 def find_token(value) value = value.intern if productions.key?(value) typed_nonterminals.find { |term| term.name == value } || Token::Nonterminal.new(value) elsif terminal = terminals. find { |term| term.name == value } terminal elsif value == :$error || value == :error Token::Error.new elsif [:nothing, :ε, :"%empty"].include?(value) Token::Epsilon.new else raise UndefinedTokenError, "Could not find a token " \ "named #{value.inspect}" end end |
#generate_production_for(rule, id) ⇒ Production (private)
Generates a production for a given compiler rule. Converts the tokens in the set to their Token counterparts, and then sets the precedence for the production. If the precedence declaration from the compiler rule is empty, then it'll use the last terminal from the set to check for precedence; otherwise, it'll use the precedence declaration. This is to make sure that every production has a precedence declaration.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/antelope/grammar/productions.rb', line 97 def generate_production_for(rule, id) left = Token::Nonterminal.new(rule[:label]) items = rule[:set].map { |_| find_token(_[0]) } prec = if rule[:prec].empty? items.select(&:terminal?).first else rule[:prec].intern end prec = precedence_for(prec) left.type = type_for(rule[:label]) left.id = rule[:label_id] rule[:set].each_with_index do |tok, i| items[i] = items[i].dup items[i].id = tok[1] end items.delete_if(&:epsilon?) Production.new(left, items, rule[:block], prec, id + 1) end |
#generate_productions ⇒ Hash<(Symbol, Array<Production>)> (private)
Actually generates the productions. Uses the rules from the compiler to construct the productions. Makes two loops over the compiler's rules; the first to tell the grammar that the nonterminal does exist, and the second to actually construct the productions. The first loop is for #find_token, because otherwise it wouldn't be able to return a nonterminal properly.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/antelope/grammar/productions.rb', line 65 def generate_productions @_productions = {} index = 0 rules = @compiler.rules.each do |rule| productions[rule[:label]] = [] end while index < rules.size rule = rules[index] productions[rule[:label]] << generate_production_for(rule, index) index += 1 end productions[:$start] = [default_production] productions end |
#productions ⇒ Hash<(Symbol, Array<Production>)>
Returns a hash of all of the productions. The result is cached.
13 14 15 |
# File 'lib/antelope/grammar/productions.rb', line 13 def productions @_productions || generate_productions end |
#type_for(token) ⇒ Object (private)
Returns the defined type for the given token name.
Uses the %type
directive to infer the corresponding types.
124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/antelope/grammar/productions.rb', line 124 def type_for(token) token = find_token(token) unless token.is_a?(Token) case token when Token::Nonterminal token.type when Token::Terminal token.type when Token::Epsilon "" when Token::Error "" end end |