#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(unused_parens)]
#![allow(unused_mut)]
#![allow(unused_assignments)]
#![allow(unused_doc_comments)]
#![allow(unused_imports)]
use std::collections::{HashMap,HashSet,BTreeSet};
use std::cell::{RefCell,Ref,RefMut};
use std::hash::{Hash,Hasher};
use std::mem;
use crate::grammar_processor::*;
use crate::Stateaction::*;
#[derive(Clone,PartialEq,Eq,Hash,Debug)]
pub struct LRitem
{
ri: usize, pi: usize, la: String, }
pub fn printrulela(ri:usize, Gmr:&Grammar, la:&str)
{
if ri>=Gmr.Rules.len() {println!("printing invalid rule number {}",ri); return;}
let ref lhs_sym = Gmr.Rules[ri].lhs.sym;
let ref rhs = Gmr.Rules[ri].rhs;
print!(" (Rule {}) {} --> ",ri,lhs_sym);
for gsym in rhs { print!("{} ",gsym.sym); }
println!(" , lookahead {}",la);
}
pub fn printitem(item:&LRitem, Gmr:&Grammar)
{
let ref lhs_sym = Gmr.Rules[item.ri].lhs.sym;
let ref rhs = Gmr.Rules[item.ri].rhs;
print!(" ({}) {} --> ",item.ri,lhs_sym);
let mut position = 0;
for gsym in rhs
{
if &position==&item.pi {print!(".");}
print!("{} ",gsym.sym);
position+=1;
}
if &position==&item.pi {print!(". ");}
println!(", {}",&item.la);
}
pub type Itemset = HashSet<LRitem>;
pub type LookupSet<T> = BTreeSet<T>;
pub fn stateeq(s1:&Itemset, s2:&Itemset) -> bool
{
if s1.len()!=s2.len() { return false; }
for s in s1 {
if !s2.contains(s) {return false;}
}
return true;
}
fn extract_core(items:&Itemset) -> HashSet<(usize,usize)> {
let mut core0 = HashSet::with_capacity(256);
for LRitem{ri:r, pi:p, la} in items { core0.insert((*r,*p)); }
core0
}
fn sub_core(s1:&Itemset, s2:&Itemset) -> bool {
for LRitem{ri:r1,pi:p1,la:la1} in s1
{
let mut bx = false;
for LRitem{ri:r2,pi:p2,la} in s2
{
if r1==r2 && p1==p2 {bx=true; break;}
}
if !bx {return false;}
}
return true;
}
fn eq_core(s1:&Itemset, s2:&Itemset) -> bool
{
let (core1,core2) = (extract_core(s1),extract_core(s2));
if core1.len()!=core2.len() {return false;}
for item_core in &core1
{
if !core2.contains(item_core) {return false; }
}
return true;
}
#[derive(Clone,Debug)]
pub struct LR1State
{
index: usize, items:Itemset,
lhss: BTreeSet<String>, }
impl LR1State
{
pub fn new() -> LR1State
{
LR1State {
index : 0, items : HashSet::with_capacity(256),
lhss: BTreeSet::new(), }
}
pub fn insert(&mut self, item:LRitem, lhs:&str) -> bool
{
let inserted = self.items.insert(item);
self.lhss.insert(String::from(lhs));
inserted
}
pub fn hashval(&self) -> String {
let mut key=self.items.len().to_string(); for s in &self.lhss {key.push_str(s);}
key
}
pub fn hashval_lalr(&self) -> String {
let mut key = extract_core(&self.items).len().to_string(); for s in &self.lhss {key.push_str(s);}
key
}
pub fn contains(&self, x:&LRitem) -> bool {self.items.contains(x)}
fn core_eq(&self, state2:&LR1State) -> bool { eq_core(&self.items,&state2.items) }
fn merge_states(&mut self, state2:&LR1State) {
for item in &state2.items {self.items.insert(item.clone());}
}
}
impl PartialEq for LR1State
{
fn eq(&self, other:&LR1State) -> bool
{stateeq(&self.items,&other.items)}
fn ne(&self, other:&LR1State) ->bool
{!stateeq(&self.items,&other.items)}
}
impl Eq for LR1State {}
pub fn printstate(state:&LR1State,Gmr:&Grammar)
{
println!("state {}:",state.index);
let mut lamap:HashMap<(usize,usize),Vec<&String>> = HashMap::with_capacity(Gmr.Rules.len()*4);
for item in &state.items
{
let laset:&mut Vec<&String> = match lamap.get_mut(&(item.ri,item.pi)) {
Some(x) => x,
None => {
let mut newset = Vec::<&String>::with_capacity(16);
lamap.insert((item.ri,item.pi),newset);
lamap.get_mut(&(item.ri,item.pi)).unwrap()
},
}; laset.push(&item.la);
}
for (ri,pi) in lamap.keys()
{
let ref lhs_sym = Gmr.Rules[*ri].lhs.sym;
let ref rhs = Gmr.Rules[*ri].rhs;
print!(" ({}) {} --> ",ri,lhs_sym);
let mut position = 0;
for gsym in rhs
{
if &position==pi {print!(".");}
print!("{} ",gsym.sym);
position+=1;
}
if &position==pi {print!(". ");}
print!(" {{ ");
for la in lamap.get(&(*ri,*pi)).unwrap()
{
print!("{},",la);
}
println!(" }}");
}}pub fn printstate_raw(state:&LR1State,Gmr:&Grammar)
{
for item in &state.items
{ printitem(item,Gmr); }
}
pub fn stateclosure(mut state:LR1State, Gmr:&Grammar)
-> LR1State {
let mut closed =LR1State::new(); closed.index = state.index;
while state.items.len()>0
{
let nextitem = state.items.iter().next().unwrap().clone();
let item = state.items.take(&nextitem).unwrap();
let (ri,pi,la) = (item.ri,item.pi,&item.la);
let rulei = &Gmr.Rules[ri]; let lhs = &rulei.lhs.sym;
closed.insert(nextitem,lhs);
if pi<rulei.rhs.len() && !rulei.rhs[pi].terminal {
let nti = &rulei.rhs[pi]; let lookaheads=&Gmr.Firstseq(&rulei.rhs[pi+1..],la);
for rulent in Gmr.Rulesfor.get(&nti.sym).unwrap() {
for lafollow in lookaheads
{
let newitem = LRitem {
ri: *rulent,
pi: 0,
la: lafollow.clone(),
};
if !closed.items.contains(&newitem) {
state.insert(newitem,&nti.sym); }
} } } } closed
}
#[derive(Copy,Clone,PartialEq,Eq,Debug)]
pub enum Stateaction {
Shift(usize), Reduce(usize), Gotonext(usize), Accept,
Error(&'static str),
}
pub struct Statemachine {
pub Gmr: Grammar,
pub States: Vec<LR1State>,
pub Statelookup: HashMap<String,LookupSet<usize>>,
pub FSM: Vec<HashMap<String,Stateaction>>,
pub lalr: bool,
pub Open: Vec<usize>, }
impl Statemachine
{
pub fn new(gram:Grammar) -> Statemachine
{
Statemachine {
Gmr: gram,
States: Vec::with_capacity(8*1024), Statelookup: HashMap::with_capacity(1024),
FSM: Vec::with_capacity(8*1024),
lalr: false,
Open: Vec::new(), }
}
fn addstate(&mut self, mut state:LR1State, psi:usize, nextsym:String)
{
let newstateindex = self.States.len(); state.index = newstateindex;
let lookupkey = if self.lalr {state.hashval_lalr()} else {state.hashval()};
if let None=self.Statelookup.get(&lookupkey) {
self.Statelookup.insert(lookupkey.clone(),LookupSet::new());
}
let indices = self.Statelookup.get_mut(&lookupkey).unwrap();
let mut toadd = newstateindex; if self.lalr {
for i in indices.iter()
{
if state.core_eq(&self.States[*i]) {
toadd=*i;
let mut stateclone = LR1State {
index : toadd,
items : state.items.clone(),
lhss: BTreeSet::new(),
};
stateclone.merge_states(&self.States[toadd]);
if stateclone.items.len() > self.States[toadd].items.len() {
self.States[toadd] = stateclosure(stateclone,&self.Gmr);
self.Open.push(toadd);
if TRACE>3 { print!("===> MERGED STATE: ");
printstate(&self.States[toadd],&self.Gmr);
}
} break;
} } } else { for i in indices.iter()
{
if &state==&self.States[*i] {toadd=*i; break; } }
}
if TRACE>3 {println!("transition to state {} from state {}, symbol {}..",toadd,psi,&nextsym);}
if toadd==newstateindex { if TRACE>2 {printstate(&state,&self.Gmr);}
indices.insert(newstateindex); self.States.push(state);
self.FSM.push(HashMap::with_capacity(64)); if self.lalr {self.Open.push(newstateindex)}
}
let gsymbol = &self.Gmr.Symbols[*self.Gmr.Symhash.get(&nextsym).unwrap()];
let mut newaction = Stateaction::Gotonext(toadd);
if gsymbol.terminal {newaction=Stateaction::Shift(toadd);}
let currentaction = self.FSM[psi].get(&nextsym);
let mut changefsm = true;
match currentaction { Some(Accept) => { changefsm=false; },
Some(Reduce(ri2)) => {
let prec2 = self.Gmr.Rules[*ri2].precedence;
let prec1 = gsymbol.precedence;
if prec1==prec2 && prec1>0 {changefsm=false;} else if prec2.abs()>prec1.abs() {changefsm=false;} if TRACE>0 {println!("shift-reduce conflict resolved by operator precedence/associativity:"); printrulela(*ri2,&self.Gmr,&nextsym); }
},
_ => {},
} if changefsm {self.FSM[psi].insert(nextsym,newaction);}
}
fn addreduce(FSM: &mut Vec<HashMap<String,Stateaction>>, Gmr:&Grammar, item:&LRitem, si:usize)
{
let isaccept = (item.ri == Gmr.Rules.len()-1 && item.la=="EOF");
let currentaction = FSM[si].get(&item.la);
let mut changefsm = true;
let ri1 = &item.ri;
match currentaction {
Some(Accept) => {
changefsm = false;
if !isaccept {println!("Reduce({})-Accept conflict resolved in favor of Accept",ri1)}
},
Some(Reduce(ri2)) if ri2<ri1 && !isaccept => {
changefsm=false;
println!("Reduce-Reduce Conflict conflicted detected between rules {} and {}, resolved in favor of {}",ri2,ri1,ri2);
printrulela(*ri1,Gmr,&item.la); printrulela(*ri2,Gmr,&item.la);
},
Some(Reduce(ri2)) if ri2>ri1 => {
println!("Reduce-Reduce Conflict conflicted detected between rules {} and {}, resolved in favor of {}",ri2,ri1,ri1);
printrulela(*ri1,Gmr,&item.la); printrulela(*ri2,Gmr,&item.la);
},
Some(Reduce(ri2)) if ri2==ri1 && !isaccept => {changefsm=false;},
Some(Shift(_)) if !isaccept => { let prec1 = Gmr.Rules[item.ri].precedence;
let prec2 = Gmr.Symbols[*Gmr.Symhash.get(&item.la).unwrap()].precedence;
if prec1==prec2 && prec1<0 {changefsm=false;} else if prec2.abs()>prec1.abs() {changefsm=false;} if TRACE>0 {println!("Shift-Reduce conflict resolved by operator precedence/associativity:"); printrulela(*ri1,Gmr,&item.la); }
},
_ => {},
} if changefsm { if isaccept {
if let None = ¤taction {}
else {println!("Accept has precedence over {:?}",¤taction);}
FSM[si].insert(item.la.clone(),Stateaction::Accept);
}
else {
if TRACE>1 {println!("++adding Reduce({}) at state {}, lookahead {}",item.ri,si,&item.la);}
FSM[si].insert(item.la.clone(),Stateaction::Reduce(item.ri));
}
} }
fn makegotos(&mut self, si:usize)
{
let ref state = self.States[si];
let mut newstates:HashMap<String,LR1State> = HashMap::with_capacity(64);
let mut keyvec:Vec<String> = Vec::new(); for item in &state.items
{
let rule = self.Gmr.Rules.get(item.ri).unwrap();
if item.pi<rule.rhs.len() { let ref nextsym = rule.rhs[item.pi].sym;
if let None = newstates.get(nextsym) {
newstates.insert(nextsym.to_owned(),LR1State::new());
keyvec.push(nextsym.clone());
}
let symstate = newstates.get_mut(nextsym).unwrap();
let newitem = LRitem {
ri : item.ri,
pi : item.pi+1,
la : item.la.clone(),
};
let lhssym = &self.Gmr.Rules[item.ri].lhs.sym;
symstate.insert(newitem,lhssym);
} else {
Statemachine::addreduce(&mut self.FSM,&self.Gmr,item,si);
} } for key in keyvec
{
let kernel = newstates.remove(&key).unwrap();
let fullstate = stateclosure(kernel,&self.Gmr);
self.addstate(fullstate,si,key);
}
}
pub fn generatefsm(&mut self)
{
let mut startstate=LR1State::new();
startstate.insert( LRitem {
ri : self.Gmr.Rules.len()-1, pi : 0,
la : "EOF".to_owned(), },"START");
startstate = stateclosure(startstate,&self.Gmr);
self.States.push(startstate); self.FSM.push(HashMap::with_capacity(64)); let mut closed:usize = 0;
if !self.lalr {
while closed<self.States.len()
{
self.makegotos(closed);
closed += 1;
} } else { self.Open.push(0);
while closed<self.Open.len()
{
let si = self.Open[closed]; self.makegotos(si);
closed += 1;
}
} }
}
pub fn decode_action(code:u64) -> Stateaction
{
let actiontype = code & 0x000000000000ffff;
let actionvalue = (code & 0x00000000ffff0000) >> 16;
match (actiontype,actionvalue) {
(0,si) => Shift(si as usize),
(1,si) => Gotonext(si as usize),
(2,ri) => Reduce(ri as usize),
(3,_) => Accept,
(4,x) => Error("shouldn't be here"),
_ => Error("unrecognized action in TABLE"),
}
}