From 1f572973c3a5fa580e3d318415e1d4d297bd059b Mon Sep 17 00:00:00 2001 From: Charles Baker Date: Sun, 28 May 2023 16:21:19 +1200 Subject: [PATCH] Reduce memory usage by omitting labels in normal parsers Labels are only used to add meaningful text to states in Graphviz DOT graphs. But these strings can take lots of time and memory to generate especially in large grammars like that for PostgreSQL. Therefore only generate labels when they will be used. --- src/lalr/GrammarCompiler.cpp | 8 +++++++- src/lalr/GrammarCompiler.hpp | 2 ++ src/lalr/lalrc/lalrc.cpp | 9 ++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/lalr/GrammarCompiler.cpp b/src/lalr/GrammarCompiler.cpp index cf0a33d..29b0065 100644 --- a/src/lalr/GrammarCompiler.cpp +++ b/src/lalr/GrammarCompiler.cpp @@ -41,6 +41,7 @@ GrammarCompiler::GrammarCompiler() , lexer_() , whitespace_lexer_() , parser_state_machine_() +, labels_enabled_{ false } { lexer_.reset( new RegexCompiler ); whitespace_lexer_.reset( new RegexCompiler ); @@ -67,6 +68,11 @@ const ParserStateMachine* GrammarCompiler::parser_state_machine() const return parser_state_machine_.get(); } +void GrammarCompiler::labels_enabled( bool enabled ) +{ + labels_enabled_ = enabled; +} + int GrammarCompiler::compile( const char* begin, const char* end, ErrorPolicy* error_policy ) { Grammar grammar; @@ -239,7 +245,7 @@ void GrammarCompiler::populate_parser_state_machine( const Grammar& grammar, con state->index = state_index; state->length = grammar_state->count_valid_transitions(); state->transitions = &transitions[transition_index]; - state->label = add_string( generator.label_state(*grammar_state) ); + state->label = labels_enabled_ ? add_string( generator.label_state(*grammar_state) ) : nullptr; if ( grammar_state == generator.start_state() ) { start_state = state; diff --git a/src/lalr/GrammarCompiler.hpp b/src/lalr/GrammarCompiler.hpp index 8ce1f8b..f3571ac 100644 --- a/src/lalr/GrammarCompiler.hpp +++ b/src/lalr/GrammarCompiler.hpp @@ -30,6 +30,7 @@ class GrammarCompiler std::unique_ptr lexer_; ///< Allocated lexer state machine. std::unique_ptr whitespace_lexer_; ///< Allocated whitespace lexer state machine. std::unique_ptr parser_state_machine_; ///< Allocated parser state machine. + bool labels_enabled_; ///< True to generate labels for states and symbols. public: GrammarCompiler(); @@ -37,6 +38,7 @@ public: const RegexCompiler* lexer() const; const RegexCompiler* whitespace_lexer() const; const ParserStateMachine* parser_state_machine() const; + void labels_enabled( bool enabled ); int compile( const char* begin, const char* end, ErrorPolicy* error_policy = nullptr ); private: diff --git a/src/lalr/lalrc/lalrc.cpp b/src/lalr/lalrc/lalrc.cpp index 1a2685e..8d8e5b3 100644 --- a/src/lalr/lalrc/lalrc.cpp +++ b/src/lalr/lalrc/lalrc.cpp @@ -135,7 +135,14 @@ int main( int argc, char** argv ) return EXIT_FAILURE; } + // Enable state labels only when generating Graphviz DOT graphs + // because generating so many strings takes lots of time and memory. GrammarCompiler compiler; + if ( dot ) + { + compiler.labels_enabled( true ); + } + ErrorPolicy error_policy; int errors = compiler.compile( &grammar_source[0], &grammar_source[0] + grammar_source.size(), &error_policy ); if ( errors != 0 ) @@ -344,7 +351,7 @@ void generate_cxx_parser_state_machine( const ParserStateMachine* state_machine state->index, state->length, state->transitions->index, - sanitize( state->label ).c_str() + state->label ? sanitize( state->label ).c_str() : nullptr ); } write( " {-1, 0, nullptr}\n" );