Add RuleSet#id to use when reducing

Parser will know what state to go to after reducing a Rule based on the
RuleSet ID.
Start on Parser class.
This commit is contained in:
Josh Holtrop 2022-06-21 20:07:27 -04:00
parent 60e2818075
commit f17efe8c82
4 changed files with 85 additions and 5 deletions

View File

@ -118,7 +118,7 @@ class <%= @classname %>
} }
<% transition_table, state_table = @lexer.build_tables %> <% transition_table, state_table = @lexer.build_tables %>
private static const Transition transitions[] = [ private static immutable Transition transitions[] = [
<% transition_table.each do |transition_table_entry| %> <% transition_table.each do |transition_table_entry| %>
Transition(<%= transition_table_entry[:first] %>u, <%= transition_table_entry[:last] %>u, <%= transition_table_entry[:destination] %>u), Transition(<%= transition_table_entry[:first] %>u, <%= transition_table_entry[:last] %>u, <%= transition_table_entry[:destination] %>u),
<% end %> <% end %>
@ -251,4 +251,54 @@ class <%= @classname %>
return cast(uint)-1; return cast(uint)-1;
} }
} }
static class Parser
{
private struct Shift
{
uint token_id;
uint state_id;
}
private struct Reduce
{
uint token_id;
uint rule_id;
uint rule_set_id;
}
private struct State
{
uint shift_table_index;
uint n_shift_entries;
uint reduce_table_index;
uint n_reduce_entries;
}
<% state_table, shift_table, reduce_table = @parser.build_tables %>
private static immutable Shift shifts[] = [
<% shift_table.each do |shift| %>
Shift(<%= shift[:token_id] %>u, <%= shift[:state_id] %>u),
<% end %>
];
private static immutable Reduce reduces[] = [
<% reduce_table.each do |reduce| %>
Reduce(<%= reduce[:token_id] %>u, <%= reduce[:rule_id] %>u, <%= reduce[:rule_set_id] %>u),
<% end %>
];
private static immutable State states[] = [
<% state_table.each do |state| %>
State(<%= state[:shift_index] %>u, <%= state[:n_shifts] %>u, <%= state[:reduce_index] %>u, <%= state[:n_reduces] %>u),
<% end %>
];
private Lexer m_lexer;
this(const(ubyte) * input, size_t input_length)
{
m_lexer = new Lexer(input, input_length);
}
}
} }

View File

@ -33,7 +33,9 @@ class Propane
if tokens_by_name.include?(rule.name) if tokens_by_name.include?(rule.name)
raise Error.new("Rule name collides with token name #{rule.name.inspect}") raise Error.new("Rule name collides with token name #{rule.name.inspect}")
end end
rule_sets[rule.name] ||= RuleSet.new(rule.name) @_rule_set_id ||= @grammar.tokens.size
rule_sets[rule.name] ||= RuleSet.new(rule.name, @_rule_set_id)
@_rule_set_id += 1
rule.rule_set = rule_sets[rule.name] rule.rule_set = rule_sets[rule.name]
rule_sets[rule.name] << rule rule_sets[rule.name] << rule
end end

View File

@ -60,22 +60,43 @@ class Propane
def build_tables def build_tables
shift_table = [] shift_table = []
state_table = [] state_table = []
reduce_table = []
@item_sets.each do |item_set| @item_sets.each do |item_set|
shift_entries = item_set.following_symbols.select do |following_symbol| shift_entries = item_set.following_symbols.select do |following_symbol|
following_symbol.is_a?(Token) following_symbol.is_a?(Token)
end.map do |following_symbol| end.map do |following_symbol|
state_id =
if following_symbol == @eof_token
0
else
item_set.following_item_set[following_symbol].id
end
{ {
token_id: following_symbol.id, token_id: following_symbol.id,
state_id: item_set.following_item_set[following_symbol].id, state_id: state_id,
} }
end end
reduce_entries =
case ra = item_set.reduce_actions
when Rule
[{token_id: TOKEN_NONE, rule_id: ra.id, rule_set_id: ra.rule_set.id}]
when Hash
ra.map do |token, rule|
{token_id: token.id, rule_id: rule.id, rule_set_id: rule.rule_set.id}
end
else
[]
end
state_table << { state_table << {
shift_index: shift_table.size, shift_index: shift_table.size,
n_shifts: shift_entries.size, n_shifts: shift_entries.size,
reduce_index: reduce_table.size,
n_reduces: reduce_entries.size,
} }
shift_table += shift_entries shift_table += shift_entries
reduce_table += reduce_entries
end end
[state_table, shift_table] [state_table, shift_table, reduce_table]
end end
private private

View File

@ -2,6 +2,10 @@ class Propane
class RuleSet class RuleSet
# @return [Integer]
# ID of the RuleSet.
attr_accessor :id
# @return [String] # @return [String]
# Name of the RuleSet. # Name of the RuleSet.
attr_reader :name attr_reader :name
@ -18,7 +22,10 @@ class Propane
# #
# @param name [String] # @param name [String]
# Name of the RuleSet. # Name of the RuleSet.
def initialize(name) # @param id [Integer]
# ID of the RuleSet.
def initialize(name, id)
@id = id
@name = name @name = name
@rules = [] @rules = []
@could_be_empty = false @could_be_empty = false