- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
对于 Spirit X3 解析器的开发,我想使用语义操作(脚注 1)。控制如何将属性存储到 STL 容器中对我来说很重要。
这个问题是关于如何控制解析器属性:_attr(ctx) 匹配规则类型:_val(ctx),以便它可以正确分配。也许这个问题归结为如何应用未记录的 transform_attribute特征。但请和我一起阅读示例代码,看看这是否真的能为我解决问题。
打印对象/变量的类型
当我尝试不同的语法表达式时,我发现非常有用的是能够在语义操作中打印 _attr( ctx ) 和 _val( ctx ) 的类型。
所以根据Howard Hinnant的回答,我根据自己的喜好编写了一个实用程序头文件来提供这样的设施。
下面的代码将放在一个名为 utility.h 的文件中
#include <string>
#include <type_traits>
#include <typeinfo>
#include <cxxabi.h>
namespace utility
{
template<typename T>
std::string type2string()
{
std::string r;
typedef typename std::remove_reference<T>::type TR;
std::string space = "";
if ( std::is_const<TR>::value )
{ r = "const"; space = " "; }
if ( std::is_volatile<TR>::value )
{ r += space + " volatile"; space = " "; }
int status;
char* demangled =
abi::__cxa_demangle( typeid(TR).name(), nullptr, nullptr, &status );
switch ( status )
{
case 0: { goto proceed; }
case -1: { r = "type2string failed: malloc failure"; goto fail; }
case -2: { r = "type2string failed: " + std::string(typeid(TR).name()) +
" nonvalid C++ ABI name"; goto fail; }
case -3: { r = "type2string failed: invalid argument(s)"; goto fail; }
default: { r = "type2string failed: unknown status " +
status; goto fail; }
}
proceed:
r += space + demangled;
free( demangled );
/* references are without a space */
if ( std::is_lvalue_reference<T>::value ) { r += '&'; }
if ( std::is_rvalue_reference<T>::value ) { r += "&&"; }
fail:
return r;
}
}
现在是实际工作的示例代码:
#include <cstddef>
#include <cstdio>
#include <cstdint>
#define BOOST_SPIRIT_X3_DEBUG
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <string>
#include <vector>
#include <utility> // this is for std::move
#include "utility.h" // to print types
namespace client
{
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
namespace semantic_actions
{
using x3::_val; // assign to _val( ctx )
using x3::_attr; // from _attr( ctx )
struct move_assign
{
template <typename Context>
void operator()(const Context& ctx) const
{
printf( "move_assign\n" );
_val( ctx ) = std::move( _attr( ctx ) );
}
};
struct print_type
{
template <typename Context>
void operator()(const Context& ctx) const
{
printf( "print_type\n" );
std::string str;
str = utility::type2string< decltype( _attr( ctx ) ) >();
printf( "_attr type: %s\n", str.c_str() );
// reuse str
str = utility::type2string< decltype( _val( ctx ) ) >();
printf( "_val type: %s\n", str.c_str() );
}
};
}
namespace parser
{
using x3::char_;
using x3::lit;
using namespace semantic_actions;
x3::rule<struct main_rule_class, std::string> main_rule_ = "main_rule";
const auto main_rule__def = (*( !lit(';') >> char_) >> lit(';'))[print_type()][move_assign()];
BOOST_SPIRIT_DEFINE( main_rule_ )
const auto entry_point = x3::skip(x3::space)[ main_rule_ ];
}
}
int main()
{
printf( "Give me a string to test rule.\n" );
printf( "Type [q or Q] to quit.\n" );
std::string input_str;
std::string output_str;
while (getline(std::cin, input_str))
{
if ( input_str.empty() || input_str[0] == 'q' || input_str[0] == 'Q')
{ break; }
auto first = input_str.begin(), last = input_str.end();
if ( parse( first, last, client::parser::entry_point, output_str) )
{
printf( "Parsing succeeded\n" );
printf( "input: \"%s\"\n", input_str.c_str() );
printf( "output: \"%s\"\n", output_str.c_str() );
}
else
{
printf( "Parsing failed\n" );
}
}
return 0;
}
输入总是:abcd;
输出:
Give me a string to test rule.
Type [q or Q] to quit.
<main_rule>
<try>abcd;</try>
print_type
_attr type: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&
_val type: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&
move_assign
<success></success>
<attributes>[a, b, c, d]</attributes>
</main_rule>
Parsing succeeded
input: "abcd;"
output: "abcd"
好的,到目前为止一切正常,但假设我想在解析结果中包含分号。我将语法行更改为:
const auto main_rule__def = (*( !lit(';') >> char_) >> char_(";"))[print_type()];
注意:我删除了语义操作 [move_assign()],因为它由于不兼容的 _attr 和 _val 类型而无法编译。现在输出是:
Give me a string to test rule.
Type [q or Q] to quit.
<main_rule>
<try>abcd;</try>
print_type
_attr type: boost::fusion::deque<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, char>&
_val type: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&
<success></success>
<attributes>[]</attributes>
</main_rule>
Parsing succeeded
input: "abcd;"
output: ""
现在 _attr 类型的 boost::fusion::deque<> 不是我想要的,我只是想成为 std::string。我不明白为什么如果我在语义操作括号内有语法赋值的完整右侧,_attr 仍然不是 _val 类型。 X3 功能 transform_attribute 在这里有帮助吗?我应该如何应用它?或者有什么解决此问题的好方法,而无需使用 boost fusion 类接口(interface)或其他实现细节。
当前的解决方法
我目前的解决方法是定义另一个规则,只是从具有语义操作的第一条规则分配。只有那里的 _attr 是 std::string 类型。
namespace parser
{
using x3::char_;
using x3::lit;
using namespace semantic_actions;
x3::rule<struct main_rule_class, std::string> main_rule_ = "main_rule";
x3::rule<struct main_rule2_class, std::string> main_rule2_ = "main_rule2";
const auto main_rule__def = *( !lit(';') >> char_) >> char_(";");
const auto main_rule2__def = main_rule_[print_type()][move_assign()];
BOOST_SPIRIT_DEFINE( main_rule_, main_rule2_ )
const auto entry_point = x3::skip(x3::space)[ main_rule2_ ];
}
输出:
Give me a string to test rule.
Type [q or Q] to quit.
<main_rule2>
<try>abcd;</try>
<main_rule>
<try>abcd;</try>
<success></success>
<attributes>[a, b, c, d, ;]</attributes>
</main_rule>
print_type
_attr type: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&
_val type: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&
move_assign
<success></success>
<attributes>[a, b, c, d, ;]</attributes>
</main_rule2>
Parsing succeeded
input: "abcd;"
output: "abcd;"
我希望有一种方法,无需制定另一条规则即可使 _attr 的类型与 _val 匹配。
(1)我不欣赏作者在这个库中隐藏的聪明才智。因为只是一个看似无害的变化就可以破坏应用程序。而更明确和详尽的方法将更清楚地传达正在发生的事情。我只需要把它说出来。
最佳答案
transform_attribute
还没有 X3 ( https://www.boost.org/doc/libs/1_70_0/libs/spirit/doc/x3/html/index.html ) 的文档,但您可以在这里找到它的 Qi 对应物:https://www.boost.org/doc/libs/1_70_0/libs/spirit/doc/html/spirit/advanced/customize/transform.html .
Would the X3 feature transform_attribute help here? And how should I apply that?
无论如何,它是您可以使用规则轻松访问的实现细节。我喜欢使用匿名规则来帮助解决这个问题:
template <typename T>
struct as_type {
template <typename E>
constexpr auto operator[](E e) const { return x3::rule<struct _, T> {} = e; }
};
template <typename T>
static inline constexpr as_type<T> as;
现在你可以写了
const auto main_rule__def = as<std::string> [ (*(char_ - ';') >> char_(';')) ];
#include <iostream>
//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <iomanip> // std::quoted
namespace client {
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
namespace parser {
using x3::char_;
using x3::lit;
x3::rule<struct main_rule_class, std::string> main_rule_ = "main_rule";
template <typename T>
struct as_type {
template <typename E>
constexpr auto operator[](E e) const { return x3::rule<struct _, T> {} = e; }
};
template <typename T>
static inline constexpr as_type<T> as;
const auto main_rule__def = as<std::string> [ (*(char_ - ';') >> char_(';')) ];
BOOST_SPIRIT_DEFINE(main_rule_)
const auto entry_point = x3::skip(x3::space)[main_rule_];
} // namespace parser
} // namespace client
int main() {
std::string output_str;
for(std::string const input_str : { "abcd;" }) {
auto first = input_str.begin(), last = input_str.end();
if (parse(first, last, client::parser::entry_point, output_str)) {
std::cout << "Parsing succeeded\n";
std::cout << "input: " << std::quoted(input_str) << "\n";
std::cout << "output: " << std::quoted(output_str) << "\n";
} else {
std::cout << "Parsing failed\n";
}
}
}
打印
Parsing succeeded
input: "abcd;"
output: "abcd;"
理论上可能会有性能开销,但我强烈怀疑所有编译器都会在这里内联所有内容,因为没有任何外部链接或 vtables,并且所有内容都是 const/constexpr。
x3::raw
在这种情况下,您可以使用现有指令获得所需的行为:x3::raw
const auto main_rule__def = x3::raw [ *(char_ - ';') >> ';' ];
rule<>
总是仅当您有递归规则或需要规则的外部链接时才需要(在单独的翻译单元中定义它们)。整个程序缩小到...
#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <iomanip> // std::quoted
namespace x3 = boost::spirit::x3;
namespace client::parser {
auto const entry_point = x3::raw [ *(x3::char_ - ';') >> ';' ];
}
int main() {
for(std::string const input : { "abcd;" }) {
std::string output;
if (parse(input.begin(), input.end(), client::parser::entry_point, output)) {
std::cout << "Parsing succeeded\n";
std::cout << "input: " << std::quoted(input) << "\n";
std::cout << "output: " << std::quoted(output) << "\n";
} else {
std::cout << "Parsing failed\n";
}
}
}
我不认为你想要char_ - ';'
(或者更详细的拼写方式:!lit(';') >> char_
)。使用 skipper ,它将跨空格解析("ab c\nd ;"
-> "abcd;"`)。
您可能希望使规则更具限制性(例如 lexeme [+(graph - ';')]
或什至简单地 raw[lexeme[+(alnum|'_')]
或 lexeme[+char_("a-zA-Z0-9_")]
)。
关于c++ - Spirit X3,如何让属性类型匹配规则类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56819120/
我正在尝试编写一个相当多态的库。我遇到了一种更容易表现出来却很难说出来的情况。它看起来有点像这样: {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE
谁能解释一下这个表达式是如何工作的? type = type || 'any'; 这是否意味着如果类型未定义则使用“任意”? 最佳答案 如果 type 为“falsy”(即 false,或 undef
我有一个界面,在IAnimal.fs中, namespace Kingdom type IAnimal = abstract member Eat : Food -> unit 以及另一个成功
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: What is the difference between (type)value and type(va
在 C# 中,default(Nullable) 之间有区别吗? (或 default(long?) )和 default(long) ? Long只是一个例子,它可以是任何其他struct类型。 最
假设我有一个案例类: case class Foo(num: Int, str: String, bool: Boolean) 现在我还有一个简单的包装器: sealed trait Wrapper[
这个问题在这里已经有了答案: Create C# delegate type with ref parameter at runtime (1 个回答) 关闭 2 年前。 为了即时创建委托(dele
我正在尝试获取图像的 dct。一开始我遇到了错误 The function/feature is not implemented (Odd-size DCT's are not implemented
我正在尝试使用 AFNetworking 的 AFPropertyListRequestOperation,但是当我尝试下载它时,出现错误 预期的内容类型{( “应用程序/x-plist” )}, 得
我在下面收到错误。我知道这段代码的意思,但我不知道界面应该是什么样子: Element implicitly has an 'any' type because index expression is
我尝试将 SignalType 从 ReactiveCocoa 扩展为自定义 ErrorType,代码如下所示 enum MyError: ErrorType { // .. cases }
我无法在任何其他问题中找到答案。假设我有一个抽象父类(super class) Abstract0,它有两个子类 Concrete1 和 Concrete1。我希望能够在 Abstract0 中定义类
我想知道为什么这个索引没有用在 RANGE 类型中,而是用在 INDEX 中: 索引: CREATE INDEX myindex ON orders(order_date); 查询: EXPLAIN
我正在使用 RxJava,现在我尝试通过提供 lambda 来订阅可观察对象: observableProvider.stringForKey(CURRENT_DELETED_ID) .sub
我已经尝试了几乎所有解决问题的方法,其中包括。为 提供类型使用app.use(express.static('public'))还有更多,但我似乎无法为此找到解决方案。 index.js : imp
以下哪个 CSS 选择器更快? input[type="submit"] { /* styles */ } 或 [type="submit"] { /* styles */ } 只是好
我不知道这个设置有什么问题,我在 IDEA 中获得了所有注释(@Controller、@Repository、@Service),它在行号左侧显示 bean,然后转到该 bean。 这是错误: 14-
我听从了建议 registering java function as a callback in C function并且可以使用“简单”类型(例如整数和字符串)进行回调,例如: jstring j
有一些 java 类,加载到 Oracle 数据库(版本 11g)和 pl/sql 函数包装器: create or replace function getDataFromJava( in_uLis
我已经从 David Walsh 的 css 动画回调中获取代码并将其修改为 TypeScript。但是,我收到一个错误,我不知道为什么: interface IBrowserPrefix { [
我是一名优秀的程序员,十分优秀!