use crate::grammar::Grammar;
use crate::tvec::TVec;
use crate::util::{word_size, Bitmat, Bitv32};
use crate::warshall::reflexive_transitive_closure;
use crate::Symbol;
use crate::{Item, Rule, State, Var};
use log::{debug, log_enabled, trace};
use ramp_table::RampTable;
use std::fmt::Write;
pub(crate) const INITIAL_STATE_SYMBOL: Symbol = Symbol(0);
pub(crate) struct LR0Output {
pub nstates: usize,
pub accessing_symbol: TVec<State, Symbol>,
pub shifts: RampTable<State>,
pub reductions: RampTable<Rule>,
pub derives: RampTable<Rule>,
pub state_items: RampTable<Item>,
}
impl LR0Output {
pub fn nstates(&self) -> usize {
self.nstates
}
}
pub(crate) fn compute_lr0(gram: &Grammar) -> LR0Output {
let derives = set_derives(gram);
let mut kernel_items_count: usize = 0;
let mut symbol_count: Vec<usize> = vec![0; gram.nsyms];
for &symbol in gram.ritem.iter() {
if symbol.is_symbol() {
let symbol = symbol.as_symbol();
kernel_items_count += 1;
symbol_count[symbol.index()] += 1;
}
}
let mut kernel_base: Vec<usize> = vec![0; gram.nsyms];
let mut count: usize = 0;
for i in 0..gram.nsyms {
kernel_base[i] = count;
count += symbol_count[i];
}
let mut kernel_items: Vec<Item> = vec![Item(0); kernel_items_count];
let mut kernel_end: Vec<usize> = vec![0; gram.nsyms];
let mut states: RampTable<Item> = RampTable::new();
let mut accessing_symbol: TVec<State, Symbol> = TVec::new();
states.push_entry_extend(
derives[gram.symbol_to_var(gram.start()).index()]
.iter()
.map(|&item| gram.rrhs(item)),
);
accessing_symbol.push(INITIAL_STATE_SYMBOL);
let mut state_set: Vec<Vec<State>> = vec![vec![]; gram.nitems()];
let first_derives = set_first_derives(gram, &derives);
let mut item_set: Vec<Item> = Vec::with_capacity(gram.nitems());
let mut rule_set: Bitv32 = Bitv32::from_elem(gram.nrules, false);
let mut shift_symbol: Vec<Symbol> = Vec::new();
let mut this_state: usize = 0;
let mut reductions = RampTable::<Rule>::new();
let mut shifts = RampTable::<State>::new();
while this_state < states.len() {
assert!(item_set.len() == 0);
trace!("computing closure for state s{}:", this_state);
closure(
gram,
&states[this_state],
&first_derives,
&mut rule_set,
&mut item_set,
);
save_reductions(gram, &item_set, &mut reductions);
new_item_sets(
&kernel_base,
&mut kernel_items,
&mut kernel_end,
gram,
&item_set,
&mut shift_symbol,
);
shift_symbol.sort();
for symbol in shift_symbol.iter().copied() {
let symbol_items =
&kernel_items[kernel_base[symbol.index()]..kernel_end[symbol.index()]];
let this_state_set: &mut Vec<State> = &mut state_set[symbol_items[0].index()];
let shift_state = if let Some(&existing_state) = this_state_set
.iter()
.find(|state| *symbol_items == states[state.index()])
{
existing_state
} else {
let new_state: State = states.len().into();
states.push_entry_copy(symbol_items);
accessing_symbol.push(symbol);
this_state_set.push(new_state);
new_state
};
shifts.push_value(shift_state);
}
shifts.finish_key();
item_set.clear();
shift_symbol.clear();
this_state += 1;
}
let output = LR0Output {
nstates: states.len(),
accessing_symbol,
reductions,
shifts,
derives,
state_items: states,
};
dump_lr0_output(gram, &output);
output
}
fn dump_lr0_output(gram: &Grammar, output: &LR0Output) {
if !log_enabled!(log::Level::Debug) {
return;
}
debug!("States: (nstates: {})", output.nstates);
for istate in 0..output.nstates {
let state = State(istate as i16);
debug!(
"s{}: (accessing_symbol {})",
state,
gram.name(output.accessing_symbol[state])
);
let items = &output.state_items[istate];
let mut line = String::new();
for i in 0..items.len() {
let rhs = items[i].index();
line.push_str(&format!("item {:4} : ", rhs));
let mut rhs_first = rhs;
while rhs_first > 0 && gram.ritem[rhs_first - 1].is_symbol() {
rhs_first -= 1;
}
let mut j = rhs_first;
while gram.ritem[j].is_symbol() {
let s = gram.ritem[j].as_symbol();
if j == rhs {
line.push_str(" .");
}
line.push_str(&format!(" {}", gram.name(s)));
j += 1;
}
if j == rhs {
line.push_str(" .");
}
if gram.ritem[rhs].is_rule() {
let r = gram.ritem[rhs].as_rule();
write!(
line,
" -> reduction (r{}) {}",
r.index(),
gram.name(gram.rlhs(r)),
)
.unwrap();
}
debug!(" {}", line);
line.clear();
}
for &r in &output.reductions[istate] {
debug!(" reduction: {}", gram.rule_to_str(r));
}
for &s in output.shifts[istate].iter() {
debug!(
" shift: {:-20} --> s{}",
gram.name(output.accessing_symbol[s]),
s.index()
);
}
}
}
fn new_item_sets(
kernel_base: &[usize],
kernel_items: &mut [Item],
kernel_end: &mut [usize],
gram: &Grammar,
item_set: &[Item],
shift_symbol: &mut Vec<Symbol>,
) {
assert!(shift_symbol.len() == 0);
kernel_end.copy_from_slice(kernel_base);
for &item in item_set.iter() {
let symbol = gram.ritem(item);
if symbol.is_symbol() {
let symbol = symbol.as_symbol();
let base = kernel_base[symbol.index()];
let end = &mut kernel_end[symbol.index()];
if *end == base {
shift_symbol.push(symbol);
}
kernel_items[*end] = item + 1;
*end += 1;
}
}
}
fn save_reductions(gram: &Grammar, item_set: &[Item], rules: &mut RampTable<Rule>) {
for &item in item_set {
let sr = gram.ritem(item);
if sr.is_rule() {
rules.push_value(sr.as_rule());
}
}
rules.finish_key();
}
fn set_derives(gram: &Grammar) -> RampTable<Rule> {
let mut derives = RampTable::<Rule>::with_capacity(gram.nsyms, gram.nrules);
for lhs in gram.iter_var_syms() {
for rule in gram.iter_rules() {
if gram.rlhs(rule) == lhs {
derives.push_value(rule as Rule);
}
}
derives.finish_key();
}
if log_enabled!(log::Level::Debug) {
debug!("DERIVES:");
for lhs in gram.iter_vars() {
let lhs_sym = gram.var_to_symbol(lhs);
debug!(" {} derives rules: ", gram.name(lhs_sym));
for &rule in &derives[lhs.index()] {
debug!(" {}", &gram.rule_to_str(rule));
}
}
}
derives
}
pub(crate) fn set_nullable(gram: &Grammar) -> TVec<Symbol, bool> {
let mut nullable: TVec<Symbol, bool> = TVec::from_vec(vec![false; gram.nsyms]);
loop {
let mut done = true;
let mut i = 1;
while i < gram.ritem.len() {
let mut empty = true;
let rule = loop {
let sr = gram.ritem[i];
if sr.is_rule() {
break sr.as_rule();
}
let sym = sr.as_symbol();
if !nullable[sym] {
empty = false;
}
i += 1;
};
if empty {
let sym = gram.rlhs(rule);
if !nullable[sym] {
nullable[sym] = true;
done = false;
}
}
i += 1;
}
if done {
break;
}
}
if log_enabled!(log::Level::Debug) {
debug!("Nullable symbols:");
for sym in gram.iter_var_syms() {
if nullable[sym] {
debug!("{}", gram.name(sym));
}
}
}
nullable
}
fn set_eff(gram: &Grammar, derives: &RampTable<Rule>) -> Bitmat {
let nvars = gram.nvars;
let mut eff: Bitmat = Bitmat::new(nvars, nvars);
for row in 0..nvars {
for &rule in &derives[row] {
let derived_rule_or_symbol = gram.ritem(gram.rrhs(rule));
if derived_rule_or_symbol.is_rule() {
continue;
}
let symbol = derived_rule_or_symbol.as_symbol();
if gram.is_var(symbol) {
eff.set(row, gram.symbol_to_var(symbol).index());
}
}
}
reflexive_transitive_closure(&mut eff);
print_eff(gram, &eff);
eff
}
fn print_eff(gram: &Grammar, eff: &Bitmat) {
debug!("Epsilon Free Firsts");
for i in 0..eff.rows {
let var = Var(i as i16);
debug!("{}", gram.name(gram.var_to_symbol(var)));
for j in eff.iter_ones_in_row(i) {
debug!(" {}", gram.name(gram.var_to_symbol(Var(j as i16))));
}
}
}
pub(crate) fn set_first_derives(gram: &Grammar, derives: &RampTable<Rule>) -> Bitmat {
let eff = set_eff(gram, derives);
assert!(eff.rows == gram.nvars);
assert!(eff.cols == gram.nvars);
let mut first_derives = Bitmat::new(gram.nvars, gram.nrules);
for (i, j) in eff.iter_ones() {
for &rule in &derives[j] {
first_derives.set(i, rule.index());
}
}
print_first_derives(gram, &first_derives);
first_derives
}
pub(crate) fn closure(
gram: &Grammar,
nucleus: &[Item],
first_derives: &Bitmat,
rule_set: &mut Bitv32,
item_set: &mut Vec<Item>,
) {
assert!(item_set.len() == 0);
let rulesetsize = word_size(rule_set.nbits);
rule_set.set_all(false);
for &item in nucleus.iter() {
let symbol_or_rule = gram.ritem(item);
if symbol_or_rule.is_symbol() {
let symbol = symbol_or_rule.as_symbol();
if gram.is_var(symbol) {
let var = gram.symbol_to_var(symbol);
let dsp = var.index() * first_derives.rowsize;
for i in 0..rulesetsize {
rule_set.data[i] |= first_derives.data[dsp + i];
}
}
}
}
let mut i: usize = 0; for rule in rule_set.iter_ones() {
let item = gram.rrhs[rule];
while i < nucleus.len() && nucleus[i] < item {
item_set.push(nucleus[i]);
i += 1;
}
item_set.push(item);
while i < nucleus.len() && nucleus[i] == item {
i += 1;
}
}
while i < nucleus.len() {
item_set.push(nucleus[i]);
i += 1;
}
}
fn print_first_derives(gram: &Grammar, first_derives: &Bitmat) {
debug!("");
debug!("First Derives");
debug!("");
for i in 0..gram.nvars {
let var = Var(i as i16);
debug!("{} derives:", gram.name(gram.var_to_symbol(var)));
for j in first_derives.iter_ones_in_row(i) {
debug!(" {}", gram.rule_to_str(Rule(j as i16)));
}
}
}