- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我使用来自网络上各种来源的 boost 库拼凑了一个解析器。它有效(虽然不像我希望的那样干净)但我遇到了一个特定的问题。在解析器的第一部分,我首先解析函数名,然后是括号中的一组参数。稍后,在解析实际表达式时,在解析 factor
中我允许解析数字和变量。但是,我只想解析那些先前在 vars
中声明的变量。解析器。这是我的语法:
template<typename Iterator>
struct exp_parser : qi::grammar<Iterator, expression(), ascii::space_type>
{
exp_parser() : exp_parser::base_type(all)
{
using qi::_val;
using qi::_1;
using qi::char_;
using qi::double_;
using qi::lit;
using phoenix::at_c;
using phoenix::push_back;
using phoenix::bind;
all =
name [at_c<0>(_val) = _1] >> '(' >> vars [at_c<1>(_val) = _1] >> ')' >> '='
>> expr [at_c<2>(_val) = _1];
// Parsing of actual expression
expr =
term [_val = _1]
>> *( ('+' >> term [_val += _1])
| ('-' >> term [_val -= _1])
);
term =
factor [_val = _1]
>> *( ('*' >> factor [_val *= _1])
| ('/' >> factor [_val /= _1])
);
factor =
simple [_val = _1]
| '(' >> expr [_val = _1] >> ')'
| ('-' >> factor [_val = bind(make_unary, UN_OP::MIN, _1)])
| ("sin" >> factor [_val = bind(make_unary, UN_OP::SIN, _1)])
| ("cos" >> factor [_val = bind(make_unary, UN_OP::COS, _1)])
| ("tan" >> factor [_val = bind(make_unary, UN_OP::TAN, _1)])
| ('+' >> factor [_val = _1]);
// Prototyping of expression
prtctd %= lit("sin") | lit("cos") | lit("tan");
var %= !prtctd >> char_('a','z');
num %= double_;
simple %= var | num | ('(' >> expr >> ')');
name %= ((char_('a','z') | char_('A','Z') ) >> *(char_('a','z') | char_('A','Z') | char_('0','9') ));
vars %= (char_('a','z') >> *(',' >> char_('a','z')));
}
qi::rule<Iterator, ast(), ascii::space_type> expr, term, factor, simple;
qi::rule<Iterator, expression(), ascii::space_type> all;
qi::rule<Iterator, std::string(), ascii::space_type> name, prtctd;
qi::rule<Iterator, std::vector<char>(), ascii::space_type> vars;
qi::rule<Iterator, char(), ascii::space_type> var;
qi::rule<Iterator, double(), ascii::space_type> num;
};
这是我用来存储所有内容的结构:
struct expression {
std::string name;
std::vector<char> arguments;
ast syntax_tree;
};
现在,我如何访问 std::vector<char>
在factor
解析器,以便我只解析正确的变量。
此外,我还不熟悉使用 boost 并将其用作自己的练习以开始学习一些知识。如果有人有任何建议,请告诉我如何清理此代码。
提前致谢!
最佳答案
这是 Spirit 中的一个大反模式:
all =
name [at_c<0>(_val) = _1] >> '(' >> vars [at_c<1>(_val) = _1] >> ')' >> '='
>> expr [at_c<2>(_val) = _1];
事实上,我相信您一直在查看的示例显示了更好的方法。另外,我注意到您从相互冲突的方法中选择了代码(当语义操作动态评估表达式值时,您无法合成语法树)。
首先,摆脱语义 Action 思维:Boost Spirit: "Semantic actions are evil"?
BOOST_FUSION_ADAPT_STRUCT(expression, name, arguments, syntax_tree)
all = name >> '(' >> vars >> ')' >> '=' >> expr;
还有很多其他的“病”:
prtctd
应该是一个词位,所以 si\nn
不匹配*(char_('a','z') | char_('A','Z') | char_('0','9') )
就是*alnum
name 也应该是一个词素,所以简单
name = alpha >> *alnum;
vars
甚至不使用 var
?
总而言之,这是这些规则的简化(假设您从 prtctd
和 name
中删除了 skipper ):
prtctd = lit("sin") | "cos" | "tan";
var = !prtctd >> ascii::lower;
num = double_;
simple = var | num | '(' >> expr >> ')';
name = ascii::alpha >> *ascii::alnum;
vars = var % ',';
让我们在上面添加一些模拟部分,并有一些我们可以测试的东西:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/adapted.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
struct ast {
template <typename T> ast& operator+=(T&&) { return *this; }
template <typename T> ast& operator*=(T&&) { return *this; }
template <typename T> ast& operator/=(T&&) { return *this; }
template <typename T> ast& operator-=(T&&) { return *this; }
ast() = default;
template <typename T> ast(T&&) { }
template <typename T> ast& operator =(T&&) { return *this; }
friend std::ostream& operator<<(std::ostream& os, ast) { return os << "syntax_tree"; }
};
struct expression {
std::string name;
std::vector<std::string> arguments;
ast syntax_tree;
friend std::ostream& operator<<(std::ostream& os, expression const& e) {
os << e.name << "(";
for (auto arg : e.arguments) os << arg << ", ";
return os << ") = " << e.syntax_tree;
}
};
BOOST_FUSION_ADAPT_STRUCT(expression, name, arguments, syntax_tree)
enum UN_OP { MIN, SIN, COS, TAN };
struct make_unary_f {
template <typename... Ts> qi::unused_type operator()(Ts&&...) const { return qi::unused; }
} static const make_unary = {};
template<typename Iterator>
struct exp_parser : qi::grammar<Iterator, expression(), ascii::space_type>
{
exp_parser() : exp_parser::base_type(all)
{
using qi::_val;
using qi::_1;
using qi::char_;
using qi::double_;
using qi::lit;
using phoenix::at_c;
using phoenix::push_back;
using phoenix::bind;
all = name >> '(' >> vars >> ')' >> '=' >> expr;
// Parsing of actual expression
expr =
term [_val = _1]
>> *( ('+' >> term [_val += _1])
| ('-' >> term [_val -= _1])
);
term =
factor [_val = _1]
>> *( ('*' >> factor [_val *= _1])
| ('/' >> factor [_val /= _1])
);
factor =
simple [_val = _1]
| '(' >> expr [_val = _1] >> ')'
| ('-' >> factor [_val = bind(make_unary, UN_OP::MIN, _1)])
| ("sin" >> factor [_val = bind(make_unary, UN_OP::SIN, _1)])
| ("cos" >> factor [_val = bind(make_unary, UN_OP::COS, _1)])
| ("tan" >> factor [_val = bind(make_unary, UN_OP::TAN, _1)])
| ('+' >> factor [_val = _1]);
// Prototyping of expression
prtctd = lit("sin") | "cos" | "tan";
var = !prtctd >> ascii::lower;
num = double_;
simple = var | num | '(' >> expr >> ')';
name = ascii::alpha >> *ascii::alnum;
vars = var % ',';
}
private:
qi::rule<Iterator, ast(), ascii::space_type> expr, term, factor, simple;
qi::rule<Iterator, expression(), ascii::space_type> all;
qi::rule<Iterator, std::vector<std::string>(), ascii::space_type> vars;
// lexemes
qi::rule<Iterator, std::string()> name, prtctd;
qi::rule<Iterator, std::string()> var;
qi::rule<Iterator, double()> num;
};
int main() {
for (std::string const& input : {
"",
"foo (a) = 3*8+a",
"bar (x, y) = (sin(x) + y*y) / (x + y)",
"oops (x, y) = (sin(x) + y*y) / (x + a)",
})
try {
using It = std::string::const_iterator;
It f = input.begin(), l = input.end();
expression e;
bool ok = qi::phrase_parse(f, l, exp_parser<It>{} >> qi::eoi, ascii::space, e);
if (ok) {
std::cout << "Parse success: '" << input << "' -> " << e << "\n";
} else {
std::cout << "Parse failed: '" << input << "'\n";
}
if (f != l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
} catch(std::exception const& e) {
std::cout << "Exception: '" << e.what() << "'\n";
}
}
正如预期的那样,它仍然解析所有非空行,包括 oops
错误地使用了 a
而不是 y
:
Parse failed: ''
Parse success: 'foo (a) = 3*8+a' -> foo(a, ) = syntax_tree
Parse success: 'bar (x, y) = (sin(x) + y*y) / (x + y)' -> bar(x, y, ) = syntax_tree
Parse success: 'oops (x, y) = (sin(x) + y*y) / (x + a)' -> oops(x, y, ) = syntax_tree
为了匹配声明的变量,我会 use qi::symbols<>
:
qi::symbols<char> _declared;
simple = _declared | num | '(' >> expr >> ')';
现在,要添加已声明的项目,我们将设计一个 Phoenix 函数,
struct add_declaration_f {
add_declaration_f(qi::symbols<char>& ref) : _p(std::addressof(ref)) {}
qi::symbols<char>* _p;
void operator()(std::string const& arg) const { _p->add(arg); }
};
phoenix::function<add_declaration_f> _declare { _declared };
并使用它:
vars %= var [ _declare(_1) ] % ',';
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/adapted.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;
struct ast {
template <typename T> ast& operator+=(T&&) { return *this; }
template <typename T> ast& operator*=(T&&) { return *this; }
template <typename T> ast& operator/=(T&&) { return *this; }
template <typename T> ast& operator-=(T&&) { return *this; }
ast() = default;
template <typename T> ast(T&&) { }
template <typename T> ast& operator =(T&&) { return *this; }
friend std::ostream& operator<<(std::ostream& os, ast) { return os << "syntax_tree"; }
};
struct expression {
std::string name;
std::vector<std::string> arguments;
ast syntax_tree;
friend std::ostream& operator<<(std::ostream& os, expression const& e) {
os << e.name << "(";
for (auto arg : e.arguments) os << arg << ", ";
return os << ") = " << e.syntax_tree;
}
};
BOOST_FUSION_ADAPT_STRUCT(expression, name, arguments, syntax_tree)
enum UN_OP { MIN, SIN, COS, TAN };
struct make_unary_f {
template <typename... Ts> qi::unused_type operator()(Ts&&...) const { return qi::unused; }
} static const make_unary = {};
template<typename Iterator>
struct exp_parser : qi::grammar<Iterator, expression(), ascii::space_type>
{
exp_parser() : exp_parser::base_type(all)
{
using qi::_val;
using qi::_1;
using qi::char_;
using qi::double_;
using qi::lit;
using phoenix::at_c;
using phoenix::push_back;
using phoenix::bind;
all = name >> '(' >> vars >> ')' >> '=' >> expr;
// Parsing of actual expression
expr =
term [_val = _1]
>> *( ('+' >> term [_val += _1])
| ('-' >> term [_val -= _1])
);
term =
factor [_val = _1]
>> *( ('*' >> factor [_val *= _1])
| ('/' >> factor [_val /= _1])
);
factor =
simple [_val = _1]
| '(' >> expr [_val = _1] >> ')'
| ('-' >> factor [_val = bind(make_unary, UN_OP::MIN, _1)])
| ("sin" >> factor [_val = bind(make_unary, UN_OP::SIN, _1)])
| ("cos" >> factor [_val = bind(make_unary, UN_OP::COS, _1)])
| ("tan" >> factor [_val = bind(make_unary, UN_OP::TAN, _1)])
| ('+' >> factor [_val = _1]);
// Prototyping of expression
prtctd = lit("sin") | "cos" | "tan";
var = !prtctd >> ascii::lower;
num = double_;
simple = _declared | num | '(' >> expr >> ')';
name = ascii::alpha >> *ascii::alnum;
vars %= var [ _declare(_1) ] % ',';
}
private:
qi::symbols<char> _declared;
struct add_declaration_f {
add_declaration_f(qi::symbols<char>& ref) : _p(std::addressof(ref)) {}
qi::symbols<char>* _p;
void operator()(std::string const& arg) const { _p->add(arg); }
};
phoenix::function<add_declaration_f> _declare { _declared };
qi::rule<Iterator, ast(), ascii::space_type> expr, term, factor, simple;
qi::rule<Iterator, expression(), ascii::space_type> all;
qi::rule<Iterator, std::vector<std::string>(), ascii::space_type> vars;
// lexemes
qi::rule<Iterator, std::string()> name, prtctd;
qi::rule<Iterator, std::string()> var;
qi::rule<Iterator, double()> num;
};
int main() {
for (std::string const& input : {
"",
"foo (a) = 3*8+a",
"bar (x, y) = (sin(x) + y*y) / (x + y)",
"oops (x, y) = (sin(x) + y*y) / (x + a)",
})
try {
using It = std::string::const_iterator;
It f = input.begin(), l = input.end();
expression e;
bool ok = qi::phrase_parse(f, l, exp_parser<It>{}, ascii::space, e);
if (ok) {
std::cout << "Parse success: '" << input << "' -> " << e << "\n";
} else {
std::cout << "Parse failed: '" << input << "'\n";
}
if (f != l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
} catch(std::exception const& e) {
std::cout << "Exception: '" << e.what() << "'\n";
}
}
打印:
Parse failed: ''
Parse success: 'foo (a) = 3*8+a' -> foo(a, ) = syntax_tree
Parse success: 'bar (x, y) = (sin(x) + y*y) / (x + y)' -> bar(x, y, ) = syntax_tree
Parse success: 'oops (x, y) = (sin(x) + y*y) / (x + a)' -> oops(x, y, ) = syntax_tree
Remaining unparsed: '/ (x + a)'
添加>> qi::eoi
我们得到的解析器表达式: Live On Coliru
Parse failed: ''
Parse success: 'foo (a) = 3*8+a' -> foo(a, ) = syntax_tree
Parse success: 'bar (x, y) = (sin(x) + y*y) / (x + y)' -> bar(x, y, ) = syntax_tree
Parse failed: 'oops (x, y) = (sin(x) + y*y) / (x + a)'
Remaining unparsed: 'oops (x, y) = (sin(x) + y*y) / (x + a)'
关于c++ - Boost:仅解析先前声明的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43983833/
我一直在使用 AJAX 从我正在创建的网络服务中解析 JSON 数组时遇到问题。我的前端是一个简单的 ajax 和 jquery 组合,用于显示从我正在创建的网络服务返回的结果。 尽管知道我的数据库查
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我在尝试运行 Android 应用程序时遇到问题并收到以下错误 java.lang.NoClassDefFoundError: com.parse.Parse 当我尝试运行该应用时。 最佳答案 在这
有什么办法可以防止etree在解析HTML内容时解析HTML实体吗? html = etree.HTML('&') html.find('.//body').text 这给了我 '&' 但我想
我有一个有点疯狂的例子,但对于那些 JavaScript 函数作用域专家来说,它看起来是一个很好的练习: (function (global) { // our module number one
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 8 年前。 Improve th
我需要编写一个脚本来获取链接并解析链接页面的 HTML 以提取标题和其他一些数据,例如可能是简短的描述,就像您链接到 Facebook 上的内容一样。 当用户向站点添加链接时将调用它,因此在客户端启动
在 VS Code 中本地开发时,包解析为 C:/Users//AppData/Local/Microsoft/TypeScript/3.5/node_modules/@types//index而不是
我在将 json 从 php 解析为 javascript 时遇到问题 这是我的示例代码: //function MethodAjax = function (wsFile, param) {
我在将 json 从 php 解析为 javascript 时遇到问题 这是我的示例代码: //function MethodAjax = function (wsFile, param) {
我被赋予了将一种语言“翻译”成另一种语言的工作。对于使用正则表达式的简单逐行方法来说,源代码过于灵活(复杂)。我在哪里可以了解更多关于词法分析和解析器的信息? 最佳答案 如果你想对这个主题产生“情绪化
您好,我在解析此文本时遇到问题 { { { {[system1];1;1;0.612509325}; {[system2];1;
我正在为 adobe after effects 在 extendscript 中编写一些代码,最终变成了 javascript。 我有一个数组,我想只搜索单词“assemble”并返回整个 jc3_
我有这段代码: $(document).ready(function() { // }); 问题:FB_RequireFeatures block 外部的代码先于其内部的代码执行。因此 who
背景: netcore项目中有些服务是在通过中间件来通信的,比如orleans组件。它里面服务和客户端会指定网关和端口,我们只需要开放客户端给外界,服务端关闭端口。相当于去掉host,这样省掉了些
1.首先贴上我试验成功的代码 复制代码 代码如下: protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
什么是 XML? XML 指可扩展标记语言(eXtensible Markup Language),标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。 你可以通过本站学习 X
【PHP代码】 复制代码 代码如下: $stmt = mssql_init('P__Global_Test', $conn) or die("initialize sto
在SQL查询分析器执行以下代码就可以了。 复制代码代码如下: declare @t varchar(255),@c varchar(255) declare table_cursor curs
前言 最近练习了一些前端算法题,现在做个总结,以下题目都是个人写法,并不是标准答案,如有错误欢迎指出,有对某道题有新的想法的友友也可以在评论区发表想法,互相学习🤭 题目 题目一: 二维数组中的
我是一名优秀的程序员,十分优秀!