Skip to content

Commit

Permalink
Merge pull request #310 from yui-knk/simplify_normalize_rules
Browse files Browse the repository at this point in the history
Simplify normalize rules
  • Loading branch information
yui-knk authored Dec 24, 2023
2 parents c30569b + ed59e31 commit 95909d0
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 112 deletions.
37 changes: 1 addition & 36 deletions lib/lrama/grammar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
10 changes: 1 addition & 9 deletions lib/lrama/grammar/rule_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions sig/lrama/grammar/rule_builder.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 12 additions & 10 deletions spec/lrama/grammar/rule_builder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
80 changes: 40 additions & 40 deletions spec/lrama/parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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([
Expand Down Expand Up @@ -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([
Expand Down Expand Up @@ -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([
Expand Down Expand Up @@ -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: "<i>"), 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: "<i>"), 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: "<i>"), 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: "<i>"), 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([
Expand Down Expand Up @@ -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([
Expand Down Expand Up @@ -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([
Expand Down Expand Up @@ -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([
Expand Down Expand Up @@ -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([
Expand Down Expand Up @@ -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: "<i>"), 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: "<i>"), 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),
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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: "<i>"), 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: "<i>"), term: false, token_id: 4, nullable: false),
])
expect(grammar.rules).to eq([
Rule.new(
Expand Down
30 changes: 15 additions & 15 deletions spec/lrama/states_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 95909d0

Please sign in to comment.