Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r85201 - in trunk/libs/log: doc src
From: andrey.semashev_at_[hidden]
Date: 2013-08-03 12:47:58


Author: andysem
Date: 2013-08-03 12:47:58 EDT (Sat, 03 Aug 2013)
New Revision: 85201
URL: http://svn.boost.org/trac/boost/changeset/85201

Log:
Settings parser rewritten without Boost.Spirit to reduce compiled binary size. Refs #8773.

Text files modified:
   trunk/libs/log/doc/changelog.qbk | 1
   trunk/libs/log/src/parser_utils.cpp | 2
   trunk/libs/log/src/parser_utils.hpp | 2
   trunk/libs/log/src/settings_parser.cpp | 254 +++++++++++++++++++++++++--------------
   4 files changed, 164 insertions(+), 95 deletions(-)

Modified: trunk/libs/log/doc/changelog.qbk
==============================================================================
--- trunk/libs/log/doc/changelog.qbk Sat Aug 3 12:04:39 2013 (r85200)
+++ trunk/libs/log/doc/changelog.qbk 2013-08-03 12:47:58 EDT (Sat, 03 Aug 2013) (r85201)
@@ -14,6 +14,7 @@
 [*General changes:]
 
 * Added a new configuration macro `BOOST_LOG_WITHOUT_DEFAULT_FACTORIES`. By defining this macro the user can disable compilation of the default filter and formatter factories used by settings parsers. This can substantially reduce binary sizes while still retaining support for settings parsers. Note that when this macro is defined the user will have to register _all_ attributes in the library.
+* Rewritten some of the parsers to reduce the compiled binary size.
 
 [heading 2.1, Boost 1.54]
 

Modified: trunk/libs/log/src/parser_utils.cpp
==============================================================================
--- trunk/libs/log/src/parser_utils.cpp Sat Aug 3 12:04:39 2013 (r85200)
+++ trunk/libs/log/src/parser_utils.cpp 2013-08-03 12:47:58 EDT (Sat, 03 Aug 2013) (r85201)
@@ -32,6 +32,7 @@
 
 const char_constants< char >::char_type char_constants< char >::char_comment;
 const char_constants< char >::char_type char_constants< char >::char_comma;
+const char_constants< char >::char_type char_constants< char >::char_dot;
 const char_constants< char >::char_type char_constants< char >::char_quote;
 const char_constants< char >::char_type char_constants< char >::char_percent;
 const char_constants< char >::char_type char_constants< char >::char_exclamation;
@@ -117,6 +118,7 @@
 
 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_comment;
 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_comma;
+const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_dot;
 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_quote;
 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_percent;
 const char_constants< wchar_t >::char_type char_constants< wchar_t >::char_exclamation;

Modified: trunk/libs/log/src/parser_utils.hpp
==============================================================================
--- trunk/libs/log/src/parser_utils.hpp Sat Aug 3 12:04:39 2013 (r85200)
+++ trunk/libs/log/src/parser_utils.hpp 2013-08-03 12:47:58 EDT (Sat, 03 Aug 2013) (r85201)
@@ -42,6 +42,7 @@
     typedef char char_type;
     static const char_type char_comment = '#';
     static const char_type char_comma = ',';
+ static const char_type char_dot = '.';
     static const char_type char_quote = '"';
     static const char_type char_percent = '%';
     static const char_type char_exclamation = '!';
@@ -158,6 +159,7 @@
     typedef wchar_t char_type;
     static const char_type char_comment = L'#';
     static const char_type char_comma = L',';
+ static const char_type char_dot = L'.';
     static const char_type char_quote = L'"';
     static const char_type char_percent = L'%';
     static const char_type char_exclamation = L'!';

Modified: trunk/libs/log/src/settings_parser.cpp
==============================================================================
--- trunk/libs/log/src/settings_parser.cpp Sat Aug 3 12:04:39 2013 (r85200)
+++ trunk/libs/log/src/settings_parser.cpp 2013-08-03 12:47:58 EDT (Sat, 03 Aug 2013) (r85201)
@@ -16,56 +16,37 @@
 #ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
 
 #include <string>
-#include <iostream>
 #include <locale>
-#include <memory>
+#include <iostream>
 #include <stdexcept>
-#include <boost/ref.hpp>
-#include <boost/bind.hpp>
+#include <algorithm>
 #include <boost/throw_exception.hpp>
 #include <boost/io/ios_state.hpp>
 #include <boost/move/core.hpp>
 #include <boost/move/utility.hpp>
-#include <boost/algorithm/string/trim.hpp>
-#include <boost/spirit/include/qi_core.hpp>
-#include <boost/spirit/include/qi_char.hpp>
-#include <boost/spirit/include/qi_lit.hpp>
-#include <boost/spirit/include/qi_eoi.hpp>
-#include <boost/spirit/include/qi_eol.hpp>
-#include <boost/spirit/include/qi_raw.hpp>
-#include <boost/spirit/include/qi_lexeme.hpp>
-#include <boost/range/iterator_range_core.hpp>
 #include <boost/log/detail/config.hpp>
 #include <boost/log/detail/code_conversion.hpp>
-#include <boost/log/exceptions.hpp>
 #include <boost/log/utility/setup/settings_parser.hpp>
+#include <boost/log/exceptions.hpp>
 #include "parser_utils.hpp"
 #include "spirit_encoding.hpp"
 #include <boost/log/detail/header.hpp>
 
-namespace qi = boost::spirit::qi;
-
 namespace boost {
 
 BOOST_LOG_OPEN_NAMESPACE
 
 BOOST_LOG_ANONYMOUS_NAMESPACE {
 
-//! Settings parsing grammar
+//! Settings parser
 template< typename CharT >
-class settings_grammar :
- public qi::grammar<
- const CharT*,
- typename log::aux::encoding_specific< typename log::aux::encoding< CharT >::type >::space_type
- >
+class settings_parser
 {
 private:
     typedef CharT char_type;
     typedef const char_type* iterator_type;
- typedef log::aux::encoding_specific< typename log::aux::encoding< char_type >::type > encoding_specific;
- typedef settings_grammar< char_type > this_type;
- typedef qi::grammar< iterator_type, typename encoding_specific::space_type > base_type;
- typedef typename base_type::start_type rule_type;
+ typedef typename log::aux::encoding< char_type >::type encoding;
+ typedef settings_parser< char_type > this_type;
 
     typedef std::basic_string< char_type > string_type;
     typedef log::aux::char_constants< char_type > constants;
@@ -83,70 +64,134 @@
     //! Current line number
     unsigned int& m_LineCounter;
 
- //! A parser for a comment
- rule_type comment;
- //! A parser for a section name
- rule_type section_name;
- //! A parser for a quoted string
- rule_type quoted_string;
- //! A parser for a parameter name and value
- rule_type parameter;
- //! A parser for a single line
- rule_type line;
-
 public:
     //! Constructor
- explicit settings_grammar(settings_type& setts, unsigned int& line_counter, std::locale const& loc) :
- base_type(line, "settings_grammar"),
+ explicit settings_parser(settings_type& setts, unsigned int& line_counter, std::locale const& loc) :
         m_Settings(setts),
         m_Locale(loc),
         m_LineCounter(line_counter)
     {
- comment = qi::lit(constants::char_comment) >> *qi::char_;
+ }
+
+ //! Parses a line of the input
+ void parse_line(iterator_type& begin, iterator_type end)
+ {
+ iterator_type p = begin;
+ trim_spaces_left(p, end);
+ if (p != end)
+ {
+ char_type c = *p;
+ if (c == constants::char_section_bracket_left)
+ {
+ // We have a section name
+ iterator_type start = ++p;
+ trim_spaces_left(start, end);
+ iterator_type stop = std::find(start, end, constants::char_section_bracket_right);
+ if (stop == end)
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section header is invalid.", (m_LineCounter));
+
+ p = stop + 1;
+ trim_spaces_right(start, stop);
 
- section_name =
- qi::raw[ qi::lit(constants::char_section_bracket_left) >> +(encoding_specific::graph - constants::char_section_bracket_right) >> constants::char_section_bracket_right ]
- [boost::bind(&this_type::set_section_name, this, _1)] >>
- -comment;
-
- quoted_string = qi::lexeme
- [
- qi::lit(constants::char_quote) >>
- *(
- (qi::lit(constants::char_backslash) >> qi::char_) |
- (qi::char_ - qi::lit(constants::char_quote))
- ) >>
- qi::lit(constants::char_quote)
- ];
-
- parameter =
- // Parameter name
- qi::raw[ qi::lexeme[ encoding_specific::alpha >> *(encoding_specific::graph - constants::char_equal) ] ]
- [boost::bind(&this_type::set_parameter_name, this, _1)] >>
- qi::lit(constants::char_equal) >>
- // Parameter value
- (
- qi::raw[ quoted_string ][boost::bind(&this_type::set_parameter_quoted_value, this, _1)] |
- qi::raw[ +encoding_specific::graph ][boost::bind(&this_type::set_parameter_value, this, _1)]
- ) >>
- -comment;
+ set_section_name(start, stop);
+ }
+ else if (c != constants::char_comment)
+ {
+ // We have a parameter
+ iterator_type eq = std::find(p, end, constants::char_equal);
+ if (eq == end)
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter description is invalid.", (m_LineCounter));
+
+ // Parameter name
+ iterator_type stop = eq;
+ trim_spaces_right(p, stop);
+
+ set_parameter_name(p, stop);
+
+ // Parameter value
+ p = eq + 1;
+ trim_spaces_left(p, end);
+ if (p == end || *p == constants::char_comment)
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter value is not specified.", (m_LineCounter));
+
+ c = *p;
+ if (c == constants::char_quote)
+ {
+ // The value is specified as a quoted string
+ iterator_type start = ++p;
+ for (; p != end; ++p)
+ {
+ c = *p;
+ if (c == constants::char_quote)
+ {
+ break;
+ }
+ else if (c == constants::char_backslash)
+ {
+ ++p;
+ if (p == end)
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Invalid escape sequence in the parameter value.", (m_LineCounter));
+ }
+ }
+ if (p == end)
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Unterminated quoted string in the parameter value.", (m_LineCounter));
+
+ set_parameter_quoted_value(start, p);
+
+ ++p; // skip the closing quote
+ }
+ else
+ {
+ // The value is specified as a single word
+ iterator_type start = p;
+ for (++p; p != end; ++p)
+ {
+ c = *p;
+ if (c == constants::char_comment || !encoding::isgraph(c))
+ break;
+ }
+
+ set_parameter_value(start, p);
+ }
+ }
+
+ // In the end of the line we may have a comment
+ trim_spaces_left(p, end);
+ if (p != end)
+ {
+ c = *p;
+ if (c == constants::char_comment)
+ {
+ // The comment spans until the end of the line
+ p = end;
+ }
+ else
+ {
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Unexpected characters in the end of the line.", (m_LineCounter));
+ }
+ }
+ }
 
- line = (comment | section_name | parameter) >> qi::eoi;
+ begin = p;
     }
 
 private:
     //! The method sets the parsed section name
- void set_section_name(iterator_range< iterator_type > const& sec)
+ void set_section_name(iterator_type begin, iterator_type end)
     {
- // Trim square brackets
- m_SectionName = log::aux::to_narrow(string_type(sec.begin() + 1, sec.end() - 1), m_Locale);
- algorithm::trim(m_SectionName, m_Locale);
- if (m_SectionName.empty())
+ // Check that the section name is valid
+ if (begin == end)
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section name is empty.", (m_LineCounter));
+
+ for (iterator_type p = begin; p != end; ++p)
         {
- // The section starter is broken
- BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "The section header is invalid.", (m_LineCounter));
+ char_type c = *p;
+ if (c != constants::char_dot && !encoding::isalnum(c))
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section name is invalid.", (m_LineCounter));
         }
 
+ m_SectionName = log::aux::to_narrow(string_type(begin, end), m_Locale);
+
         // For compatibility with Boost.Log v1, we replace the "Sink:" prefix with "Sinks."
         // so that all sink parameters are placed in the common Sinks section.
         if (m_SectionName.compare(0, 5, "Sink:") == 0)
@@ -154,7 +199,7 @@
     }
 
     //! The method sets the parsed parameter name
- void set_parameter_name(iterator_range< iterator_type > const& name)
+ void set_parameter_name(iterator_type begin, iterator_type end)
     {
         if (m_SectionName.empty())
         {
@@ -162,30 +207,56 @@
             BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameters are only allowed within sections.", (m_LineCounter));
         }
 
- m_ParameterName = log::aux::to_narrow(string_type(name.begin(), name.end()), m_Locale);
+ // Check that the parameter name is valid
+ if (begin == end)
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is empty.", (m_LineCounter));
+
+ iterator_type p = begin;
+ if (!encoding::isalpha(*p))
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is invalid.", (m_LineCounter));
+ for (++p; p != end; ++p)
+ {
+ char_type c = *p;
+ if (!encoding::isgraph(c))
+ BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is invalid.", (m_LineCounter));
+ }
+
+ m_ParameterName = log::aux::to_narrow(string_type(begin, end), m_Locale);
     }
 
     //! The method sets the parsed parameter value (non-quoted)
- void set_parameter_value(iterator_range< iterator_type > const& value)
+ void set_parameter_value(iterator_type begin, iterator_type end)
     {
- string_type val(value.begin(), value.end());
- m_Settings[m_SectionName][m_ParameterName] = val;
+ m_Settings[m_SectionName][m_ParameterName] = string_type(begin, end);
         m_ParameterName.clear();
     }
 
     //! The method sets the parsed parameter value (quoted)
- void set_parameter_quoted_value(iterator_range< iterator_type > const& value)
+ void set_parameter_quoted_value(iterator_type begin, iterator_type end)
     {
         // Cut off the quotes
- string_type val(value.begin() + 1, value.end() - 1);
+ string_type val(begin, end);
         constants::translate_escape_sequences(val);
         m_Settings[m_SectionName][m_ParameterName] = val;
         m_ParameterName.clear();
     }
 
+ //! Skips spaces in the beginning of the input
+ static void trim_spaces_left(iterator_type& begin, iterator_type end)
+ {
+ while (begin != end && encoding::isspace(*begin))
+ ++begin;
+ }
+ //! Skips spaces in the end of the input
+ static void trim_spaces_right(iterator_type begin, iterator_type& end)
+ {
+ while (begin != end && encoding::isspace(*(end - 1)))
+ --end;
+ }
+
     // Assignment and copying are prohibited
- BOOST_DELETED_FUNCTION(settings_grammar(settings_grammar const&))
- BOOST_DELETED_FUNCTION(settings_grammar& operator= (settings_grammar const&))
+ BOOST_DELETED_FUNCTION(settings_parser(settings_parser const&))
+ BOOST_DELETED_FUNCTION(settings_parser& operator= (settings_parser const&))
 };
 
 } // namespace
@@ -196,9 +267,8 @@
 {
     typedef CharT char_type;
     typedef std::basic_string< char_type > string_type;
- typedef settings_grammar< char_type > settings_grammar_type;
+ typedef settings_parser< char_type > settings_parser_type;
     typedef basic_settings< char_type > settings_type;
- typedef log::aux::encoding_specific< typename log::aux::encoding< char_type >::type > encoding_specific;
 
     if (!strm.good())
         BOOST_THROW_EXCEPTION(std::invalid_argument("The input stream for parsing settings is not valid"));
@@ -209,23 +279,17 @@
     settings_type settings;
     unsigned int line_number = 1;
     std::locale loc = strm.getloc();
- settings_grammar_type gram(settings, line_number, loc);
+ settings_parser_type parser(settings, line_number, loc);
 
     string_type line;
     while (!strm.eof())
     {
         std::getline(strm, line);
- algorithm::trim(line, loc);
 
- if (!line.empty())
- {
- if (!qi::phrase_parse(line.c_str(), line.c_str() + line.size(), gram, encoding_specific::space))
- {
- BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Could not parse settings from stream.", (line_number));
- }
- line.clear();
- }
+ const char_type* p = line.c_str();
+ parser.parse_line(p, p + line.size());
 
+ line.clear();
         ++line_number;
     }
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk