1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
/*
* Copyright 2022 Arnaud Golfouse
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
//! Structures outputed by [`compute_table`](crate::compute_table).
pub mod error;
/// Contains [`Lookahead`].
mod lookahead;
/// Contains things related to [`State`], [`Item`] and [`Action`].
mod state;
mod statistics;
pub use self::{
error::Error,
lookahead::Lookahead,
state::{Action, ActionTable, GotoTable, Item, State, StateIdx},
statistics::Statistics,
};
use crate::{grammar_data::GrammarData, indices::StateIdxRaw, input::Node, structures::Map};
use std::collections::BTreeMap;
/// The parsing table generated by the [`IELR`](crate::compute_table) algorithm.
#[derive(Debug, Clone)]
pub struct Table {
/// States of the parsing table.
pub states: Vec<State>,
/// For a node `n`, gives the index of the state on which to start to parse `n`.
pub(crate) starting_states: BTreeMap<Node, StateIdx>,
}
impl Table {
/// Get the starting state for `node` if the table can start here.
pub fn get_starting_state(&self, node: Node) -> Option<StateIdx> {
self.starting_states.get(&node).copied()
}
/// Get all possible starting nodes of this table, and their associated state.
pub fn get_all_starts(&self) -> impl Iterator<Item = (Node, StateIdx)> + '_ {
self.starting_states
.iter()
.map(|(node, state)| (*node, *state))
}
/// Fill all reduction information, based on items lookaheads.
// TODO: merge the items that only differ by precedence annotations
pub(crate) fn finish(&mut self, grammar_data: &GrammarData) {
let end_states = {
let mut end_states = Map::default();
for (node, &state) in &self.starting_states {
let state = &self.states[state];
let end_state = state.goto_table[node];
end_states.insert(end_state, *node);
}
end_states
};
for (state_idx, state) in self.states.iter_mut().enumerate() {
let state_idx = StateIdx(state_idx as StateIdxRaw);
let mut has_reduce_on_eof = false;
for item in &mut state.items {
let rhs = grammar_data.get_rhs(item.production).unwrap_or_default();
if item.index as usize != rhs.len() {
continue;
}
for &lookahead in &item.lookaheads {
has_reduce_on_eof |= lookahead == Lookahead::Eof;
state
.action_table
.insert(lookahead, Action::Reduce(item.production));
}
}
if let Some(&node) = end_states.get(&state_idx) {
if has_reduce_on_eof {
todo!("handle reduce/accept conflicts")
} else {
state
.action_table
.insert(Lookahead::Eof, Action::Accept(node));
}
}
}
}
}