Class: Rley::Syntax::BaseGrammarBuilder

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

Overview

Builder GoF pattern. Builder 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) ⇒ BaseGrammarBuilder

Creates a new grammar builder.

Examples:

Building a tiny English grammar

builder = Rley::Syntax::GrammarBuilder.new do
  add_terminals('n', 'v', 'adj', 'det')
  rule 'S' => %w[NP VP]
  rule 'VP' => %w[v NP]
  rule 'NP' => %w[det n]
  rule 'NP' => %w[adj NP]
end
tiny_eng = builder.grammar

Parameters:

  • aBlock (Proc)

    code block used to build the grammar.



34
35
36
37
38
39
# File 'lib/rley/syntax/base_grammar_builder.rb', line 34

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

  instance_exec(&aBlock) if block_given?
end

Instance Attribute Details

#productionsArray<Production> (readonly)

Returns The list of production rules for the grammar to build.

Returns:

  • (Array<Production>)

    The list of production rules for the grammar to build.



21
22
23
# File 'lib/rley/syntax/base_grammar_builder.rb', line 21

def productions
  @productions
end

#symbolsHash{String, GrmSymbol} (readonly)

Returns The mapping of grammar symbol names to the matching grammar symbol object.

Returns:

  • (Hash{String, GrmSymbol})

    The mapping of grammar symbol names to the matching grammar symbol object.



17
18
19
# File 'lib/rley/syntax/base_grammar_builder.rb', line 17

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 grammar symbol.

Returns:

  • (GrmSymbol)

    the retrieved symbol object.



45
46
47
# File 'lib/rley/syntax/base_grammar_builder.rb', line 45

def [](aSymbolName)
  symbols[aSymbolName]
end

#add_marker(aMarkerSymbol) ⇒ void

This method returns an undefined value.

Add the given marker symbol to the grammar of the language

Parameters:

  • aMarkerSymbol (Syntax::Marker)

    A mazker symbol



60
61
62
63
# File 'lib/rley/syntax/base_grammar_builder.rb', line 60

def add_marker(aMarkerSymbol)
  new_symb = build_symbol(Marker, aMarkerSymbol)
  symbols[aMarkerSymbol.name] = new_symb
end

#add_production(aProductionRepr) ⇒ Production 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.

Examples:

Equivalent call syntaxes

builder.add_production('A' => ['a', 'A', 'c'])
builder.rule('A' => ['a', 'A', 'c']) # 'rule' is a synonym
builder.rule('A' => %w[a A  c]) # Use %w syntax for Array of String
builder.rule 'A' => %w[a A  c]  # Call parentheses are optional

Parameters:

  • aProductionRepr (Hash{String, Array<String>})

    A Hash-based representation of a production.

Returns:

  • (Production)

    The created Production instance



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/rley/syntax/base_grammar_builder.rb', line 79

def add_production(aProductionRepr)
  aProductionRepr.each_pair do |(lhs_name, rhs_repr)|
    lhs = get_grm_symbol(lhs_name)
    case rhs_repr
      when Array
        rhs_members = rhs_repr.map { |name| get_grm_symbol(name) }
      when String
        rhs_lexemes = rhs_repr.scan(/\S+/)
        rhs_members = rhs_lexemes.map { |name| get_grm_symbol(name) }
      when Terminal
        rhs_members = [rhs_repr]
    end
    new_prod = Production.new(lhs, rhs_members)
    productions << new_prod
  end

  return productions.last
end

#add_terminals(*terminalSymbols) ⇒ void

This method returns an undefined value.

Add the given terminal symbols to the grammar of the language

Parameters:

  • terminalSymbols (String or Terminal)

    1..* terminal symbols.



52
53
54
55
# File 'lib/rley/syntax/base_grammar_builder.rb', line 52

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

#grammarGrammar

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

Returns:

  • (Grammar)

    the created grammar object.



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/rley/syntax/base_grammar_builder.rb', line 101

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 terminal appears at least in a rhs of a production
    all_terminals = symbols.values.select do |a_symb|
      a_symb.kind_of?(Terminal)
    end
    in_use = Set.new
    productions.each do |prod|
      prod.rhs.members.each do |symb|
        in_use << symb if symb.kind_of?(Syntax::Terminal)
      end
    end

    unused = all_terminals.reject { |a_term| in_use.include?(a_term) }
    unless unused.empty?
      suffix = "#{unused.map(&:name).join(', ')}."
      raise StandardError, "Useless terminal symbol(s): #{suffix}"
    end

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

  return @grammar
end

#suffix_plusObject

When a symbol, say symb, in a rhs is followed by a '+' modifier, then a rule will be generated with a lhs named symb + suffix_plus



133
134
135
# File 'lib/rley/syntax/base_grammar_builder.rb', line 133

def suffix_plus
  '_plus'
end

#suffix_plus_lastObject



141
142
143
# File 'lib/rley/syntax/base_grammar_builder.rb', line 141

def suffix_plus_last
  'base_plus_last'
end

#suffix_plus_moreObject



137
138
139
# File 'lib/rley/syntax/base_grammar_builder.rb', line 137

def suffix_plus_more
  'base_plus_more'
end