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:



21
22
23
# File 'lib/antelope/ace/grammar/productions.rb', line 21

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:



116
117
118
119
120
121
# File 'lib/antelope/ace/grammar/productions.rb', line 116

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

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:



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

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, ].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.

Parameters:

  • rule (Hash)

    the compiler's rule.

  • id (Numeric)

    the id for the production.

Returns:



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/antelope/ace/grammar/productions.rb', line 90

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

  unless rule[:prec].empty?
    puts "PREC, #{prec.inspect}"
  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:



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

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:



14
15
16
# File 'lib/antelope/ace/grammar/productions.rb', line 14

def productions
  @_productions || generate_productions
end