- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我有一个用于解析输入的 Qi 语法定义。后来我有一个 Karma 生成器以类似于输入的方式输出。
这可能吗?似乎可以自动将解析器语法转换为生成器语法(??)。
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <iostream>
int main(){
//test input
std::string s = "Xx 1.233 pseudo";
//input variables
std::string element;
double mass;
std::string pseudo;
auto GRAMMAR =
boost::spirit::qi::lexeme[+(boost::spirit::qi::char_ - ' ' - '\n')]
>> boost::spirit::qi::double_
>> boost::spirit::qi::lexeme[+(boost::spirit::qi::char_ - ' ' - '\n')];
bool r = boost::spirit::qi::phrase_parse(
s.begin(), s.end(),
GRAMMAR,
boost::spirit::qi::space, element, mass, pseudo
);
std::cout << boost::spirit::karma::format(
GRAMMAR ??? is it possible?
,
element,
mass,
pseudo
);
}
最佳答案
遗憾的是,不可能以一般方式实现您想要的(或者至少我不知道如何实现),但如果您愿意只使用 Spirit.Qi 的有限子集,下面的方法可能会奏效。
首先要知道的是,当你使用类似的东西时:
int_ >> double_
您只有一个 Boost.Proto 表达式,它描述了多个终端以及它们之间的关系。该表达式本身并不知道如何解析一个 int 然后再解析一个 double。每当你使用 parse
/phrase_parse
或将这些 Proto 表达式之一分配给 rule
Spirit 为一个领域(Qi 或 Karma)“编译”该表达式,并创建执行实际工作的解析器/生成器。
Here你可以看到一个小例子,它显示了 Proto 和编译后的 Qi 表达式的确切类型:
Raw proto type:
boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right, boost::proto::argsns_::list2<boost::spirit::terminal<boost::spirit::tag::int_> const&, boost::spirit::terminal<boost::spirit::tag::double_> const&>, 2l>
"Pretty" proto type:
shift_right(
terminal(boost::spirit::tag::int_)
, terminal(boost::spirit::tag::double_)
)
Compiled Qi type:
boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::any_int_parser<int, 10u, 1u, -1>, boost::fusion::cons<boost::spirit::qi::any_real_parser<double, boost::spirit::qi::real_policies<double> >, boost::fusion::nil_> > >
只要您可以访问原始表达式,您就可以使用 Proto 转换/语法将其转换为合适的 Karma 表达式。
在下面的示例中,我使用了以下转换:
Qi |Karma |Reason
------------|---------------|------
lexeme[expr]|verbatim[expr] | lexeme does not exist in Karma
omit[expr] |no_delimit[eps]| omit consumes an attribute in Karma
a >> b |a << b |
a > b |a << b | < does not exist in Karma
a - b |a | - does not exist in Karma
为了实现这种转换,您可以使用 boost::proto::or_
得到类似于:
struct Grammar : proto::or_<
proto::when<Matcher1,Transform1>,
proto::when<Matcher2,Transform2>,
Matcher3,
Matcher4
>{};
我将尝试解释这是如何工作的。
MatcherN
在下面的例子中可以是:
proto::terminal<boost::spirit::tag::omit>
: 只匹配那个特定的终端。proto::terminal<proto::_>
: 匹配之前未具体匹配的任何终端。proto::subscript<proto::terminal<boost::spirit::tag::omit>,proto::_>
: 匹配omit[expr]
其中 expr
可以是任何东西。proto::shift_right<ToKarma,ToKarma>
: 匹配expr1 >> expr2
其中 expr1
和 expr2
必须递归地符合 ToKarma
语法。proto::nary_expr<proto::_,proto::vararg<ToKarma> >
: 匹配任何 n 元(一元、二进制或实际上 n 元,如函数调用 a(b,c,d,e)
),其中表达式的每个元素都符合 ToKarma 语法。所有 TransformN
在这个例子中是表达式构建器,这里有一些解释:
_make_terminal(boost::spirit::tag::lexeme())
: 构建一个 proto::terminal<boost::spirit::tag::lexeme>
(注意标签后面必须加()
,忘记了会报错)_make_subscript(_make_terminal(tag::no_delimit()), _make_terminal(tag::eps()))
: 构建一个 proto::subscript<proto::terminal<tag::no_delimit>, proto::terminal<tag::eps> >
,或相当于 no_delimit[eps]
._make_shift_left(ToKarma(proto::_left), ToKarma(proto::_right))
: proto::_left
表示采用原始表达式的 lhs。 ToKarma(proto::_left)
意味着递归地将 ToKarma 语法/转换应用于原始表达式的 lhs。整体_make_shift_left
基本上构建transformed_lhs << transformed_rhs
.A MatcherN
本身(不在 proto::when
内)是构建相同类型的表达式的简写,使用作为元素递归地将转换应用于原始元素的结果。
完整样本 (Running on WandBox)
#include <iostream>
#include <string>
#include <tuple>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/std_tuple.hpp>
namespace proto= boost::proto;
struct ToKarma: proto::or_<
//translation of directives
proto::when<proto::terminal<boost::spirit::tag::lexeme>, proto::_make_terminal(boost::spirit::tag::verbatim())>, //lexeme -> verbatim
proto::when<
proto::subscript<proto::terminal<boost::spirit::tag::omit>,proto::_>, //omit[expr] -> no_delimit[eps]
proto::_make_subscript(proto::_make_terminal(boost::spirit::tag::no_delimit()),proto::_make_terminal(boost::spirit::tag::eps()))
>,
proto::terminal<proto::_>, //if the expression is any other terminal leave it as is
//translation of operators
proto::when<proto::shift_right<ToKarma,ToKarma>, proto::_make_shift_left(ToKarma(proto::_left),ToKarma(proto::_right)) >, //changes '>>' into '<<'
proto::when<proto::greater<ToKarma,ToKarma>, proto::_make_shift_left(ToKarma(proto::_left),ToKarma(proto::_right)) >, //changes '>' into '<<'
proto::when<proto::minus<ToKarma,ToKarma>, ToKarma(proto::_left)>, //changes 'expr-whatever' into 'expr'
proto::nary_expr<proto::_,proto::vararg<ToKarma> > //if it's anything else leave it unchanged and recurse into the expression tree
>{};
template <typename ... Attr, typename Parser>
void test(const std::string& input, const Parser& parser)
{
std::cout << "Original: \"" << input << "\"\n";
std::tuple<Attr...> attr;
std::string::const_iterator iter = input.begin(), end = input.end();
bool result = boost::spirit::qi::phrase_parse(iter,end,parser,boost::spirit::qi::space,attr);
if(result && iter==end)
{
ToKarma to_karma;
std::cout << "Generated: \"" << boost::spirit::karma::format_delimited(to_karma(parser), boost::spirit::karma::space, attr) << '"' << std::endl;
}
else
{
std::cout << "Parsing failed. Unparsed: ->" << std::string(iter,end) << "<-" << std::endl;
}
}
int main(){
using namespace boost::spirit::qi;
test<std::string,double,std::string >("Xx 1.233 pseudo", lexeme[+(char_-' '-'\n')] >> double_ >> lexeme[+(char_-' '-'\n')]);
test<int,double>("foo 1 2.5", omit[lexeme[+alpha]] > int_ > double_);
}
附言:
绝对行不通的事情:
qi::rule
qi::grammar
qi::symbols
Karma 中不存在的东西:
qi::attr
qi::matches
qi::hold
^
||
Karma 中具有不同语义的事物:
qi::skip
&
!
关于c++ - 灵气文法可以作为灵业文法复用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39522372/
如何重启job取消后 kotlin coroutines 我有 2 个按钮,1 个用于启动协程,另一个用于取消作业。 但是在我取消作业后,协程不会再次启动。 class TestFragment :
我发现很难将阶段限制为仅在 MR 上运行并且是手动的 我有以下规则 rules: - when: manual - if: '$CI_PIPELINE_SOUR
我最近刚开始使用Hadoop,但在开始的第一刻就出现了一些问题,到目前为止,我已经能够解决它们,但是有一个我无法克服的问题。事实是,一切似乎都工作正常,但是当我尝试启动Hadoop作业时,它就挂了,而
我在我的 java 应用程序中使用 Spring Batch。 我想安排一个作业在特定时间运行,例如 - 从现在起 48 小时内运行,仅运行一次。我怎样才能实现这种行为? 在文档中找不到任何内容...
我目前正在尝试弄清楚如何让它工作,但第二行有问题: Uncaught SyntaxError: Unexpected token = ArrayList = new ArrayList(); 稍后我
您好,我在 JAVA 中的 Spark 配置是: ss=SparkSession.builder() .config("spark.driver.host", "192.168.0.103")
我正在尝试在我的 spring boot 应用程序中使用 spring-batch。我有一个用例在一天中的特定时间段内停止作业,一旦时间窗口过去,我想从暂停的步骤重新启 Action 业。到目前为止,
我有一个 oozie 配置: ${jobTracker} ${nameNode} map
是否可以将 gitlab ci 作业标记为手动启动? 我需要它来部署应用程序,但我想决定是否要部署它 最佳答案 自第一个答案发布以来,情况已发生变化。这是原始链接Gitlab Issue 。现在支持执
我有几个要同时触发的 http 请求。我正在尝试使用 async for 来执行此操作。 import asyncio async def ticker(delay, to): for i i
我正在做一个Web应用程序,使用Spring 3.0.5.RELEASE +quartz 1.8.6,并使用MySQL 5.5来存储调度信息。当我重新启动 tomcat 时,quartz 已重新启动,
有什么办法可以让作业停止并从 Spring Batch 中的同一点恢复吗? (动态而非静态) 也许启动一项新工作会停止当前工作?有人做过类似的事情吗? 最佳答案 应该是调用JobExecution::
我想等待外部提交的作业完成。 我的第一个想法是通过调用 qstat 获取 jobID,然后执行 session.wait(jobID, Session.TIMEOUT_WAIT_FOREVER);。但
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 9 年前。 Improve this
有人知道是否可以在 ttys 之间转移工作吗? 例子:在 ttys004 开始一项工作,按 Ctrl+Z 将其分离,键入 bg 1 将其移至后台。然后我想从示例 ttys002 中获取它。 最佳答案
我正在尝试通过 Jenkins DSL 启动一个项目,但不需要等待它完成。基本上我希望它能够启动一项孤儿工作。 node("slave-node") { // Launch pipeline
这可能是一个只能由管理员解决的特定于集群的问题,但是当我有一个低优先级的工作而一个高优先级的工作出现时,进程就会被终止。 当高优先级作业完成后,低优先级作业将重新启动。用户端有没有办法让它在最初通过
我的 jenkins安装工作正常,只是我的代码上的 phpunit+coverage 需要 5 分钟才能完成 - 因为文件太多。 对我来说,仅仅知道我的最后一次提交是否破坏了构建就需要等待太多时间。
我目前正在为我最近的项目编写管理门户。我一直在和我的电脑争斗,让 upstart 工作,现在,我希望能够从 web 操作 upstart。我需要在我的 php 脚本中执行以下命令 sudo resta
我正在努力使我的闹钟应用程序与即将发布的 Android 12 兼容,最近我偶然发现了一个问题。似乎自 Android 12 更新以来,在锁定/直接启动期间在 Job Scheduler 中安排的作业
我是一名优秀的程序员,十分优秀!