Class: EBNF::Parser

Inherits:
Object
  • Object
show all
Includes:
EBNF::PEG::Parser, Terminals
Defined in:
lib/ebnf/parser.rb

Constant Summary

Constants included from Terminals

Terminals::CHAR, Terminals::HEX, Terminals::LHS, Terminals::O_RANGE, Terminals::PASS, Terminals::POSTFIX, Terminals::RANGE, Terminals::RANGE_NOT_LHS, Terminals::R_CHAR, Terminals::STRING1, Terminals::STRING2, Terminals::SYMBOL, Terminals::SYMBOL_BASE

Instance Attribute Summary collapse

Attributes included from EBNF::PEG::Parser

#packrat, #scanner, #whitespace

Instance Method Summary collapse

Methods included from EBNF::PEG::Parser

#clear_packrat, #debug, #depth, #error, #find_rule, #onFinish, #onStart, #onTerminal, #parse, #prod_data, #progress, #terminal_options, #terminal_regexp, #update_furthest_failure, #warn

Constructor Details

#initialize(input, **options, &block) ⇒ EBNFParser

Parser invocation.

On start, yield ourselves if a block is given, otherwise, return this parser instance

Parameters:

  • input (#read, #to_s)
  • options (Hash{Symbol => Object})

Options Hash (**options):

  • :level (Boolean)

    Trace level. 0(debug), 1(info), 2(warn), 3(error).



293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/ebnf/parser.rb', line 293

def initialize(input, **options, &block)
  # If the `level` option is set, instantiate a logger for collecting trace information.
  if options.key?(:level)
    options[:logger] ||= Logger.new(STDERR).
      tap {|x| x.level = options[:level]}.
      tap {|x| x.formatter = lambda {|severity, datetime, progname, msg| "#{severity} #{msg}\n"}}
  end

  # This is established on the first rule.
  self.class.instance_variable_set(:@lhs_includes_identifier, nil)

  # Read input, if necessary, which will be used in a Scanner.
  @input = input.respond_to?(:read) ? input.read : input.to_s

  parsing_terminals = false
  @ast = []
  parse(@input, :ebnf, EBNFMeta::RULES,
                       # Use an optimized Regexp for whitespace
                       whitespace: EBNF::Terminals::PASS,
                       **options
  ) do |context, *data|
    rule = case context
    when :terminals
      # After parsing `@terminals`
      # This changes the state of the parser to treat subsequent rules as terminals.
      parsing_terminals = true
      rule = EBNF::Rule.new(nil, nil, data.first, kind: :terminals)
    when :pass
      # After parsing `@pass`
      # This defines a specific rule for whitespace.
      rule = EBNF::Rule.new(nil, nil, data.first, kind: :pass)
    when :rule
      # A rule which has already been turned into a `Rule` object.
      rule = data.first
      rule.kind = :terminal if parsing_terminals
      rule
    end
    @ast << rule if rule
  end
rescue EBNF::PEG::Parser::Error => e
  raise SyntaxError, e.message
end

Instance Attribute Details

#astArray<EBNF::Rule> (readonly)

Abstract syntax tree from parse

Returns:



12
13
14
# File 'lib/ebnf/parser.rb', line 12

def ast
  @ast
end

#lhs_includes_identifierObject (readonly)

Set on first rule



15
16
17
# File 'lib/ebnf/parser.rb', line 15

def lhs_includes_identifier
  @lhs_includes_identifier
end

#rangeObject (readonly)

Regular expression to match a […] range, which may be distinguisehd from an LHS



18
19
20
# File 'lib/ebnf/parser.rb', line 18

def range
  @range
end