// <COMMA*> OR <SEMICOLON+>
let mut newtok3; // will be new strtok
let septoks:Vec<&str> = strtok.split(':').collect();
if septoks.len()>0 && septoks[0].len()>2 && (septoks[0].ends_with("*>") || septoks[0].ends_with("+>") {
let (lb,rb) = findmatch(strtok,'<','>');
let termi;
if lr!=0 && lr+2<rb {
// determine if what's inside <> is valid
let termsym = &strtok[lb+1..rb-1]; // like COMMA
let termiopt = self.Symhash.get(termsym);
if !self.terminal(termsym) {
panic!("ERROR ON LINE {}, {} is not a terminal symbol of this grammar\n",linenum,termsym);
}
termi = *termiopt.unwrap();
} else {panic!("MALFORMED EXPRESSION LINE {}\n",linenum);}
strtok = septoks[0]; // to the left of :, E<,*>
let defaultrelab3 = format!("_item{}_",i-1-iadjust);
let relabel3 = if septoks.len()>1 && septoks[1].len()>0 {septoks[1]} else {&defaultrelab3};
let mut gsympart3 = strtok[0..lb].trim(); //before <,*>
if gsympart3=="_" {gsympart3="_WILDCARD_TOKEN_";}
let errmsg = format!("UNRECOGNIZED GRAMMAR SYMBOL '{}', LINE {}\n",gsympart3,linenum);
let gsymi = *self.Symhash.get(gsympart3).expect(&errmsg);
let newntname3 = format!("NEWSEPNT{}_{}_{}",gsympart3,self.Rules.len(),ntcnt); ntcnt+=1;
let mut newnt3 = Gsym::new(&newntname3,false);
newnt3.rusttype = "()".to_owned();2
if &self.Symbols[gsymi].rusttype!="()" || (septoks.len()>1 && septoks[1].len()>0) {
newnt3.rusttype = format!("Vec<LBox<{}>>",&self.Symbols[gsymi].rusttype);
} // else rusttype stays ()
if !self.enumhash.contains_key(&newnt3.rusttype) {
self.enumhash.insert(newnt.rusttype.clone(),ntcx);
ntcx+=1;
}
self.Symbols.push(newnt3.clone()); // register new nt
self.Symhash.insert(newntname3.clone(),self.Symbols.len()-1);
// add new rules
let mut newrule3 = Grule::new_skeleton(&newntname3);
let mut newrule4 = Grule::new_skeleton(&newntname3);
newrule3.lhs.rusttype = newnt3.rusttype.clone();
newrule4.lhs.rusttype = newnt3.rusttype.clone();
newrule3.precedence = self.Symbols[gsymi].precedence;
//PRECEDENCE SET TO SEPARATOR SYMBOL
newrule4.precedence = self.Symbols[termi].precedence;
// GENERATE AS FOR <COMMA+>
newrule3.rhs.push(self.Symbols[gsymi].clone()); //N-->E
newrule4.rhs.push(newnt3.clone());
newrule4.rhs.push(self.Symbols[termi].clone());
newrule4.rhs.push(self.Symbols[gsymi].clone());//N-->N,E
if newnt3.rusttype.starts_with("Vec") {
newrule3.action=String::from(" vec![parser.lbx(0,_item0_)] }");
newrule4.action=String::from(" _item0_.push(parser.lbx(2,_item2_)); _item0_ }");
} // else leave at default
self.Rules.push(newrule3);
self.Rules.push(newrule4);
let mut rulesforset3 = HashSet::with_capacity(2);
rulesforset3.insert(self.Rules.len()-2);
rulesforset3.insert(self.Rules.len()-1);
newtok3 = format!("{}:{}",&newntname3,relabel3);
self.Rulesfor.insert(newntname3,rulesforset3);
// ANOTHER RULE IS NEEDED IF strtok ends in *>
if strtok.ends_with("*>") { // M --> | N
let newntname5 = format!("NEWSEPNT2_{}_{}",self.Rules.len(),ntcnt); ntcnt+=1;
let mut newnt5 = Gsym::new(&newntname5,false);
newnt5.rusttype = newnt3.rusttype.clone();
self.Symhash.insert(newntname5.clone(),self.Symbols.len());
self.Symbols.push(newnt5.clone()); // register new nt
let mut newrule5 = Grule::new_skeleton(&newntname5);
let mut newrule6 = Grule::new_skeleton(&newntname5);
newrule5.lhs.rusttype = newnt5.rusttype.clone();
newrule6.lhs.rusttype = newnt5.rusttype.clone();
// 0 precedence for rule, newrule5 has empty rhs
newrule6.rhs.push(newnt3.clone());
if newnt5.rusttype.starts_with("Vec") {
newrule5.action = String::from(" vec![] }");
newrule6.action = String::from("_item0_ }");
}
self.Rules.push(newrule5);
self.Rules.push(newrule6);
let mut rulesforset5 = HashSet::with_capacity(2);
rulesforset5.insert(self.Rules.len()-2);
rulesforset5.insert(self.Rules.len()-1);
newtok3 = format!("{}:{}",&newntname5,relabel3);
self.Rulesfor.insert(newntname5,rulesforset5);
} // *>
strtok = &newtok3;
} // if ends with *> or +>
//////////// copied over stuff
if strtok.ends_with('?') {
newrule1.rhs.push(self.Symbols[gsymi].clone());
if newrule1.lhs.rusttype.starts_with("Option<LBox<") {
newrule1.action=String::from(" Some(parser.lbx(0,_item0_)) }"); } else if newrule1.lhs.rusttype.starts_with("Option<") {newrule1.action = String::from(" Some(_item0_) }"); } // else nothing
}// end with ?
else { // * or +
newrule1.rhs.push(newnt.clone());
newrule1.rhs.push(self.Symbols[gsymi].clone());
if &newrule1.lhs.rusttype!="()" {
newrule1.action = String::from(" _item0_.push(parser.lbx(1,_item1_)); _item0_ }");
}
} // * or +
let mut newrule0 = Grule::new_skeleton(&newntname);
newrule0.lhs.rusttype = newnt.rusttype.clone();
if strtok.ends_with('+') {
newrule0.rhs.push(self.Symbols[gsymi].clone());
if &newrule0.lhs.rusttype!="()" {
newrule0.action=String::from(" vec![parser.lbx(0,_item0_)] }");
}
}// ends with +
else if strtok.ends_with('*') && &newrule0.lhs.rusttype!="()" {
newrule0.action = String::from(" Vec::new() }");
}
else if strtok.ends_with('?') && &newrule0.lhs.rusttype!="()" {
newrule0.action = String::from(" None }");
}
if self.tracelev>4 {
printrule(&newrule0,self.Rules.len());
printrule(&newrule1,self.Rules.len()+1);
}
self.Rules.push(newrule0);
self.Rules.push(newrule1);
let mut rulesforset = HashSet::with_capacity(2);
rulesforset.insert(self.Rules.len()-2);
rulesforset.insert(self.Rules.len()-1);
newtok = format!("{}:{}",&newntname,relabel);
self.Rulesfor.insert(newntname,rulesforset);
// change strtok to new form
strtok = &newtok;
//println!("2 strtok now {}",strtok);
}// processes RE directive - add new productions