- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想解析一个 double vector 。然而,这个 vector 也可能包含两种类型的语句,它们对数据进行了一定程度的压缩:FOR
和 RAMP
.
如果FOR
在字符串中,格式应该是"<double> FOR <int>"
.这意味着重复 <double>
<int>
次。
例如"1 1.5 2 2.5 3 FOR 4 3.5"
应该解析为 { 1, 1.5, 2, 2.5, 3, 3, 3, 3, 3.5 }
如果RAMP
在字符串中,格式应该是"<double1> RAMP <int> <double2>"
.这意味着在 <double1>
之间进行线性插值和 <double2>
在 <int>
期间。
例如"1 2 3 4 RAMP 3 6 7 8"
应该解析为 { 1, 2, 3, 4, 5, 6, 7, 8 }
除了为单个元素定义解析器之外,我不知道如何继续。遇到扩展时,如何提供自定义代码来执行扩展?
谢谢!
最佳答案
没有语义操作的最简单方法¹ 是解析成一个 AST,然后您可以解释它。
更乏味的方法是使用语义操作来构建结果。 (请记住,回溯语法会带来问题。)
我做过的类似回答:
事不宜迟:
AST 示例:
namespace AST {
using N = unsigned long;
using V = double;
struct repeat { N n; V value; };
struct interpolate {
N n; V start, end;
bool is_valid() const;
};
using element = boost::variant<repeat, interpolate>;
using elements = std::vector<element>;
The
is_valid
is a good place where we can do logic asserts like "the number of periods isn't zero" or "if the number of periods is 1, start and end must coincide".
现在,对于我们的最终结果,我们希望将其转换为 just-a-vector-of-V:
using values = std::vector<V>;
static inline values expand(elements const& v) {
struct {
values result;
void operator()(repeat const& e) {
result.insert(result.end(), e.n, e.value);
}
void operator()(interpolate const& e) {
if (!e.is_valid()) {
throw std::runtime_error("bad interpolation");
}
if (e.n>0) { result.push_back(e.start); }
if (e.n>2) {
auto const delta = (e.end-e.start)/(e.n-1);
for (N i=1; i<(e.n-1); ++i)
result.push_back(e.start + i * delta);
}
if (e.n>1) { result.push_back(e.end); }
}
} visitor;
for (auto& el : v) {
boost::apply_visitor(visitor, el);
}
return std::move(visitor.result);
}
}
现在我们已经掌握了基础知识,让我们来解析和测试:
首先,让我们调整 AST 类型:
BOOST_FUSION_ADAPT_STRUCT(AST::repeat, value, n)
BOOST_FUSION_ADAPT_STRUCT(AST::interpolate, start, n, end)
Note: the "natural grammar order" of the adapted properties makes attribute propagation painless without semantic actions
现在让我们推出一个语法:
namespace qi = boost::spirit::qi;
template <typename It> struct Grammar : qi::grammar<It, AST::elements()> {
Grammar() : Grammar::base_type(start) {
elements_ = *element_;
element_ = interpolate_ | repeat_;
repeat_
= value_ >> "FOR" >> qi::uint_
| value_ >> qi::attr(1u)
;
interpolate_
= value_ >> "RAMP" >> qi::uint_ >> value_
;
value_ = qi::auto_;
start = qi::skip(qi::space) [ elements_ ];
BOOST_SPIRIT_DEBUG_NODES((start)(elements_)(element_)(repeat_)(interpolate_)(value_))
}
private:
qi::rule<It, AST::elements()> start;
qi::rule<It, AST::elements(), qi::space_type> elements_;
qi::rule<It, AST::element(), qi::space_type> element_;
qi::rule<It, AST::repeat(), qi::space_type> repeat_;
qi::rule<It, AST::interpolate(), qi::space_type> interpolate_;
qi::rule<It, AST::V(), qi::space_type> value_;
};
Note:
BOOST_SPIRIT_DEBUG_NODES
enables rule debugging- The order of
interpolate_ | repeat_
is important, sincerepeat_
also parses individual numbers (so it would preventFROM
from being parsed in time.
调用解析器和 expand()
中间表示的简单实用程序:
AST::values do_parse(std::string const& input) {
static const Grammar<std::string::const_iterator> g;
auto f = begin(input), l = end(input);
AST::elements intermediate;
if (!qi::parse(f, l, g >> qi::eoi, intermediate)) {
throw std::runtime_error("bad input");
}
return expand(intermediate);
}
布丁的证明在于吃:
int main() {
std::cout << std::boolalpha;
struct { std::string input; AST::values expected; } cases[] = {
{ "1 1.5 2 2.5 3 FOR 4 3.5", { 1, 1.5, 2, 2.5, 3, 3, 3, 3, 3.5 } },
{ "1 2 3 4 RAMP 3 6 7 8", { 1, 2, 3, 4, 5, 6, 7, 8 } },
};
for (auto const& test : cases) {
try {
std::cout << std::quoted(test.input) << " -> ";
auto actual = Parse::do_parse(test.input);
std::cout << (actual==test.expected? "PASSED":"FAILED") << " { ";
// print the actual for reference
std::cout << " {";
for (auto& v : actual) std::cout << v << ", ";
std::cout << "}\n";
} catch(std::exception const& e) {
std::cout << "ERROR " << std::quoted(e.what()) << "\n";
}
}
}
打印
"1 1.5 2 2.5 3 FOR 4 3.5" -> PASSED { {1, 1.5, 2, 2.5, 3, 3, 3, 3, 3.5, }
"1 2 3 4 RAMP 3 6 7 8" -> PASSED { {1, 2, 3, 4, 5, 6, 7, 8, }
这可能更有效,而且我发现我实际上更喜欢这种方法的表现力。
随着语法变得越来越复杂,它可能无法很好地扩展。
这里我们“反转”流程:
Grammar() : Grammar::base_type(start) {
element_ =
qi::double_ [ px::push_back(qi::_val, qi::_1) ]
| ("FOR" >> qi::uint_) [ handle_for(qi::_val, qi::_1) ]
| ("RAMP" >> qi::uint_ >> qi::double_) [ handle_ramp(qi::_val, qi::_1, qi::_2) ]
;
start = qi::skip(qi::space) [ *element_ ];
}
此处语义 Action 中的handle_for
和handle_ramp
是惰性Actor,它们基本上执行与AST 中的expand()
相同的操作-基于方法,但是
这会进行一些额外的检查(当用户传递以 "FOR"
或 "RAMP"
开头的字符串时,我们不希望 UB) :
struct handle_for_f {
void operator()(Values& vec, unsigned n) const {
if (vec.empty() || n<1)
throw std::runtime_error("bad quantifier");
vec.insert(vec.end(), n-1, vec.back());
}
};
struct handle_ramp_f {
void operator()(Values& vec, unsigned n, double target) const {
if (vec.empty())
throw std::runtime_error("bad quantifier");
if ((n == 0) || (n == 1 && (vec.back() != target)))
throw std::runtime_error("bad interpolation");
auto start = vec.back();
if (n>2) {
auto const delta = (target-start)/(n-1);
for (std::size_t i=1; i<(n-1); ++i)
vec.push_back(start + i * delta);
}
if (n>1) { vec.push_back(target); }
}
};
为了避免语义操作中繁琐的 boost::phoenix::bind
,让我们适应 Phoenix Functions:
px::function<handle_for_f> handle_for;
px::function<handle_ramp_f> handle_ramp;
do_parse
助手变得更简单了,因为我们没有中间表示:
Values do_parse(std::string const& input) {
static const Grammar<std::string::const_iterator> g;
auto f = begin(input), l = end(input);
Values values;
if (!qi::parse(f, l, g >> qi::eoi, values)) {
throw std::runtime_error("bad input");
}
return values;
}
同样,布丁的证明在于吃。未修改main()
的测试程序:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <iostream>
#include <iomanip>
using Values = std::vector<double>;
namespace Parse {
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
template <typename It> struct Grammar : qi::grammar<It, Values()> {
Grammar() : Grammar::base_type(start) {
element_ =
qi::double_ [ px::push_back(qi::_val, qi::_1) ]
| ("FOR" >> qi::uint_) [ handle_for(qi::_val, qi::_1) ]
| ("RAMP" >> qi::uint_ >> qi::double_) [ handle_ramp(qi::_val, qi::_1, qi::_2) ]
;
start = qi::skip(qi::space) [ *element_ ];
}
private:
qi::rule<It, Values()> start;
qi::rule<It, Values(), qi::space_type> element_;
struct handle_for_f {
void operator()(Values& vec, unsigned n) const {
if (vec.empty() || n<1)
throw std::runtime_error("bad quantifier");
vec.insert(vec.end(), n-1, vec.back());
}
};
struct handle_ramp_f {
void operator()(Values& vec, unsigned n, double target) const {
if (vec.empty())
throw std::runtime_error("bad quantifier");
if ((n == 0) || (n == 1 && (vec.back() != target)))
throw std::runtime_error("bad interpolation");
auto start = vec.back();
if (n>2) {
auto const delta = (target-start)/(n-1);
for (std::size_t i=1; i<(n-1); ++i)
vec.push_back(start + i * delta);
}
if (n>1) { vec.push_back(target); }
}
};
px::function<handle_for_f> handle_for;
px::function<handle_ramp_f> handle_ramp;
};
Values do_parse(std::string const& input) {
static const Grammar<std::string::const_iterator> g;
auto f = begin(input), l = end(input);
Values values;
if (!qi::parse(f, l, g >> qi::eoi, values)) {
throw std::runtime_error("bad input");
}
return values;
}
}
int main() {
std::cout << std::boolalpha;
struct { std::string input; Values expected; } cases[] = {
{ "1 1.5 2 2.5 3 FOR 4 3.5", { 1, 1.5, 2, 2.5, 3, 3, 3, 3, 3.5 } },
{ "1 2 3 4 RAMP 3 6 7 8", { 1, 2, 3, 4, 5, 6, 7, 8 } },
};
for (auto const& test : cases) {
try {
std::cout << std::quoted(test.input) << " -> ";
auto actual = Parse::do_parse(test.input);
std::cout << (actual==test.expected? "PASSED":"FAILED") << " { ";
// print the actual for reference
std::cout << " {";
for (auto& v : actual) std::cout << v << ", ";
std::cout << "}\n";
} catch(std::exception const& e) {
std::cout << "ERROR " << std::quoted(e.what()) << "\n";
}
}
}
打印和之前一样:
"1 1.5 2 2.5 3 FOR 4 3.5" -> PASSED { {1, 1.5, 2, 2.5, 3, 3, 3, 3, 3.5, }
"1 2 3 4 RAMP 3 6 7 8" -> PASSED { {1, 2, 3, 4, 5, 6, 7, 8, }
关于c++ - 振奋 spirit : how to use custom logic when parsing a list of doubles with text specifiers,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59198525/
Closed. This question is opinion-based。它当前不接受答案。 想改善这个问题吗?更新问题,以便editing this post用事实和引用来回答。 上个月关闭。
我正在 VHDL 中实现正交解码器,并提出了两种解决方案。 在方法 1 中,所有逻辑都放在一个对时钟和复位敏感的进程中。 在 Spartan-3A 上,这使用四个切片、七个 FF 和四个输入 LUT。
我现在在我的项目中使用 Logic-Apps。我认为这很好而且很容易!但是,在逻辑编码过程中很难调试。因为我无法在代码的中间点确认变量或状态。通常,开发人员可以在 Visual Studio 上执行程
我试图让一个方法仅在 unicode 字符的 char 值是数字、大写字母或小写字母时才采取操作。 if ((48=57)||(65=90)||(97=122) // only if numeral
所以我得到了我编写的代码示例。我的目标是打印存储在 ptr char 变量中的句子中的数字。所以代码的第一部分完成了这项工作。 #include #include void preg(char *
我有很多 JavaScript 遗留代码,我想重写所有松散的等式以使用严格的等式,即。 == 与 ===。但我常常不知道比较变量存储的是什么值。 在不知道这些值是什么的情况下,有没有办法重写这样的东西
我在尝试附加包 tidyselect 和尝试调用 tidyselect::any_function 时遇到此错误。 错误发生在 Rstudio 或类似的命令行中,在 RStudio 中它会在我输入时立
有什么方法可以在调用子逻辑应用时动态更新工作流: 正常工作流程配置如下: 我想要实现的目标如下,使用属性、变量任何更新运行时的工作流程,我尝试使用如下: 当我尝试按上述方式保存时,结果为错误:保存失败
有什么方法可以在调用子逻辑应用时动态更新工作流: 正常工作流程配置如下: 我想要实现的目标如下,使用属性、变量任何更新运行时的工作流程,我尝试使用如下: 当我尝试按上述方式保存时,结果为错误:保存失败
例如,考虑逻辑“用户只能编辑或删除该用户发表的评论”。 My Controller Actions会重复检查当前登录用户是否可以影响评论的逻辑。示例 [Authorize] public Action
在基于规则的专家系统中,知识库包含大量“if (template) then (action)”形式的规则。推理引擎选择与输入事实相匹配的规则。即那些条件部分与输入数据相匹配的规则被列入候选名单,并选
谁能解释一下这个分离逻辑的例子? 第一行和第二行有什么区别? 最佳答案 第一行说堆只包含一个小堆,因此存储中的引用 x 指向它,并且它包含值 4,4。 在 A 中为假,因为它忘记了 y 指向的小堆(它
我尝试了几天编写 NLTK 语法来将简单的法语句子转换为逻辑公式。我的问题可能与英语句子相似。我的目标是这个语法接受多个订单(家庭自动化)并将它们转换为逻辑公式。一些订单示例: 开灯: exists
我正在大学/学院学习自然演绎,作为我正式规范和验证计算机科学类(class)的一部分。 我觉得这很有趣,但是当我找到实际用途时,我会学得更好。 谁能向我解释除了用于正式验证代码位之外是否以及如何使用自
Closed. This question does not meet Stack Overflow guidelines。它当前不接受答案。 想改善这个问题吗?更新问题,以便将其作为on-topic
物理量子位和逻辑量子位有什么区别? 我希望有人能帮助我解决这个问题,我无法弄清楚到底有什么区别。 最好的,迪尔玛 最佳答案 逻辑量子位是可以用于编程的,它保存了 |0> 和 |1> 状态的叠加。它可以
我正在尝试学习如何使用 C++ 修改内存位置,并且在使用 MineSweeper 时,我注意到当内存中的时钟值为 1101004800 时,游戏进入了 20 秒。数字 1101529088 对应于游戏
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 11 年前。 Improve thi
首先介绍一些术语(取自here,第14页): 正程序是有错误的程序。 否定程序是没有错误的程序。 因此,程序有四种类型: 积极计划,分析为积极->真正积极(TP)。 积极计划,分析为否定->假否定(F
任何人都可以推荐可用于评估逻辑表达式的软件(最好是mac)或基于网络的工具吗? 例如,我希望能够快速测试两个表达式是否如下: $a = 'foo'; $b = 'bar'; $c = 'foo'; (
我是一名优秀的程序员,十分优秀!