Class: Rley::Syntax::GrammarBuilder
- Inherits:
-
Object
- Object
- Rley::Syntax::GrammarBuilder
- Defined in:
- lib/rley/syntax/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
-
#productions ⇒ Array<Production>
readonly
The list of production rules for the grammar to build.
-
#symbols ⇒ Hash{String, GrmSymbol}
readonly
The mapping of grammar symbol names to the matching grammar symbol object.
Instance Method Summary collapse
-
#[](aSymbolName) ⇒ GrmSymbol
Retrieve a grammar symbol from its name.
-
#add_production(aProductionRepr) ⇒ Production
(also: #rule)
Add a production rule in the grammar given one key-value pair of the form: String => Array.
-
#add_terminals(*terminalSymbols) ⇒ void
Add the given terminal symbols to the grammar of the language.
-
#grammar ⇒ Grammar
Given the grammar symbols and productions added to the builder, build the resulting grammar (if not yet done).
-
#initialize(&aBlock) ⇒ GrammarBuilder
constructor
Creates a new grammar builder.
Constructor Details
#initialize(&aBlock) ⇒ GrammarBuilder
Creates a new grammar builder.
36 37 38 39 40 41 |
# File 'lib/rley/syntax/grammar_builder.rb', line 36 def initialize(&aBlock) @symbols = {} @productions = [] instance_exec(&aBlock) if block_given? end |
Instance Attribute Details
#productions ⇒ Array<Production> (readonly)
Returns The list of production rules for the grammar to build.
23 24 25 |
# File 'lib/rley/syntax/grammar_builder.rb', line 23 def productions @productions end |
#symbols ⇒ Hash{String, GrmSymbol} (readonly)
Returns The mapping of grammar symbol names to the matching grammar symbol object.
19 20 21 |
# File 'lib/rley/syntax/grammar_builder.rb', line 19 def symbols @symbols end |
Instance Method Details
#[](aSymbolName) ⇒ GrmSymbol
Retrieve a grammar symbol from its name. Raise an exception if not found.
47 48 49 |
# File 'lib/rley/syntax/grammar_builder.rb', line 47 def [](aSymbolName) return symbols[aSymbolName] 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.
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 73 def add_production(aProductionRepr) aProductionRepr.each_pair do |(lhs_name, rhs_repr)| lhs = get_nonterminal(lhs_name) case rhs_repr when Array rhs_members = rhs_repr.map { |name| get_nonterminal(name) } when String rhs_lexemes = rhs_repr.scan(/\S+/) rhs_members = rhs_lexemes.map { |name| get_nonterminal(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
54 55 56 57 |
# File 'lib/rley/syntax/grammar_builder.rb', line 54 def add_terminals(*terminalSymbols) new_symbs = build_symbols(Terminal, terminalSymbols) symbols.merge!(new_symbs) end |
#grammar ⇒ Grammar
Given the grammar symbols and productions added to the builder, build the resulting grammar (if not yet done).
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/rley/syntax/grammar_builder.rb', line 95 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 |