rustlr 0.6.6

Bottom-Up Parser Generator with Advanced Options
Documentation
#![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