1

When I compile the following code I get this error:

boost\spirit\home\qi\detail\assign_to.hpp(164): error C2440: 'static_cast' : cannot convert from 'const wchar_t' to 'element_type'

The comment right above line 164 reads as follows:

// This handles the case where the attribute is a single element fusion
// sequence. We silently assign to the only element and treat it as the
// attribute to parse the results into.

I have read the post "Spirit Qi attribute propagation issue with single-member struct" and hence added the qi::eps to all rules. However, this doesn't do the trick, so I also tried out workarounds #1 and #3 of the article above but to no avail, either. I'm therefore not sure the error is related to single element fusion sequence at all...

How do I solve this problem?

-Mario

#pragma once

#include <string>
#include <vector>

#define BOOST_SPIRIT_UNICODE
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/qi_alternative.hpp>

namespace nsunic = boost::spirit::unicode;
namespace nsqi = boost::spirit::qi;


namespace overmath
{
    struct identifier
    {
        std::wstring name;
    };

    struct assignment
    {
        identifier variable_reference;
        identifier expression;
    };

    struct statement
    {
        assignment assign;
    };

    struct statement_list
    {
        std::vector<statement> statements;
    };

    struct function
    {
        identifier name;
        statement_list slist;
    };

    struct program
    {
        std::vector<function> functions;
    };

}

BOOST_FUSION_ADAPT_STRUCT(
    overmath::identifier,
    (std::wstring, name)
)

BOOST_FUSION_ADAPT_STRUCT(
    overmath::assignment,
    (overmath::identifier, variable_reference)
    (overmath::identifier, expression)
)

BOOST_FUSION_ADAPT_STRUCT(
    overmath::statement,
    (overmath::assignment, assign)
)

BOOST_FUSION_ADAPT_STRUCT(
    overmath::statement_list,
    (std::vector<overmath::statement>, statements)
)

BOOST_FUSION_ADAPT_STRUCT(
    overmath::function,
    (overmath::identifier, name)
    (overmath::statement_list, slist)
)

BOOST_FUSION_ADAPT_STRUCT(
    overmath::program,
    (std::vector<overmath::function>, functions)
)


namespace overmath
{



    template<typename Iterator> struct function_parser : nsqi::grammar<Iterator, program(), nsqi::space_type>
    {
        function_parser() : function_parser::base_type(program)
        {
            identifier %=
                nsqi::eps
                >> +nsqi::alnum;

            assignment %=
                nsqi::eps
                >> identifier
                >> nsqi::char_('=')
                >> identifier;

            statement %=
                nsqi::eps
                >> assignment;

            statement_list %=
                nsqi::eps
                >> +statement;

            function %=
                nsqi::eps
                >> nsqi::lit("def")
                >> identifier
                >> nsqi::char_('(')
                >> nsqi::char_(')')
                >> statement_list
                >> nsqi::lit("enddef");

            program %=
                nsqi::eps
                >> +function;
        }

        nsqi::rule<Iterator, identifier()> identifier;
        nsqi::rule<Iterator, assignment(), nsqi::space_type> assignment;
        nsqi::rule<Iterator, statement(), nsqi::space_type> statement;
        nsqi::rule<Iterator, statement_list(), nsqi::space_type> statement_list;
        nsqi::rule<Iterator, function(), nsqi::space_type> function;
        nsqi::rule<Iterator, program(), nsqi::space_type> program;
    };


    template<typename Iterator> std::wstring parse(Iterator first, Iterator last)
    {
        using nsqi::phrase_parse;

        program f;
        function_parser<Iterator> fp;

        auto b = phrase_parse(first, last, fp, nsqi::space, f);
        if(b)
        {
            return std::wstring(L"OK");
        }
        return std::wstring(L"FAIL");
    }

}
Community
  • 1
  • 1
Sakuragaoka
  • 177
  • 1
  • 8
  • I think the problem is in your `assignment` rule, you have `nsqi::char_('=')` that exposes an attribute when you should have `nsqi::lit('=')` (`lit(L'=')`?). And you definitely went overboard with the `eps`s, you only need them when you have a single element and that element is a "container", so `identifier`, `statement_list` and `program`. – llonesmiz Dec 07 '15 at 15:44
  • http://coliru.stacked-crooked.com/a/dde9543607c06127 – llonesmiz Dec 07 '15 at 16:00
  • How can I make this comment my accepted answer? – Sakuragaoka Dec 07 '15 at 17:11

1 Answers1

0

Some of your rules have the usual problem of having something container-like as the single element in an adapted struct that is explained in the question you linked, but you have sidestepped it by adding the qi::eps (even when it wasn't really required).

The error your code has is due to your assignment rule. It has an attribute of overmath::assignment which is basically your_attr=tuple<identifier,identifier>. If we analyze its synthesized attribute we see that it is synt_attr=tuple<identifier,wchar_t,identifier>. When Spirit parses your rule it tries to assign the synthesized attribute to your attribute. It assigns the first element of synt_attr to your_attr (identifier to identifier, no problem), then it tries to assign the second element (wchar_t to identifier) but it doesn't work. Since identifier is an adapted struct (basically a fusion sequence tuple<wstring>) it makes wchar_t into a single element sequence tuple<wchar_t> and tries to assign it (wchar_t to wstring, and fails), causing the error.

So the problem is that you have an extra wchar_t that shouldn't be there. This is due to your use of char_('='), if you use lit('=') (or even omit[char_('=')]) it should work.

llonesmiz
  • 155
  • 2
  • 11
  • 20