diff --git a/lib/lrama/grammar.rb b/lib/lrama/grammar.rb index 01ff9892..42337682 100644 --- a/lib/lrama/grammar.rb +++ b/lib/lrama/grammar.rb @@ -359,29 +359,8 @@ def append_special_symbols @accept_symbol = term end - # 1. Add $accept rule to the top of rules - # 2. Extract action in the middle of RHS into new Empty rule - # 3. Append id and extract action then create Rule - # - # Bison 3.8.2 uses different orders for symbol number and rule number - # when a rule has actions in the middle of a rule. - # - # For example, - # - # `program: $@1 top_compstmt` - # - # Rules are ordered like below, - # - # 1 $@1: ε - # 2 program: $@1 top_compstmt - # - # Symbols are ordered like below, - # - # 164 program - # 165 $@1 - # def normalize_rules - # 1. Add $accept rule to the top of rules + # Add $accept rule to the top of rules accept = @accept_symbol eof = @eof_symbol lineno = @rule_builders.first ? @rule_builders.first.line : 0 @@ -390,24 +369,10 @@ def normalize_rules setup_rules @rule_builders.each do |builder| - # Extract actions in the middle of RHS into new rules. - builder.midrule_action_rules.each do |rule| - @rules << rule - end - builder.rules.each do |rule| - add_nterm(id: rule._lhs) - @rules << rule - end - - builder.parameterizing_rules.each do |rule| add_nterm(id: rule._lhs, tag: rule.lhs_tag) @rules << rule end - - builder.midrule_action_rules.each do |rule| - add_nterm(id: rule._lhs) - end end @rules.sort_by!(&:id) diff --git a/lib/lrama/grammar/rule_builder.rb b/lib/lrama/grammar/rule_builder.rb index 27ff85eb..4730cc39 100644 --- a/lib/lrama/grammar/rule_builder.rb +++ b/lib/lrama/grammar/rule_builder.rb @@ -57,16 +57,8 @@ def setup_rules(parameterizing_resolver) build_rules end - def parameterizing_rules - @parameterizing_rules - end - - def midrule_action_rules - @midrule_action_rules - end - def rules - @rules + @parameterizing_rules + @midrule_action_rules + @rules end private diff --git a/sig/lrama/grammar/rule_builder.rbs b/sig/lrama/grammar/rule_builder.rbs index 7522c77f..924ca509 100644 --- a/sig/lrama/grammar/rule_builder.rbs +++ b/sig/lrama/grammar/rule_builder.rbs @@ -25,8 +25,6 @@ module Lrama def precedence_sym=: (Lexer::Token user_code) -> void def complete_input: () -> void def setup_rules: (Grammar::ParameterizingRuleResolver parameterizing_resolver) -> void - def parameterizing_rules: () -> Array[Rule] - def midrule_action_rules: () -> Array[Rule] def rules: () -> Array[Rule] private diff --git a/spec/lrama/grammar/rule_builder_spec.rb b/spec/lrama/grammar/rule_builder_spec.rb index ff2bedb2..fd6a18cd 100644 --- a/spec/lrama/grammar/rule_builder_spec.rb +++ b/spec/lrama/grammar/rule_builder_spec.rb @@ -347,16 +347,18 @@ class : keyword_class tSTRING tSTRING keyword_end { $class = $tSTRING; } rule_builder.complete_input rule_builder.setup_rules(Lrama::Grammar::ParameterizingRuleResolver.new) - rule = rule_builder.rules.first - rules = rule_builder.midrule_action_rules - - expect(rules.count).to eq 2 - expect(rules[0]._lhs.s_value).to eq '@1' - expect(rules[0].token_code.s_value).to eq '$1' - expect(rules[0].original_rule).to eq rule - expect(rules[1]._lhs.s_value).to eq '$@2' - expect(rules[1].token_code.s_value).to eq '$2 + $3' - expect(rules[1].original_rule).to eq rule + rules = rule_builder.rules + midrule_1 = rules.find {|rule| rule._lhs.s_value == "@1"} + midrule_2 = rules.find {|rule| rule._lhs.s_value == "$@2"} + rule = rules.find {|rule| rule._lhs.s_value == "class"} + + expect(rules.count).to eq 3 + expect(midrule_1._lhs.s_value).to eq '@1' + expect(midrule_1.token_code.s_value).to eq '$1' + expect(midrule_1.original_rule).to eq rule + expect(midrule_2._lhs.s_value).to eq '$@2' + expect(midrule_2.token_code.s_value).to eq '$2 + $3' + expect(midrule_2.original_rule).to eq rule end end diff --git a/spec/lrama/parser_spec.rb b/spec/lrama/parser_spec.rb index 7bb8c057..327b6599 100644 --- a/spec/lrama/parser_spec.rb +++ b/spec/lrama/parser_spec.rb @@ -567,10 +567,10 @@ expect(grammar.nterms.sort_by(&:number)).to match_symbols([ Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 5, tag: nil, term: false, token_id: 0, nullable: false), - Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: true), - Sym.new(id: T::Ident.new(s_value: "option_number"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: true), - Sym.new(id: T::Ident.new(s_value: "alias"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: true), - Sym.new(id: T::Ident.new(s_value: "option_number_alias"), alias_name: nil, number: 9, tag: nil, term: false, token_id: 4, nullable: true), + Sym.new(id: T::Ident.new(s_value: "option_number"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: true), + Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: true), + Sym.new(id: T::Ident.new(s_value: "option_number_alias"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: true), + Sym.new(id: T::Ident.new(s_value: "alias"), alias_name: nil, number: 9, tag: nil, term: false, token_id: 4, nullable: true), ]) expect(grammar.rules).to eq([ @@ -656,10 +656,10 @@ expect(grammar.nterms.sort_by(&:number)).to match_symbols([ Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 5, tag: nil, term: false, token_id: 0, nullable: false), - Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: true), - Sym.new(id: T::Ident.new(s_value: "option_number"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: true), - Sym.new(id: T::Ident.new(s_value: "alias"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: true), - Sym.new(id: T::Ident.new(s_value: "option_number_alias"), alias_name: nil, number: 9, tag: nil, term: false, token_id: 4, nullable: true), + Sym.new(id: T::Ident.new(s_value: "option_number"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: true), + Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: true), + Sym.new(id: T::Ident.new(s_value: "option_number_alias"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: true), + Sym.new(id: T::Ident.new(s_value: "alias"), alias_name: nil, number: 9, tag: nil, term: false, token_id: 4, nullable: true), ]) expect(grammar.rules).to eq([ @@ -744,8 +744,8 @@ expect(grammar.nterms.sort_by(&:number)).to match_symbols([ Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 0, nullable: false), - Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 1, nullable: false), - Sym.new(id: T::Ident.new(s_value: "option_bar"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 2, nullable: true), + Sym.new(id: T::Ident.new(s_value: "option_bar"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 1, nullable: true), + Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 2, nullable: false), ]) expect(grammar.rules).to eq([ @@ -804,10 +804,10 @@ expect(grammar.nterms.sort_by(&:number)).to match_symbols([ Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 5, tag: nil, term: false, token_id: 0, nullable: false), - Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: true), - Sym.new(id: T::Ident.new(s_value: "option_number"), alias_name: nil, number: 7, tag: T::Tag.new(s_value: ""), term: false, token_id: 2, nullable: true), - Sym.new(id: T::Ident.new(s_value: "alias"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: true), - Sym.new(id: T::Ident.new(s_value: "option_number_alias"), alias_name: nil, number: 9, tag: T::Tag.new(s_value: ""), term: false, token_id: 4, nullable: true), + Sym.new(id: T::Ident.new(s_value: "option_number"), alias_name: nil, number: 6, tag: T::Tag.new(s_value: ""), term: false, token_id: 1, nullable: true), + Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: true), + Sym.new(id: T::Ident.new(s_value: "option_number_alias"), alias_name: nil, number: 8, tag: T::Tag.new(s_value: ""), term: false, token_id: 3, nullable: true), + Sym.new(id: T::Ident.new(s_value: "alias"), alias_name: nil, number: 9, tag: nil, term: false, token_id: 4, nullable: true), ]) expect(grammar.rules).to eq([ @@ -896,10 +896,10 @@ expect(grammar.nterms.sort_by(&:number)).to match_symbols([ Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 5, tag: nil, term: false, token_id: 0, nullable: false), - Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: false), - Sym.new(id: T::Ident.new(s_value: "nonempty_list_number"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: false), - Sym.new(id: T::Ident.new(s_value: "alias"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: false), - Sym.new(id: T::Ident.new(s_value: "nonempty_list_number_alias"), alias_name: nil, number: 9, tag: nil, term: false, token_id: 4, nullable: false), + Sym.new(id: T::Ident.new(s_value: "nonempty_list_number"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: false), + Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: false), + Sym.new(id: T::Ident.new(s_value: "nonempty_list_number_alias"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: false), + Sym.new(id: T::Ident.new(s_value: "alias"), alias_name: nil, number: 9, tag: nil, term: false, token_id: 4, nullable: false), ]) expect(grammar.rules).to eq([ @@ -990,10 +990,10 @@ expect(grammar.nterms.sort_by(&:number)).to match_symbols([ Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 5, tag: nil, term: false, token_id: 0, nullable: false), - Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: true), - Sym.new(id: T::Ident.new(s_value: "list_number"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: true), - Sym.new(id: T::Ident.new(s_value: "alias"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: true), - Sym.new(id: T::Ident.new(s_value: "list_number_alias"), alias_name: nil, number: 9, tag: nil, term: false, token_id: 4, nullable: true), + Sym.new(id: T::Ident.new(s_value: "list_number"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: true), + Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: true), + Sym.new(id: T::Ident.new(s_value: "list_number_alias"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: true), + Sym.new(id: T::Ident.new(s_value: "alias"), alias_name: nil, number: 9, tag: nil, term: false, token_id: 4, nullable: true), ]) expect(grammar.rules).to eq([ @@ -1079,9 +1079,9 @@ grammar = Lrama::Parser.new(y, path).parse expect(grammar.nterms.sort_by(&:number)).to match_symbols([ - Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 5, tag: nil, term: false, token_id: 0, nullable: false), - Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: false), - Sym.new(id: T::Ident.new(s_value: "separated_nonempty_list_number"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: false), + Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 5, tag: nil, term: false, token_id: 0, nullable: false), + Sym.new(id: T::Ident.new(s_value: "separated_nonempty_list_number"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: false), + Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: false), ]) expect(grammar.rules).to eq([ @@ -1141,10 +1141,10 @@ grammar = Lrama::Parser.new(y, path).parse expect(grammar.nterms.sort_by(&:number)).to match_symbols([ - Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 5, tag: nil, term: false, token_id: 0, nullable: false), - Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: true), - Sym.new(id: T::Ident.new(s_value: "separated_list_number"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: true), - Sym.new(id: T::Ident.new(s_value: "separated_nonempty_list_number"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: false), + Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 5, tag: nil, term: false, token_id: 0, nullable: false), + Sym.new(id: T::Ident.new(s_value: "separated_list_number"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: true), + Sym.new(id: T::Ident.new(s_value: "separated_nonempty_list_number"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: false), + Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: true), ]) expect(grammar.rules).to eq([ @@ -1225,8 +1225,8 @@ expect(grammar.nterms.sort_by(&:number)).to match_symbols([ Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 0, nullable: false), - Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 1, nullable: true), - Sym.new(id: T::Ident.new(s_value: "defined_option_number"), alias_name: nil, number: 8, tag: T::Tag.new(s_value: ""), term: false, token_id: 2, nullable: true), + Sym.new(id: T::Ident.new(s_value: "defined_option_number"), alias_name: nil, number: 7, tag: T::Tag.new(s_value: ""), term: false, token_id: 1, nullable: true), + Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 2, nullable: true), Sym.new(id: T::Ident.new(s_value: "multi_args_number_string"), alias_name: nil, number: 9, tag: nil, term: false, token_id: 3, nullable: false), Sym.new(id: T::Ident.new(s_value: "multi_args_number_number"), alias_name: nil, number: 10, tag: nil, term: false, token_id: 4, nullable: false), Sym.new(id: T::Ident.new(s_value: "pair_number_string"), alias_name: nil, number: 11, tag: nil, term: false, token_id: 5, nullable: false), @@ -1386,10 +1386,10 @@ expect(grammar.nterms.sort_by(&:number)).to match_symbols([ Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 5, tag: nil, term: false, token_id: 0, nullable: false), - Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: true), - Sym.new(id: T::Ident.new(s_value: "option_number"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: true), - Sym.new(id: T::Ident.new(s_value: "nested_option_number"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: true), - Sym.new(id: T::Ident.new(s_value: "nested_nested_option_number"), alias_name: nil, number: 9, tag: nil, term: false, token_id: 4, nullable: true), + Sym.new(id: T::Ident.new(s_value: "option_number"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 1, nullable: true), + Sym.new(id: T::Ident.new(s_value: "nested_option_number"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 2, nullable: true), + Sym.new(id: T::Ident.new(s_value: "nested_nested_option_number"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 3, nullable: true), + Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 9, tag: nil, term: false, token_id: 4, nullable: true), Sym.new(id: T::Ident.new(s_value: "multi_option_number_string"), alias_name: nil, number: 10, tag: nil, term: false, token_id: 5, nullable: true), Sym.new(id: T::Ident.new(s_value: "nested_multi_option_number"), alias_name: nil, number: 11, tag: nil, term: false, token_id: 6, nullable: true), Sym.new(id: T::Ident.new(s_value: "nested_multi_option_string"), alias_name: nil, number: 12, tag: nil, term: false, token_id: 7, nullable: true) @@ -1700,11 +1700,11 @@ class : keyword_class { code 1 } tSTRING { code 2 } keyword_end { code 3 } grammar = Lrama::Parser.new(y, "parse.y").parse expect(grammar.nterms.sort_by(&:number)).to match_symbols([ - Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 11, tag: nil, term: false, token_id: 0, nullable: false), - Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 12, tag: nil, term: false, token_id: 1, nullable: false), - Sym.new(id: T::Ident.new(s_value: "class"), alias_name: nil, number: 13, tag: T::Tag.new(s_value: ""), term: false, token_id: 2, nullable: false), - Sym.new(id: T::Ident.new(s_value: "$@1"), alias_name: nil, number: 14, tag: nil, term: false, token_id: 3, nullable: true), - Sym.new(id: T::Ident.new(s_value: "$@2"), alias_name: nil, number: 15, tag: nil, term: false, token_id: 4, nullable: true), + Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 11, tag: nil, term: false, token_id: 0, nullable: false), + Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 12, tag: nil, term: false, token_id: 1, nullable: false), + Sym.new(id: T::Ident.new(s_value: "$@1"), alias_name: nil, number: 13, tag: nil, term: false, token_id: 2, nullable: true), + Sym.new(id: T::Ident.new(s_value: "$@2"), alias_name: nil, number: 14, tag: nil, term: false, token_id: 3, nullable: true), + Sym.new(id: T::Ident.new(s_value: "class"), alias_name: nil, number: 15, tag: T::Tag.new(s_value: ""), term: false, token_id: 4, nullable: false), ]) expect(grammar.rules).to eq([ Rule.new( diff --git a/spec/lrama/states_spec.rb b/spec/lrama/states_spec.rb index 07b0cf77..90fbf1d6 100644 --- a/spec/lrama/states_spec.rb +++ b/spec/lrama/states_spec.rb @@ -993,46 +993,46 @@ class go to state 5 $default reduce using rule 1 ($@1) - program go to state 1 - $@1 go to state 2 + $@1 go to state 1 + program go to state 2 State 1 - 0 $accept: program • "EOI" + 2 program: $@1 • expr + 3 expr: • tNUMBER - "EOI" shift, and go to state 3 + tNUMBER shift, and go to state 3 + expr go to state 4 -State 2 - 2 program: $@1 • expr - 3 expr: • tNUMBER +State 2 - tNUMBER shift, and go to state 4 + 0 $accept: program • "EOI" - expr go to state 5 + "EOI" shift, and go to state 5 State 3 - 0 $accept: program "EOI" • + 3 expr: tNUMBER • - $default accept + $default reduce using rule 3 (expr) State 4 - 3 expr: tNUMBER • + 2 program: $@1 expr • - $default reduce using rule 3 (expr) + $default reduce using rule 2 (program) State 5 - 2 program: $@1 expr • + 0 $accept: program "EOI" • - $default reduce using rule 2 (program) + $default accept STR