Class: Dhaka::Parser

Inherits:
Object
  • Object
show all
Includes:
ParserMethods
Defined in:
lib/dhaka/parser/parser.rb

Overview

The parser generator. To generate a parser from a grammar specification ArithmeticPrecedenceGrammar, one would write:

parser = Dhaka::Parser.new(ArithmeticPrecedenceGrammar)

To compile this parser to Ruby source as ArithmeticPrecedenceParser:

parser.compile_to_ruby_source_as(:ArithmeticPrecedenceParser)

which returns a string of Ruby code.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ParserMethods

#parse

Constructor Details

#initialize(grammar, logger = nil) ⇒ Parser

Creates a new parser from the given grammar. Messages are logged by default to STDOUT and the log level is WARN. Shift-reduce conflicts are reported at WARN and reduce-reduce conflicts at ERROR. You may pass in your own logger. Logging at DEBUG shows a lot of progress output.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/dhaka/parser/parser.rb', line 16

def initialize(grammar, logger = nil)
  @shift_actions  = Hash.new {|hash, state| hash[state] = ShiftAction.new(state)}
  @reduce_actions = Hash.new {|hash, production| hash[production] = ReduceAction.new(production)}
  @logger         = logger || default_logger
  @transitions    = Hash.new {|hash, state| hash[state] = {}}
  @grammar        = grammar
  @channels       = Hash.new {|hash, start_item| hash[start_item] = []}
  @states = Hash.new do |hash, kernel|
      closure, channels = grammar.closure(kernel)
      channels.each do |start_item, channel_set|
        @channels[start_item].concat channel_set.to_a
      end
      new_state    = ParserState.new(self, closure)
      hash[kernel] = new_state
      @logger.debug("Created #{new_state.unique_name}.")
      new_state.transition_items.each do |symbol, items|
        destination_kernel = ItemSet.new(items.collect{|item| item.next_item})
        destination_state  = hash[destination_kernel]
        items.each {|item| @channels[item] << grammar.passive_channel(item, destination_state.items[item.next_item])}
        @transitions[new_state][symbol] = destination_state
      end
      new_state
  end
  initialize_states
end

Instance Attribute Details

#grammarObject (readonly)

Returns the value of attribute grammar.



11
12
13
# File 'lib/dhaka/parser/parser.rb', line 11

def grammar
  @grammar
end

Instance Method Details

#compile_to_ruby_source_as(parser_class_name) ⇒ Object

Returns the Ruby source of the generated parser compiled as parser_class_name. This can be written out to a file.



43
44
45
46
47
48
49
50
51
52
# File 'lib/dhaka/parser/parser.rb', line 43

def compile_to_ruby_source_as parser_class_name
  result = "class #{parser_class_name} < Dhaka::CompiledParser\n\n"
  result << "  self.grammar = #{grammar.name}\n\n"
  result << "  start_with #{start_state.id}\n\n"
  states.each do |state|
    result << "#{state.compile_to_ruby_source}\n\n"
  end
  result << "end"
  result
end

#inspectObject



68
69
70
# File 'lib/dhaka/parser/parser.rb', line 68

def inspect
  "<Dhaka::Parser grammar : #{grammar}>"
end

#to_dot(options = {}) ⇒ Object

Returns the dot representation of the parser. If :hide_lookaheads is set to true in the options hash, lookaheads are not written out to the parser states, which is helpful when there are dozens of lookahead symbols for every item in every state.



57
58
59
60
61
62
63
64
65
66
# File 'lib/dhaka/parser/parser.rb', line 57

def to_dot(options = {})
  Dot::Digraph.new(:fontsize => 10, :shape => :box, :size => 5) do |g|
    states.each do |state|
      g.node(state, :label => state.items.values.collect{|item| item.to_s(options)}.join("\n"))
      @transitions[state].each do |symbol, dest_state|
        g.edge(state, dest_state, :label => symbol.name)
      end
    end
  end.to_dot
end