Class: Rley::Syntax::GrammarBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/rley/syntax/grammar_builder.rb

Overview

Builder GoF pattern. Builder pattern builds a complex object (say, a grammar) from simpler objects (terminals and productions) and using a step by step approach.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&aBlock) ⇒ GrammarBuilder

Returns a new instance of GrammarBuilder.



22
23
24
25
26
27
# File 'lib/rley/syntax/grammar_builder.rb', line 22

def initialize(&aBlock)
  @symbols = {}
  @productions = []

  instance_exec(&aBlock) if block_given?
end

Instance Attribute Details

#productionsObject (readonly)

The list of production rules for the grammar to build



19
20
21
# File 'lib/rley/syntax/grammar_builder.rb', line 19

def productions
  @productions
end

#symbolsObject (readonly)

The list of symbols of the language. Grammar symbols are categorized into terminal (symbol) and non-terminal (symbol).



16
17
18
# File 'lib/rley/syntax/grammar_builder.rb', line 16

def symbols
  @symbols
end

Instance Method Details

#[](aSymbolName) ⇒ GrmSymbol

Retrieve a grammar symbol from its name. Raise an exception if not found.

Parameters:

  • aSymbolName (String)

    the name of a symbol grammar.

Returns:



33
34
35
# File 'lib/rley/syntax/grammar_builder.rb', line 33

def [](aSymbolName)
  return symbols[aSymbolName]
end

#add_production(aProductionRepr) ⇒ Object Also known as: rule

Add a production rule in the grammar given one key-value pair of the form: String => Array. Where the key is the name of the non-terminal appearing in the left side of the rule. The value, an Array, is a sequence of grammar symbol names. The rule is created and inserted in the grammar. Example: builder.add_production('A' => ['a', 'A', 'c'])

Parameters:

  • aProductionRepr (Hash)

    A Hash-based representation of production



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/rley/syntax/grammar_builder.rb', line 54

def add_production(aProductionRepr)
  aProductionRepr.each_pair do |(lhs_name, rhs_repr)|
    lhs = get_nonterminal(lhs_name)
    case rhs_repr
      when Array
        rhs_constituents = rhs_repr.map { |name| get_nonterminal(name) }
      when String
        rhs_constituents = [ get_nonterminal(rhs_repr) ]
      when Terminal
        rhs_constituents = [ rhs_repr ]
    end
    new_prod = Production.new(lhs, rhs_constituents)
    productions << new_prod
  end
end

#add_terminals(*terminalSymbols) ⇒ Object

Add the given terminal symbols to the grammar of the language

Parameters:

  • terminalSymbols (String or Terminal)

    1..* terminal symbols.



39
40
41
42
# File 'lib/rley/syntax/grammar_builder.rb', line 39

def add_terminals(*terminalSymbols)
  new_symbs = build_symbols(Terminal, terminalSymbols)
  symbols.merge!(new_symbs)
end

#grammarObject

Given the grammar symbols and productions added to the builder, build the resulting grammar (if not yet done).



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/rley/syntax/grammar_builder.rb', line 72

def grammar()
  unless @grammar
    raise StandardError, 'No symbol found for grammar' if symbols.empty?
    if productions.empty?
      raise StandardError, 'No production found for grammar'
    end
    
    # Check that each non-terminal appears at least once in lhs.
    all_non_terminals = symbols.values.select { |s| s.is_a?(NonTerminal) }
    all_non_terminals.each do |n_term|
      next if productions.any? { |prod| n_term == prod.lhs }
      raise StandardError, "Nonterminal #{n_term.name} not rewritten"
    end

    @grammar = Grammar.new(productions.dup)
  end
  
  return @grammar
end