lib/lrama/grammar.rb in lrama-0.6.9 vs lib/lrama/grammar.rb in lrama-0.6.10

- old
+ new

@@ -1,45 +1,42 @@ +# frozen_string_literal: true + require "forwardable" -require "lrama/grammar/auxiliary" -require "lrama/grammar/binding" -require "lrama/grammar/code" -require "lrama/grammar/counter" -require "lrama/grammar/destructor" -require "lrama/grammar/error_token" -require "lrama/grammar/parameterizing_rule" -require "lrama/grammar/percent_code" -require "lrama/grammar/precedence" -require "lrama/grammar/printer" -require "lrama/grammar/reference" -require "lrama/grammar/rule" -require "lrama/grammar/rule_builder" -require "lrama/grammar/symbol" -require "lrama/grammar/symbols" -require "lrama/grammar/type" -require "lrama/grammar/union" -require "lrama/lexer" +require_relative "grammar/auxiliary" +require_relative "grammar/binding" +require_relative "grammar/code" +require_relative "grammar/counter" +require_relative "grammar/destructor" +require_relative "grammar/error_token" +require_relative "grammar/parameterizing_rule" +require_relative "grammar/percent_code" +require_relative "grammar/precedence" +require_relative "grammar/printer" +require_relative "grammar/reference" +require_relative "grammar/rule" +require_relative "grammar/rule_builder" +require_relative "grammar/symbol" +require_relative "grammar/symbols" +require_relative "grammar/type" +require_relative "grammar/union" +require_relative "lexer" module Lrama # Grammar is the result of parsing an input grammar file class Grammar extend Forwardable - attr_reader :percent_codes, :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux - attr_accessor :union, :expect, - :printers, :error_tokens, - :lex_param, :parse_param, :initial_action, + attr_reader :percent_codes, :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol, :aux, :parameterizing_rule_resolver + attr_accessor :union, :expect, :printers, :error_tokens, :lex_param, :parse_param, :initial_action, :after_shift, :before_reduce, :after_reduce, :after_shift_error_token, :after_pop_stack, - :symbols_resolver, :types, - :rules, :rule_builders, - :sym_to_rules, :no_stdlib + :symbols_resolver, :types, :rules, :rule_builders, :sym_to_rules, :no_stdlib, :locations def_delegators "@symbols_resolver", :symbols, :nterms, :terms, :add_nterm, :add_term, :find_symbol_by_number!, :find_symbol_by_id!, :token_to_symbol, :find_symbol_by_s_value!, :fill_symbol_number, :fill_nterm_type, :fill_printer, :fill_destructor, :fill_error_token, :sort_by_number! - def initialize(rule_counter) @rule_counter = rule_counter # Code defined by "%code" @percent_codes = [] @@ -57,14 +54,19 @@ @error_symbol = nil @undef_symbol = nil @accept_symbol = nil @aux = Auxiliary.new @no_stdlib = false + @locations = false append_special_symbols end + def create_rule_builder(rule_counter, midrule_action_counter) + RuleBuilder.new(rule_counter, midrule_action_counter, @parameterizing_rule_resolver) + end + def add_percent_code(id:, code:) @percent_codes << PercentCode.new(id.s_value, code.s_value) end def add_destructor(ident_or_tags:, token_code:, lineno:) @@ -139,18 +141,20 @@ def epilogue=(epilogue) @aux.epilogue = epilogue end def prepare + resolve_inline_rules normalize_rules collect_symbols set_lhs_and_rhs fill_default_precedence fill_symbols fill_sym_to_rules compute_nullable compute_first_set + set_locations end # TODO: More validation methods # # * Validation for no_declared_type_reference @@ -253,11 +257,11 @@ end end def setup_rules @rule_builders.each do |builder| - builder.setup_rules(@parameterizing_rule_resolver) + builder.setup_rules end end def append_special_symbols # YYEMPTY (token_id: -2, number: -2) is added when a template is evaluated @@ -287,14 +291,27 @@ term = add_nterm(id: Lrama::Lexer::Token::Ident.new(s_value: "$accept")) term.accept_symbol = true @accept_symbol = term end + def resolve_inline_rules + while @rule_builders.any? {|r| r.has_inline_rules? } do + @rule_builders = @rule_builders.flat_map do |builder| + if builder.has_inline_rules? + builder.resolve_inline_rules + else + builder + end + end + end + end + def normalize_rules # Add $accept rule to the top of rules - lineno = @rule_builders.first ? @rule_builders.first.line : 0 - @rules << Rule.new(id: @rule_counter.increment, _lhs: @accept_symbol.id, _rhs: [@rule_builders.first.lhs, @eof_symbol.id], token_code: nil, lineno: lineno) + rule_builder = @rule_builders.first # : RuleBuilder + lineno = rule_builder ? rule_builder.line : 0 + @rules << Rule.new(id: @rule_counter.increment, _lhs: @accept_symbol.id, _rhs: [rule_builder.lhs, @eof_symbol.id], token_code: nil, lineno: lineno) setup_rules @rule_builders.each do |builder| builder.rules.each do |rule| @@ -368,14 +385,18 @@ errors = [] rules.each do |rule| next if rule.lhs.nterm? - errors << "[BUG] LHS of #{rule} (line: #{rule.lineno}) is term. It should be nterm." + errors << "[BUG] LHS of #{rule.display_name} (line: #{rule.lineno}) is term. It should be nterm." end return if errors.empty? raise errors.join("\n") + end + + def set_locations + @locations = @locations || @rules.any? {|rule| rule.contains_at_reference? } end end end