我使用boost spirit x3创建了一个语法。在测试我生成的解析器时,我发现有一种情况是解析器抛出以下异常:
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
我不知道这可能会发生使用boost spirit x3,我认为解析方法eighter返回false或抛出boost::spirit::x3::expectation_failure
,我在语法中做错了什么,因为这不应该发生在这里。
我上传了我的mcve HERE,如果执行二进制文件,则会抛出std :: logic错误。
example.cpp
#include "example_def.hpp"
#include "config.hpp"
namespace client { namespace parser {
BOOST_SPIRIT_INSTANTIATE(var_dec_type, iterator_type, context_type)
}}
的main.cpp
#include <iostream>
//#define SINGLE_TU
#if defined(SINGLE_TU)
#pragma message "yesdef(SINGLE_TU)"
#else
#pragma message "notdef(SINGLE_TU)"
#endif
#ifdef SINGLE_TU
#include "types_def.hpp"
#include "example_def.hpp"
#else
#include "example.hpp"
#endif
template<typename Parser, typename Attribute>
bool test(const std::string& str, Parser&& p, Attribute&& attr)
{
using iterator_type = std::string::const_iterator;
iterator_type in = str.begin();
iterator_type end = str.end();
bool ret = boost::spirit::x3::phrase_parse(in, end, p, boost::spirit::x3::ascii::space, attr);
ret &= (in == end);
return ret;
}
int main()
{
client::ast::VariableDec attr;
std::cout << test("var foo : foo<bar, baz<bahama>>", client::var_dec() , attr);
return 0;
}
types.cpp
#include "config.hpp"
#include "types_def.hpp"
#include <iostream>
namespace client {namespace parser {
BOOST_SPIRIT_INSTANTIATE(type_type, iterator_type, context_type);
BOOST_SPIRIT_INSTANTIATE(class_type_type, iterator_type, context_type);
#define PARSE_RULE_BODY
#if defined(PARSE_RULE_BODY)
#pragma message "yesdef(PARSE_RULE_BODY)"
//This causes the parse_rule generated by
//BOOST_SPIRIT_DEFINE for type
//to *not* be used.
#include <boost/fusion/iterator/deref.hpp>
#else
#pragma message "notdef(PARSE_RULE_BODY)"
//This causes the parse_rule generated by
//BOOST_SPIRIT_DEFINE for type
//to be used.
#endif
#define SEHE_TYPES_DEF_HPP_PASTE
#define EXPLICT_SPECIALIZATION_FROM_LINKER_ERROR_MSG
#if defined(SEHE_TYPES_DEF_HPP_PASTE)
#pragma message "yesdef(SEHE_TYPES_DEF_HPP_PASTE)"
//Source:
// The following code was copy&pasted&reformatted from lines 38-53 of:
// https://github.com/sehe/linker_error_example/blob/explicit_instantiation/types_def.hpp
// on about 2016-11-15.
// with minor modifications:
// * reformatting
// * Added body with:
// * printing first..last.
//=======================
namespace {
template <typename Seq, size_t N>
using field_at =
boost::fusion::basic_iterator
< boost::fusion::struct_iterator_tag
, boost::fusion::random_access_traversal_tag
, Seq
, N
>;
template <typename Seq, size_t N, size_t M>
using fields =
boost::fusion::iterator_range<field_at<Seq, N>, field_at<Seq, M> >;
using Attributes =
fields<client::ast::VariableDec, 1, 2>;
using Context =
x3::context
< x3::skipper_tag
, x3::char_class<boost::spirit::char_encoding::ascii, x3::space_tag> const
, x3::unused_type
>;
}
template
#ifdef PARSE_RULE_BODY
<>
#endif
bool parse_rule
< std::string::const_iterator
, Context
, Attributes
>(
decltype(type) rule,
std::string::const_iterator &first,
std::string::const_iterator const &last,
Context const &context,
Attributes &attr)
#ifndef PARSE_RULE_BODY
;
#else
{
std::cout<<"***in function="<<__func__<<"\n";
std::string::const_iterator beg=first;
std::cout<<":input=\n{";
for(; beg!=last; ++beg) std::cout<<*beg;
std::cout<<"}\n";
using required_t=type_type::attribute_type;
required_t required_v=boost::fusion::deref(attr.first);
//attr type required by parse_rule generated by:
// BOOST_SPIRIT_INSTANTIATE(type_type, iterator_type, context_type)
;
bool result=parse_rule(rule,first,last,context,required_v)
//This should call the parse_rule generated by:
// BOOST_SPIRIT_INSTANTIATE(type_type, iterator_type, context_type)
;
std::cout<<":result="<<result<<"\n";
return result;
}
#endif
#elif defined(EXPLICT_SPECIALIZATION_FROM_LINKER_ERROR_MSG)
#pragma message "yesdef(EXPLICT_SPECIALIZATION_FROM_LINKER_ERROR_MSG)"
template
#ifdef PARSE_RULE_BODY
<>
#endif
//The following simply copied&pasted from an earlier linker error
//message, and then reformatted to clarify what
//was being specialized.
bool
parse_rule
< __gnu_cxx::__normal_iterator
< char const*
, std::__cxx11::basic_string
< char
, std::char_traits<char>
, std::allocator<char>
>
>
, boost::spirit::x3::context
< boost::spirit::x3::skipper_tag
, boost::spirit::x3::char_class
< boost::spirit::char_encoding::ascii
, boost::spirit::x3::space_tag
> const
, boost::spirit::x3::unused_type
>
, boost::fusion::iterator_range
< boost::fusion::basic_iterator
< boost::fusion::struct_iterator_tag
, boost::fusion::random_access_traversal_tag
, client::ast::VariableDec
, 1
>
, boost::fusion::basic_iterator
< boost::fusion::struct_iterator_tag
, boost::fusion::random_access_traversal_tag
, client::ast::VariableDec
, 2
>
>
>
( boost::spirit::x3::rule//==decltype(type) where types from types_def.hpp:16
< client::parser::type_class//types.hpp:15
, boost::spirit::x3::variant
< client::ast::nil
, boost::spirit::x3::forward_ast
< client::ast::LambdaType
>
, boost::spirit::x3::forward_ast
< client::ast::ClassType
>
>
, false
>
, __gnu_cxx::__normal_iterator//==std::string::const_iterator
< char const*
, std::__cxx11::basic_string
< char
, std::char_traits<char>
, std::allocator<char>
>
>& first
, __gnu_cxx::__normal_iterator//==std::string::const_iterator
< char const*
, std::__cxx11::basic_string
< char
, std::char_traits<char>
, std::allocator<char>
>
> const& last
, boost::spirit::x3::context//=?Context from #if defined(SEHE_TYPES_DEF_HPP_PASTE)
< boost::spirit::x3::skipper_tag
, boost::spirit::x3::char_class
< boost::spirit::char_encoding::ascii
, boost::spirit::x3::space_tag
> const
, boost::spirit::x3::unused_type
> const& context
, boost::fusion::iterator_range//=?Attributes from #if defined(SEHE_TYPES_DEF_HPP_PASTE)
< boost::fusion::basic_iterator
< boost::fusion::struct_iterator_tag
, boost::fusion::random_access_traversal_tag
, client::ast::VariableDec
, 1
>
, boost::fusion::basic_iterator
< boost::fusion::struct_iterator_tag
, boost::fusion::random_access_traversal_tag
, client::ast::VariableDec
, 2
>
>& attr
)
#ifndef PARSE_RULE_BODY
;
#else
{
std::cout<<"***in function="<<__func__<<"\n";
std::string::const_iterator beg=first;
std::cout<<":input=\n{";
for(; beg!=last; ++beg) std::cout<<*beg;
std::cout<<"}\n";
return false;
}
#endif//PARSE_RULE_BODY
#endif//(SEHE_TYPES_DEF_HPP_PASTE)
}}
ast.hpp
//
// Created by lukas on 11.11.16.
//
#ifndef LINKER_ERROR_EXAMPLE_AST_HPP_HPP
#define LINKER_ERROR_EXAMPLE_AST_HPP_HPP
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <vector>
#include <string>
namespace client { namespace ast {
namespace x3 = boost::spirit::x3;
struct LambdaType;
struct ClassType;
struct nil{};
typedef x3::variant <
nil,
x3::forward_ast<LambdaType>,
x3::forward_ast<ClassType>
> Type;
struct LambdaType {
std::vector<Type> parameters_;
Type return_type_;
};
struct ClassType {
std::vector<std::string> name_;
std::vector<Type> template_args_;
};
struct VariableDec {
std::string _name;
Type _type;
};
}}
BOOST_FUSION_ADAPT_STRUCT(client::ast::LambdaType, parameters_, return_type_)
BOOST_FUSION_ADAPT_STRUCT(client::ast::ClassType, name_, template_args_)
BOOST_FUSION_ADAPT_STRUCT(client::ast::VariableDec, _name, _type)
#endif //LINKER_ERROR_EXAMPLE_AST_HPP_HPP
config.hpp
#ifndef LINKER_ERROR_EXAMPLE_CONFIG_HPP
#define LINKER_ERROR_EXAMPLE_CONFIG_HPP
#include <boost/spirit/home/x3.hpp>
namespace client{
namespace parser{
namespace x3 = boost::spirit::x3;
typedef std::string::const_iterator iterator_type;
typedef x3::phrase_parse_context<x3::ascii::space_type>::type context_type;
}
}
#endif //LINKER_ERROR_EXAMPLE_CONFIG_HPP
example_def.hpp
#ifndef LINKER_ERROR_EXAMPLE_EXAMPLE_DEF_HPP
#define LINKER_ERROR_EXAMPLE_EXAMPLE_DEF_HPP
#include "ast.hpp"
#include "example.hpp"
#include "types.hpp"
namespace client { namespace parser {
#ifndef SINGLE_TU
namespace { const auto& type = client::type(); }
#endif
const var_dec_type var_dec = "var_dec";
#define EXAMPLE_DEF_LINK_ERR
#if defined(EXAMPLE_DEF_LINK_ERR)
#pragma message "yesdef(EXAMPLE_DEF_LINK_ERR)"
#else
#pragma message "notdef(EXAMPLE_DEF_LINK_ERR)"
#endif
auto const var_dec_def = x3::lexeme["var "]
> +x3::alnum
> ":"
#ifdef EXAMPLE_DEF_LINK_ERR
>> type //<- this gets linker error.
#else
> type //<- This links.
#endif
> ";";
BOOST_SPIRIT_DEFINE(
var_dec
)
}}
namespace client {
const parser::var_dec_type& var_dec()
{
return parser::var_dec;
}
}
#endif //LINKER_ERROR_EXAMPLE_EXAMPLE_DEF_HPP
example.hpp
#ifndef LINKER_ERROR_EXAMPLE_EXAMPLE_HPP
#define LINKER_ERROR_EXAMPLE_EXAMPLE_HPP
#include <boost/spirit/home/x3.hpp>
#include "ast.hpp"
namespace client { namespace parser {
namespace x3 = boost::spirit::x3;
class var_dec_class {};
typedef x3::rule<var_dec_class, ast::VariableDec> var_dec_type;
BOOST_SPIRIT_DECLARE(var_dec_type)
}}
namespace client {
const parser::var_dec_type& var_dec();
}
#endif //LINKER_ERROR_EXAMPLE_EXAMPLE_HPP
types_def.hpp
#ifndef KYLE_TYPES_DEF_HPP
#define KYLE_TYPES_DEF_HPP
#include "types.hpp"
namespace client { namespace parser {
namespace x3 = boost::spirit::x3;
typedef x3::rule<struct lambda_type_class, ast::LambdaType> lambda_type_type;
const class_type_type class_type = "class_type";
const lambda_type_type lambda_type = "lambda_type";
const type_type type = "type";
auto const identifier = +x3::alnum;
auto const type_def =
(lambda_type | class_type);
auto const lambda_type_def =
("(" > -(type % ",") > ")" > "=>" > type)
| (x3::repeat(1)[class_type] >> "=>" > type);
auto const class_type_def =
(identifier % "::") >> -("<" > type % "," > ">");
BOOST_SPIRIT_DEFINE(
lambda_type,
class_type,
type
)
}}
namespace client {
const parser::class_type_type& class_type()
{
return parser::class_type;
}
const parser::type_type& type()
{
return parser::type;
}
}
#endif //KYLE_TYPES_DEF_HPP
types.hpp
#ifndef KYLE_PARSER_TYPES_HPP
#define KYLE_PARSER_TYPES_HPP
#include <boost/spirit/home/x3.hpp>
#include "ast.hpp"
namespace client { namespace parser {
namespace x3 = boost::spirit::x3;
struct class_type_class;
struct type_class;
typedef x3::rule<class_type_class, ast::ClassType> class_type_type;
typedef x3::rule<type_class, ast::Type> type_type;
BOOST_SPIRIT_DECLARE(class_type_type,
type_type)
}}
namespace client {
const parser::class_type_type& class_type();
const parser::type_type& type();
}
#endif
答案 0 :(得分:2)
它会抛出expectation_failed异常。
很明显,这是因为你遗失了;
。
清除了与旧的链接器错误解决方法相关的可怕的kludges后,我只是将example_def
表达式更改为:
auto const var_dec_def = x3::lexeme["var "] > +x3::alnum >> (":" > type) > ";";
现在,添加正确的错误处理:
int main()
{
client::ast::VariableDec attr;
std::string const input("var foo : foo<bar, baz<bahama>>;");
try {
std::cout << test(input, client::var_dec() , attr);
} catch(boost::spirit::x3::expectation_failure<std::string::const_iterator> const& e) {
std::cout << "Expected: " << e.which() << " at '" << std::string(e.where(), input.end()) << "'\n";
return 255;
}
}
打印:
1
抛出尾随的;
打印件:
Expected: ';' at ''
完整演示:error-handling分支
CMakeLists.txt | 6 +-
example.cpp | 9 +++
example_def.hpp | 33 +--------
main.cpp | 20 ++----
types.cpp | 203 ++++----------------------------------------------------
types_def.hpp | 20 ++----
6 files changed, 38 insertions(+), 253 deletions(-)
example.cpp
#include "example_def.hpp"
#include "config.hpp"
namespace client { namespace parser {
BOOST_SPIRIT_INSTANTIATE(var_dec_type, iterator_type, context_type)
}}
namespace client {
const parser::var_dec_type& var_dec()
{
return parser::var_dec;
}
}
的main.cpp
#include <iostream>
#include "example.hpp"
template<typename Parser, typename Attribute>
bool test(const std::string& str, Parser&& p, Attribute&& attr)
{
using iterator_type = std::string::const_iterator;
iterator_type in = str.begin();
iterator_type end = str.end();
bool ret = boost::spirit::x3::phrase_parse(in, end, p, boost::spirit::x3::ascii::space, attr);
ret &= (in == end);
return ret;
}
int main()
{
client::ast::VariableDec attr;
std::string const input("var foo : foo<bar, baz<bahama>>");
try {
std::cout << test(input, client::var_dec() , attr);
} catch(boost::spirit::x3::expectation_failure<std::string::const_iterator> const& e) {
std::cout << "Expected: " << e.which() << " at '" << std::string(e.where(), input.end()) << "'\n";
return 255;
}
}
types.cpp
#include "config.hpp"
#include "types_def.hpp"
namespace client {namespace parser {
BOOST_SPIRIT_INSTANTIATE(type_type, iterator_type, context_type);
BOOST_SPIRIT_INSTANTIATE(class_type_type, iterator_type, context_type);
}}
namespace client {
const parser::class_type_type& class_type()
{
return parser::class_type;
}
const parser::type_type& type()
{
return parser::type;
}
}
ast.hpp
//
// Created by lukas on 11.11.16.
//
#ifndef LINKER_ERROR_EXAMPLE_AST_HPP_HPP
#define LINKER_ERROR_EXAMPLE_AST_HPP_HPP
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <vector>
#include <string>
namespace client { namespace ast {
namespace x3 = boost::spirit::x3;
struct LambdaType;
struct ClassType;
struct nil{};
typedef x3::variant <
nil,
x3::forward_ast<LambdaType>,
x3::forward_ast<ClassType>
> Type;
struct LambdaType {
std::vector<Type> parameters_;
Type return_type_;
};
struct ClassType {
std::vector<std::string> name_;
std::vector<Type> template_args_;
};
struct VariableDec {
std::string _name;
Type _type;
};
}}
BOOST_FUSION_ADAPT_STRUCT(client::ast::LambdaType, parameters_, return_type_)
BOOST_FUSION_ADAPT_STRUCT(client::ast::ClassType, name_, template_args_)
BOOST_FUSION_ADAPT_STRUCT(client::ast::VariableDec, _name, _type)
#endif //LINKER_ERROR_EXAMPLE_AST_HPP_HPP
config.hpp
#ifndef LINKER_ERROR_EXAMPLE_CONFIG_HPP
#define LINKER_ERROR_EXAMPLE_CONFIG_HPP
#include <boost/spirit/home/x3.hpp>
namespace client{
namespace parser{
namespace x3 = boost::spirit::x3;
typedef std::string::const_iterator iterator_type;
typedef x3::phrase_parse_context<x3::ascii::space_type>::type context_type;
}
}
#endif //LINKER_ERROR_EXAMPLE_CONFIG_HPP
example_def.hpp
#ifndef LINKER_ERROR_EXAMPLE_EXAMPLE_DEF_HPP
#define LINKER_ERROR_EXAMPLE_EXAMPLE_DEF_HPP
#include "ast.hpp"
#include "example.hpp"
#include "types.hpp"
namespace client { namespace parser {
namespace { const auto& type = client::type(); }
const var_dec_type var_dec = "var_dec";
auto const var_dec_def = x3::lexeme["var "] > +x3::alnum >> (":" > type) > ";";
BOOST_SPIRIT_DEFINE(var_dec)
}}
#endif //LINKER_ERROR_EXAMPLE_EXAMPLE_DEF_HPP
example.hpp
#ifndef LINKER_ERROR_EXAMPLE_EXAMPLE_HPP
#define LINKER_ERROR_EXAMPLE_EXAMPLE_HPP
#include <boost/spirit/home/x3.hpp>
#include "ast.hpp"
namespace client { namespace parser {
namespace x3 = boost::spirit::x3;
class var_dec_class {};
typedef x3::rule<var_dec_class, ast::VariableDec> var_dec_type;
BOOST_SPIRIT_DECLARE(var_dec_type)
}}
namespace client {
const parser::var_dec_type& var_dec();
}
#endif //LINKER_ERROR_EXAMPLE_EXAMPLE_HPP
types_def.hpp
#ifndef KYLE_TYPES_DEF_HPP
#define KYLE_TYPES_DEF_HPP
#include "types.hpp"
namespace client { namespace parser {
namespace x3 = boost::spirit::x3;
typedef x3::rule<struct lambda_type_class, ast::LambdaType> lambda_type_type;
const class_type_type class_type = "class_type";
const lambda_type_type lambda_type = "lambda_type";
const type_type type = "type";
auto const identifier = +x3::alnum;
auto const type_def =
(lambda_type | class_type);
auto const lambda_type_def =
("(" > -(type % ",") > ")" > "=>" > type)
| x3::repeat(1)[class_type] >> "=>" > type;
auto const class_type_def =
(identifier % "::") >> -("<" > type % "," > ">");
BOOST_SPIRIT_DEFINE(
lambda_type,
class_type,
type
)
}}
#endif //KYLE_TYPES_DEF_HPP
types.hpp
#ifndef KYLE_PARSER_TYPES_HPP
#define KYLE_PARSER_TYPES_HPP
#include <boost/spirit/home/x3.hpp>
#include "ast.hpp"
namespace client { namespace parser {
namespace x3 = boost::spirit::x3;
struct class_type_class;
struct type_class;
typedef x3::rule<class_type_class, ast::ClassType> class_type_type;
typedef x3::rule<type_class, ast::Type> type_type;
BOOST_SPIRIT_DECLARE(class_type_type,
type_type)
}}
namespace client {
const parser::class_type_type& class_type();
const parser::type_type& type();
}
#endif