Module: Antelope::Ace::Grammar::Productions

Included in:
Antelope::Ace::Grammar
Defined in:
lib/antelope/ace/grammar/productions.rb

Overview

Manages the productions of the grammar.

Instance Method Summary collapse

Instance Method Details

#all_productionsArray<Production>

Returns all productions for all nonterminals, sorted by id.

Returns:



19
20
21
# File 'lib/antelope/ace/grammar/productions.rb', line 19

def all_productions
  productions.values.flatten.sort_by(&:id)
end

#default_productionProduction (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.

Returns:



83
84
85
86
87
88
# File 'lib/antelope/ace/grammar/productions.rb', line 83

def default_production
  Production.new(Token::Nonterminal.new(:$start), [
      Token::Nonterminal.new(@compiler.rules.first[:label]),
      Token::Terminal.new(:"$")
    ], "", precedence.last, 0)
end

#find_token(value) ⇒ Token (private)

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.

Parameters:

  • value (String, Symbol, #intern)

    the token's symbol to check.

Returns:

Raises:



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/antelope/ace/grammar/productions.rb', line 101

def find_token(value)
  value = value.intern
  if productions.key?(value)
    Token::Nonterminal.new(value)
  elsif terminal = terminals.
      find { |term| term.name == value }
    terminal
  elsif value == :error
    Token::Error.new
  elsif [:nothing, :

#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.

Parameters:

  • rule (Hash)

    the compiler's rule.

  • id (Numeric)

    the id for the production.

Returns:



61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/antelope/ace/grammar/productions.rb', line 61

def generate_production_for(rule, id)
  left  = rule[:label]
  items = rule[:set].map { |_| find_token(_) }
  prec  = if rule[:prec].empty?
    items.select(&:terminal?).last
  else
    find_token(rule[:prec])
  end

  prec  = precedence_for(prec)

  Production.new(Token::Nonterminal.new(left), items,
       rule[:block], prec, id + 1)
end

#generate_productionsHash<(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.

Returns:



34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/antelope/ace/grammar/productions.rb', line 34

def generate_productions
  @_productions = {}

  @compiler.rules.each do |rule|
    productions[rule[:label]] = []
  end.each_with_index do |rule, id|
    productions[rule[:label]] <<
      generate_production_for(rule, id)
  end

  productions[:$start] = [default_production]

  productions
end

#productionsHash<(Symbol, Array<Production>)>

Returns a hash of all of the productions. The result is cached.

Returns:



12
13
14
# File 'lib/antelope/ace/grammar/productions.rb', line 12

def productions
  @_productions || generate_productions
end