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.



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

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:



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

def rules
  @rules
end

#stateSymbol (readonly)

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

Returns:

  • (Symbol)

    one of: :declaring, :building, :complete



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

def state
  @state
end

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

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

Returns:



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

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)


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

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.



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

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).


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

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)


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
100
# File 'lib/dendroid/grm_dsl/base_grm_builder.rb', line 75

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::Production.new(lhs, build_symbol_seq(raw_rhs))
  else
    rhs = raw_rhs.map { |raw| build_symbol_seq(raw) }
    new_prod = Dendroid::Syntax::Choice.new(lhs, rhs)
  end
  rules << new_prod
  new_prod
end