Class: Lrama::Grammar

Inherits:
Object
  • Object
show all
Defined in:
lib/lrama/grammar.rb

Overview

Grammar is the result of parsing an input grammar file

Defined Under Namespace

Classes: Aux

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeGrammar

Returns a new instance of Grammar.



296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/lrama/grammar.rb', line 296

def initialize
  @printers = []
  @symbols = []
  @types = []
  @_rules = []
  @rules = []
  @sym_to_rules = {}
  @empty_symbol = nil
  @eof_symbol = nil
  @error_symbol = nil
  @undef_symbol = nil
  @accept_symbol = nil
  @aux = Aux.new

  append_special_symbols
end

Instance Attribute Details

#_rulesObject

Returns the value of attribute _rules.



289
290
291
# File 'lib/lrama/grammar.rb', line 289

def _rules
  @_rules
end

#accept_symbolObject (readonly)

Returns the value of attribute accept_symbol.



288
289
290
# File 'lib/lrama/grammar.rb', line 288

def accept_symbol
  @accept_symbol
end

#auxObject (readonly)

Returns the value of attribute aux.



288
289
290
# File 'lib/lrama/grammar.rb', line 288

def aux
  @aux
end

#eof_symbolObject (readonly)

Returns the value of attribute eof_symbol.



288
289
290
# File 'lib/lrama/grammar.rb', line 288

def eof_symbol
  @eof_symbol
end

#error_symbolObject (readonly)

Returns the value of attribute error_symbol.



288
289
290
# File 'lib/lrama/grammar.rb', line 288

def error_symbol
  @error_symbol
end

#expectObject

Returns the value of attribute expect.



289
290
291
# File 'lib/lrama/grammar.rb', line 289

def expect
  @expect
end

#initial_actionObject

Returns the value of attribute initial_action.



289
290
291
# File 'lib/lrama/grammar.rb', line 289

def initial_action
  @initial_action
end

#lex_paramObject

Returns the value of attribute lex_param.



289
290
291
# File 'lib/lrama/grammar.rb', line 289

def lex_param
  @lex_param
end

#parse_paramObject

Returns the value of attribute parse_param.



289
290
291
# File 'lib/lrama/grammar.rb', line 289

def parse_param
  @parse_param
end

#printersObject

Returns the value of attribute printers.



289
290
291
# File 'lib/lrama/grammar.rb', line 289

def printers
  @printers
end

#rulesObject

Returns the value of attribute rules.



289
290
291
# File 'lib/lrama/grammar.rb', line 289

def rules
  @rules
end

#sym_to_rulesObject

Returns the value of attribute sym_to_rules.



289
290
291
# File 'lib/lrama/grammar.rb', line 289

def sym_to_rules
  @sym_to_rules
end

#symbolsObject

Returns the value of attribute symbols.



289
290
291
# File 'lib/lrama/grammar.rb', line 289

def symbols
  @symbols
end

#typesObject

Returns the value of attribute types.



289
290
291
# File 'lib/lrama/grammar.rb', line 289

def types
  @types
end

#undef_symbolObject (readonly)

Returns the value of attribute undef_symbol.



288
289
290
# File 'lib/lrama/grammar.rb', line 288

def undef_symbol
  @undef_symbol
end

#unionObject

Returns the value of attribute union.



289
290
291
# File 'lib/lrama/grammar.rb', line 289

def union
  @union
end

Instance Method Details

#add_left(sym, precedence) ⇒ Object



363
364
365
# File 'lib/lrama/grammar.rb', line 363

def add_left(sym, precedence)
  set_precedence(sym, Precedence.new(type: :left, precedence: precedence))
end

#add_nonassoc(sym, precedence) ⇒ Object



359
360
361
# File 'lib/lrama/grammar.rb', line 359

def add_nonassoc(sym, precedence)
  set_precedence(sym, Precedence.new(type: :nonassoc, precedence: precedence))
end

#add_nterm(id:, alias_name: nil, tag: nil) ⇒ Object



342
343
344
345
346
347
348
349
350
351
352
353
# File 'lib/lrama/grammar.rb', line 342

def add_nterm(id:, alias_name: nil, tag: nil)
  return if @symbols.find {|s| s.id == id }

  sym = Symbol.new(
    id: id, alias_name: alias_name, number: nil, tag: tag,
    term: false, token_id: nil, nullable: nil,
  )
  @symbols << sym
  @nterms = nil

  return sym
end

#add_printer(ident_or_tags:, code:, lineno:) ⇒ Object



313
314
315
# File 'lib/lrama/grammar.rb', line 313

def add_printer(ident_or_tags:, code:, lineno:)
  @printers << Printer.new(ident_or_tags: ident_or_tags, code: code, lineno: lineno)
end

#add_right(sym, precedence) ⇒ Object



367
368
369
# File 'lib/lrama/grammar.rb', line 367

def add_right(sym, precedence)
  set_precedence(sym, Precedence.new(type: :right, precedence: precedence))
end

#add_rule(lhs:, rhs:, lineno:) ⇒ Object



380
381
382
# File 'lib/lrama/grammar.rb', line 380

def add_rule(lhs:, rhs:, lineno:)
  @_rules << [lhs, rhs, lineno]
end

#add_term(id:, alias_name: nil, tag: nil, token_id: nil, replace: false) ⇒ Object



317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# File 'lib/lrama/grammar.rb', line 317

def add_term(id:, alias_name: nil, tag: nil, token_id: nil, replace: false)
  if token_id && (sym = @symbols.find {|s| s.token_id == token_id })
    if replace
      sym.id = id
      sym.alias_name = alias_name
      sym.tag = tag
    end

    return sym
  end

  if sym = @symbols.find {|s| s.id == id }
    return sym
  end

  sym = Symbol.new(
    id: id, alias_name: alias_name, number: nil, tag: tag,
    term: true, token_id: token_id, nullable: false
  )
  @symbols << sym
  @terms = nil

  return sym
end

#add_type(id:, tag:) ⇒ Object



355
356
357
# File 'lib/lrama/grammar.rb', line 355

def add_type(id:, tag:)
  @types << Type.new(id: id, tag: tag)
end

#build_code(type, token_code) ⇒ Object



392
393
394
395
# File 'lib/lrama/grammar.rb', line 392

def build_code(type, token_code)
  build_references(token_code)
  Code.new(type: type, token_code: token_code)
end

#build_references(token_code) ⇒ Object



384
385
386
387
388
389
390
# File 'lib/lrama/grammar.rb', line 384

def build_references(token_code)
  token_code.references.map! do |type, number, tag, first_column, last_column|
    Reference.new(type: type, number: number, ex_tag: tag, first_column: first_column, last_column: last_column)
  end

  token_code
end

#compute_nullableObject



430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
# File 'lib/lrama/grammar.rb', line 430

def compute_nullable
  @rules.each do |rule|
    case
    when rule.rhs.empty?
      rule.nullable = true
    when rule.rhs.any?(&:term)
      rule.nullable = false
    else
      # noop
    end
  end

  while true do
    rs  = @rules.select {|e| e.nullable.nil? }
    nts = nterms.select {|e| e.nullable.nil? }
    rule_count_1  = rs.count
    nterm_count_1 = nts.count

    rs.each do |rule|
      if rule.rhs.all?(&:nullable)
        rule.nullable = true
      end
    end

    nts.each do |nterm|
      find_rules_by_symbol!(nterm).each do |rule|
        if rule.nullable
          nterm.nullable = true
        end
      end
    end

    rule_count_2  = @rules.count {|e| e.nullable.nil? }
    nterm_count_2 = nterms.count {|e| e.nullable.nil? }

    if (rule_count_1 == rule_count_2) && (nterm_count_1 == nterm_count_2)
      break
    end
  end

  rules.select {|r| r.nullable.nil? }.each do |rule|
    rule.nullable = false
  end

  nterms.select {|r| r.nullable.nil? }.each do |nterm|
    nterm.nullable = false
  end
end

#epilogue=(epilogue) ⇒ Object



409
410
411
# File 'lib/lrama/grammar.rb', line 409

def epilogue=(epilogue)
  @aux.epilogue = epilogue
end

#epilogue_first_lineno=(epilogue_first_lineno) ⇒ Object



405
406
407
# File 'lib/lrama/grammar.rb', line 405

def epilogue_first_lineno=(epilogue_first_lineno)
  @aux.epilogue_first_lineno = epilogue_first_lineno
end

#find_rules_by_symbol(sym) ⇒ Object



513
514
515
# File 'lib/lrama/grammar.rb', line 513

def find_rules_by_symbol(sym)
  @sym_to_rules[sym.number]
end

#find_rules_by_symbol!(sym) ⇒ Object



509
510
511
# File 'lib/lrama/grammar.rb', line 509

def find_rules_by_symbol!(sym)
  find_rules_by_symbol(sym) || (raise "Rules for #{sym} not found")
end

#find_symbol_by_id(id) ⇒ Object



489
490
491
492
493
494
# File 'lib/lrama/grammar.rb', line 489

def find_symbol_by_id(id)
  @symbols.find do |sym|
    # TODO: validate uniqueness of Token#s_value and Symbol#alias_name
    sym.id == id || sym.alias_name == id.s_value
  end
end

#find_symbol_by_id!(id) ⇒ Object



496
497
498
# File 'lib/lrama/grammar.rb', line 496

def find_symbol_by_id!(id)
  find_symbol_by_id(id) || (raise "Symbol not found: #{id}")
end

#find_symbol_by_number!(number) ⇒ Object



500
501
502
503
504
505
506
507
# File 'lib/lrama/grammar.rb', line 500

def find_symbol_by_number!(number)
  sym = @symbols[number]

  raise "Symbol not found: #{number}" unless sym
  raise "[BUG] Symbol number mismatch. #{number}, #{sym}" if sym.number != number

  sym
end

#find_symbol_by_s_value(s_value) ⇒ Object



479
480
481
482
483
# File 'lib/lrama/grammar.rb', line 479

def find_symbol_by_s_value(s_value)
  @symbols.find do |sym|
    sym.id.s_value == s_value
  end
end

#find_symbol_by_s_value!(s_value) ⇒ Object



485
486
487
# File 'lib/lrama/grammar.rb', line 485

def find_symbol_by_s_value!(s_value)
  find_symbol_by_s_value(s_value) || (raise "Symbol not found: #{s_value}")
end

#ntermsObject



529
530
531
# File 'lib/lrama/grammar.rb', line 529

def nterms
  @nterms ||= @symbols.select(&:nterm?)
end

#nterms_countObject



525
526
527
# File 'lib/lrama/grammar.rb', line 525

def nterms_count
  nterms.count
end

#prepareObject



413
414
415
416
417
418
419
420
421
422
423
# File 'lib/lrama/grammar.rb', line 413

def prepare
  normalize_rules
  collect_symbols
  replace_token_with_symbol
  fill_symbol_number
  fill_default_precedence
  fill_sym_to_rules
  fill_nterm_type
  fill_symbol_printer
  @symbols.sort_by!(&:number)
end

#prologue=(prologue) ⇒ Object



401
402
403
# File 'lib/lrama/grammar.rb', line 401

def prologue=(prologue)
  @aux.prologue = prologue
end

#prologue_first_lineno=(prologue_first_lineno) ⇒ Object



397
398
399
# File 'lib/lrama/grammar.rb', line 397

def prologue_first_lineno=(prologue_first_lineno)
  @aux.prologue_first_lineno = prologue_first_lineno
end

#set_precedence(sym, precedence) ⇒ Object



371
372
373
374
# File 'lib/lrama/grammar.rb', line 371

def set_precedence(sym, precedence)
  raise "" if sym.nterm?
  sym.precedence = precedence
end

#set_union(code, lineno) ⇒ Object



376
377
378
# File 'lib/lrama/grammar.rb', line 376

def set_union(code, lineno)
  @union = Union.new(code: code, lineno: lineno)
end

#termsObject



521
522
523
# File 'lib/lrama/grammar.rb', line 521

def terms
  @terms ||= @symbols.select(&:term?)
end

#terms_countObject



517
518
519
# File 'lib/lrama/grammar.rb', line 517

def terms_count
  terms.count
end

#validate!Object

TODO: More validation methods



426
427
428
# File 'lib/lrama/grammar.rb', line 426

def validate!
  validate_symbol_number_uniqueness!
end