$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r85391 - trunk/libs/log/src
From: andrey.semashev_at_[hidden]
Date: 2013-08-18 11:10:27
Author: andysem
Date: 2013-08-18 11:10:24 EDT (Sun, 18 Aug 2013)
New Revision: 85391
URL: http://svn.boost.org/trac/boost/changeset/85391
Log:
Filter parser rewritten to avoid using Boost.Spirit to reduce compiled binary size. Refs #8773.
Text files modified: 
   trunk/libs/log/src/filter_parser.cpp    |   340 ++++++++++++++++++++++----------------- 
   trunk/libs/log/src/formatter_parser.cpp |   110 +++---------                            
   trunk/libs/log/src/parser_utils.cpp     |   159 +++++++++++++++++-                      
   trunk/libs/log/src/parser_utils.hpp     |    16 +                                       
   trunk/libs/log/src/settings_parser.cpp  |    78 ++------                                
   5 files changed, 408 insertions(+), 295 deletions(-)
Modified: trunk/libs/log/src/filter_parser.cpp
==============================================================================
--- trunk/libs/log/src/filter_parser.cpp	Sun Aug 18 06:04:46 2013	(r85390)
+++ trunk/libs/log/src/filter_parser.cpp	2013-08-18 11:10:24 EDT (Sun, 18 Aug 2013)	(r85391)
@@ -23,23 +23,14 @@
 #include <stdexcept>
 #include <utility>
 #include <boost/assert.hpp>
-#include <boost/bind.hpp>
 #include <boost/none.hpp>
 #include <boost/move/core.hpp>
 #include <boost/move/utility.hpp>
 #include <boost/optional/optional.hpp>
 #include <boost/utility/in_place_factory.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_raw.hpp>
-#include <boost/spirit/include/qi_lexeme.hpp>
-#include <boost/spirit/include/qi_as.hpp>
-#include <boost/spirit/include/qi_symbols.hpp>
 #include <boost/phoenix/core.hpp>
 #include <boost/phoenix/bind/bind_function_object.hpp>
 #include <boost/phoenix/operator/logical.hpp>
-#include <boost/range/iterator_range_core.hpp>
 #include <boost/log/detail/singleton.hpp>
 #include <boost/log/exceptions.hpp>
 #include <boost/log/utility/setup/filter_parser.hpp>
@@ -54,8 +45,6 @@
 #include "spirit_encoding.hpp"
 #include <boost/log/detail/header.hpp>
 
-namespace qi = boost::spirit::qi;
-
 namespace boost {
 
 BOOST_LOG_OPEN_NAMESPACE
@@ -125,23 +114,17 @@
     }
 };
 
-//! Filter parsing grammar
+//! Filter parser
 template< typename CharT >
-class filter_grammar :
-    public qi::grammar<
-        const CharT*,
-        typename log::aux::encoding_specific< typename log::aux::encoding< CharT >::type >::space_type
-    >
+class filter_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 typename log::aux::encoding< char_type >::type encoding;
+    typedef log::aux::encoding_specific< encoding > encoding_specific;
     typedef std::basic_string< char_type > string_type;
     typedef log::aux::char_constants< char_type > constants;
-    typedef filter_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 filter_factory< char_type > filter_factory_type;
 
     typedef filter (filter_factory_type::*comparison_relation_handler_t)(attribute_name const&, string_type const&);
@@ -159,147 +142,220 @@
     //! Filter subexpressions as they are parsed
     mutable std::stack< filter > m_Subexpressions;
 
-    //! A parser for an attribute name in a single relation
-    rule_type attr_name;
-    //! A parser for a quoted string
-    rule_type quoted_string_operand;
-    //! A parser for an operand in a single relation
-    rule_type operand;
-    //! A parser for a single relation that consists of two operands and an operation between them
-    rule_type relation;
-    //! A set of comparison relation symbols with corresponding pointers to callbacks
-    qi::symbols< char_type, comparison_relation_handler_t > comparison_relation;
-    //! A parser for a custom relation word
-    rule_type custom_relation;
-    //! A parser for a term, which can be a relation, an expression in parenthesis or a negation thereof
-    rule_type term;
-    //! A parser for the complete filter expression that consists of one or several terms with boolean operations between them
-    rule_type expression;
-
 public:
     //! Constructor
-    filter_grammar() :
-        base_type(expression),
+    filter_parser() :
         m_ComparisonRelation(NULL)
     {
-        attr_name = qi::lexeme
-        [
-            // An attribute name in form %name%
-            qi::as< string_type >()[ qi::lit(constants::char_percent) >> +(encoding_specific::print - constants::char_percent) >> qi::lit(constants::char_percent) ]
-                [boost::bind(&filter_grammar::on_attribute_name, this, _1)]
-        ];
-
-        quoted_string_operand = qi::raw
-        [
-            qi::lexeme
-            [
-                // A quoted string with C-style escape sequences support
-                qi::lit(constants::char_quote) >>
-                *(
-                     (qi::lit(constants::char_backslash) >> qi::char_) |
-                     (qi::char_ - qi::lit(constants::char_quote))
-                ) >>
-                qi::lit(constants::char_quote)
-            ]
-        ]
-            [boost::bind(&filter_grammar::on_quoted_string_operand, this, _1)];
-
-        operand =
-        (
-            quoted_string_operand |
-            // A single word, enclosed with white spaces. It cannot contain parenthesis, since it is used by the filter parser.
-            qi::raw[ qi::lexeme[ +(encoding_specific::graph - qi::lit(constants::char_paren_bracket_left) - qi::lit(constants::char_paren_bracket_right)) ] ]
-                [boost::bind(&filter_grammar::on_operand, this, _1)]
-        );
-
-        // Custom relation is a keyword that may contain either alphanumeric characters or an underscore
-        custom_relation = qi::as< string_type >()[ qi::lexeme[ +(encoding_specific::alnum | qi::char_(constants::char_underline)) ] ]
-            [boost::bind(&filter_grammar::set_custom_relation, this, _1)];
-
-        comparison_relation.add
-            (constants::equal_keyword(), &filter_factory_type::on_equality_relation)
-            (constants::not_equal_keyword(), &filter_factory_type::on_inequality_relation)
-            (constants::greater_keyword(), &filter_factory_type::on_greater_relation)
-            (constants::less_keyword(), &filter_factory_type::on_less_relation)
-            (constants::greater_or_equal_keyword(), &filter_factory_type::on_greater_or_equal_relation)
-            (constants::less_or_equal_keyword(), &filter_factory_type::on_less_or_equal_relation);
-
-        relation =
-        (
-            attr_name >> // The relation may be as simple as a sole attribute name, in which case the filter checks for the attribute value presence
-            -(
-                (comparison_relation[boost::bind(&filter_grammar::set_comparison_relation, this, _1)] >> operand) |
-                (custom_relation >> operand)
-            )
-        )
-            [boost::bind(&filter_grammar::on_relation_complete, this)];
-
-        term =
-        (
-            (qi::lit(constants::char_paren_bracket_left) >> expression >> constants::char_paren_bracket_right) |
-            ((qi::lit(constants::not_keyword()) | constants::char_exclamation) >> term)[boost::bind(&filter_grammar::on_negation, this)] |
-            relation
-        );
-
-        expression =
-        (
-            term >>
-            *(
-                ((qi::lit(constants::and_keyword()) | constants::char_and) >> term)[boost::bind(&filter_grammar::on_and, this)] |
-                ((qi::lit(constants::or_keyword()) | constants::char_or) >> term)[boost::bind(&filter_grammar::on_or, this)]
-            )
-        );
     }
 
     //! The method returns the constructed filter
     filter get_filter()
     {
-        BOOST_ASSERT(!m_Subexpressions.empty());
+        if (m_Subexpressions.empty())
+            return filter();
         return boost::move(m_Subexpressions.top());
     }
 
-private:
-    //! The attribute name handler
-    void on_attribute_name(string_type const& name)
+    //! The pethod parses filter from the string
+    void parse(iterator_type& begin, iterator_type end, unsigned int depth = 0)
     {
-        m_AttributeName = attribute_name(log::aux::to_narrow(name));
+        typedef void (filter_parser::*logical_op_t)();
+        logical_op_t logical_op = NULL;
+        iterator_type p = constants::trim_spaces_left(begin, end);
+        while (p != end)
+        {
+            // Parse subexpression
+            parse_subexpression(p, end, depth);
+            if (logical_op)
+            {
+                // This was the right-hand subexpression. Compose the two top subexpressions into a single filter.
+                (this->*logical_op)();
+                logical_op = NULL;
+            }
+
+            p = constants::trim_spaces_left(p, end);
+            if (p != end)
+            {
+                char_type c = *p;
+                iterator_type next = p + 1;
+                if (c == constants::char_paren_bracket_right)
+                {
+                    // The subexpression has ended
+                    if (depth == 0)
+                        BOOST_LOG_THROW_DESCR(parse_error, "Invalid filter definition: unmatched closing parenthesis");
+
+                    p = next;
+                    --depth;
+                    break;
+                }
+                else if (c == constants::char_and || scan_keyword(p, end, next, constants::and_keyword()))
+                {
+                    logical_op = &filter_parser::on_and;
+                }
+                else if (c == constants::char_or || scan_keyword(p, end, next, constants::or_keyword()))
+                {
+                    logical_op = &filter_parser::on_or;
+                }
+                else
+                {
+                    BOOST_LOG_THROW_DESCR(parse_error, "Invalid filter definition: unexpected character encountered");
+                }
+
+                p = constants::trim_spaces_left(next, end);
+            }
+            else
+                break;
+        }
+
+        if (logical_op)
+        {
+            BOOST_LOG_THROW_DESCR(parse_error, "Invalid filter definition: logical operation without the right-hand subexpression");
+        }
+
+        if (p == end && depth > 0)
+        {
+            BOOST_LOG_THROW_DESCR(parse_error, "Invalid filter definition: unterminated parenthesis");
+        }
+
+        begin = p;
     }
 
-    //! The operand string handler
-    void on_operand(iterator_range< iterator_type > const& arg)
+private:
+    //! The method parses a single subexpression
+    void parse_subexpression(iterator_type& begin, iterator_type end, unsigned int depth)
     {
-        // An attribute name should have been parsed at this point
-        if (!m_AttributeName)
-            BOOST_LOG_THROW_DESCR(parse_error, "Invalid filter definition: operand is not expected");
+        bool negated = false, negation_present = false;
+        iterator_type p = begin;
 
-        m_Operand = boost::in_place(arg.begin(), arg.end());
+        while (p != end)
+        {
+            char_type c = *p;
+            iterator_type next = p + 1;
+            if (c == constants::char_percent)
+            {
+                // We found an attribute placeholder
+                iterator_type start = constants::trim_spaces_left(next, end);
+                p = constants::scan_attr_placeholder(start, end);
+                if (p == end)
+                    BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the filter string");
+
+                on_attribute_name(start, p);
+
+                p = constants::trim_spaces_left(p, end);
+                if (p == end || *p != constants::char_percent)
+                    BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the filter string");
+
+                // Skip the closing char_percent
+                p = constants::trim_spaces_left(++p, end);
+
+                // If the filter has negation operator, do not expect a relation (i.e. "!%attr% > 1" is not valid because "!%attr%" is interpreted as an attribute presence test)
+                if (!negation_present)
+                    p = parse_relation(p, end);
+            }
+            else if (c == constants::char_exclamation || scan_keyword(p, end, next, constants::not_keyword()))
+            {
+                // We found negation operation. Parse the subexpression to be negated.
+                negated ^= true;
+                negation_present = true;
+                p = constants::trim_spaces_left(next, end);
+                continue;
+            }
+            else if (c == constants::char_paren_bracket_left)
+            {
+                // We found a nested subexpression
+                parse(next, end, depth + 1);
+                p = next;
+            }
+            else
+            {
+                BOOST_LOG_THROW_DESCR(parse_error, "Invalid filter definition: unexpected character");
+            }
+
+            if (negated)
+                on_negation();
+
+            break;
+        }
+
+        begin = p;
     }
 
-    //! The quoted string handler
-    void on_quoted_string_operand(iterator_range< iterator_type > const& arg)
+    //! Parses filtering relation
+    iterator_type parse_relation(iterator_type begin, iterator_type end)
     {
-        // An attribute name should have been parsed at this point
-        if (!m_AttributeName)
-            BOOST_LOG_THROW_DESCR(parse_error, "Invalid filter definition: quoted string operand is not expected");
+        iterator_type p = begin;
+        if (p != end)
+        {
+            iterator_type next = p;
+            if (scan_keyword(p, end, next, constants::equal_keyword()))
+                m_ComparisonRelation = &filter_factory_type::on_equality_relation;
+            else if (scan_keyword(p, end, next, constants::not_equal_keyword()))
+                m_ComparisonRelation = &filter_factory_type::on_inequality_relation;
+            else if (scan_keyword(p, end, next, constants::greater_keyword()))
+                m_ComparisonRelation = &filter_factory_type::on_greater_relation;
+            else if (scan_keyword(p, end, next, constants::less_keyword()))
+                m_ComparisonRelation = &filter_factory_type::on_less_relation;
+            else if (scan_keyword(p, end, next, constants::greater_or_equal_keyword()))
+                m_ComparisonRelation = &filter_factory_type::on_greater_or_equal_relation;
+            else if (scan_keyword(p, end, next, constants::less_or_equal_keyword()))
+                m_ComparisonRelation = &filter_factory_type::on_less_or_equal_relation;
+            else
+            {
+                // Check for custom relation
+                while (next != end && (encoding::isalnum(*next) || *next == constants::char_underline))
+                    ++next;
+                if (p == next)
+                    goto DoneL;
+                m_CustomRelation.assign(p, next);
+            }
+
+            // We have parsed a relation operator, there must be an operand
+            next = constants::trim_spaces_left(next, end);
+            string_type operand;
+            p = constants::parse_operand(next, end, operand);
+            if (next == p)
+                BOOST_LOG_THROW_DESCR(parse_error, "Missing operand for a relation in the filter string");
+
+            m_Operand = boost::in_place(operand);
+        }
 
-        // Cut off the quotes
-        string_type str(arg.begin() + 1, arg.end() - 1);
+    DoneL:
+        // The relation can be as simple as a sole attribute placeholder (which means that only attribute presence has to be checked).
+        // So regardless how we get here, the relation is parsed completely.
+        on_relation_complete();
 
-        // Translate escape sequences
-        constants::translate_escape_sequences(str);
-        m_Operand = str;
+        return p;
     }
 
-    //! The method saves the relation word into an internal string
-    void set_comparison_relation(comparison_relation_handler_t rel)
+    //! Checks if the string contains a keyword
+    static bool scan_keyword(iterator_type begin, iterator_type end, iterator_type& next, iterator_type keyword)
     {
-        m_ComparisonRelation = rel;
+        for (iterator_type p = begin; p != end; ++p, ++keyword)
+        {
+            char_type c1 = *p, c2 = *keyword;
+            if (c2 == 0)
+            {
+                if (encoding::isspace(c1))
+                {
+                    next = p;
+                    return true;
+                }
+                break;
+            }
+            if (c1 != c2)
+                break;
+        }
+
+        return false;
     }
 
-    //! The method saves the relation word into an internal string
-    void set_custom_relation(string_type const& rel)
+    //! The attribute name handler
+    void on_attribute_name(iterator_type begin, iterator_type end)
     {
-        m_CustomRelation = rel;
+        if (begin == end)
+            BOOST_LOG_THROW_DESCR(parse_error, "Empty attribute name encountered");
+        m_AttributeName = attribute_name(log::aux::to_narrow(string_type(begin, end)));
     }
 
     //! The comparison relation handler
@@ -401,8 +457,8 @@
     }
 
     //  Assignment and copying are prohibited
-    BOOST_DELETED_FUNCTION(filter_grammar(filter_grammar const&))
-    BOOST_DELETED_FUNCTION(filter_grammar& operator= (filter_grammar const&))
+    BOOST_DELETED_FUNCTION(filter_parser(filter_parser const&))
+    BOOST_DELETED_FUNCTION(filter_parser& operator= (filter_parser const&))
 };
 
 } // namespace
@@ -427,21 +483,15 @@
     typedef CharT char_type;
     typedef log::aux::encoding_specific< typename log::aux::encoding< char_type >::type > encoding_specific;
 
-    filter_grammar< char_type > gram;
+    filter_parser< char_type > parser;
     const char_type* p = begin;
 
     BOOST_LOG_EXPR_IF_MT(filters_repository< CharT >& repo = filters_repository< CharT >::get();)
     BOOST_LOG_EXPR_IF_MT(log::aux::shared_lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);)
 
-    bool result = qi::phrase_parse(p, end, gram, encoding_specific::space);
-    if (!result || p != end)
-    {
-        std::ostringstream strm;
-        strm << "Could not parse the filter, parsing stopped at position " << p - begin;
-        BOOST_LOG_THROW_DESCR(parse_error, strm.str());
-    }
+    parser.parse(p, end);
 
-    return gram.get_filter();
+    return parser.get_filter();
 }
 
 #ifdef BOOST_LOG_USE_CHAR
Modified: trunk/libs/log/src/formatter_parser.cpp
==============================================================================
--- trunk/libs/log/src/formatter_parser.cpp	Sun Aug 18 06:04:46 2013	(r85390)
+++ trunk/libs/log/src/formatter_parser.cpp	2013-08-18 11:10:24 EDT (Sun, 18 Aug 2013)	(r85391)
@@ -15,7 +15,6 @@
 
 #ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS
 
-#include <ctime>
 #include <map>
 #include <string>
 #include <sstream>
@@ -201,7 +200,7 @@
                     // We found an escaped character
                     ++p;
                     if (p == end)
-                        BOOST_LOG_THROW_DESCR(parse_error, "Invalid escape sequence in the formatter string.");
+                        BOOST_LOG_THROW_DESCR(parse_error, "Invalid escape sequence in the formatter string");
                 }
                 else if (c == constants::char_percent)
                 {
@@ -216,22 +215,16 @@
             if (p != end)
             {
                 // We found an attribute placeholder
-                iterator_type start = p = constants::trim_spaces_left(++p, end);
-                while (p != end)
-                {
-                    char_type c = *p;
-                    if (!encoding::isalnum(c) && c != constants::char_underline)
-                        break;
-                    ++p;
-                }
+                iterator_type start = constants::trim_spaces_left(++p, end);
+                p = constants::scan_attr_placeholder(start, end);
                 if (p == end)
-                    BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string.");
+                    BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
 
-                on_attr_name(start, p);
+                on_attribute_name(start, p);
 
                 p = constants::trim_spaces_left(p, end);
                 if (p == end)
-                    BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string.");
+                    BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
 
                 if (*p == constants::char_paren_bracket_left)
                 {
@@ -239,11 +232,11 @@
                     p = parse_args(constants::trim_spaces_left(++p, end), end);
                     p = constants::trim_spaces_left(p, end);
                     if (p == end)
-                        BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string.");
+                        BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
                 }
 
                 if (*p != constants::char_percent)
-                    BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string.");
+                    BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder in the formatter string");
 
                 ++p;
 
@@ -272,7 +265,7 @@
     {
         iterator_type p = begin;
         if (p == end)
-            BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string.");
+            BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string");
         if (*p == constants::char_paren_bracket_right)
             return p;
 
@@ -283,76 +276,36 @@
             // Read argument name
             iterator_type start = p;
             if (!encoding::isalpha(*p))
-                BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid.");
+                BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid");
             for (++p; p != end; ++p)
             {
                 c = *p;
                 if (encoding::isspace(c) || c == constants::char_equal)
                     break;
                 if (!encoding::isalnum(c))
-                    BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid.");
+                    BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid");
             }
 
             if (start == p)
-                BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is empty.");
+                BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is empty");
 
             on_arg_name(start, p);
 
             p = constants::trim_spaces_left(p, end);
             if (p == end || *p != constants::char_equal)
-                BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument description is not valid.");
+                BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument description is not valid");
 
             // Read argument value
-            p = constants::trim_spaces_left(++p, end);
-
-            if (p == end)
-                BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument value is empty.");
-
-            c = *p;
-            if (c == constants::char_quote)
-            {
-                // The value is specified as a quoted string
-                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(parse_error, "Invalid escape sequence in the argument value.");
-                    }
-                }
-                if (p == end)
-                    BOOST_LOG_THROW_DESCR(parse_error, "Unterminated quoted string in the argument value.");
-
-                on_quoted_string_arg_value(start, p);
-
-                ++p; // skip the closing quote
-            }
-            else
-            {
-                // The value is specified as a single word
-                start = p;
-                for (++p; p != end; ++p)
-                {
-                    c = *p;
-                    if (!encoding::isgraph(c) || c == constants::char_comma || c == constants::char_paren_bracket_left || c == constants::char_paren_bracket_right)
-                        break;
-                }
-
-                on_arg_value(start, p);
-            }
+            start = p = constants::trim_spaces_left(++p, end);
+            p = constants::parse_operand(p, end, m_ArgValue);
+            if (p == start)
+                BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument value is not specified");
 
             push_arg();
 
             p = constants::trim_spaces_left(p, end);
             if (p == end)
-                BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string.");
+                BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string");
 
             c = *p;
             if (c == constants::char_paren_bracket_right)
@@ -363,11 +316,11 @@
             {
                 p = constants::trim_spaces_left(++p, end);
                 if (p == end)
-                    BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid.");
+                    BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid");
             }
             else
             {
-                BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string.");
+                BOOST_LOG_THROW_DESCR(parse_error, "Invalid attribute placeholder arguments description in the formatter string");
             }
         }
 
@@ -379,18 +332,7 @@
     {
         m_ArgName.assign(begin, end);
     }
-    //! The method is called when an argument value is discovered
-    void on_quoted_string_arg_value(iterator_type begin, iterator_type end)
-    {
-        // Cut off the quotes
-        m_ArgValue.assign(begin, end);
-        constants::translate_escape_sequences(m_ArgValue);
-    }
-    //! The method is called when an argument value is discovered
-    void on_arg_value(iterator_type begin, iterator_type end)
-    {
-        m_ArgValue.assign(begin, end);
-    }
+
     //! The method is called when an argument is filled
     void push_arg()
     {
@@ -400,16 +342,22 @@
     }
 
     //! The method is called when an attribute name is discovered
-    void on_attr_name(iterator_type begin, iterator_type end)
+    void on_attribute_name(iterator_type begin, iterator_type end)
     {
         if (begin == end)
             BOOST_LOG_THROW_DESCR(parse_error, "Empty attribute name encountered");
 
         // For compatibility with Boost.Log v1 we recognize %_% as the message attribute name
-        if (std::char_traits< char_type >::compare(constants::message_text_keyword(), begin, end - begin) == 0)
+        const std::size_t len = end - begin;
+        if (std::char_traits< char_type >::length(constants::message_text_keyword()) == len &&
+            std::char_traits< char_type >::compare(constants::message_text_keyword(), begin, len) == 0)
+        {
             m_AttrName = log::aux::default_attribute_names::message();
+        }
         else
+        {
             m_AttrName = attribute_name(log::aux::to_narrow(string_type(begin, end)));
+        }
     }
     //! The method is called when an attribute is filled
     void push_attr()
Modified: trunk/libs/log/src/parser_utils.cpp
==============================================================================
--- trunk/libs/log/src/parser_utils.cpp	Sun Aug 18 06:04:46 2013	(r85390)
+++ trunk/libs/log/src/parser_utils.cpp	2013-08-18 11:10:24 EDT (Sun, 18 Aug 2013)	(r85391)
@@ -18,6 +18,7 @@
 #include <cctype>
 #include <iterator>
 #include <algorithm>
+#include <boost/log/exceptions.hpp>
 #include "parser_utils.hpp"
 #include <boost/log/detail/header.hpp>
 #ifdef BOOST_LOG_USE_WCHAR_T
@@ -72,12 +73,80 @@
     return end;
 }
 
+//! Scans for the attribute name placeholder in the input
+const char* char_constants< char >::scan_attr_placeholder(const char_type* begin, const char_type* end)
+{
+    using namespace std;
+    while (begin != end)
+    {
+        char_type c = *begin;
+        if (!isalnum(c) && c != char_underline)
+            break;
+        ++begin;
+    }
+
+    return begin;
+}
+
+//! Parses an operand string (possibly quoted) from the input
+const char* char_constants< char >::parse_operand(const char_type* begin, const char_type* end, string_type& operand)
+{
+    using namespace std; // to make sure we can use C functions unqualified
+
+    const char_type* p = begin;
+    if (p == end)
+        BOOST_LOG_THROW_DESCR(parse_error, "Operand value is empty");
+
+    char_type c = *p;
+    if (c == char_quote)
+    {
+        // The value is specified as a quoted string
+        const char_type* start = ++p;
+        for (; p != end; ++p)
+        {
+            c = *p;
+            if (c == char_quote)
+            {
+                break;
+            }
+            else if (c == char_backslash)
+            {
+                ++p;
+                if (p == end)
+                    BOOST_LOG_THROW_DESCR(parse_error, "Invalid escape sequence in the argument value");
+            }
+        }
+        if (p == end)
+            BOOST_LOG_THROW_DESCR(parse_error, "Unterminated quoted string in the argument value");
+
+        operand.assign(start, p);
+        translate_escape_sequences(operand);
+
+        ++p; // skip the closing quote
+    }
+    else
+    {
+        // The value is specified as a single word
+        const char_type* start = p;
+        for (++p; p != end; ++p)
+        {
+            c = *p;
+            if (!isalnum(c) && c != '_' && c != '-' && c != '+' && c != '.')
+                break;
+        }
+
+        operand.assign(start, p);
+    }
+
+    return p;
+}
+
 //! Converts escape sequences to the corresponding characters
-void char_constants< char >::translate_escape_sequences(std::basic_string< char_type >& str)
+void char_constants< char >::translate_escape_sequences(string_type& str)
 {
     using namespace std; // to make sure we can use C functions unqualified
 
-    std::basic_string< char_type >::iterator it = str.begin();
+    string_type::iterator it = str.begin();
     while (it != str.end())
     {
         it = std::find(it, str.end(), '\\');
@@ -100,7 +169,7 @@
                 *it = '\b'; break;
             case 'x':
                 {
-                    std::basic_string< char_type >::iterator b = it;
+                    string_type::iterator b = it;
                     if (std::distance(++b, str.end()) >= 2)
                     {
                         char_type c1 = *b++, c2 = *b++;
@@ -116,7 +185,7 @@
                 {
                     if (*it >= '0' && *it <= '7')
                     {
-                        std::basic_string< char_type >::iterator b = it;
+                        string_type::iterator b = it;
                         int c = (*b++) - '0';
                         if (*b >= '0' && *b <= '7')
                             c = c * 8 + (*b++) - '0';
@@ -177,10 +246,80 @@
     return end;
 }
 
+//! Scans for the attribute name placeholder in the input
+const wchar_t* char_constants< wchar_t >::scan_attr_placeholder(const char_type* begin, const char_type* end)
+{
+    using namespace std;
+    while (begin != end)
+    {
+        char_type c = *begin;
+        if (!iswalnum(c) && c != char_underline)
+            break;
+        ++begin;
+    }
+
+    return begin;
+}
+
+//! Parses an operand string (possibly quoted) from the input
+const wchar_t* char_constants< wchar_t >::parse_operand(const char_type* begin, const char_type* end, string_type& operand)
+{
+    using namespace std; // to make sure we can use C functions unqualified
+
+    const char_type* p = begin;
+    if (p == end)
+        BOOST_LOG_THROW_DESCR(parse_error, "Operand value is empty");
+
+    char_type c = *p;
+    if (c == char_quote)
+    {
+        // The value is specified as a quoted string
+        const char_type* start = ++p;
+        for (; p != end; ++p)
+        {
+            c = *p;
+            if (c == char_quote)
+            {
+                break;
+            }
+            else if (c == char_backslash)
+            {
+                ++p;
+                if (p == end)
+                    BOOST_LOG_THROW_DESCR(parse_error, "Invalid escape sequence in the argument value");
+            }
+        }
+        if (p == end)
+            BOOST_LOG_THROW_DESCR(parse_error, "Unterminated quoted string in the argument value");
+
+        operand.assign(start, p);
+        translate_escape_sequences(operand);
+
+        ++p; // skip the closing quote
+    }
+    else
+    {
+        // The value is specified as a single word
+        const char_type* start = p;
+        for (++p; p != end; ++p)
+        {
+            c = *p;
+            if (!iswalnum(c) && c != L'_' && c != L'-' && c != L'+' && c != L'.')
+                break;
+        }
+
+        operand.assign(start, p);
+    }
+
+    return p;
+}
+
 //! Converts escape sequences to the corresponding characters
-void char_constants< wchar_t >::translate_escape_sequences(std::basic_string< char_type >& str)
+void char_constants< wchar_t >::translate_escape_sequences(string_type& str)
 {
-    std::basic_string< char_type >::iterator it = str.begin();
+    using namespace std; // to make sure we can use C functions unqualified
+
+    string_type::iterator it = str.begin();
     while (it != str.end())
     {
         it = std::find(it, str.end(), L'\\');
@@ -203,7 +342,7 @@
                 *it = L'\b'; break;
             case L'x':
                 {
-                    std::basic_string< char_type >::iterator b = it;
+                    string_type::iterator b = it;
                     if (std::distance(++b, str.end()) >= 2)
                     {
                         char_type c1 = *b++, c2 = *b++;
@@ -217,7 +356,7 @@
                 }
             case L'u':
                 {
-                    std::basic_string< char_type >::iterator b = it;
+                    string_type::iterator b = it;
                     if (std::distance(++b, str.end()) >= 4)
                     {
                         char_type c1 = *b++, c2 = *b++, c3 = *b++, c4 = *b++;
@@ -235,7 +374,7 @@
                 }
             case L'U':
                 {
-                    std::basic_string< char_type >::iterator b = it;
+                    string_type::iterator b = it;
                     if (std::distance(++b, str.end()) >= 8)
                     {
                         char_type c1 = *b++, c2 = *b++, c3 = *b++, c4 = *b++;
@@ -261,7 +400,7 @@
                 {
                     if (*it >= L'0' && *it <= L'7')
                     {
-                        std::basic_string< char_type >::iterator b = it;
+                        string_type::iterator b = it;
                         int c = (*b++) - L'0';
                         if (*b >= L'0' && *b <= L'7')
                             c = c * 8 + (*b++) - L'0';
Modified: trunk/libs/log/src/parser_utils.hpp
==============================================================================
--- trunk/libs/log/src/parser_utils.hpp	Sun Aug 18 06:04:46 2013	(r85390)
+++ trunk/libs/log/src/parser_utils.hpp	2013-08-18 11:10:24 EDT (Sun, 18 Aug 2013)	(r85391)
@@ -40,6 +40,8 @@
 struct char_constants< char >
 {
     typedef char char_type;
+    typedef std::basic_string< char_type > string_type;
+
     static const char_type char_comment = '#';
     static const char_type char_comma = ',';
     static const char_type char_dot = '.';
@@ -152,8 +154,12 @@
     static const char_type* trim_spaces_left(const char_type* begin, const char_type* end);
     //! Skips spaces in the end of the input
     static const char_type* trim_spaces_right(const char_type* begin, const char_type* end);
+    //! Scans for the attribute name placeholder in the input
+    static const char_type* scan_attr_placeholder(const char_type* begin, const char_type* end);
+    //! Parses an operand string (possibly quoted) from the input
+    static const char_type* parse_operand(const char_type* begin, const char_type* end, string_type& operand);
     //! Converts escape sequences to the corresponding characters
-    static void translate_escape_sequences(std::basic_string< char_type >& str);
+    static void translate_escape_sequences(string_type& str);
 };
 #endif
 
@@ -162,6 +168,8 @@
 struct char_constants< wchar_t >
 {
     typedef wchar_t char_type;
+    typedef std::basic_string< char_type > string_type;
+
     static const char_type char_comment = L'#';
     static const char_type char_comma = L',';
     static const char_type char_dot = L'.';
@@ -278,8 +286,12 @@
     static const char_type* trim_spaces_left(const char_type* begin, const char_type* end);
     //! Skips spaces in the end of the input
     static const char_type* trim_spaces_right(const char_type* begin, const char_type* end);
+    //! Scans for the attribute name placeholder in the input
+    static const char_type* scan_attr_placeholder(const char_type* begin, const char_type* end);
+    //! Parses an operand string (possibly quoted) from the input
+    static const char_type* parse_operand(const char_type* begin, const char_type* end, string_type& operand);
     //! Converts escape sequences to the corresponding characters
-    static void translate_escape_sequences(std::basic_string< char_type >& str);
+    static void translate_escape_sequences(string_type& str);
 };
 #endif
 
Modified: trunk/libs/log/src/settings_parser.cpp
==============================================================================
--- trunk/libs/log/src/settings_parser.cpp	Sun Aug 18 06:04:46 2013	(r85390)
+++ trunk/libs/log/src/settings_parser.cpp	2013-08-18 11:10:24 EDT (Sun, 18 Aug 2013)	(r85391)
@@ -21,6 +21,9 @@
 #include <stdexcept>
 #include <algorithm>
 #include <boost/throw_exception.hpp>
+#include <boost/exception/exception.hpp>
+#include <boost/exception/info.hpp>
+#include <boost/exception/errinfo_at_line.hpp>
 #include <boost/io/ios_state.hpp>
 #include <boost/move/core.hpp>
 #include <boost/move/utility.hpp>
@@ -88,7 +91,7 @@
                 start = constants::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));
+                    BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section header is invalid", (m_LineCounter));
 
                 p = stop + 1;
                 stop = constants::trim_spaces_right(start, stop);
@@ -100,7 +103,7 @@
                 // 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));
+                    BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter description is invalid", (m_LineCounter));
 
                 // Parameter name
                 set_parameter_name(p, constants::trim_spaces_right(p, eq));
@@ -108,46 +111,17 @@
                 // Parameter value
                 p = constants::trim_spaces_left(eq + 1, end);
                 if (p == end || *p == constants::char_comment)
-                    BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter value is not specified.", (m_LineCounter));
+                    BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter value is not specified", (m_LineCounter));
 
-                c = *p;
-                if (c == constants::char_quote)
+                try
                 {
-                    // 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
+                    string_type value;
+                    p = constants::parse_operand(p, end, value);
+                    set_parameter_value(value);
                 }
-                else
+                catch (parse_error& e)
                 {
-                    // 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);
+                    throw boost::enable_error_info(e) << boost::errinfo_at_line(m_LineCounter);
                 }
             }
 
@@ -163,7 +137,7 @@
                 }
                 else
                 {
-                    BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Unexpected characters in the end of the line.", (m_LineCounter));
+                    BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Unexpected characters in the end of the line", (m_LineCounter));
                 }
             }
         }
@@ -177,13 +151,13 @@
     {
         // Check that the section name is valid
         if (begin == end)
-            BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section name is empty.", (m_LineCounter));
+            BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section name is empty", (m_LineCounter));
 
         for (iterator_type p = begin; p != end; ++p)
         {
             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));
+                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);
@@ -200,40 +174,30 @@
         if (m_SectionName.empty())
         {
             // The parameter encountered before any section starter
-            BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameters are only allowed within sections.", (m_LineCounter));
+            BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameters are only allowed within sections", (m_LineCounter));
         }
 
         // Check that the parameter name is valid
         if (begin == end)
-            BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is empty.", (m_LineCounter));
+            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));
+            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));
+                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_type begin, iterator_type end)
-    {
-        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_type begin, iterator_type end)
+    void set_parameter_value(string_type const& value)
     {
-        // Cut off the quotes
-        string_type val(begin, end);
-        constants::translate_escape_sequences(val);
-        m_Settings[m_SectionName][m_ParameterName] = val;
+        m_Settings[m_SectionName][m_ParameterName] = value;
         m_ParameterName.clear();
     }