Jan 31

Most questions on the main Spirit mailing list are centered around attributes and how to correctly utilize Spirit’s attribute propagation rules. We discussed the related basics in several posts already, but many people still have problems to understand the rules. Somebody recently asked on the mailing list whether it would be possible to print the attribute type exposed by an arbitrary parser expression. I answered by posting a sketchy code snippet (see here), but afterwards I realized it might be a good topic for yet another ‘Tip of the Day’.

Before you read on, please be aware that the interfaces described in this post are not set in stone and may change in the future without attempting to be backwards compatible. I’ll write about the current implementation anyway as I think those are important. Generally, understanding attribute handling is crucial to understanding Spirit. Nuff said.

Naturally, Spirit internally implements the means of retrieving the attribute type of any parser expression. So all we need to do is to invoke those and wrap them into a nicely reusable tool.

Let us start by briefly describing some implementation details related to parser construction and attribute composition. As you might already know, any parser expression provided by the user (such as for instance qi::int_ >> qi::double_) is not something you could directly use to parse input. The qi::int_, qi::double_, etc. are just placeholder symbols denoting the type of the parser component required to match the input. These parser expressions have to be compiled into real parser instances responsible for the actual matching of the input. Spirit has a built in facility boost::spirit::compile which performs the conversion of the parser expression into the corresponding parser instance. Here is the (simplified) prototype:

namespace boost { namespace spirit
{
    template <typename Domain, typename Expr>
    typename result_of::compile<Domain, Expr>::type
    compile(Expr const& expr);
}}

where Domain is a tag type which in our case is qi::domain, thus identifying Qi (i.e. telling the function we want to create a parser), and Expr is the parser expression to compile. As most (meta-) template facilities in Spirit the compile construct consists out of two parts: the meta-calculation of the resulting type of the parser instance (result_of::compile) and the actual function doing the runtime compilation. For the purpose of this post we are interested in the resulting type of the parser instance only.

Among other things, after compiling the parser expression, the member function parse() is called on the returned parser instance. In the article about Creating Your Own Parser Component for Spirit.Qi we saw that the parser instance additionally exposes its attribute type. Spirit implements another facility we can invoke to extract this attribute type for a given parser instance type:

namespace boost { namespace spirit { namespace traits
{
    template <typename Component, typename Context = unused_type
      , typename Iterator = unused_type>
    struct attribute_of;
}}}

where Component is the type of the parser expression to query for its attribute type, the Context is not relevant in our case and Iterator is the iterator type used to do the actual matching. Most parser components are independent of any iterator type, but components as the raw[] directives are. So most of the time we can leave out supplying an iterator type.

These two Spirit facilities are all what we need! Let us combine the two in order to get the type of the attribute exposed by a parser created from a given parser expression.

template <typename Expr, typename Iterator = spirit::unused_type>
struct attribute_of_parser
{
    typedef typename spirit::result_of::compile<
        spirit::qi::domain, Expr
    >::type parser_expression_type;

    typedef typename spirit::traits::attribute_of<
        parser_expression_type, spirit::unused_type, Iterator
    >::type type;
};

Now as we have a tool to get the attribute type, we can use a simple utility function to print it out to the console (in this example we ignore the iterator type):

template <typename T>
void display_attribute_of_parser(T const&)
{
    typedef typename attribute_of_parser<T>::type attribute_type;
    std::cout << typeid(attribute_type).name() << std::endl;
}

// this will print something like: boost::fusion::vector2<int, double>
display_attribute_of_parser(qi::int_ >> qi::double_);

That’s it! We created a nice, reusable function printing the attribute type of an arbitrary parser expression. I added this as an example to the Boost SVN here and here, allowing you to reuse it for your needs. The last thing to mention is that a similar utility can be easily written for Karma generators. The only thing to change is the passed Domain which needs to be spirit::karma::domain.

3 Responses to “What is the Attribute Type Exposed by a Parser?”

  1. metagoto says:

    Interesting article. Thanks!

    In display_attribute_type.hpp, template function void display_attribute_of_parser(std::ostream& os, T const &) should directs its output to os rather than std::cout.

  2. Olaf says:

    “Most parser components are independent of any iterator type, but components as the raw[] directives are. So most of the time we can leave out supplying an iterator type.”

    What is to do to support even this, e.g. by use of a lexer we always have an iterator.

    Thanks,
    Olaf

Leave a Reply to metagoto

preload preload preload