- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试使用 boost-spirit 解析以下文本,但到目前为止没有成功,请参阅下面的评论
Output_A :=
LE600ms.{
(LE1s.{FE1s.{Signal1}} AND
LE1s.{FE1s.{Signal2}})
OR
(LE3ms.{FE2ms.{NOT.Signal3}} AND
LE3ms.{FE2ms.{Signal4}})};
我试过遵守规则(有关声明,请参阅随附的来源)
start = (ident_ >> ":=" > expr_)
[ _val = phx::construct<binop<op_equ> >(_1, _2) ]
;
expr_ = tok_.alias();
tok_ = ( not_ >> binop_ >> tok_ )
[ _val = phx::bind(make_binop, qi::_2, qi::_1, qi::_3) ]
| not_ [ _val = _1 ] ;
not_ = "NOT." >> simple [ _val = phx::construct<unop <op_not> >(_1) ]
| simple [ _val = _1 ] ;
// Not sure how to use something like following rule for
// final expression
// Here I need the edge type LE or FE and duration,
// so something like binary operator
tdelay_ = lexeme[ ( lit("LE") | lit("FE") )
> double_ > *char_("mn") > "s." ] ; // ???
simple = ('(' > expr_ > ')')
| ('[' > expr_ > ']')
| ('{' > expr_ > '}')
| ident_
| lexeme[double_] ;
ident_ = lexeme[ char_("a-zA-Z_") >> *char_("a-zA-Z_0-9")];
此外,
是否可以在 lexeme
中使用规则,例如我如何使用 ident_
检查它的属性 say
Output_A.status := Signal_4;
所以这样的规则:
lexeme[ident_ >> '.' "status" ] > ":=" ident_ ;
有可能吗?
我的 source
.
使用 Boost-1.55.0
最佳答案
对于各种“其他问题”:
我认为您错过了 not 规则中括号的平衡:
not_ = ("NOT." >> simple [ _val = phx::construct<unop <op_not> >(_1) ]
| simple [ _val = _1 ] )
| (tdelay_ >> simple [ _val = phx::construct<unop <op_not> >(_1) ]
| simple [ _val = _1 ] )
;
归结为
not_ = ("NOT." >> simple | simple)
| (tdelay_ >> simple | simple)
;
这样写好像比较乱
not_ = "NOT." >> simple
| simple
| tdelay_ >> simple
;
现在您可能会发现问题:simple
可能是 ident_
和 ident_
匹配 tdelay_ 之类的东西(直到结束 .
)。所以我们拥有的是一个成功解析的 _ident
(例如 LE600ms
),但随后... unexpected 。
.这正是报告的内容:
Expectation Failure at '.{ ....'
所以,有两种方法可以解决问题:
要么让 ident_
忽略可能被解释为 tdelay_
的表达式:
simple = ('(' > expr_ > ')')
| ('[' > expr_ > ']')
| ('{' > expr_ > '}')
| lexeme[double_]
| (!tdelay_ >> ident_) // HERE
;
虽然这可能会导致相当大的回溯,所以
或者,您可以在 not_
中“修复”解析器分支的首选顺序:`
not_ = ("NOT." >> simple [ _val = phx::construct<unop <op_not> >(_1) ])
| (tdelay_ >> simple [ _val = phx::construct<unop <op_not> >(_1) ])
| simple [ _val = _1 ]
;
这是我的建议
您对 prop_ident_
的“整合”是……笨拙。而不是
start = (ident_ >> ":=" > expr_) [ _val = phx::construct<binop<op_equ> >(_1, _2) ]
| prop_ident_ // [ _val = _2 ]
;
// ~20 lines of grammar skipped
prop_ident_ = lexeme[ char_("a-zA-Z_") >> *char_("a-zA-Z_0-9")
>> prop_
> ":="
> char_("a-zA-Z_") >> *char_("a-zA-Z_0-9")
]
//[ _val = _2 ]
;
您应该按照您描述的方式考虑表达您的语法:
program_ = *statement_;
statement_ = (signal_def_ | prop_assgn_) >> ';';
signal_def_ = ident_ >> ":=" >> expr_;
prop_assgn_ = ident_ >> lexeme ['.' >> raw [ prop_ ]] >> ":=" >> ident_;
哇!?所有的语义 Action 都去哪儿了?好吧,我发明了一些最简单的 AST 类型来反射(reflect)实际解析的结构:
qi::rule<It, signal_definition(), Skipper> signal_def_;
qi::rule<It, property_assignment(),Skipper> prop_assgn_;
qi::rule<It, statement(), Skipper> statement_;
qi::rule<It, program(), Skipper> program_;
还有实际的类型?呜呜呜:
struct signal_definition { std::string name; expr value; };
struct property_assignment { std::string signal, property, value_ident; };
BOOST_FUSION_ADAPT_STRUCT(signal_definition, (std::string, name)(expr, value))
BOOST_FUSION_ADAPT_STRUCT(property_assignment, (std::string, signal)(std::string, property)(std::string, value_ident))
typedef boost::variant<signal_definition, property_assignment> statement;
typedef std::vector<statement> program;
查看此转换的结果 Live On Coliru
现在如果我们也“修复”延迟表达式以与我们的 AST 集成,我们可以
语法更易读
program_ = *statement_;
statement_ = (signal_def_ | prop_assgn_) >> ';';
signal_def_ = ident_ >> ":=" >> expr_;
prop_assgn_ = ident_ >> lexeme ['.' >> raw [ prop_ ]] >> ":=" >> ident_;
expr_ = ( not_ >> binop_ >> expr_ ) [ _val = phx::bind(make_binop, qi::_2, qi::_1, qi::_3) ]
| not_ [ _val = _1 ];
not_ = neg_expr_
| delay_expr_
| simple
;
neg_expr_ = "NOT." >> simple [ _val = phx::construct<unop <op_not> >(_1) ];
delay_expr_ = tdelay_ >> expr_;
tdelay_ = raw[edge_] > double_ > raw[unit_];
simple = ('(' > expr_ > ')')
| ('[' > expr_ > ']')
| ('{' > expr_ > '}')
| lexeme[double_]
| ident_
;
ident_ = char_("a-zA-Z_") >> *char_("a-zA-Z_0-9");
在不丢失信息的情况下打印我们的 AST:例如输入:
Test_Q := LE600ms.Signal12;
Test_A := Signal1;
Test_Z := (Signal1);
Test_B := (Signal1 OR Signal12) AND Signal3;
Test_A.expire := Signal2;
Output_B :=
LE600ms.{
(LE1s.{FE1s.{Signal1}} AND
LE1s.{FE1s.{Signal2}})
OR
(LE3ms.{FE2ms.{NOT.Signal3}} AND
LE3ms.{FE2ms.{Signal4}})};
产生输出:
Test_Q := (with LE delay of 600ms. Signal12);
Test_A := Signal1;
Test_Z := Signal1;
Test_B := ((Signal1 | Signal12) & Signal3);
Test_A.expire := Signal2;
Output_B := (with LE delay of 600ms. ((with LE delay of 1s. ((with FE delay of 1s. Signal1) & (with LE delay of 1s. (with FE delay of 1s. Signal2)))) | (with LE delay of 3ms. ((with FE delay of 2ms. (!Signal3)) & (with LE delay of 3ms. (with FE delay of 2ms. Signal4))))));
请注意,既然语法正确处理了...语法(例如多语句的概念),主要驱动程序也更简单:
static const Skip skip = qi::space | "--" >> *(qi::char_ - qi::eol) >> qi::eol;
static const parser<It, Skip> p;
try
{
program result;
bool ok = qi::phrase_parse(f, l, p, skip, result);
if (!ok) std::cerr << "invalid input\n";
else std::cout << result << "\n";
if (f!=l)
std::cerr << "remaining unparsed input: '" << std::string(f,l) << "'\n";
}
catch (const qi::expectation_failure<It>& e)
{
std::cerr << "Expectation Failure at '" << std::string(e.first, e.last) << "'" << std::endl;
}
事实上,整个代码 list 现在更短了,尽管它做了更多的事情。见<强>Live On Coliru 还有!
完整的代码 list 在 Coliru(上方)和这篇文章中(以备将来使用)
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <fstream>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/variant/recursive_wrapper.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
typedef std::string var;
template <typename tag> struct binop;
template <typename tag> struct unop;
struct delayed_expr;
typedef boost::variant<var,double,
// Logical Operators
boost::recursive_wrapper<binop<struct op_equ> >,
boost::recursive_wrapper<unop <struct op_not> >,
boost::recursive_wrapper<binop<struct op_and> >,
boost::recursive_wrapper<binop<struct op_xor> >,
boost::recursive_wrapper<binop<struct op_or> >,
// /*Airthemetic Operators*/
boost::recursive_wrapper<binop<struct op_plus> >,
boost::recursive_wrapper<binop<struct op_minus> >,
boost::recursive_wrapper<binop<struct op_mul> >,
boost::recursive_wrapper<binop<struct op_div> >,
boost::recursive_wrapper<binop<struct op_mod> >,
// /*Relational Operators*/
boost::recursive_wrapper<binop<struct op_gt> >,
boost::recursive_wrapper<binop<struct op_lt> >,
boost::recursive_wrapper<binop<struct op_gte> >,
boost::recursive_wrapper<binop<struct op_lte> >,
boost::recursive_wrapper<binop<struct op_eq> >,
boost::recursive_wrapper<binop<struct op_ne> >,
// tentative stuff
boost::recursive_wrapper<delayed_expr>
> expr;
template <typename tag> struct binop
{
//explicit binop(const expr& l, const std::string& c, const expr& r) : oper1(l), oper2(r), op(c) { }
explicit binop(const expr& l, const expr& r) : oper1(l), oper2(r) { }
expr oper1, oper2;
//std::string op;
};
template <typename tag> struct unop
{
explicit unop(const expr& o) : oper1(o) { }
expr oper1;
};
struct signal_definition {
std::string name; expr value;
friend std::ostream& operator<<(std::ostream& os, signal_definition const& sd) {
return os << sd.name << " := " << sd.value;
}
};
struct property_assignment {
std::string signal, property, value_ident;
friend std::ostream& operator<<(std::ostream& os, property_assignment const& pa) {
return os << pa.signal << '.' << pa.property << " := " << pa.value_ident;
}
};
struct tdelay {
std::string edge, unit;
double amount;
friend std::ostream& operator<<(std::ostream& os, tdelay const& td) {
return os << "with " << td.edge << " delay of " << td.amount << td.unit << " ";
}
};
struct delayed_expr {
tdelay delay;
expr e;
};
BOOST_FUSION_ADAPT_STRUCT(signal_definition, (std::string, name)(expr, value))
BOOST_FUSION_ADAPT_STRUCT(property_assignment, (std::string, signal)(std::string, property)(std::string, value_ident))
BOOST_FUSION_ADAPT_STRUCT(tdelay, (std::string, edge)(double, amount)(std::string, unit))
BOOST_FUSION_ADAPT_STRUCT(delayed_expr, (tdelay, delay)(expr, e))
typedef boost::variant<signal_definition, property_assignment> statement;
typedef std::vector<statement> program;
std::ostream& operator<<(std::ostream& os, const expr& e);
struct printer : boost::static_visitor<void>
{
printer(std::ostream& os) : _os(os) {}
std::ostream& _os;
void operator()(const var& v) const { _os << v; }
void operator()(const double& val) const { _os << val; }
void operator()(const binop<op_and>& b) const { print(" & ", b.oper1, b.oper2); }
void operator()(const binop<op_or >& b) const { print(" | ", b.oper1, b.oper2); }
void operator()(const binop<op_xor>& b) const { print(" ^ ", b.oper1, b.oper2); }
void operator()(const binop<op_equ>& b) const { print(" = ", b.oper1, b.oper2); }
void operator()(const binop<op_plus>& b) const { print(" + ", b.oper1, b.oper2); }
void operator()(const binop<op_minus>& b) const { print(" - ", b.oper1, b.oper2); }
void operator()(const binop<op_mul>& b) const { print(" * ", b.oper1, b.oper2); }
void operator()(const binop<op_div>& b) const { print(" / ", b.oper1, b.oper2); }
void operator()(const binop<op_mod>& b) const { print(" % ", b.oper1, b.oper2); }
void operator()(const binop<op_gt>& b) const { print(" > ", b.oper1, b.oper2); }
void operator()(const binop<op_lt>& b) const { print(" < ", b.oper1, b.oper2); }
void operator()(const binop<op_gte>& b) const { print(" >= ", b.oper1, b.oper2); }
void operator()(const binop<op_lte>& b) const { print(" <= ", b.oper1, b.oper2); }
void operator()(const binop<op_eq>& b) const { print(" == ", b.oper1, b.oper2); }
void operator()(const binop<op_ne>& b) const { print(" != ", b.oper1, b.oper2); }
void print(const std::string& op, const expr& l, const expr& r) const
{
_os << "(";
boost::apply_visitor(*this, l);
_os << op;
boost::apply_visitor(*this, r);
_os << ")";
}
void operator()(const delayed_expr& u) const
{
_os << '(' << u.delay << u. e << ')';
}
void operator()(const unop<op_not>& u) const
{
_os << "(!";
boost::apply_visitor(*this, u.oper1);
_os << ")";
}
};
std::ostream& operator<<(std::ostream& os, const expr& e)
{
boost::apply_visitor(printer(os), e);
return os;
}
std::ostream& operator<<(std::ostream& os, const program& p)
{
for (auto& stmt : p) os << stmt << ";\n";
return os;
}
template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, program(), Skipper>
{
enum op_token {
TOK_PLUS, TOK_MINUS, TOK_DIV, TOK_MULT, TOK_MOD,
TOK_LT, TOK_LTE, TOK_GT, TOK_GTE,
TOK_EQ, TOK_NE,TOK_AND,TOK_OR,TOK_XOR
};
static expr make_binop(op_token discriminant, const expr& left, const expr& right)
{
switch(discriminant)
{
case TOK_PLUS: return binop<op_plus>(left , right); // "+" ,
case TOK_MINUS: return binop<op_minus>(left, right); // "-" ,
case TOK_DIV: return binop<op_div>(left , right); // "/" ,
case TOK_MULT: return binop<op_mul>(left , right); // "*" ,
case TOK_MOD: return binop<op_mod>(left , right); // "%" ,
case TOK_LT: return binop<op_lt>(left , right); // "<" ,
case TOK_LTE: return binop<op_lte>(left , right); // "<=",
case TOK_GT: return binop<op_gt>(left , right); // ">" ,
case TOK_GTE: return binop<op_gte>(left , right); // ">" ,
case TOK_EQ: return binop<op_eq>(left , right); // ">=",
case TOK_NE: return binop<op_ne>(left , right); // "!" ,
case TOK_AND: return binop<op_and>(left , right);
case TOK_OR: return binop<op_or>(left , right);
case TOK_XOR: return binop<op_xor>(left , right);
}
throw std::runtime_error("unreachable in make_binop");
}
parser() : parser::base_type(program_)
{
using namespace qi;
program_ = *statement_;
statement_ = (signal_def_ | prop_assgn_) >> ';';
signal_def_ = ident_ >> ":=" >> expr_;
prop_assgn_ = ident_ >> lexeme ['.' >> raw [ prop_ ]] >> ":=" >> ident_;
expr_ = ( not_ >> binop_ >> expr_ ) [ _val = phx::bind(make_binop, qi::_2, qi::_1, qi::_3) ]
| not_ [ _val = _1 ];
not_ = neg_expr_
| delay_expr_
| simple
;
neg_expr_ = "NOT." >> simple [ _val = phx::construct<unop <op_not> >(_1) ];
delay_expr_ = tdelay_ >> expr_;
tdelay_ = raw[edge_] > double_ > raw[unit_];
simple = ('(' > expr_ > ')')
| ('[' > expr_ > ']')
| ('{' > expr_ > '}')
| lexeme[double_]
| ident_
;
ident_ = char_("a-zA-Z_") >> *char_("a-zA-Z_0-9");
BOOST_SPIRIT_DEBUG_NODES(
(program_) (signal_def_) (prop_assgn_)
(expr_) (not_) (neg_expr_) (delay_expr_)
(simple) (ident_) (tdelay_)
)
binop_.add
("-", TOK_MINUS)
("+", TOK_PLUS)
("/", TOK_DIV)
("*", TOK_MULT)
("%", TOK_MOD)
("<", TOK_LT)
("<=", TOK_LTE)
(">", TOK_GT)
(">=", TOK_GTE)
("==", TOK_EQ)
("!=", TOK_NE)
("AND", TOK_AND)
("OR", TOK_OR)
("XOR", TOK_XOR)
;
prop_.add("status")("expire")("collect")("inhibit");
edge_.add("LE")("FE");
unit_.add("ms.")("ns.")("s.");
}
private:
qi::symbols<char, bool> edge_, prop_, unit_;
qi::symbols<char, op_token> binop_;
qi::rule<It, var()> ident_;
qi::rule<It, tdelay()> tdelay_;
qi::rule<It, delayed_expr(), Skipper> delay_expr_;
qi::rule<It, expr(), Skipper> not_, simple, expr_, neg_expr_;
qi::rule<It, signal_definition(), Skipper> signal_def_;
qi::rule<It, property_assignment(),Skipper> prop_assgn_;
qi::rule<It, statement(), Skipper> statement_;
qi::rule<It, program(), Skipper> program_;
};
int main()
{
std::ifstream fin("input.txt");
std::stringstream buffer;
buffer << fin.rdbuf();
std::string input = buffer.str();
fin.close();
typedef std::string::const_iterator It;
typedef qi::rule<It> Skip;
It f(input.begin()), l(input.end());
static const Skip skip = qi::space | "--" >> *(qi::char_ - qi::eol) >> qi::eol;
static const parser<It, Skip> p;
try
{
program result;
bool ok = qi::phrase_parse(f, l, p, skip, result);
if (!ok) std::cerr << "invalid input\n";
else std::cout << result << "\n";
if (f!=l)
std::cerr << "remaining unparsed input: '" << std::string(f,l) << "'\n";
}
catch (const qi::expectation_failure<It>& e)
{
std::cerr << "Expectation Failure at '" << std::string(e.first, e.last) << "'" << std::endl;
}
}
关于c++ - 扩展现有的 Spirit 语法(AST 和船长的问题),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21604865/
我正在将一个手写解析器迁移到 Boost.Spirit (2.5.4)。第一印象是积极的,但由于我使用的是 C++17,X3 似乎是一个非常有吸引力的选择。 幸运的是,有很多关于 X3 的可用资源:
是否可以使用 boost::spirit::qi 来解析以下内容? A_B --> (A, B) A_B_C --> (A_B, C) A_B_C_D --> (A_B_
我正在尝试解析一种类似 lisp 的语言,它具有一些通用功能的语法糖。例如,plus 函数可以写成 (+ 1 2) 或 1 + 2。我认为在尝试解释语言之前消除句法糖会显着促进解释过程,因为那样的话,
我正在尝试解析一种类似 lisp 的语言,它具有一些通用功能的语法糖。例如,plus 函数可以写成 (+ 1 2) 或 1 + 2。我认为在尝试解释语言之前消除句法糖会显着促进解释过程,因为那样的话,
我想使用解析后的值作为循环解析器的输入。 语法定义了一个 header ,它指定了以下字符串的(可变)大小。例如,假设以下字符串是某个解析器的输入。 12\r\nTest Payload 解析器应提取
我正在编写 DSL 并使用 Boost Spirit 词法分析器来标记我的输入。在我的语法中,我想要一个类似于此的规则(其中 tok 是词法分析器): header_block = tok.n
我有以下精神语法。我正在尝试在 struct myresult 中创建 AST 节点的向量使用标准 push_back(at_c(qi::_val), qi::_1)但出现编译错误(见下文)。 typ
需要为 std::pair 对象提供类型为 boost::variant 的对象的值。您将如何使用其他资源来实现这个想法?下面还有其他方法吗? struct aggr_pair_visitor
我有一个词法分析器,基于该词法分析器,我现在想创建一个使用该词法分析器生成的标记的语法。我尝试改编我发现的一些示例,现在我有一些可以编译和工作的东西至少有一点,但我的一个应该失败的测试却没有。现在我想
当我使用此 qi 语法从 Lex 接受标记时: pair %= token(ID_MARKER) >> ':' >> atom >> ',' >> atom
如何解析可能包含 double 或 int 的字符串,具体取决于是否设置了点。例如。 6.0是double类型,6是int类型。规则是 rule,skipper> r = qi::double_|qi
请帮助我诊断以下错误。我有一个简单的语法: struct json_start_elem_grammar_object : qi::grammar { json_start_elem_gramma
作为使用 Boost.Spirit 的更大语法的第一阶段,我尝试解析“true”和“false”以生成相应的 bool 值,true 和 false. 我正在使用 Spirit.Lex 对输入进行标记
我正在尝试解析一个也可以包含标识符的表达式并将每个元素推送到 std::vector 中,我想出了以下语法: #include #include #include #include name
我正在为 if 函数实现生产规则: qi::rule f_if; f_if = qi::ascii::string("if") >> qi::char_('(')
我编写了这段代码示例并期望它打印OPERATION( OPERATOR(aaa) ID(bbb) ) 但我只得到OPERATION ( OPERATOR(aaa) )反而。 result2 和 it1
我的数据定义为: std::string data("START34*23*43**"); 我的语法: "START" >> boost::spirit::hex % '*' 题: 如何解析有两颗星的
我编写了这段代码示例并期望它打印OPERATION( OPERATOR(aaa) ID(bbb) ) 但我只得到OPERATION ( OPERATOR(aaa) )反而。 result2 和 it1
我需要解析一个键值对,其中键本身是示例中的固定字符串lke'cmd'。不幸的是qi::lit没有综合属性,并且qi::char_没有解析固定的字符串。 以下代码无法编译。执行后,我需要那个result
我正在尝试编写精神规则,但我无法弄清楚这个新规则的属性是什么。 以下代码按我预期的方式工作。 #include #include #include #include #include nam
我是一名优秀的程序员,十分优秀!