#![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::fmt::Display;
use std::default::Default;
use std::collections::{HashMap,HashSet,BTreeSet};
use std::io::{self,Read,Write,BufReader,BufRead};
use std::cell::{RefCell,Ref,RefMut};
use std::hash::{Hash,Hasher};
use std::any::Any;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::mem;
use crate::{TRACE,Stateaction,Statemachine,TerminalToken,Tokenizer};
use crate::{LBox,LRc};
use crate::Stateaction::*;
use std::rc::Rc;
use crate::{StandardReporter};
#[derive(Clone)]
pub struct ZCRProduction<AT:Default,ET:Default> {
pub lhs: &'static str, pub Ruleaction : fn(&mut ZCParser<AT,ET>) -> AT, }
impl<AT:Default,ET:Default> ZCRProduction<AT,ET>
{
pub fn new_skeleton(lh:&'static str) -> ZCRProduction<AT,ET>
{
ZCRProduction {
lhs : lh,
Ruleaction : |p|{ <AT>::default()},
}
}
}
pub struct StackedItem<AT:Default> {
si : usize, pub value : AT, pub line: usize, pub column: usize,
}
impl<AT:Default> StackedItem<AT>
{
pub fn new(si:usize,value:AT,line:usize,column:usize) -> StackedItem<AT>
{ StackedItem{si,value,line,column} }
pub fn lbox(self) -> LBox<AT>
{ LBox::new(self.value,self.line,self.column) }
}
pub struct ZCParser<AT:Default,ET:Default>
{
pub exstate : ET, pub RSM : Vec<HashMap<&'static str,Stateaction>>, pub Rules : Vec<ZCRProduction<AT,ET>>, stopparsing : bool,
pub stack : Vec<StackedItem<AT>>, pub resynch : HashSet<&'static str>,
pub Errsym : &'static str,
err_occurred : bool,
pub linenum : usize,
pub column : usize,
pub src_id : usize,
report_line : usize,
pub Symset : HashSet<&'static str>,
popped : Vec<(usize,usize)>,
}
impl<AT:Default,ET:Default> ZCParser<AT,ET>
{
pub fn new(rlen:usize, slen:usize) -> ZCParser<AT,ET>
{ let mut p = ZCParser {
RSM : Vec::with_capacity(slen),
Rules : Vec::with_capacity(rlen),
stopparsing : false,
exstate : ET::default(),
stack : Vec::with_capacity(1024),
Errsym : "",
err_occurred : false,
linenum : 0,
column : 0,
src_id : 0,
report_line : 0,
resynch : HashSet::new(),
Symset : HashSet::with_capacity(64),
popped: Vec::with_capacity(8),
};
for _ in 0..slen {
p.RSM.push(HashMap::with_capacity(16));
}
return p;
}
pub fn abort(&mut self, msg:&str)
{
eprintln!("\n!!!Parsing Aborted: {}",msg);
self.err_occurred = true;
self.stopparsing=true;
}
pub fn report(&mut self, errmsg:&str)
{ if (self.report_line != self.linenum || self.linenum==0) {
eprintln!("PARSER ERROR: {}",errmsg);
self.report_line = self.linenum;
}
else {
eprint!(" {} ",errmsg);
}
self.err_occurred = true;
}
pub fn bad_pattern(&mut self,pattern:&str) -> AT
{
let msg = format!("pattern {} failed to bind to stacked values\n",pattern);
self.report(&msg);
AT::default()
}
fn errshift(&mut self, sym:&str) -> bool
{
let csi = self.stack[self.stack.len()-1].si; let actionopt = self.RSM[csi].get(sym);
if let Some(Shift(ni)) = actionopt {
self.stack.push(StackedItem::new(*ni,AT::default(),self.linenum,self.column)); true
}
else {false}
}
fn shift<'t>(&mut self, nextstate:usize, lookahead:TerminalToken<'t,AT>, tokenizer:&mut dyn Tokenizer<'t,AT>) -> TerminalToken<'t, AT>
{
self.linenum = lookahead.line; self.column=lookahead.column;
self.stack.push(StackedItem::new(nextstate,lookahead.value,lookahead.line,lookahead.column));
tokenizer.next_tt()
}
pub fn popstack(&mut self) -> StackedItem<AT>
{
let item = self.stack.pop().expect("PARSER STATE MACHINE/STACK CORRUPTED");
self.linenum = item.line; self.column=item.column;
self.popped.push((item.line,item.column));
item
}
fn reduce(&mut self, ri:&usize)
{
self.popped.clear();
let rulei = &self.Rules[*ri];
let ruleilhs = rulei.lhs; let val = (rulei.Ruleaction)(self); let newtop = self.stack[self.stack.len()-1].si;
let goton = self.RSM[newtop].get(ruleilhs).expect("PARSER STATEMACHINE CORRUPTED");
if let Stateaction::Gotonext(nsi) = goton {
self.stack.push(StackedItem::new(*nsi,val,self.linenum,self.column));
} else {
self.report("state transition table corrupted: no suitable action after reduce");
self.stopparsing=true;
}
}
pub fn error_occurred(&self) -> bool {self.err_occurred}
pub fn lb<T>(&self,e:T) -> LBox<T> { LBox::new(e,self.linenum,self.column ) }
pub fn lba<T:'static>(&self,e:T) -> LBox<dyn Any> { LBox::upcast(LBox::new(e,self.linenum,self.column )) }
pub fn lrc<T>(&self,e:T) -> LRc<T> { LRc::new(e,self.linenum,self.column ) }
pub fn lrca<T:'static>(&self,e:T) -> LRc<dyn Any> { LRc::upcast(LRc::new(e,self.linenum,self.column )) }
pub fn lbx<T>(&self,i:usize,e:T) -> LBox<T>
{
let (mut ln,mut cl) = (self.linenum,self.column);
if i<self.popped.len() {
let index = self.popped.len() - 1 - i;
let lc = self.popped[index];
ln = lc.0; cl=lc.1;
}
LBox::new(e,ln,cl)
}
pub fn lrcn<T>(&self,i:usize,e:T) -> LRc<T>
{
let (mut ln,mut cl) = (self.linenum,self.column);
if i<self.popped.len() {
let index = self.popped.len() - 1 - i;
let lc = self.popped[index];
ln = lc.0; cl=lc.1;
}
LRc::new(e,ln,cl)
}
}
impl Statemachine
{ pub fn writezcparser(&self, filename:&str)->Result<(),std::io::Error>
{
let ref absyn = self.Gmr.Absyntype;
let ref extype = self.Gmr.Externtype;
let ref lifetime = self.Gmr.lifetime;
let has_lt = lifetime.len()>0 && (absyn.contains(lifetime) || extype.contains(lifetime));
let ltopt = if has_lt {format!("<{}>",lifetime)} else {String::from("")};
let mut fd = File::create(filename)?;
write!(fd,"//Parser generated by rustlr for grammar {}",&self.Gmr.name)?;
write!(fd,"\n
#![allow(unused_variables)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(unused_parens)]
#![allow(unused_mut)]
#![allow(unused_imports)]
#![allow(unused_assignments)]
#![allow(dead_code)]
#![allow(irrefutable_let_patterns)]
#![allow(unreachable_patterns)]
extern crate rustlr;
use rustlr::{{Tokenizer,TerminalToken,ZCParser,ZCRProduction,Stateaction,decode_action}};\n")?;
if self.Gmr.genlex {
write!(fd,"use rustlr::{{StrTokenizer,RawToken,LexSource}};
use std::collections::{{HashMap,HashSet}};\n")?;
}
write!(fd,"{}\n",&self.Gmr.Extras)?;
write!(fd,"static SYMBOLS:[&'static str;{}] = [",self.Gmr.Symbols.len())?;
for i in 0..self.Gmr.Symbols.len()-1
{
write!(fd,"\"{}\",",&self.Gmr.Symbols[i].sym)?;
}
write!(fd,"\"{}\"];\n\n",&self.Gmr.Symbols[self.Gmr.Symbols.len()-1].sym)?;
let mut totalsize = 0;
for i in 0..self.FSM.len() { totalsize+=self.FSM[i].len(); }
write!(fd,"static TABLE:[u64;{}] = [",totalsize)?;
let mut encode:u64 = 0;
for i in 0..self.FSM.len() {
let row = &self.FSM[i];
for key in row.keys()
{ let k = *self.Gmr.Symhash.get(key).unwrap(); encode = ((i as u64) << 48) + ((k as u64) << 32);
match row.get(key) {
Some(Shift(statei)) => { encode += (*statei as u64) << 16; },
Some(Gotonext(statei)) => { encode += ((*statei as u64) << 16)+1; },
Some(Reduce(rulei)) => { encode += ((*rulei as u64) << 16)+2; },
Some(Accept) => {encode += 3; },
_ => {encode += 4; }, } write!(fd,"{},",encode)?;
} } write!(fd,"];\n\n")?;
write!(fd,"pub fn make_parser{}() -> ZCParser<{},{}>",<opt,absyn,extype)?;
write!(fd,"\n{{\n")?;
write!(fd," let mut parser1:ZCParser<{},{}> = ZCParser::new({},{});\n",absyn,extype,self.Gmr.Rules.len(),self.States.len())?;
write!(fd," let mut rule = ZCRProduction::<{},{}>::new_skeleton(\"{}\");\n",absyn,extype,"start")?;
for i in 0..self.Gmr.Rules.len()
{
write!(fd," rule = ZCRProduction::<{},{}>::new_skeleton(\"{}\");\n",absyn,extype,self.Gmr.Rules[i].lhs.sym)?;
write!(fd," rule.Ruleaction = |parser|{{ ")?;
let mut k = self.Gmr.Rules[i].rhs.len();
let mut labels = String::from("(");
let mut patterns = String::from("(");
while k>0 {
let gsym = &self.Gmr.Rules[i].rhs[k-1];
let findat = gsym.label.find('@');
let mut plab = format!("_item{}_",k-1);
match &findat {
None if gsym.label.len()>0 && !gsym.label.contains('(') => {
plab=format!("{}",gsym.label.trim());
},
Some(ati) if *ati>0 => {plab=format!("{}",&gsym.label[0..*ati]);},
_ => {},
} let poppedlab = plab.as_str();
write!(fd,"let mut {} = parser.popstack(); ",poppedlab)?;
if gsym.label.len()>1 && findat.is_some() { let atindex = findat.unwrap();
if atindex>0 { labels.push_str("&mut "); labels.push_str(poppedlab); labels.push_str(".value,");
}
else { labels.push_str(poppedlab); labels.push_str(".value,");
}
patterns.push_str(&gsym.label[atindex+1..]); patterns.push(',');
} else if gsym.label.len()>0 && gsym.label.contains('(') { labels.push_str(poppedlab); labels.push_str(".value,");
patterns.push_str(&gsym.label[..]); patterns.push(',')
} k -= 1;
} let defaultaction = format!("<{}>::default()}}",absyn);
let mut semaction = &self.Gmr.Rules[i].action; if semaction.len()<=1 {semaction = &defaultaction;}
if labels.len()<2 { write!(fd,"{};\n",semaction.trim_end())?; } else { labels.push(')'); patterns.push(')');
write!(fd,"\n if let {}={} {{ {} else {{parser.bad_pattern(\"{}\")}} }};\n",&patterns,&labels,semaction.trim_end(),&patterns)?;
}
write!(fd," parser1.Rules.push(rule);\n")?;
} write!(fd," parser1.Errsym = \"{}\";\n",&self.Gmr.Errsym)?;
for s in &self.Gmr.Resynch {write!(fd," parser1.resynch.insert(\"{}\");\n",s)?;}
write!(fd,"\n for i in 0..{} {{\n",totalsize)?;
write!(fd," let symi = ((TABLE[i] & 0x0000ffff00000000) >> 32) as usize;\n")?;
write!(fd," let sti = ((TABLE[i] & 0xffff000000000000) >> 48) as usize;\n")?;
write!(fd," parser1.RSM[sti].insert(SYMBOLS[symi],decode_action(TABLE[i]));\n }}\n\n")?;
write!(fd," for s in SYMBOLS {{ parser1.Symset.insert(s); }}\n\n")?;
write!(fd," load_extras(&mut parser1);\n")?;
write!(fd," return parser1;\n")?;
write!(fd,"}} //make_parser\n\n")?;
if self.Gmr.genlex { self.Gmr.genlexer(&mut fd,"from_raw")?; }
write!(fd,"fn load_extras{}(parser:&mut ZCParser<{},{}>)\n{{\n",<opt,absyn,extype)?;
write!(fd,"}}//end of load_extras: don't change this line as it affects augmentation\n")?;
Ok(())
}
pub fn writelbaparser(&self, filename:&str)->Result<(),std::io::Error>
{
let ref absyn = self.Gmr.Absyntype;
if !is_lba(absyn) {
return self.writezcparser(filename);
}
let ref extype = self.Gmr.Externtype;
let ref lifetime = self.Gmr.lifetime;
let has_lt = lifetime.len()>0 && (absyn.contains(lifetime) || extype.contains(lifetime));
let ltopt = if has_lt {format!("<{}>",lifetime)} else {String::from("")};
let rlen = self.Gmr.Rules.len();
let mut actions:Vec<String> = Vec::with_capacity(rlen);
for ri in 0..rlen
{
let lhs = &self.Gmr.Rules[ri].lhs.sym;
let lhsi = self.Gmr.Symhash.get(lhs).expect("GRAMMAR REPRESENTATION CORRUPTED");
let rettype = &self.Gmr.Symbols[*lhsi].rusttype; let ltoptr = if has_lt || (lifetime.len()>0 && rettype.contains(lifetime))
{format!("<{}>",lifetime)} else {String::from("")};
let mut fndef = format!("fn _semaction_for_{}_{}(parser:&mut ZCParser<{},{}>) -> {} {{\n",ri,<optr,absyn,extype,rettype);
let mut k = self.Gmr.Rules[ri].rhs.len();
let mut labels = String::from("(");
let mut patterns = String::from("(");
while k>0 {
let gsym = &self.Gmr.Rules[ri].rhs[k-1]; let gsymi = *self.Gmr.Symhash.get(&gsym.sym).unwrap();
let findat = gsym.label.find('@');
let mut plab = format!("_item{}_",k-1);
match &findat {
None if gsym.label.len()>0 => {plab = format!("{}",&gsym.label);},
Some(ati) if *ati>0 => {plab=format!("{}",&gsym.label[0..*ati]);},
_ => {},
} let poppedlab = plab.as_str();
let ref symtype = gsym.rusttype;
let mut stat = format!("let mut {} = lbdown!(parser.popstack().value,{}); ",poppedlab,symtype); if symtype.len()<2 || symtype=="LBox<dyn Any>" || symtype=="LBox<Any>" {
stat = format!("let mut {} = parser.popstack().value; ",poppedlab);
}
fndef.push_str(&stat);
if gsym.label.len()>1 && findat.is_some() { labels.push_str("&mut *"); labels.push_str(poppedlab); labels.push(',');
let atindex = findat.unwrap();
patterns.push_str(&gsym.label[atindex+1..]); patterns.push(',');
} k -= 1;
} let defaultaction = format!("<{}>::default()}}",rettype);
let mut semaction = &self.Gmr.Rules[ri].action; if semaction.len()<=1 {semaction = &defaultaction;}
if labels.len()<2 {
fndef.push_str(semaction.trim_end()); fndef.push_str("\n");
} else { labels.push(')'); patterns.push(')');
let pat2= format!("\n if let {}={} {{ {} else {{parser.report(\"{}\"); <{}>::default()}} }}\n",&patterns,&labels,semaction.trim_end(),&patterns,rettype);
fndef.push_str(&pat2);
} actions.push(fndef);
}
let mut fd = File::create(filename)?;
write!(fd,"//Parser generated by rustlr for grammar {}",&self.Gmr.name)?;
write!(fd,"\n
#![allow(unused_variables)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(unused_parens)]
#![allow(unused_mut)]
#![allow(unused_imports)]
#![allow(unused_assignments)]
#![allow(dead_code)]
#![allow(irrefutable_let_patterns)]
use std::any::Any;
extern crate rustlr;
use rustlr::{{Tokenizer,TerminalToken,ZCParser,ZCRProduction,Stateaction,decode_action,LBox,lbdown,lbup,lbget,unbox}};\n")?;
if self.Gmr.genlex {
write!(fd,"use rustlr::{{StrTokenizer,RawToken,LexSource}};
use std::collections::{{HashMap,HashSet}};\n")?;
}
write!(fd,"{}\n",&self.Gmr.Extras)?;
write!(fd,"static SYMBOLS:[&'static str;{}] = [",self.Gmr.Symbols.len())?;
for i in 0..self.Gmr.Symbols.len()-1
{
write!(fd,"\"{}\",",&self.Gmr.Symbols[i].sym)?;
}
write!(fd,"\"{}\"];\n\n",&self.Gmr.Symbols[self.Gmr.Symbols.len()-1].sym)?;
let mut totalsize = 0;
for i in 0..self.FSM.len() { totalsize+=self.FSM[i].len(); }
write!(fd,"static TABLE:[u64;{}] = [",totalsize)?;
let mut encode:u64 = 0;
for i in 0..self.FSM.len() {
let row = &self.FSM[i]; for key in row.keys()
{ let k = *self.Gmr.Symhash.get(key).unwrap(); encode = ((i as u64) << 48) + ((k as u64) << 32);
match row.get(key) {
Some(Shift(statei)) => { encode += (*statei as u64) << 16; },
Some(Gotonext(statei)) => { encode += ((*statei as u64) << 16)+1; },
Some(Reduce(rulei)) => { encode += ((*rulei as u64) << 16)+2; },
Some(Accept) => {encode += 3; },
_ => {encode += 4; }, } write!(fd,"{},",encode)?;
} } write!(fd,"];\n\n")?;
for deffn in &actions { write!(fd,"{}",deffn)?; }
write!(fd,"\npub fn make_parser{}() -> ZCParser<{},{}>",<opt,absyn,extype)?;
write!(fd,"\n{{\n")?;
write!(fd," let mut parser1:ZCParser<{},{}> = ZCParser::new({},{});\n",absyn,extype,self.Gmr.Rules.len(),self.States.len())?;
write!(fd," let mut rule = ZCRProduction::<{},{}>::new_skeleton(\"{}\");\n",absyn,extype,"start")?; for i in 0..self.Gmr.Rules.len()
{
write!(fd," rule = ZCRProduction::<{},{}>::new_skeleton(\"{}\");\n",absyn,extype,self.Gmr.Rules[i].lhs.sym)?;
write!(fd," rule.Ruleaction = |parser|{{ ")?;
let lhsi = self.Gmr.Symhash.get(&self.Gmr.Rules[i].lhs.sym).expect("GRAMMAR REPRESENTATION CORRUPTED");
let fnname = format!("_semaction_for_{}_",i);
let typei = &self.Gmr.Symbols[*lhsi].rusttype;
if is_lba(typei) {
write!(fd," {}(parser) }};\n",&fnname)?;
}
else {
write!(fd," lbup!( LBox::new({}(parser),parser.linenum,parser.column)) }};\n",&fnname)?;
}
write!(fd," parser1.Rules.push(rule);\n")?;
}
write!(fd," parser1.Errsym = \"{}\";\n",&self.Gmr.Errsym)?;
for s in &self.Gmr.Resynch {write!(fd," parser1.resynch.insert(\"{}\");\n",s)?;}
write!(fd,"\n for i in 0..{} {{\n",totalsize)?;
write!(fd," let symi = ((TABLE[i] & 0x0000ffff00000000) >> 32) as usize;\n")?;
write!(fd," let sti = ((TABLE[i] & 0xffff000000000000) >> 48) as usize;\n")?;
write!(fd," parser1.RSM[sti].insert(SYMBOLS[symi],decode_action(TABLE[i]));\n }}\n\n")?;
write!(fd," for s in SYMBOLS {{ parser1.Symset.insert(s); }}\n\n")?;
write!(fd," load_extras(&mut parser1);\n")?;
write!(fd," return parser1;\n")?;
write!(fd,"}} //make_parser\n\n")?;
if self.Gmr.genlex { self.Gmr.genlexer(&mut fd,"raw_to_lba")?; }
write!(fd,"fn load_extras{}(parser:&mut ZCParser<{},{}>)\n{{\n",<opt,absyn,extype)?;
write!(fd,"}}//end of load_extras: don't change this line as it affects augmentation\n")?;
Ok(())
}
}
fn iserror(actionopt:&Option<&Stateaction>) -> bool
{
match actionopt {
None => true,
Some(Error(_)) => true,
_ => false,
}
}
fn is_lba(t:&str) -> bool {
t.contains("LBox") && t.contains("Any") && t.contains('<') && t.contains('>')
}
impl<AT:Default,ET:Default> ZCParser<AT,ET>
{
pub fn error_recover<'t>(&mut self, lookahead:&mut TerminalToken<'t,AT>, tokenizer:&mut dyn Tokenizer<'t,AT>) -> Option<Stateaction>
{
let mut erraction = None;
if self.Errsym.len()>0 {
let errsym = self.Errsym;
let mut k = self.stack.len(); let mut spos = k+1;
while k>0 && spos>k
{
let ksi = self.stack[k-1].si;
erraction = self.RSM[ksi].get(errsym);
if let None = erraction {k-=1;} else {spos=k;}
} if spos==k { self.stack.truncate(k); } while let Some(Reduce(ri)) = erraction {
self.popped.clear();
let rulei = &self.Rules[*ri];
let ruleilhs = rulei.lhs; let val = (rulei.Ruleaction)(self);
let newtop = self.stack[self.stack.len()-1].si;
let gotonopt = self.RSM[newtop].get(ruleilhs);
match gotonopt {
Some(Gotonext(nsi)) => {
self.stack.push(StackedItem::new(*nsi,val,self.linenum,self.column));
}, _ => {self.abort("recovery failed"); },
}
let tos=self.stack[self.stack.len()-1].si;
erraction = self.RSM[tos].get(self.Errsym).clone();
} if let Some(Shift(i)) = erraction { self.stack.push(StackedItem::new(*i,AT::default(),lookahead.line,lookahead.column));
while let None = self.RSM[*i].get(lookahead.sym) {
if lookahead.sym=="EOF" {break;}
*lookahead = tokenizer.next_tt();
} erraction = self.RSM[*i].get(lookahead.sym);
} }
if iserror(&erraction) && self.resynch.len()>0 {
while lookahead.sym!="EOF" &&
!self.resynch.contains(lookahead.sym) {
self.linenum = lookahead.line; self.column = lookahead.column;
*lookahead = tokenizer.next_tt();
} if lookahead.sym!="EOF" {
self.linenum = lookahead.line; self.column = lookahead.column;
*lookahead = tokenizer.next_tt();
}
let mut k = self.stack.len()-1; let mut position = 0;
while k>0 && erraction==None
{
let ksi = self.stack[k-1].si;
erraction = self.RSM[ksi].get(lookahead.sym);
if let None=erraction {k-=1;}
} match erraction {
None => {}, _ => { self.stack.truncate(k);}, } }
let mut eofcx = 0;
while iserror(&erraction) && eofcx<1 { self.linenum = lookahead.line; self.column = lookahead.column;
*lookahead = tokenizer.next_tt();
if lookahead.sym=="EOF" {eofcx+=1;}
let csi =self.stack[self.stack.len()-1].si;
erraction = self.RSM[csi].get(lookahead.sym);
} match erraction {
Some(act) if eofcx<1 => Some(*act),
_ => None,
} }
}
pub trait ErrReporter<AT:Default,ET:Default> {
fn err_reporter(&mut self, parser:&mut ZCParser<AT,ET>, lookahead:&TerminalToken<AT>, erropt:&Option<Stateaction>);
fn report_err(&self, parser:&mut ZCParser<AT,ET>, msg:&str) { parser.report(msg) }
}
impl<AT:Default,ET:Default> ErrReporter<AT,ET> for StandardReporter
{
fn err_reporter(&mut self, parser:&mut ZCParser<AT,ET>, lookahead:&TerminalToken<AT>, erropt:&Option<Stateaction>)
{
let mut wresult:std::io::Result<()> = Err(std::io::Error::new(std::io::ErrorKind::Other,"")); let cstate = parser.stack[parser.stack.len()-1].si; let mut actionopt = if let Some(act)=erropt {Some(act)} else {None};
let lksym = &lookahead.sym[..];
if parser.Symset.contains(lksym) {
if let None=actionopt {
actionopt = parser.RSM[cstate].get("ANY_ERROR");
}
} else {
actionopt = parser.RSM[cstate].get("ANY_ERROR");
} let errmsg = if let Some(Error(em)) = &actionopt {
format!("unexpected symbol {} on line {}, column {}: ** {} ** ..",lksym,lookahead.line,lookahead.column,em.trim())
} else {format!("unexpected symbol {} on line {}, column {} .. ",lksym,lookahead.line,lookahead.column)};
parser.report(&errmsg);
if self.training { let csym = lookahead.sym.to_owned();
let mut inp = String::from("");
if let None=self.scriptinopt { if let Some(outfd1) = &self.scriptoutopt {
let mut outfd = outfd1;
print!("\n>>>TRAINER: if this message is not adequate (for state {}), enter a replacement (default no change): ",cstate);
let rrrflush = io::stdout().flush();
if let Ok(n) = io::stdin().read_line(&mut inp) {
if inp.len()>5 && parser.Symset.contains(lksym) {
print!(">>>TRAINER: should this message be given for all unexpected symbols in the current state? (default yes) ");
let rrrflush2 = io::stdout().flush();
let mut inp2 = String::new();
if let Ok(n) = io::stdin().read_line(&mut inp2) {
if inp2.trim()=="no" || inp2.trim()=="No" {
wresult = write!(outfd,"{}\t{}\t{} ::: {}\n",lookahead.line,lookahead.column,&csym,inp.trim());
self.trained.insert((cstate,csym),inp);
}
else { wresult = write!(outfd,"{}\t{}\t{} ::: {}\n",lookahead.line,lookahead.column,"ANY_ERROR",inp.trim());
self.trained.insert((cstate,String::from("ANY_ERROR")),inp);
}
} } else if inp.len()>5 && !parser.Symset.contains(lksym) {
wresult = write!(outfd,"{}\t{}\t{} ::: {}\n",lookahead.line,lookahead.column,"ANY_ERROR",inp.trim());
self.trained.insert((cstate,String::from("ANY_ERROR")),inp);
}
} }} else { if let Some(brfd) = &mut self.scriptinopt {
let mut scin = brfd;
let mut readn = 0;
while readn < 1
{
inp = String::new();
match scin.read_line(&mut inp) {
Ok(n) if n>1 && &inp[0..1]!="#" && inp.trim().len()>0 => {readn=n;},
Ok(n) if n>0 => { readn=0; }, _ => {readn = 1; } } if readn>1 { let inpsplit:Vec<&str> = inp.split_whitespace().collect();
if inpsplit.len()>4 && inpsplit[3].trim()==":::" {
let inline = inpsplit[0].trim().parse::<usize>().unwrap();
let incolumn = inpsplit[1].trim().parse::<usize>().unwrap();
let insym = inpsplit[2].trim();
if parser.linenum==inline && parser.column==incolumn {
if &csym==insym || insym=="ANY_ERROR" {
let posc = inp.find(":::").unwrap()+4;
println!("\n>>>Found matching entry from training script for {}, error message: {}",insym,&inp[posc..]);
self.trained.insert((cstate,String::from(insym)),String::from(&inp[posc..]));
} } } } } }} }
}}
impl<AT:Default,ET:Default> ZCParser<AT,ET>
{
pub fn parse_core<'u,'t:'u>(&mut self, tokenizer:&'u mut dyn Tokenizer<'t,AT>, err_handler:&mut dyn ErrReporter<AT,ET>) -> AT
{
self.stack.clear();
self.err_occurred = false;
let mut result = AT::default();
self.exstate = ET::default();
self.stack.push(StackedItem::new(0,AT::default(),0,0));
self.stopparsing = false;
let mut action = Stateaction::Error("");
let mut lookahead = TerminalToken::new("EOF",AT::default(),0,0); if let Some(tok) = tokenizer.nextsym() {lookahead=tok;}
else {self.stopparsing=true;}
while !self.stopparsing
{
self.linenum = self.stack[self.stack.len()-1].line;
self.column=self.stack[self.stack.len()-1].column;
let currentstate = self.stack[self.stack.len()-1].si;
let mut actionopt = self.RSM[currentstate].get(lookahead.sym);
let actclone:Option<Stateaction> = match actionopt {
Some(a) => Some(*a),
None => None,
};
if iserror(&actionopt) { if !self.err_occurred {self.err_occurred = true;}
err_handler.err_reporter(self,&lookahead,&actclone);
match self.error_recover(&mut lookahead,tokenizer) {
None => { self.stopparsing=true; break; }
Some(act) => {action = act;}, } } else { action = actclone.unwrap(); }
match &action {
Shift(nextstate) => {
lookahead = self.shift(*nextstate,lookahead,tokenizer);
},
Reduce(rulei) => { self.reduce(rulei); },
Accept => {
self.stopparsing=true;
if self.stack.len()>0 {result = self.stack.pop().unwrap().value;}
else {self.err_occurred=true;}
},
_ => {}, } } return result;
}
pub fn parse<'t>(&mut self, tokenizer:&mut dyn Tokenizer<'t,AT>) -> AT
{
let mut stdeh = StandardReporter::new();
self.parse_core(tokenizer,&mut stdeh)
}
pub fn parse_train<'t>(&mut self, tokenizer:&mut dyn Tokenizer<'t,AT>, parserfile:&str) -> AT
{
let mut stdtrainer = StandardReporter::new_interactive_training(parserfile);
let result = self.parse_core(tokenizer,&mut stdtrainer);
if let Err(m) = stdtrainer.augment_training(parserfile) {
eprintln!("Error in augmenting parser: {:?}",m)
}
return result;
}
pub fn train_from_script<'t>(&mut self, tokenizer:&mut dyn Tokenizer<'t,AT>,parserfile:&str, scriptfile:&str)
{
let mut stdtrainer = StandardReporter::new_script_training(parserfile,scriptfile);
let result = self.parse_core(tokenizer,&mut stdtrainer);
if let Err(m) = stdtrainer.augment_training(parserfile) {
eprintln!("Error in augmenting parser: {:?}",m)
}
if !self.err_occurred {println!("no errors encountered during parsing");}
}
}