From 3a727af2645fb41d3f2151d1b1b4893232e49c06 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 4 Jan 2019 15:26:48 -0800 Subject: [PATCH] Add flag for logging the item set associated with a certain parse state --- src/build_tables/build_parse_table.rs | 43 ++++++++++++++------------- src/build_tables/item.rs | 18 ++++++++++- src/build_tables/mod.rs | 3 +- src/generate.rs | 16 ++++++---- src/main.rs | 15 +++++++++- 5 files changed, 66 insertions(+), 29 deletions(-) diff --git a/src/build_tables/build_parse_table.rs b/src/build_tables/build_parse_table.rs index 7fb668dd..cda1d7ea 100644 --- a/src/build_tables/build_parse_table.rs +++ b/src/build_tables/build_parse_table.rs @@ -39,6 +39,7 @@ struct ParseTableBuilder<'a> { parse_state_queue: VecDeque, parse_table: ParseTable, following_tokens: Vec, + state_ids_to_log: Vec, } impl<'a> ParseTableBuilder<'a> { @@ -64,29 +65,26 @@ impl<'a> ParseTableBuilder<'a> { ); while let Some(entry) = self.parse_state_queue.pop_front() { - // info!( - // "state: {}, item set: {}", - // entry.state_id, - // super::item::ParseItemSetDisplay( - // &self.item_sets_by_state_id[entry.state_id], - // self.syntax_grammar, - // self.lexical_grammar, - // ) - // ); - let item_set = self .item_set_builder .transitive_closure(&self.item_sets_by_state_id[entry.state_id]); - // info!( - // "state: {}, closed item set: {}", - // entry.state_id, - // super::item::ParseItemSetDisplay( - // &item_set, - // self.syntax_grammar, - // self.lexical_grammar, - // ) - // ); + if self.state_ids_to_log.contains(&entry.state_id) { + eprintln!( + "state: {}\n\ninitial item set:\n\n{}closed item set:\n\n{}", + entry.state_id, + super::item::ParseItemSetDisplay( + &self.item_sets_by_state_id[entry.state_id], + self.syntax_grammar, + self.lexical_grammar, + ), + super::item::ParseItemSetDisplay( + &item_set, + self.syntax_grammar, + self.lexical_grammar, + ) + ); + } self.add_actions( entry.preceding_symbols, @@ -553,6 +551,7 @@ impl<'a> ParseTableBuilder<'a> { ) .unwrap(); } + write!(&mut msg, "\n").unwrap(); } for item in &conflicting_items { @@ -560,7 +559,7 @@ impl<'a> ParseTableBuilder<'a> { resolution_count += 1; write!( &mut msg, - " {}: Specify a higher precedence in `{}` than in the other rules.\n", + " {}: Specify a higher precedence in `{}` than in the other rules.\n", resolution_count, self.symbol_name(&Symbol::non_terminal(item.variable_index as usize)) ) @@ -571,7 +570,7 @@ impl<'a> ParseTableBuilder<'a> { resolution_count += 1; write!( &mut msg, - " {}: Add a conflict for these rules: ", + " {}: Add a conflict for these rules: ", resolution_count ) .unwrap(); @@ -714,10 +713,12 @@ pub(crate) fn build_parse_table( syntax_grammar: &SyntaxGrammar, lexical_grammar: &LexicalGrammar, inlines: &InlinedProductionMap, + state_ids_to_log: Vec, ) -> Result<(ParseTable, Vec)> { ParseTableBuilder { syntax_grammar, lexical_grammar, + state_ids_to_log, item_set_builder: ParseItemSetBuilder::new(syntax_grammar, lexical_grammar, inlines), state_ids_by_item_set: HashMap::new(), item_sets_by_state_id: Vec::new(), diff --git a/src/build_tables/item.rs b/src/build_tables/item.rs index d1d0cbbf..bbd5bbfa 100644 --- a/src/build_tables/item.rs +++ b/src/build_tables/item.rs @@ -45,7 +45,7 @@ pub(crate) struct ParseItemSet<'a> { pub(crate) struct ParseItemDisplay<'a>( pub &'a ParseItem<'a>, pub &'a SyntaxGrammar, - pub &'a LexicalGrammar + pub &'a LexicalGrammar, ); pub(crate) struct LookaheadSetDisplay<'a>(&'a LookaheadSet, &'a SyntaxGrammar, &'a LexicalGrammar); @@ -252,6 +252,13 @@ impl<'a> fmt::Display for ParseItemDisplay<'a> { for (i, step) in self.0.production.steps.iter().enumerate() { if i == self.0.step_index as usize { write!(f, " •")?; + if step.precedence != 0 || step.associativity.is_some() { + write!( + f, + " (prec {:?} assoc {:?})", + step.precedence, step.associativity + )?; + } } write!(f, " ")?; @@ -274,6 +281,15 @@ impl<'a> fmt::Display for ParseItemDisplay<'a> { if self.0.is_done() { write!(f, " •")?; + if let Some(step) = self.0.production.steps.last() { + if step.precedence != 0 || step.associativity.is_some() { + write!( + f, + " (prec {:?} assoc {:?})", + step.precedence, step.associativity + )?; + } + } } Ok(()) diff --git a/src/build_tables/mod.rs b/src/build_tables/mod.rs index ed47665e..04b750e3 100644 --- a/src/build_tables/mod.rs +++ b/src/build_tables/mod.rs @@ -24,9 +24,10 @@ pub(crate) fn build_tables( simple_aliases: &AliasMap, inlines: &InlinedProductionMap, minimize: bool, + state_ids_to_log: Vec, ) -> Result<(ParseTable, LexTable, LexTable, Option)> { let (mut parse_table, following_tokens) = - build_parse_table(syntax_grammar, lexical_grammar, inlines)?; + build_parse_table(syntax_grammar, lexical_grammar, inlines, state_ids_to_log)?; let token_conflict_map = TokenConflictMap::new(lexical_grammar, following_tokens); let coincident_token_index = CoincidentTokenIndex::new(&parse_table, lexical_grammar); let keywords = identify_keywords( diff --git a/src/generate.rs b/src/generate.rs index d574c165..aa8f3b5b 100644 --- a/src/generate.rs +++ b/src/generate.rs @@ -1,18 +1,24 @@ +use crate::build_tables::build_tables; use crate::error::Result; use crate::parse_grammar::parse_grammar; use crate::prepare_grammar::prepare_grammar; -use crate::build_tables::build_tables; use crate::render::render_c_code; -pub fn generate_parser_for_grammar(input: &str, minimize: bool) -> Result { +pub fn generate_parser_for_grammar( + input: &str, + minimize: bool, + state_ids_to_log: Vec, +) -> Result { let input_grammar = parse_grammar(input)?; - let (syntax_grammar, lexical_grammar, inlines, simple_aliases) = prepare_grammar(&input_grammar)?; + let (syntax_grammar, lexical_grammar, inlines, simple_aliases) = + prepare_grammar(&input_grammar)?; let (parse_table, main_lex_table, keyword_lex_table, keyword_capture_token) = build_tables( &syntax_grammar, &lexical_grammar, &simple_aliases, &inlines, - minimize + minimize, + state_ids_to_log, )?; let c_code = render_c_code( &input_grammar.name, @@ -22,7 +28,7 @@ pub fn generate_parser_for_grammar(input: &str, minimize: bool) -> Result error::Result<()> { SubCommand::with_name("generate") .about("Generate a parser") .arg(Arg::with_name("log").long("log")) + .arg( + Arg::with_name("state-ids-to-log") + .long("log-state") + .takes_value(true), + ) .arg(Arg::with_name("no-minimize").long("no-minimize")), ) .subcommand( @@ -63,10 +69,17 @@ fn run() -> error::Result<()> { } let minimize = !matches.is_present("no-minimize"); + let state_ids_to_log = matches + .values_of("state-ids-to-log") + .map_or(Vec::new(), |ids| { + ids.filter_map(|id| usize::from_str_radix(id, 10).ok()) + .collect() + }); let mut grammar_path = env::current_dir().expect("Failed to read CWD"); grammar_path.push("grammar.js"); let grammar_json = load_js_grammar_file(grammar_path); - let code = generate::generate_parser_for_grammar(&grammar_json, minimize)?; + let code = + generate::generate_parser_for_grammar(&grammar_json, minimize, state_ids_to_log)?; println!("{}", code); }