Make a trait for lookahead

This commit is contained in:
Niko Matsakis 2016-02-28 07:48:40 -05:00
parent b0b7735bbc
commit 19a0852539
4 changed files with 48 additions and 28 deletions

View File

@ -3,34 +3,34 @@
use collections::Map; use collections::Map;
use grammar::repr::*; use grammar::repr::*;
use itertools::Itertools; use itertools::Itertools;
use std::fmt::{Debug, Formatter, Error}; use std::fmt::{Debug, Display, Formatter, Error};
use std::rc::Rc; use std::rc::Rc;
use util::Prefix; use util::Prefix;
use super::lookahead::Token; use super::lookahead::*;
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Item<'grammar, L: Clone> { pub struct Item<'grammar, L: Lookahead> {
pub production: &'grammar Production, pub production: &'grammar Production,
/// the dot comes before `index`, so `index` would be 1 for X = A (*) B C /// the dot comes before `index`, so `index` would be 1 for X = A (*) B C
pub index: usize, pub index: usize,
pub lookahead: L, pub lookahead: L,
} }
pub type LR0Item<'grammar> = Item<'grammar, ()>; pub type LR0Item<'grammar> = Item<'grammar, Nil>;
pub type LR1Item<'grammar> = Item<'grammar, Token>; pub type LR1Item<'grammar> = Item<'grammar, Token>;
impl<'grammar> Item<'grammar, ()> { impl<'grammar> Item<'grammar, Nil> {
#[cfg(test)] #[cfg(test)]
pub fn lr0(production: &'grammar Production, pub fn lr0(production: &'grammar Production,
index: usize) index: usize)
-> Self { -> Self {
Item { production: production, index: index, lookahead: () } Item { production: production, index: index, lookahead: Nil }
} }
} }
impl<'grammar, L: Clone> Item<'grammar, L> { impl<'grammar, L: Lookahead> Item<'grammar, L> {
pub fn prefix(&self) -> &'grammar [Symbol] { pub fn prefix(&self) -> &'grammar [Symbol] {
&self.production.symbols[..self.index] &self.production.symbols[..self.index]
} }
@ -53,7 +53,7 @@ impl<'grammar, L: Clone> Item<'grammar, L> {
} }
pub fn to_lr0(&self) -> LR0Item<'grammar> { pub fn to_lr0(&self) -> LR0Item<'grammar> {
Item { production: self.production, index: self.index, lookahead: () } Item { production: self.production, index: self.index, lookahead: Nil }
} }
pub fn can_shift(&self) -> bool { pub fn can_shift(&self) -> bool {
@ -88,15 +88,15 @@ impl<'grammar, L: Clone> Item<'grammar, L> {
pub struct StateIndex(pub usize); pub struct StateIndex(pub usize);
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Items<'grammar, L: Clone> { pub struct Items<'grammar, L: Lookahead> {
pub vec: Rc<Vec<Item<'grammar, L>>> pub vec: Rc<Vec<Item<'grammar, L>>>
} }
pub type LR0Items<'grammar> = Items<'grammar, ()>; pub type LR0Items<'grammar> = Items<'grammar, Nil>;
pub type LR1Items<'grammar> = Items<'grammar, Token>; pub type LR1Items<'grammar> = Items<'grammar, Token>;
#[derive(Debug)] #[derive(Debug)]
pub struct State<'grammar, L: Clone> { pub struct State<'grammar, L: Lookahead> {
pub index: StateIndex, pub index: StateIndex,
pub items: Items<'grammar, L>, pub items: Items<'grammar, L>,
pub tokens: Map<Token, Action<'grammar>>, pub tokens: Map<Token, Action<'grammar>>,
@ -104,7 +104,7 @@ pub struct State<'grammar, L: Clone> {
pub gotos: Map<NonterminalString, StateIndex>, pub gotos: Map<NonterminalString, StateIndex>,
} }
pub type LR0State<'grammar> = State<'grammar, ()>; pub type LR0State<'grammar> = State<'grammar, Nil>;
pub type LR1State<'grammar> = State<'grammar, Token>; pub type LR1State<'grammar> = State<'grammar, Token>;
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -131,24 +131,18 @@ pub struct TableConstructionError<'grammar> {
pub states: Vec<LR1State<'grammar>>, pub states: Vec<LR1State<'grammar>>,
} }
impl<'grammar, L: Clone+Debug> Debug for Item<'grammar, L> { impl<'grammar, L: Lookahead> Debug for Item<'grammar, L> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
let mut lookahead_debug = format!("{:?}", self.lookahead); try!(write!(fmt, "{} ={} (*){}",
if lookahead_debug != "()" {
lookahead_debug = format!(" [{}]", lookahead_debug);
} else {
lookahead_debug = format!("");
}
write!(fmt, "{} ={} (*){}{}",
self.production.nonterminal, self.production.nonterminal,
Prefix(" ", &self.production.symbols[..self.index]), Prefix(" ", &self.production.symbols[..self.index]),
Prefix(" ", &self.production.symbols[self.index..]), Prefix(" ", &self.production.symbols[self.index..])));
lookahead_debug)
self.lookahead.fmt_as_item_suffix(fmt)
} }
} }
impl Debug for Token { impl Display for Token {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
match *self { match *self {
Token::EOF => write!(fmt, "EOF"), Token::EOF => write!(fmt, "EOF"),
@ -157,13 +151,19 @@ impl Debug for Token {
} }
} }
impl Debug for Token {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
write!(fmt, "{}", self)
}
}
impl Debug for StateIndex { impl Debug for StateIndex {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
write!(fmt, "S{}", self.0) write!(fmt, "S{}", self.0)
} }
} }
impl<'grammar, L: Clone> State<'grammar, L> { impl<'grammar, L: Lookahead> State<'grammar, L> {
/// Returns the set of symbols which must appear on the stack to /// Returns the set of symbols which must appear on the stack to
/// be in this state. This is the *maximum* prefix of any item, /// be in this state. This is the *maximum* prefix of any item,
/// basically. /// basically.

View File

@ -2,6 +2,19 @@ use bit_set::{self, BitSet};
use std::fmt::{Debug, Formatter, Error}; use std::fmt::{Debug, Formatter, Error};
use grammar::repr::*; use grammar::repr::*;
pub trait Lookahead: Clone + Debug + PartialEq + Eq + PartialOrd + Ord {
fn fmt_as_item_suffix(&self, fmt: &mut Formatter) -> Result<(), Error>;
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Nil;
impl Lookahead for Nil {
fn fmt_as_item_suffix(&self, _fmt: &mut Formatter) -> Result<(), Error> {
Ok(())
}
}
/// I have semi-arbitrarily decided to say that a "token" is either /// I have semi-arbitrarily decided to say that a "token" is either
/// one of the terminals of our language, or else the pseudo-symbol /// one of the terminals of our language, or else the pseudo-symbol
/// EOF that represents "end of input". /// EOF that represents "end of input".
@ -11,6 +24,12 @@ pub enum Token {
Terminal(TerminalString), Terminal(TerminalString),
} }
impl Lookahead for Token {
fn fmt_as_item_suffix(&self, fmt: &mut Formatter) -> Result<(), Error> {
write!(fmt, " [{}]", self)
}
}
impl Token { impl Token {
pub fn unwrap_terminal(self) -> TerminalString { pub fn unwrap_terminal(self) -> TerminalString {
match self { match self {

View File

@ -43,7 +43,7 @@ pub Ty: () = {
// Ty = Ty -> Ty (*) (reduce) // Ty = Ty -> Ty (*) (reduce)
assert!(conflict.production.symbols.len() == 3); assert!(conflict.production.symbols.len() == 3);
let item = Item { production: conflict.production, index: 1, lookahead: () }; let item = Item::lr0(conflict.production, 1);
println!("item={:?}", item); println!("item={:?}", item);
let tracer = Tracer::new(&grammar, &states); let tracer = Tracer::new(&grammar, &states);
let graph = tracer.backtrace_shift(conflict.state, item); let graph = tracer.backtrace_shift(conflict.state, item);

View File

@ -1,5 +1,6 @@
use collections::{Map, map}; use collections::{Map, map};
use lr1::core::*; use lr1::core::*;
use lr1::lookahead::*;
use lr1::example::*; use lr1::example::*;
use grammar::repr::*; use grammar::repr::*;
use petgraph::{EdgeDirection, Graph}; use petgraph::{EdgeDirection, Graph};
@ -102,7 +103,7 @@ impl<'grammar> Into<TraceGraphNode<'grammar>> for NonterminalString {
} }
} }
impl<'grammar, L: Clone> Into<TraceGraphNode<'grammar>> for Item<'grammar, L> { impl<'grammar, L: Lookahead> Into<TraceGraphNode<'grammar>> for Item<'grammar, L> {
fn into(self) -> TraceGraphNode<'grammar> { fn into(self) -> TraceGraphNode<'grammar> {
TraceGraphNode::Item(self.to_lr0()) TraceGraphNode::Item(self.to_lr0())
} }