C++ Boost Spirit在服务器应用程序上实现小型单线DSL

C++ Boost Spirit在服务器应用程序上实现小型单线DSL,c++,boost,dsl,boost-spirit,boost-spirit-qi,C++,Boost,Dsl,Boost Spirit,Boost Spirit Qi,如果这个问题以前被回答过,我表示歉意 我想在我工作的服务器应用程序中插入一个小型DSL。语法非常简单,即使在这个早期阶段,我也被难倒了。我就是不知道如何在精神上构造语法 下面是我要测试的语法示例: WHERE [not] <condition> [ and | or <condition> ] <command> [parameters] 及 我知道这是一个很大的问题,但我想知道是否有灵魂专家可以在几秒钟内完成这个语法?我尽可能地解析LIKE and=,但在

如果这个问题以前被回答过,我表示歉意

我想在我工作的服务器应用程序中插入一个小型DSL。语法非常简单,即使在这个早期阶段,我也被难倒了。我就是不知道如何在精神上构造语法

下面是我要测试的语法示例:

WHERE [not] <condition> [ and | or <condition> ] <command> [parameters]

我知道这是一个很大的问题,但我想知道是否有灵魂专家可以在几秒钟内完成这个语法?我尽可能地解析LIKE and=,但在尝试将其与and、OR和NOT混合时遇到了问题。我的问题是,当思考spirit将如何解决这个问题时,不知道从哪里开始。

有关概念证明,请参阅

我通常首先要做的是想象一下我希望如何存储解析后的数据

数据类型 我喜欢使用标准容器,
boost::variant
(有时是
boost::optional
)。自下而上阅读,看看它有多简单,自上而下:

struct regex {
    std::string _pattern;
    explicit regex(std::string const& pattern) : _pattern(pattern) {}
};

typedef boost::variant<double, int, std::string, regex> value;

enum logicOp { logicOr, logicAnd, logicPositive };

struct condition {
    bool          _negated;
    std::string   _propertyname;
    value         _operand;      // value or regex
};

struct filter {
    logicOp   _op;
    condition _cond;
};

struct setcommand {
    typedef std::list<std::pair<std::string, value> > pairs;
    pairs _propvals;
};

struct printcommand {
    std::vector<std::string> _propnames;
};

typedef boost::variant<printcommand, setcommand> command;

struct statement {
    std::vector<filter> _filters;
    command             _command;
};
注:

  • 我已经决定字符串应该能够包含引号,所以我将
    \
    设置为转义字符
  • 唯一“棘手”的事情是确保过滤器(条件)以“WHERE”开头,并且每个后续条件必须以“and”/“OR”开头。它使用语义动作

    [ _pass = (phx::size(_val) == 0) ]
    
    在解析过程中,检查过滤器的结果列表(
    vector
    )当时是否为空

  • attr(…)
    习惯用法用于获取可选关键字(
    NOT
    )的默认值。关键字仅在语法中可选,在AST中不可选:

     no_case["NOT"] >> attr(true) | attr(false)
    
我已经制作了一个演示,它使用精神业力将AST打印回来。请注意,我没有花太多精力来实现语法往返:

  • like
    运算符被打印为与正则表达式相等(
    m/../
  • 未对字符串文字中的特殊字符进行转义
  • 测试程序的输出: 完整测试程序 注意:除了
    解析器
    之外,它还包含一个
    生成器
    ,用于将解析后的AST数据类型打印回来

    //#define BOOST_SPIRIT_DEBUG
    #define BOOST_SPIRIT_USE_PHOENIX_V3
    #include <boost/fusion/adapted.hpp>
    #include <boost/variant.hpp>
    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/karma.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    namespace qi    = boost::spirit::qi;
    namespace karma = boost::spirit::karma;
    namespace phx   = boost::phoenix;
    
    struct regex
    {
        std::string _pattern;
        explicit regex(std::string const& pattern) : _pattern(pattern) {}
    };
    
    typedef boost::variant<double, int, std::string, regex> value;
    
    enum logicOp { logicOr, logicAnd, logicPositive };
    
    struct condition
    {
        bool          _negated;
        std::string   _propertyname;
        value         _operand;      // value or regex
    };
    
    struct filter
    {
        logicOp   _op;
        condition _cond;
    };
    
    struct setcommand
    {
        typedef std::list<std::pair<std::string, value> > pairs;
        pairs _propvals;
    };
    
    struct printcommand
    {
        std::vector<std::string> _propnames;
    };
    
    typedef boost::variant<printcommand, setcommand> command;
    
    struct statement
    {
        std::vector<filter> _filters;
        command             _command;
    };
    
    BOOST_FUSION_ADAPT_STRUCT(regex, (std::string, _pattern))
    BOOST_FUSION_ADAPT_STRUCT(printcommand, (std::vector<std::string>, _propnames))
    BOOST_FUSION_ADAPT_STRUCT(setcommand, (setcommand::pairs, _propvals))
    BOOST_FUSION_ADAPT_STRUCT(condition, (bool, _negated)(std::string, _propertyname)(value, _operand))
    BOOST_FUSION_ADAPT_STRUCT(filter, (logicOp, _op)(condition, _cond))
    BOOST_FUSION_ADAPT_STRUCT(statement, (std::vector<filter>, _filters)(command, _command))
    
    // see http://stackoverflow.com/a/14206443/85371
    namespace boost { namespace phoenix { namespace stl {
        template <typename This, typename Key, typename Value, typename Compare, typename Allocator, typename Index>
            struct at_impl::result<This(std::map<Key,Value,Compare,Allocator>&, Index)>
            { typedef Value & type; };
        template <typename This, typename Key, typename Value, typename Compare, typename Allocator, typename Index>
            struct at_impl::result<This(std::map<Key,Value,Compare,Allocator> const&, Index)>
            { typedef Value const& type; };
    }}}
    
    template <typename It, typename Delim>
        struct generator : karma::grammar<It, statement(), Delim>
    {
        generator() : generator::base_type(start)
        {
            using namespace karma;
    
            property_  = karma::string;
            strlit_    = '"'  << karma::string << '"';
            regex_     = "m/" << karma::string << "/";
    
            value_     = (double_ | int_ | strlit_ | regex_);
            negate_    = eps [ _pass = !_val ] | lit("NOT");
    
            condition_ = negate_  << property_  << '=' << value_;
            print_     = "PRINT " << property_ % ", ";
            set_       = "SET "   << (property_ << '=' << value_) % ", ";
            command_   = print_ | set_;
    
            static const auto logicOpNames = std::map<logicOp, std::string> { 
                { logicPositive, "WHERE" },
                { logicAnd, "AND" },
                { logicOr, "OR" } };
    
            logic_ = string [ _1 = phx::at(phx::cref(logicOpNames), _val) ];
    
            filters_ = +(logic_ << condition_);
    
            statement_ = filters_ << command_;
    
            start = statement_;
        }
    
      private:
        karma::rule<It, logicOp()            , Delim> logic_;
        karma::rule<It, statement()          , Delim> statement_;
        karma::rule<It, std::vector<filter>(), Delim> filters_;
        karma::rule<It, command()            , Delim> command_;
        karma::rule<It, condition()          , Delim> condition_;
        karma::rule<It, statement()          , Delim> start;
        karma::rule<It, bool()        > negate_;
        karma::rule<It, printcommand()> print_;
        karma::rule<It, setcommand()  > set_;
        karma::rule<It, std::string() > strlit_, property_;
        karma::rule<It, value()       > value_;
        karma::rule<It, regex()       > regex_;
    };
    
    template <typename It, typename Skipper = qi::space_type>
        struct parser : qi::grammar<It, statement(), Skipper>
    {
        parser() : parser::base_type(start)
        {
            using namespace qi;
    
            // no-skipper rules
            property_  = alpha >> *alnum;
            strlit_    = '"' >> *(  (lit('\\') >> char_) | ~char_('"') ) > '"';
    
            // with-skipper rules
            regex_     = strlit_ [ _val = phx::construct<regex>(_1) ];
            value_     = double_ | int_ | strlit_;
            condition_ = (no_case["NOT"] >> attr(true) | attr(false)) 
                >> property_ 
                >> (
                        no_case["LIKE"] >> regex_ | '=' >> value_
                   );
    
            print_   = no_case["PRINT"] >> property_ % ',';
            set_     = no_case["SET"] >> (property_ >> '=' >> value_) % ',';
            command_ = print_ | set_;
    
            filters_ %= +(
                    (
                       no_case["WHERE"] [ _pass = (phx::size(_val) == 0) ] >> attr(logicPositive)
                     | no_case["AND"]   [ _pass = (phx::size(_val) >  0) ] >> attr(logicAnd)
                     | no_case["OR"]    [ _pass = (phx::size(_val) >  0) ] >> attr(logicOr)
                    ) 
                    >> condition_);
    
            statement_ = filters_ >> command_;
    
            start = statement_;
            BOOST_SPIRIT_DEBUG_NODES((start)(condition_)(value_)(strlit_)(regex_)(property_)(statement_)(filters_)(print_)(set_)(command_));
        }
    
      private:
        qi::rule<It, statement()          , Skipper> statement_;
        qi::rule<It, std::vector<filter>(), Skipper> filters_;
        qi::rule<It, printcommand()       , Skipper> print_;
        qi::rule<It, setcommand()         , Skipper> set_;
        qi::rule<It, command()            , Skipper> command_;
        qi::rule<It, value()              , Skipper> value_, regex_;
        qi::rule<It, condition()          , Skipper> condition_;
        qi::rule<It, statement()          , Skipper> start;
        // lexemes
        qi::rule<It, std::string()> strlit_, property_; // no skipper
    };
    
    bool doParse(std::string const& input)
    {
        auto f(begin(input)), l(end(input));
    
        parser<decltype(f), qi::space_type> p;
        statement parsed;
    
        bool ok = qi::phrase_parse(f,l,p,qi::space,parsed);
        if (ok)   
        {
            std::cout << "parse success: '" << input << "'\n";
            generator<boost::spirit::ostream_iterator, karma::space_type> gen;
            std::cout << "parsed: " << karma::format_delimited(gen, karma::space, parsed) << "\n";
        }
        else      
            std::cerr << "parse failed: '" << std::string(f,l) << "'\n";
    
        if (f!=l) 
            std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
    
        return ok;
    }
    
    int main()
    {
        doParse("where currency like \"GBP|USD\" set logging = 1, logfile = \"myfile\"");
        doParse("where not status = \"ok\" print ident, errorMessage");
        doParse("where status = \"ok\" or not currency like \"GBP|USD\" print ident, errorMessage");
        // All the extra levels of escaping get a bit ugly here. Of course, you'd be reading from a file/database/etc...
        doParse("where status = \"\\\"special\\\"\" set logfile = \"C:\\\\path\\\\to\\\\logfile.txt\"");
    }
    
    /#定义BOOST_SPIRIT_调试
    #定义增强\u精神\u使用\u凤凰\u V3
    #包括
    #包括
    #包括
    #包括
    #包括
    名称空间qi=boost::spirit::qi;
    名称空间业力=提升::精神::业力;
    名称空间phx=boost::phoenix;
    结构正则表达式
    {
    std::string\u模式;
    显式正则表达式(std::string const&pattern):\u pattern(pattern){}
    };
    typedef boost::变量值;
    枚举logicOp{logicOr,logicAnd,logicPositive};
    结构条件
    {
    布尔否定;
    std::string_propertyname;
    值_操作数;//值或正则表达式
    };
    结构过滤器
    {
    逻辑运算;
    条件(cond),;
    };
    结构设置命令
    {
    typedef std::列表对;
    成对_propvals;
    };
    结构打印命令
    {
    std::vector_propname;
    };
    typedef boost::variant命令;
    结构语句
    {
    std::矢量滤波器;
    命令(u命令),;
    };
    BOOST_FUSION_ADAPT_STRUCT(regex,(std::string,_pattern))
    BOOST_FUSION_ADAPT_STRUCT(printcommand,(std::vector,_propnames))
    BOOST_FUSION_ADAPT_STRUCT(setcommand,(setcommand::pairs,_propvals))
    BOOST_FUSION_ADAPT_STRUCT(条件,(bool,_否定)(std::string,_propertyname)(值,_操作数))
    增强融合自适应结构(滤波器,(逻辑运算,运算)(条件,条件))
    BOOST_FUSION_ADAPT_STRUCT(语句,(标准::向量,_过滤器)(命令,_命令))
    //看http://stackoverflow.com/a/14206443/85371
    名称空间boost{名称空间phoenix{名称空间stl{
    模板
    位于_impl::result的结构
    {typedef Value&type;};
    模板
    位于_impl::result的结构
    {typedef Value const&type;};
    }}}
    模板
    结构生成器:karma::grammar
    {
    生成器():生成器::基本类型(启动)
    {
    利用业力;
    属性=业力::字符串;
    斯特利特=“”(
    无大小写[“LIKE”]>>正则表达式='>>值_
    );
    打印=无大小写[“打印”]>>属性“,”;
    set_>=no_ucase[“set”]>>(property_>>“='>>value_>>)%;
    命令=打印|设置|;
    过滤器%=+(
    (
    无大小写[“其中”][\u pass=(phx::size(\u val)==0)]>>attr(逻辑正)
    |无大小写[”和“][\u pass=(phx::size(\u val)>0)]>>attr(逻辑与)
    |无大小写[”或“][\u pass=(phx::size(\u val)>0)]>>attr(logicOr)
    ) 
    >>条件),;
    语句=过滤器\u>>命令;
    开始=语句;
    BOOST_-SPIRIT_-DEBUG_节点((开始)(条件)(值)(strlit_)(正则表达式)(属性)(语句)(过滤器)(打印)(设置)(命令));
    }
    私人:
    qi::规则语句;
    qi::规则过滤器;
    qi::规则打印;
    qi::规则集;
    qi::规则命令;
    qi::规则值,正则表达式;
    规则条件;
    qi::规则开始;
    //词素
    qi::规则strlit,属性///无跳过程序
    };
    booldoparse(标准::字符串常量和输入)
    {
    自动f(开始(输入)),l(结束(输入));
    语法分析器p;
    解析的语句;
    bool ok=qi::phrase_parse(f,l,p,qi::space,parsed);
    如果(确定)
    {
    
    cout“如果这个问题以前被回答过,我会道歉。”-这似乎有点可笑。不过,为了好玩,我编写了一个示例,它可以解析你的语法(并且可以打印出来检查),修复了一个缺少的大括号并制作了这个示例
    where currency like "GBP|USD" set logging = 1, logfile = "myfile"
    
    where not status = "ok" print ident, errorMessage
    
    struct regex {
        std::string _pattern;
        explicit regex(std::string const& pattern) : _pattern(pattern) {}
    };
    
    typedef boost::variant<double, int, std::string, regex> value;
    
    enum logicOp { logicOr, logicAnd, logicPositive };
    
    struct condition {
        bool          _negated;
        std::string   _propertyname;
        value         _operand;      // value or regex
    };
    
    struct filter {
        logicOp   _op;
        condition _cond;
    };
    
    struct setcommand {
        typedef std::list<std::pair<std::string, value> > pairs;
        pairs _propvals;
    };
    
    struct printcommand {
        std::vector<std::string> _propnames;
    };
    
    typedef boost::variant<printcommand, setcommand> command;
    
    struct statement {
        std::vector<filter> _filters;
        command             _command;
    };
    
    using namespace qi;
    
    // no-skipper rules
    property_  = alpha >> *alnum;
    strlit_    = '"' >> *(  (lit('\\') >> char_) | ~char_('"') ) > '"';
    
    // with-skipper rules
    regex_     = strlit_ [ _val = phx::construct<regex>(_1) ];
    value_     = double_ | int_ | strlit_;
    condition_ = (no_case["NOT"] >> attr(true) | attr(false)) 
        >> property_ 
        >> (
                no_case["LIKE"] >> regex_ | '=' >> value_
           );
    
    print_   = no_case["PRINT"] >> property_ % ',';
    set_     = no_case["SET"] >> (property_ >> '=' >> value_) % ',';
    command_ = print_ | set_;
    
    filters_ %= +(
            (
               no_case["WHERE"] [ _pass = (phx::size(_val) == 0) ] >> attr(logicPositive)
             | no_case["AND"]   [ _pass = (phx::size(_val) >  0) ] >> attr(logicAnd)
             | no_case["OR"]    [ _pass = (phx::size(_val) >  0) ] >> attr(logicOr)
            ) 
            >> condition_);
    
    statement_ = filters_ >> command_;
    
    [ _pass = (phx::size(_val) == 0) ]
    
     no_case["NOT"] >> attr(true) | attr(false)
    
    parse success: 'where currency like "GBP|USD" set logging = 1, logfile = "myfile"'
    parsed: WHERE  currency = m/GBP|USD/ SET logging=1.0, logfile="myfile" 
    parse success: 'where not status = "ok" print ident, errorMessage'
    parsed: WHERE NOT status = "ok" PRINT ident, errorMessage 
    parse success: 'where status = "ok" or not currency like "GBP|USD" print ident, errorMessage'
    parsed: WHERE  status = "ok" OR NOT currency = m/GBP|USD/ PRINT ident, errorMessage 
    parse success: 'where status = "\"special\"" set logfile = "C:\\path\\to\\logfile.txt"'
    parsed: WHERE  status = ""special"" SET logfile="C:\path\to\logfile.txt" 
    
    //#define BOOST_SPIRIT_DEBUG
    #define BOOST_SPIRIT_USE_PHOENIX_V3
    #include <boost/fusion/adapted.hpp>
    #include <boost/variant.hpp>
    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/karma.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    namespace qi    = boost::spirit::qi;
    namespace karma = boost::spirit::karma;
    namespace phx   = boost::phoenix;
    
    struct regex
    {
        std::string _pattern;
        explicit regex(std::string const& pattern) : _pattern(pattern) {}
    };
    
    typedef boost::variant<double, int, std::string, regex> value;
    
    enum logicOp { logicOr, logicAnd, logicPositive };
    
    struct condition
    {
        bool          _negated;
        std::string   _propertyname;
        value         _operand;      // value or regex
    };
    
    struct filter
    {
        logicOp   _op;
        condition _cond;
    };
    
    struct setcommand
    {
        typedef std::list<std::pair<std::string, value> > pairs;
        pairs _propvals;
    };
    
    struct printcommand
    {
        std::vector<std::string> _propnames;
    };
    
    typedef boost::variant<printcommand, setcommand> command;
    
    struct statement
    {
        std::vector<filter> _filters;
        command             _command;
    };
    
    BOOST_FUSION_ADAPT_STRUCT(regex, (std::string, _pattern))
    BOOST_FUSION_ADAPT_STRUCT(printcommand, (std::vector<std::string>, _propnames))
    BOOST_FUSION_ADAPT_STRUCT(setcommand, (setcommand::pairs, _propvals))
    BOOST_FUSION_ADAPT_STRUCT(condition, (bool, _negated)(std::string, _propertyname)(value, _operand))
    BOOST_FUSION_ADAPT_STRUCT(filter, (logicOp, _op)(condition, _cond))
    BOOST_FUSION_ADAPT_STRUCT(statement, (std::vector<filter>, _filters)(command, _command))
    
    // see http://stackoverflow.com/a/14206443/85371
    namespace boost { namespace phoenix { namespace stl {
        template <typename This, typename Key, typename Value, typename Compare, typename Allocator, typename Index>
            struct at_impl::result<This(std::map<Key,Value,Compare,Allocator>&, Index)>
            { typedef Value & type; };
        template <typename This, typename Key, typename Value, typename Compare, typename Allocator, typename Index>
            struct at_impl::result<This(std::map<Key,Value,Compare,Allocator> const&, Index)>
            { typedef Value const& type; };
    }}}
    
    template <typename It, typename Delim>
        struct generator : karma::grammar<It, statement(), Delim>
    {
        generator() : generator::base_type(start)
        {
            using namespace karma;
    
            property_  = karma::string;
            strlit_    = '"'  << karma::string << '"';
            regex_     = "m/" << karma::string << "/";
    
            value_     = (double_ | int_ | strlit_ | regex_);
            negate_    = eps [ _pass = !_val ] | lit("NOT");
    
            condition_ = negate_  << property_  << '=' << value_;
            print_     = "PRINT " << property_ % ", ";
            set_       = "SET "   << (property_ << '=' << value_) % ", ";
            command_   = print_ | set_;
    
            static const auto logicOpNames = std::map<logicOp, std::string> { 
                { logicPositive, "WHERE" },
                { logicAnd, "AND" },
                { logicOr, "OR" } };
    
            logic_ = string [ _1 = phx::at(phx::cref(logicOpNames), _val) ];
    
            filters_ = +(logic_ << condition_);
    
            statement_ = filters_ << command_;
    
            start = statement_;
        }
    
      private:
        karma::rule<It, logicOp()            , Delim> logic_;
        karma::rule<It, statement()          , Delim> statement_;
        karma::rule<It, std::vector<filter>(), Delim> filters_;
        karma::rule<It, command()            , Delim> command_;
        karma::rule<It, condition()          , Delim> condition_;
        karma::rule<It, statement()          , Delim> start;
        karma::rule<It, bool()        > negate_;
        karma::rule<It, printcommand()> print_;
        karma::rule<It, setcommand()  > set_;
        karma::rule<It, std::string() > strlit_, property_;
        karma::rule<It, value()       > value_;
        karma::rule<It, regex()       > regex_;
    };
    
    template <typename It, typename Skipper = qi::space_type>
        struct parser : qi::grammar<It, statement(), Skipper>
    {
        parser() : parser::base_type(start)
        {
            using namespace qi;
    
            // no-skipper rules
            property_  = alpha >> *alnum;
            strlit_    = '"' >> *(  (lit('\\') >> char_) | ~char_('"') ) > '"';
    
            // with-skipper rules
            regex_     = strlit_ [ _val = phx::construct<regex>(_1) ];
            value_     = double_ | int_ | strlit_;
            condition_ = (no_case["NOT"] >> attr(true) | attr(false)) 
                >> property_ 
                >> (
                        no_case["LIKE"] >> regex_ | '=' >> value_
                   );
    
            print_   = no_case["PRINT"] >> property_ % ',';
            set_     = no_case["SET"] >> (property_ >> '=' >> value_) % ',';
            command_ = print_ | set_;
    
            filters_ %= +(
                    (
                       no_case["WHERE"] [ _pass = (phx::size(_val) == 0) ] >> attr(logicPositive)
                     | no_case["AND"]   [ _pass = (phx::size(_val) >  0) ] >> attr(logicAnd)
                     | no_case["OR"]    [ _pass = (phx::size(_val) >  0) ] >> attr(logicOr)
                    ) 
                    >> condition_);
    
            statement_ = filters_ >> command_;
    
            start = statement_;
            BOOST_SPIRIT_DEBUG_NODES((start)(condition_)(value_)(strlit_)(regex_)(property_)(statement_)(filters_)(print_)(set_)(command_));
        }
    
      private:
        qi::rule<It, statement()          , Skipper> statement_;
        qi::rule<It, std::vector<filter>(), Skipper> filters_;
        qi::rule<It, printcommand()       , Skipper> print_;
        qi::rule<It, setcommand()         , Skipper> set_;
        qi::rule<It, command()            , Skipper> command_;
        qi::rule<It, value()              , Skipper> value_, regex_;
        qi::rule<It, condition()          , Skipper> condition_;
        qi::rule<It, statement()          , Skipper> start;
        // lexemes
        qi::rule<It, std::string()> strlit_, property_; // no skipper
    };
    
    bool doParse(std::string const& input)
    {
        auto f(begin(input)), l(end(input));
    
        parser<decltype(f), qi::space_type> p;
        statement parsed;
    
        bool ok = qi::phrase_parse(f,l,p,qi::space,parsed);
        if (ok)   
        {
            std::cout << "parse success: '" << input << "'\n";
            generator<boost::spirit::ostream_iterator, karma::space_type> gen;
            std::cout << "parsed: " << karma::format_delimited(gen, karma::space, parsed) << "\n";
        }
        else      
            std::cerr << "parse failed: '" << std::string(f,l) << "'\n";
    
        if (f!=l) 
            std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
    
        return ok;
    }
    
    int main()
    {
        doParse("where currency like \"GBP|USD\" set logging = 1, logfile = \"myfile\"");
        doParse("where not status = \"ok\" print ident, errorMessage");
        doParse("where status = \"ok\" or not currency like \"GBP|USD\" print ident, errorMessage");
        // All the extra levels of escaping get a bit ugly here. Of course, you'd be reading from a file/database/etc...
        doParse("where status = \"\\\"special\\\"\" set logfile = \"C:\\\\path\\\\to\\\\logfile.txt\"");
    }