Class: Dendroid::GrmDSL::BaseGrmBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/dendroid/grm_dsl/base_grm_builder.rb

Overview

Builder GoF pattern: Builder builds a complex object.

here the builder creates a grammar from simpler objects
(symbols and production rules)
and using a step by step approach.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&aBlock) ⇒ BaseGrmBuilder

Creates a new grammar builder object.

Examples:

Building a tiny English grammar

builder = Rley::Syntax::GrammarBuilder.new do
  declare_terminals('n', 'v', 'adj', 'det')
  rule 'S' => 'NP VP'
  rule 'VP' => 'v NP'
  rule 'NP' => ['det n', 'adj NP']
end
# Now with `builder`, let's create the grammar
tiny_eng = builder.grammar

Parameters:

  • aBlock (Proc)

    code block used to build the grammar.



39
40
41
42
43
44
45
46
47
48
# File 'lib/dendroid/grm_dsl/base_grm_builder.rb', line 39

def initialize(&aBlock)
  @symbols = {}
  @rules = []
  @state = :declaring

  return unless block_given?

  instance_exec(&aBlock)
  grammar_complete!
end

Instance Attribute Details

#rulesArray<Dendroid::Syntax::Rule> (readonly)

Returns The list of rules of the grammar.

Returns:



26
27
28
# File 'lib/dendroid/grm_dsl/base_grm_builder.rb', line 26

def rules
  @rules
end

#stateSymbol (readonly)

Returns one of: :declaring, :building, :complete.

Returns:

  • (Symbol)

    one of: :declaring, :building, :complete



19
20
21
# File 'lib/dendroid/grm_dsl/base_grm_builder.rb', line 19

def state
  @state
end

#symbolsHash{String, Dendroid::Syntax::GrmSymbol} (readonly)

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

Returns:



23
24
25
# File 'lib/dendroid/grm_dsl/base_grm_builder.rb', line 23

def symbols
  @symbols
end

Instance Method Details

#declare_terminals(*terminalSymbols) ⇒ void

This method returns an undefined value.

Add the given terminal symbols to the grammar of the language

Parameters:

  • terminalSymbols (String, Terminal)

    1..* terminal symbols.

Raises:

  • (StandardError)


53
54
55
56
57
58
59
# File 'lib/dendroid/grm_dsl/base_grm_builder.rb', line 53

def declare_terminals(*terminalSymbols)
  err_msg = "Terminal symbols may only be declared in state :declaring, current state is: #{state}"
  raise StandardError, err_msg unless state == :declaring

  new_symbs = build_symbols(Dendroid::Syntax::Terminal, terminalSymbols)
  symbols.merge!(new_symbs)
end

#grammarDendroid::Syntax::Grammar

Generate the grammar according to the specifications.



109
110
111
112
113
114
115
# File 'lib/dendroid/grm_dsl/base_grm_builder.rb', line 109

def grammar
  terminals = symbols.values.select(&:terminal?)
  grm = Dendroid::Syntax::Grammar.new(terminals)
  rules.each { |prod| grm.add_rule(prod) }
  grm.complete!
  grm
end

#grammar_complete!Object

A method used to notify the builder that the grammar is complete

(i.e. all rules were entered).


103
104
105
# File 'lib/dendroid/grm_dsl/base_grm_builder.rb', line 103

def grammar_complete!
  @state = :complete
end

#rule(productionRuleRepr) ⇒ Dendroid::Syntax::Rule

Add a production rule in the grammar given one key-value pair of the form: String => String.

Where the key is the name of the non-terminal appearing in the
left side of the rule.
When the value is a String, it is a sequence of grammar symbol names separated by space.
When the value is an array of String, the elements represent an alternative rhs

The rule is created and inserted in the grammar.

Examples:

builder.rule('sentence' => 'noun_phrase verb_phrase')
builder.rule('noun_phrase' => ['noun', 'adj noun'])

Parameters:

  • productionRuleRepr (Hash{String, String|Array<String>})

    A Hash-based representation of a production.

Returns:

Raises:

  • (StandardError)


74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/dendroid/grm_dsl/base_grm_builder.rb', line 74

def rule(productionRuleRepr)
  raise StandardError, 'Cannot add a production rule in state :complete' if state == :complete

  @state = :building

  return nil unless productionRuleRepr.is_a?(Hash)

  head_name = productionRuleRepr.keys.first
  if symbols.include? head_name
    err_msg = "Terminal symbol '#{head_name}' may not be on left-side of a rule."
    raise StandardError, err_msg if symbols[head_name].is_a?(Dendroid::Syntax::Terminal)
  else
    symbols.merge!(build_symbols(Dendroid::Syntax::NonTerminal, [head_name]))
  end
  lhs = symbols[head_name]
  raw_rhs = productionRuleRepr.values.first

  if raw_rhs.is_a? String
    new_prod = Dendroid::Syntax::Rule.new(lhs, [build_symbol_seq(raw_rhs)])
  else
    rhs = raw_rhs.map { |raw| build_symbol_seq(raw) }
    new_prod = Dendroid::Syntax::Rule.new(lhs, rhs)
  end
  rules << new_prod
  new_prod
end