#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(unused_parens)]
#![allow(unused_imports)]
use std::fmt::Display;
use std::default::Default;
use std::collections::{HashMap,HashSet,BTreeSet};
//mod lib;
//use lib::*;
//use crate::grammar_processor::{TRACE}
//mod bunch;
//use crate::bunch::*;
//mod runtime_parser;
//use crate::runtime_parser::*;
mod grammar_processor;
use grammar_processor::*;
mod lr_statemachine;
use lr_statemachine::*;
pub mod lexer_interface;
pub use lexer_interface::*;
pub mod runtime_parser;
use runtime_parser::*;
mod augmenter;
use augmenter::*;
pub mod generic_absyn;
pub use generic_absyn::*;
//mod enhancements;
//pub use enhancements::*;
pub mod zc_parser;
use zc_parser::*;
mod parser_writer;
use parser_writer::*;
mod ast_writer;
use ast_writer::*;
mod lalr_statemachine;
use lalr_statemachine::LALRMachine;
mod selmlk;
fn main()
{
let args:Vec<String> = std::env::args().collect(); // command-line args
rustle(&args);
}//main
fn rustle(args:&Vec<String>) // called from main
{
let argc = args.len();
if argc<2 {eprintln!("Must give path of .grammar file"); return;}
let filepath = &args[1];
let mut parserfile = String::from("");
let mut argi = 2; // next argument position
let mut lalr = false; // changed from false in version 0.2.0
let mut newlalr = true;
let mut tracelev:usize = 1; // trace-level
let mut verbose = false;
let mut zc = true;
let mut genlex = false;
let mut genabsyn = false;
while argi<argc
{
match &args[argi][..] {
"lr1" | "LR1" | "-lr1" => { lalr=false; newlalr=false; },
"lalr" | "LALR" | "-lalr" => {newlalr=true; },
"lalr1" | "LALR1" | "-lalr1" => {newlalr=true; },
"oldlalr" | "-oldlalr" => {newlalr=false; lalr=true;}
"-trace" => {
argi+=1;
if argi<argc {
if let Ok(lv) = args[argi].parse::<usize>() {tracelev=lv; }
if tracelev>0 {println!("trace-level set to {}",tracelev);}
}
},
"verbose" | "-verbose" => { verbose=true; },
"-zc" | "zero_copy" => {zc=true;},
"genlex" | "-genlex" => {genlex=true; },
"-genabsyn" | "-ast" | "-auto" => {genabsyn = true; },
"-nozc" => {zc=false;},
"binary" | "-binary" => { verbose=false; },
"-o" => {
argi+=1;
if argi<argc {parserfile = args[argi].clone();}
},
_ => {},
}//match directive
argi+=1;
}//while there are command-line args
if zc && verbose {
println!("verbose mode not compatible with -zc option");
return;
}
if tracelev>0 && verbose {println!("verbose parsers should be used for diagnositic purposes and cannot be trained/augmented");}
if tracelev>1 {println!("parsing grammar from {}",&filepath);}
let mut grammar1 = Grammar::new();
grammar1.genlex = genlex;
grammar1.genabsyn = genabsyn;
grammar1.tracelev = tracelev;
grammar1.parse_grammar(filepath);
// Check grammar integrity:
// let topi = *grammar1.Symhash.get(&grammar1.topsym).expect("FATAL ERROR: Grammar start symbol 'topsym' not defined");
// let toptype = &grammar1.Symbols[topi].rusttype;
if grammar1.name.len()<2 { // derive grammar name from filepath
let doti = if let Some(p)= filepath.rfind('.') {p} else {filepath.len()};
let mut slashi = if let Some(p) = filepath.rfind('/') {p+1} else {0};
if slashi==0 {
slashi = if let Some(p) = filepath.rfind('\\') {p+1} else {0};
}
grammar1.name = filepath[slashi..doti].to_string();
}// derive grammar name
let gramname = grammar1.name.clone();
if genabsyn {
let mut slashpos = parserfile.rfind('/');
if let None = slashpos {slashpos = parserfile.rfind('\\');}
let mut astpath = format!("{}_ast.rs",&gramname);
if let Some(pos) = slashpos { astpath=format!("{}{}",&parserfile[..pos+1],&astpath); }
let wres = grammar1.writeabsyn(&astpath);
if !wres.is_ok() {eprintln!("Failed to generate abstract syntax"); return;}
}
if tracelev>2 {println!("computing Nullable set");}
grammar1.compute_NullableRf();
if tracelev>2 {println!("computing First sets");}
grammar1.compute_FirstIM();
let mut fsm0;
if newlalr { // newlalr takes precedence over other flags
let mut lalrfsm = LALRMachine::new(grammar1);
println!("Generating LALR(1) state machine");
lalrfsm.generatefsm();
fsm0 = lalrfsm.to_statemachine();
}
else {
fsm0 = Statemachine::new(grammar1);
fsm0.lalr = lalr;
if lalr {fsm0.Open = Vec::with_capacity(1024); } // important
if tracelev>0 {println!("Generating {} state machine for grammar {}...",if lalr {"older LALR"} else {"LR1"},&gramname);}
fsm0.generatefsm(); //GENERATE THE FSM
} // old code
if tracelev>2 && !newlalr { for state in &fsm0.States {printstate(state,&fsm0.Gmr);} }
else if tracelev>1 && !newlalr { printstate(&fsm0.States[0],&fsm0.Gmr); }//print states
if parserfile.len()<1 || parserfile.ends_with('/') || parserfile.ends_with('\\') {parserfile.push_str(&format!("{}parser.rs",&gramname));}
if fsm0.States.len()>65536 {
println!("too many states: {} execeeds limit of 65536",fsm0.States.len());
return;
}
let write_result =
if zc { // write zero-copy parser
//fsm0.writezcparser(&parserfile)
//fsm0.writelbaparser(&parserfile)
fsm0.writeenumparser(&parserfile)
}
else { // non-zc, original before version 0.2.0
if verbose /*fsm0.States.len()<=16*/ {fsm0.write_verbose(&parserfile)}
else {fsm0.writeparser(&parserfile)}
}; // write_result =
if tracelev>0 {eprintln!("{} total states",fsm0.FSM.len());}
if let Ok(_) = write_result {
if tracelev>0 {println!("written parser to {}",&parserfile);}
}
else if let Err(err) = write_result {
println!("failed to write parser, likely due to invalid -o destination: {:?}",err);
}
}//rustle