1

I'm trying to implement a HTTP header parser using Boost Spirit, however I've become stuck on a basic subtask: extracting the HTTP version number from the first line.

Simplified code:

#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/sequence.hpp>
#include <iostream>
#include <string>

namespace parser
{
    namespace ast
    {
        struct version_number
        {
            int major = 0;
            int minor = 0;
        };
    }

    using boost::fusion::operator<<;
}
BOOST_FUSION_ADAPT_STRUCT(
    parser::ast::version_number,
    (int, major)
    (int, minor)
)

namespace parser
{
    using namespace boost::spirit::x3;

    class version_number_id;
    rule<version_number_id, ast::version_number> version_number = "version_number";
    auto const version_number_def = eps
        >> int_
        >> "."
        >> int_
        ;
    BOOST_SPIRIT_DEFINE(rtsp_request_line)
}

int main()
{
    using namespace std;
    string input = "4.332";


    parser::ast::version_number vn;
    auto res = boost::spirit::x3::parse(begin(input), end(input), parser::version_number, vn);
    if (res)
    {
        cout << "Success" << endl;
    }
    else
    {
        cout << "Failure" << endl;
    }
}

However even with this simple example I've run into compilation errors using Boost v1.64 and MSVC++ 14.1. Compiler output is as follows:

1>------ Build started: Project: spirit_test, Configuration: Debug Win32 ------
1>main2.cpp
1>c:\devlib\boost_1_64_0\include\boost\spirit\home\x3\nonterminal\rule.hpp(36): error C2338: BOOST_SPIRIT_DEFINE undefined for this rule.
1>c:\devlib\boost_1_64_0\include\boost\spirit\home\x3\nonterminal\rule.hpp(116): note: see reference to function template instantiation 'boost::spirit::x3::detail::default_parse_rule_result boost::spirit::x3::parse_rule<parser::version_number_id,parser::ast::version_number,Iterator,Context,Attribute_>(boost::spirit::x3::rule<parser::version_number_id,parser::ast::version_number,false>,Iterator &,const Iterator &,const Context &,ActualAttribute &)' being compiled
1>        with
1>        [
1>            Iterator=std::_String_iterator<std::_String_val<std::_Simple_types<char>>>,
1>            Context=boost::spirit::x3::unused_type,
1>            Attribute_=parser::ast::version_number,
1>            ActualAttribute=parser::ast::version_number
1>        ]
1>c:\devlib\boost_1_64_0\include\boost\spirit\home\x3\core\parse.hpp(35): note: see reference to function template instantiation 'bool boost::spirit::x3::rule<parser::version_number_id,parser::ast::version_number,false>::parse<Iterator,boost::spirit::x3::unused_type,Attribute>(Iterator &,const Iterator &,const Context &,boost::spirit::x3::unused_type,Attribute_ &) const' being compiled
1>        with
1>        [
1>            Iterator=std::_String_iterator<std::_String_val<std::_Simple_types<char>>>,
1>            Attribute=parser::ast::version_number,
1>            Context=boost::spirit::x3::unused_type,
1>            Attribute_=parser::ast::version_number
1>        ]
1>c:\devlib\boost_1_64_0\include\boost\spirit\home\x3\core\parse.hpp(35): note: see reference to function template instantiation 'bool boost::spirit::x3::rule<parser::version_number_id,parser::ast::version_number,false>::parse<Iterator,boost::spirit::x3::unused_type,Attribute>(Iterator &,const Iterator &,const Context &,boost::spirit::x3::unused_type,Attribute_ &) const' being compiled
1>        with
1>        [
1>            Iterator=std::_String_iterator<std::_String_val<std::_Simple_types<char>>>,
1>            Attribute=parser::ast::version_number,
1>            Context=boost::spirit::x3::unused_type,
1>            Attribute_=parser::ast::version_number
1>        ]
1>c:\devlib\boost_1_64_0\include\boost\spirit\home\x3\core\parse.hpp(60): note: see reference to function template instantiation 'bool boost::spirit::x3::parse_main<Iterator,Parser,Attribute>(Iterator &,Iterator,const Parser &,Attribute &)' being compiled
1>        with
1>        [
1>            Iterator=std::_String_iterator<std::_String_val<std::_Simple_types<char>>>,
1>            Parser=boost::spirit::x3::rule<parser::version_number_id,parser::ast::version_number,false>,
1>            Attribute=parser::ast::version_number
1>        ]
1>d:\documents\visual studio 2017\projects\spirit_test\spirit_test\main2.cpp(49): note: see reference to function template instantiation 'bool boost::spirit::x3::parse<std::_String_iterator<std::_String_val<std::_Simple_types<char>>>,boost::spirit::x3::rule<parser::version_number_id,parser::ast::version_number,false>,parser::ast::version_number>(const Iterator &,Iterator,const Parser &,Attribute &)' being compiled
1>        with
1>        [
1>            Iterator=std::_String_iterator<std::_String_val<std::_Simple_types<char>>>,
1>            Parser=boost::spirit::x3::rule<parser::version_number_id,parser::ast::version_number,false>,
1>            Attribute=parser::ast::version_number
1>        ]
1>c:\devlib\boost_1_64_0\include\boost\spirit\home\x3\nonterminal\rule.hpp(37): error C2039: 'parse': is not a member of 'boost::spirit::x3::unused_type'
1>c:\devlib\boost_1_64_0\include\boost\spirit\home\x3\support\traits\attribute_category.hpp(22): note: see declaration of 'boost::spirit::x3::unused_type'
1>Done building project "spirit_test.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped =========

I notice that in the debug messages, the Context=boost::spirit::x3::unused_type line appearing, and I known that unused_type is a tag class used to indicate that the rule does not populate an attribute. I don't understand where that tag is coming from in this example, however.

If I modify the code by using an inline rule with no rule<> definition, and pass a std::pair<int, int> in as the attribute instead, the code compiles and runs fine.

What's going on here, and where did I go wrong with this simple example?

Paul Belanger
  • 2,354
  • 14
  • 23
  • 1
    MSVC++ 14.1 is Visual Studio 2014? I know that boost spirit x3 works with Visual Stuiod 2017 RC – Justin Sep 16 '17 at 23:08

2 Answers2

2

In your code you have BOOST_SPIRIT_DEFINE(rtsp_request_line), but the the rule's actual name is version_number. Once this typo is fixed your code compiles cleanly for me with Boost 1.65.1 and VC++ 2017 Update 3 (compiler v19.11.25508).

ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • 1
    Derp, I can confirm that it does actually compile when the typo is fixed. – Paul Belanger Sep 20 '17 at 22:06
  • Hah - Oops. I thought the typo was too obvious (it looked like "anonymizing" the rule name went wrong). You _could_ have spotted the fix from the many (5...) online copies I linked :) – sehe Sep 20 '17 at 22:31
0

It's simply a problem with MSVC. MSVC compiler is not supported for now.

It's not a problem on other compilers: http://coliru.stacked-crooked.com/a/aba5282f5cb7bb02

Source on supported compilers: http://boost-spirit.com/home/2015/05/16/spirit-3-0-0/

Interestingly, the only online MSVC compiler I know of does underline the diagnosis: MSVC is just not supported (http://rextester.com/ZSEF55595), though it gives a different error - possibly due to Boost 1.60.0 there.

On GCC/Clang Boost 1.60.0 is not a hurdle though:

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thank you for your help! Do you know by chance what parts of the Microsoft compiler make it incompatible with the current implementation of x3? – Paul Belanger Sep 16 '17 at 23:42
  • I have to resist the strong urge to say "all parts". It's - in all seriousness - likely the standards conformance (MSVC still doesn't 2-phase lookup and stuff like that). It **could** just be that the LLVM frontend bits alleviate those issues (?). – sehe Sep 16 '17 at 23:49
  • FWIW, MS claims [here](https://blogs.msdn.microsoft.com/vcblog/2016/06/07/expression-sfinae-improvements-in-vs-2015-update-3/) that VC++ 2017 works with X3 (and this has been my personal experience as well). – ildjarn Sep 19 '17 at 13:34
  • @ildjarn That's very nice and all, but that doesn't make it any more supported in any way. Clearly, there's something amiss still :) It's good to know that MS is actively improving that area. – sehe Sep 19 '17 at 13:52
  • @sehe : Well, after fixing the `rtsp_request_line` typo, the OP's code compiles fine for me with current MSVC and Boost 1.65.1. I'd go so far as to suggest that said typo is the _only_ problem here, and that MSVC is a red herring... ;-] (It's telling that with the code as-is, Clang 6 trunk's error message is remarkably similar to OP's: `error: no member named 'parse' in 'boost::spirit::x3::unused_type'`) – ildjarn Sep 19 '17 at 14:48
  • It wasn't. I've checked and obviously corrected the typo first thing. I think the evidence should be in the links thigh I have no time to check right now – sehe Sep 19 '17 at 14:53
  • 1
    @sehe : I checked with Boost 1.65.1 and VC++ 2017U3, and the typo was the only issue. So whatever the issue, if you're right, it was either fixed between MSVC 14.10 and 14.11, or between Boost 1.64.0 and 1.65.1. I don't have any handy way to figure out which. – ildjarn Sep 19 '17 at 14:57
  • 1
    TO THE DOWNVOTER: please don't. My answer has a ton of correct info. It **also** fixed the typo that was in the sample (which I disregarded as a problem because it was so trivial). Lastly, if you have trouble, just ask a question. I happen to know of an unrelated bug in 1.66.0 that was fixed in 1.67.0 that can lead to the exact error message from the question title. I could have linked you to this: https://github.com/boostorg/spirit/commit/ee4943d5891bdae0706fb616b908e3bf528e0dfa – sehe Apr 29 '18 at 12:49