diff --git a/cli/src/generate/build_tables/minimize_parse_table.rs b/cli/src/generate/build_tables/minimize_parse_table.rs index db7e3961..5ecde0fd 100644 --- a/cli/src/generate/build_tables/minimize_parse_table.rs +++ b/cli/src/generate/build_tables/minimize_parse_table.rs @@ -26,6 +26,7 @@ pub(crate) fn minimize_parse_table( minimizer.merge_compatible_states(); minimizer.remove_unit_reductions(); minimizer.remove_unused_states(); + minimizer.reorder_states_by_descending_size(); } struct Minimizer<'a> { @@ -454,4 +455,37 @@ impl<'a> Minimizer<'a> { original_state_id += 1; } } + + fn reorder_states_by_descending_size(&mut self) { + // Get a mapping of old state index -> new_state_index + let mut old_ids_by_new_id = (0..self.parse_table.states.len()).collect::>(); + &old_ids_by_new_id.sort_unstable_by_key(|i| { + // Don't changes states 0 (the error state) or 1 (the start state). + if *i <= 1 { + return *i as i64 - 1_000_000; + } + + // Reorder all the other states by descending symbol count. + let state = &self.parse_table.states[*i]; + -((state.terminal_entries.len() + state.nonterminal_entries.len()) as i64) + }); + + // Get the inverse mapping + let mut new_ids_by_old_id = vec![0; old_ids_by_new_id.len()]; + for (id, old_id) in old_ids_by_new_id.iter().enumerate() { + new_ids_by_old_id[*old_id] = id; + } + + // Reorder the parse states and update their references to reflect + // the new ordering. + self.parse_table.states = old_ids_by_new_id + .iter() + .map(|old_id| { + let mut state = ParseState::default(); + mem::swap(&mut state, &mut self.parse_table.states[*old_id]); + state.update_referenced_states(|id, _| new_ids_by_old_id[id]); + state + }) + .collect(); + } }