如何使用boost :: spirit解析数学表达式并将其绑定到函数 [英] How to parse a mathematical expression with boost::spirit and bind it to a function
问题描述
我想定义一个带有2个参数的函数
I would like to define a function taking 2 arguments
double func(double t, double x);
从外部文本文件中读取实际实现.
例如,在文本文件中指定
where the actual implementation is read from an external text file.
For example, specifying in the text file
function = x*t;
该函数应实现x
和t
之间的乘法,以便可以在以后的阶段调用它.
我正在尝试使用boost :: spirit解析函数.但我不知道该如何实际实现.
the function should implement the multiplication between x
and t
, so that it could be called at a later stage.
I'm trying to parse the function using boost::spirit. But I do not know how to actually achieve it.
下面,我创建了一个实现乘法的简单函数.我将其绑定到boost函数,然后可以使用它.我还创建了一个简单的语法,用于解析两个双精度数之间的乘法.
Below, I created a simple function that implements the multiplication. I bind it to a boost function and I can use it. I also created a simple grammar, which parse the multiplication between two doubles.
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include "boost/function.hpp"
#include "boost/bind.hpp"
#include <boost/spirit/include/qi_symbols.hpp>
#include <iostream>
#include <string>
namespace qi = boost::spirit::qi;
namespace ascii=boost::spirit::ascii;
using boost::spirit::ascii::space;
using boost::spirit::qi::symbols;
template< typename Iterator >
struct MyGrammar : public virtual qi::grammar< Iterator, ascii::space_type >
{
MyGrammar() : MyGrammar::base_type(expression)
{
using qi::double_;
//The expression should take x and t as symbolic expressions
expression = (double_ >> '*' >> double_)[std::cout << "Parse multiplication: " << (qi::_1 * qi::_2)];
}
qi::rule<Iterator, ascii::space_type> expression;
};
double func(const double a, const double b)
{
return a*b; //This is the operation to perform
}
int main()
{
typedef std::string::const_iterator iterator_Type;
typedef MyGrammar<iterator_Type> grammar_Type;
grammar_Type calc;
std::string str = "1.*2."; // This should be changed to x*t
iterator_Type iter = str.begin();
iterator_Type end = str.end();
bool r = phrase_parse(iter, end, calc, space);
typedef boost::function < double ( const double t,
const double x) > function_Type;
function_Type multiplication = boost::bind(&func, _1, _2);
std::cout << "\nResult: " << multiplication( 2.0, 3.0) << std::endl;
return 0;
}
如果我修改了上面的代码设置
If I modify the above code setting
std::string str = "x*t";
如何解析这样的表达式并将其绑定到函数multiplication
,以便如果我调用multiplication(1.0, 2.0)
,它将t与1.0关联,将x与2.0关联,并返回运算结果?
how can I parse such an expression and bind it to the function multiplication
such that, if I call multiplication(1.0, 2.0)
, it associates t to 1.0, x to 2.0 and it returns the result of the operation?
推荐答案
您将学习Spirit.太好了!
You're going to learn Spirit. Great!
不过,似乎您在这里所咬的东西超出了您的咀嚼能力.
It seems you're biting off more than you can chew here, though.
首先,您的语法实际上尚未解析表达式.当然,它不会导致您可以绑定的功能.
Firstly, your grammar doesn't actually parse an expression yet. And it certainly doesn't result in a function that you can then bind.
-
实际上,您正在使用不产生任何结果的语法来解析输入.它只会创建一个副作用(将带有直接简单操作数的简单二进制表达式的结果打印到控制台).这种/relikes/解释性语言,尽管
In fact you're parsing the input using a grammar that is not producing any result. It only creates a side-effect (which is to print the result of the simple binary expression with immediate simple operands to the console). This /resembles/ interpreted languages, although it would soon break up when
- 您尝试解析类似
2*8 + 9
的表达式
- 您将输入回溯的信息(糟糕,副作用已经触发)
- you try to parse an expression like
2*8 + 9
- you would have input that backtracks (oops, the side effect already fired)
接下来,您将绑定func
(顺便说一句,这是多余的;您没有绑定任何参数,因此您只能在此处说function_Type multiplication(func);
)并调用它.虽然很酷,但实际上与解析输入无关.
Next up you're binding func
(which is redundant by the way; you're not binding any arguments so you could just say function_Type multiplication(func);
here), and calling it. While cool, this has literally nothing to do with the parsing input.
最后,您的问题是关于第三的问题,上面的任何地方都没有涉及.这个问题是关于符号表和标识符查找的.
Finally, your question is about a third thing, that wasn't even touched upon anywhere in the above. This question is about symbol tables and identifier lookup.
- 这意味着您应该解析源以获取实际的标识符(例如
x
或t
) - 您需要将它们存储到符号表中,以便可以将它们映射到一个值(也许是作用域/生命周期)
-
问题中存在一个逻辑漏洞,您无需定义形式参数列表"的来源(您在此处的文本中提到了它:
function = x*t;
解析器不处理它,您也没有对任何此类元数据进行硬编码);因此我们甚至无法开始将x
和t
映射到正式参数列表(因为它不存在).
- This would imply you should parse the source for actual identifiers (
x
ort
, e.g.) - you'd need to store these into a symbol table so they could be mapped to a value (and perhaps a scope/lifetime)
There is a gaping logic hole in the question where you don't define the source of the "formal parameter list" (you mention it in the text here:
function = x*t;
but the parser doesn't deal with it, neither did you hardcode any such metadata); so there is no way we could even start to map thex
andt
things to the formal argument list (because it doesn't exist).
让我们暂时假设事实上参数是位置参数(按原样,并且在使用位置参数调用绑定函数时,您似乎想要这么做.(因此,我们不必担心名称,因为没人会看到名称.)
调用方应在上下文中传递给函数,以便可以在评估期间通过标识符名称查找值.
the caller should pass in a context to the functions, so that values can be looked up by identifier name during evaluation.
因此,尽管我可以尝试让您坐下来,与您讨论所有首先需要创建的细节,然后您甚至可以梦想以自己想要的奇妙方式将它们粘合在一起,但不要这样.
So, while I could try to sit you down and talk you through all the nuts and bolts that need to be created first before you can even dream of glueing it together in fantastic ways like you are asking for, let's not.
这将花费我太多时间,并且您可能不知所措.
It would take me too much time and you would likely be overwhelmed.
我只能建议看一些简单的资源.从教程开始
I can only suggest to look at simpler resources. Start with the tutorials
- 计算器系列教程很好.在此答案中,我列出了计算器示例,并简要说明了它们演示的技术:
在此过程中如有任何疑问,请随意提问,否则有被卡住的风险.但至少到那时,我们有一个可以回答的问题,并且可以真正为您提供帮助的答案.
Ask freely if you have any questions along the way and you're at risk of getting stuck. But at least then we have a question that is answerable and answers that genuinely help you.
现在,看看我的其他答案,其中我实际上实现了这样的语法(某种程度上是通过增加复杂性来排序的):
For now, look at some other answers of mine where I actually implemented grammars like this (somewhat ordered by increasing complexity):
-
比较好:的方法)
Nice for comparison: This answer to Boost::spirit how to parse and call c++ function-like expressions interprets the parsed expressions on-the-fly (this mimics the approach with
[std::cout << "Parse multiplication: " << (qi::_1 * qi::_2)]
in your own parser)
The other answer there (Boost::spirit how to parse and call c++ function-like expressions) achieves the goal but using a dedicated AST representation, and a separate interpretation phase.
在这些答案中描述了每种方法的好处.这些解析器没有没有符号表或求值上下文.
The benefits of each approach are described in these answers. These parsers do not have a symbol table nor a evaluation context.
更多示例:
- 一个简单的布尔表达式语法评估程序(仅支持文字,不支持变量)
- 构建自定义Spirit:Qi中的表达树(没有Utree或Boost :: Variant)
这篇关于如何使用boost :: spirit解析数学表达式并将其绑定到函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
-