~ubuntu-branches/ubuntu/trusty/xpathselect/trusty

« back to all changes in this revision

Viewing changes to lib/parser.h

  • Committer: Package Import Robot
  • Author(s): Automatic PS uploader
  • Date: 2013-01-23 00:00:59 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20130123000059-ez6oz726vueubmlj
Tags: 1.1.3daily13.01.23-0ubuntu1
Automatic snapshot from revision 28

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
* Copyright (C) 2013 Canonical Ltd
 
3
*
 
4
* This program is free software: you can redistribute it and/or modify
 
5
* it under the terms of the GNU General Public License version 3 as
 
6
* published by the Free Software Foundation.
 
7
*
 
8
* This program is distributed in the hope that it will be useful,
 
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
* GNU General Public License for more details.
 
12
*
 
13
* You should have received a copy of the GNU General Public License
 
14
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
*
 
16
*/
 
17
#ifndef _PARSER_H
 
18
#define _PARSER_H
 
19
 
 
20
#include <string>
 
21
 
 
22
#include <boost/config/warning_disable.hpp>
 
23
#include <boost/fusion/include/adapt_struct.hpp>
 
24
#include <boost/spirit/include/phoenix_object.hpp>
 
25
#include <boost/spirit/include/phoenix_operator.hpp>
 
26
#include <boost/spirit/include/qi.hpp>
 
27
 
 
28
#include "xpathquerypart.h"
 
29
 
 
30
// this allows spirit to lazily construct these two structs...
 
31
BOOST_FUSION_ADAPT_STRUCT(
 
32
    xpathselect::XPathQueryPart,
 
33
    (std::string, node_name_)
 
34
    (boost::optional<xpathselect::XPathQueryParam>, parameter)
 
35
    );
 
36
 
 
37
BOOST_FUSION_ADAPT_STRUCT(
 
38
    xpathselect::XPathQueryParam,
 
39
    (std::string, param_name)
 
40
    (std::string, param_value)
 
41
    );
 
42
 
 
43
namespace xpathselect
 
44
{
 
45
namespace parser
 
46
{
 
47
namespace qi = boost::spirit::qi;
 
48
namespace phoenix = boost::phoenix;
 
49
 
 
50
    // This is the main XPath grammar. It looks horrible, until you emerse yourself in it for a few
 
51
    // days, then the beauty of boost::spirit creeps into your brain. To help future programmers,
 
52
    // I've heavily commented this.
 
53
    //
 
54
    // The first template parameter to this grammar defines the type of iterator the grammer will operate
 
55
    // on - it must adhere to std::forward_iterator. The second template parameter is the type
 
56
    // that this grammar will produce (in this case: a list of XPathQueryPart objects).
 
57
    template <typename Iterator>
 
58
    struct xpath_grammar : qi::grammar<Iterator, QueryList()>
 
59
    {
 
60
        xpath_grammar() : xpath_grammar::base_type(node_sequence) // node_sequence is the start rule.
 
61
        {
 
62
            using namespace qi::labels;
 
63
 
 
64
            // node names can either be a text string (no spaces), or a wildcard.
 
65
            node_name = ( +qi::char_("a-zA-Z0-9_\\-") | qi::char_('*') );
 
66
            // a search node is '//' as long as it's not followed by '/' or '*' or end of input.
 
67
            search_node = "//" >> !(qi::lit("*") || "/" || qi::eoi)[qi::_val = XPathQueryPart()];
 
68
            // a normal separator is a '/' as long as it's followed by something other than another '/'
 
69
            normal_sep = '/' >> !qi::lit('/');
 
70
            separator = normal_sep || search_node;  // nodes can be separated by normal_sep or search_node.
 
71
 
 
72
            // parameter name and values can contain text (no spaces)
 
73
            param_name = +qi::char_("a-zA-Z0-9_\\-");
 
74
            param_value = +qi::char_("a-zA-Z0-9_\\-");
 
75
            // parameter specification is simple: name=value
 
76
            param %= param_name >> '=' >> param_value;
 
77
 
 
78
            // a node consists of a node name, followed by an *optional* parameter inside '[' and ']'.
 
79
            node %= node_name >> -('[' >> param >> ']');
 
80
            // this is the money shot: a node sequence is one or more of a separator, followed by an
 
81
            // optional node.
 
82
            node_sequence %= +(separator >> -node);
 
83
 
 
84
            // DEBUGGING SUPPORT:
 
85
            // define DEBUG in order to have boost::spirit spit out useful debug information:
 
86
#ifdef DEBUG
 
87
            // this gives english names to all the grammar rules:
 
88
            node_name.name("node_name");
 
89
            search_node.name("search_node");
 
90
            normal_sep.name("normal_separator");
 
91
            separator.name("separator");
 
92
            param_name.name("param_name");
 
93
            param_value.name("param_value");
 
94
            param.name("parameter");
 
95
            node.name("node");
 
96
            node_sequence.name("node_sequence");
 
97
 
 
98
            // set up error logging:
 
99
            qi::on_error<qi::fail>(
 
100
                node_sequence,
 
101
                std::cout
 
102
                    << phoenix::val("Error! Expecting ")
 
103
                    << qi::_4                               // what failed?
 
104
                    << phoenix::val(" here: \"")
 
105
                    << phoenix::construct<std::string>(qi::_3, qi::_2)   // iterators to error-pos, end
 
106
                    << phoenix::val("\"")
 
107
                    << std::endl
 
108
            );
 
109
            // specify which rules we want debug info about (all of them):
 
110
            qi::debug(node_name);
 
111
            qi::debug(search_node);
 
112
            qi::debug(normal_sep);
 
113
            qi::debug(separator);
 
114
            qi::debug(param_name);
 
115
            qi::debug(param_value);
 
116
            qi::debug(param);
 
117
            qi::debug(node);
 
118
            qi::debug(node_sequence);
 
119
#endif
 
120
        }
 
121
        // declare all the rules. The second template parameter is the type they produce.
 
122
        qi::rule<Iterator, std::string()> node_name;
 
123
        qi::rule<Iterator, XPathQueryPart()> search_node;
 
124
        qi::rule<Iterator> normal_sep;
 
125
        qi::rule<Iterator, xpathselect::QueryList()> separator;
 
126
 
 
127
        qi::rule<Iterator, std::string()> param_name;
 
128
        qi::rule<Iterator, std::string()> param_value;
 
129
        qi::rule<Iterator, XPathQueryParam()> param;
 
130
 
 
131
        qi::rule<Iterator, XPathQueryPart()> node;
 
132
        qi::rule<Iterator, xpathselect::QueryList()> node_sequence;
 
133
    };
 
134
 
 
135
}
 
136
}
 
137
 
 
138
#endif