我试图创建一个Qt应用程序,我需要一个数学表达式评估器来评估这样的事情,例如: (4 + 5)* 2-9 / 3。 我将此库(http://www.partow.net/programming/exprtk/)的.hpp文件包含在Qt Creator中的项目中,并尝试启动以下代码示例:
#include <cstdio>
#include <string>
#include "exprtk.hpp"
int main()
{
typedef exprtk::expression<double> expression_t;
typedef exprtk::parser<double> parser_t;
std::string expression_string = "3 + sqrt(5) + pow(3,2) + log(5)";
expression_t expression;
parser_t parser;
if (parser.compile(expression_string,expression))
{
double result = expression.value();
printf("Result: %19.15\n",result);
}
else
printf("Error in expression\n.");
return 0;
}
当我尝试编译并运行它时,我得到以下输出:
debug\main.o:-1: error: too many sections (62303)
可能是什么问题?
答案 0 :(得分:5)
答案 1 :(得分:1)
实际上,在我的机器上(Qt 5.5,Ubuntu 16.04和g ++ 5.3),上面的代码不起作用。
尽管答案已经很老了,但我提出了我的解决方案以防有人发现它有用。
QScriptEngine使用JavaScript语法。因此,要使上述代码有效,我必须将语法更改为:
QString expression_string("3 + Math.sqrt(5) + Math.pow(3,2) + Math.log(5)");
QScriptEngine expression;
double my_val=expression.evaluate(expression_string).toNumber();
答案 2 :(得分:1)
按照评论中的要求,这里是如何使用 boost::spirit
实现算术解析器。首先,您需要下载 boost tarball,不要尝试从 GitHub 单独克隆 Spirit,因为它依赖于其他 boost 库。
Boost 是巨大的,因此如果您只需要一个足够用于解析器的子集,您可以使用 bcp
提取它。来自 boost 源目录:
cd tools/build/src/engine
./build.sh
cd ../../../bcp
../build/src/engine/b2
cd ../..
dist/bin/bcp fusion/include hana/functional spirit/home/x3 /some/path
bcp
将复制所有依赖项。您只能保留 /some/path/boost
目录,因为我们需要的所有库都只有标题。
最后,这里是解析器的完整代码。
#include <iostream>
#include <numeric>
#include <stdexcept>
#include <string>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/hana/functional/fix.hpp>
#include <boost/hana/functional/overload.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
using namespace boost::spirit;
namespace hana = boost::hana;
// Define AST. The root is `ast::expr`, which is the first left-hand side
// operand and a list of all operations on the right-hand side. Each operand is
// a recursive `variant` that has `ast::expr` inside.
namespace ast
{
struct nil {};
struct signed_;
struct expr;
struct operand : x3::variant<
nil
, double
, x3::forward_ast<signed_>
, x3::forward_ast<expr>
>
{
using base_type::base_type;
using base_type::operator=;
};
struct signed_
{
char sign;
operand operand_;
};
struct operation
{
char operator_;
operand operand_;
};
struct expr
{
operand first;
std::vector<operation> rest;
};
} // namespace ast
// Give the grammar access to the fields of AST.
BOOST_FUSION_ADAPT_STRUCT(ast::signed_, sign, operand_)
BOOST_FUSION_ADAPT_STRUCT(ast::operation, operator_, operand_)
BOOST_FUSION_ADAPT_STRUCT(ast::expr, first, rest)
// Arithmetic expression grammar definition.
namespace ArithExpr
{
x3::rule<class expression, ast::expr > const expression("expression");
x3::rule<class term, ast::expr > const term("term");
x3::rule<class factor, ast::operand> const factor("factor");
auto const expression_def =
term
>> *(
(x3::char_('+') >> term)
| (x3::char_('-') >> term)
);
auto const term_def =
factor
>> *(
(x3::char_('*') >> factor)
| (x3::char_('/') >> factor)
);
auto const factor_def =
x3::double_
| '(' >> expression >> ')'
| (x3::char_('-') >> factor)
| (x3::char_('+') >> factor);
BOOST_SPIRIT_DEFINE(expression, term, factor);
auto calc = expression;
} // namespace ArithExpr
template <typename Iterator>
double CalcArithExpr(Iterator const &first, Iterator last) {
ast::expr expr;
// Build AST.
if (!x3::phrase_parse(first, last, ArithExpr::calc, x3::ascii::space, expr)) {
throw std::runtime_error("Cannot parse arithmetic expression");
}
// Parse the AST and calculate the result.
// hana::fix allows recursive lambda call
auto astEval = hana::fix([](auto self, auto expr) -> double {
// hana::overload calls a lambda corresponding to the type in the variant
return hana::overload(
[](ast::nil) -> double {
BOOST_ASSERT(0);
return 0;
},
[](double x) -> double { return x; },
[&](ast::signed_ const &x) -> double {
double rhs = boost::apply_visitor(self, x.operand_);
switch (x.sign) {
case '-': return -rhs;
case '+': return +rhs;
}
BOOST_ASSERT(0);
return 0;
},
[&](ast::expr const &x) -> double {
return std::accumulate(
x.rest.begin(), x.rest.end(),
// evaluate recursively left-hand side
boost::apply_visitor(self, x.first),
[&](double lhs, const ast::operation &op) -> double {
// evaluate recursively right-hand side
double rhs = boost::apply_visitor(self, op.operand_);
switch (op.operator_) {
case '+': return lhs + rhs;
case '-': return lhs - rhs;
case '*': return lhs * rhs;
case '/': return lhs / rhs;
}
BOOST_ASSERT(0);
return 0;
}
);
}
)(expr);
});
return astEval(expr);
}
int main(int argc, char *argv[]) {
auto expr = std::string{"-(4.5 + 5e-1) * 2.22 - 9.1 / 3.45"};
std::cout << CalcArithExpr(expr.begin(), expr.end()) << std::endl;
}
计算-(4.5 + 5e-1) * 2.22 - 9.1 / 3.45
并输出-13.7377
。
以下是如何在 Windows 上构建 bcp
和复制选定标头的说明。虽然,没有任何保证。在 Linux 中一切正常,在 Windows 上它总是跳过一些箍,并且跳跃的方向总是不可预测的。
话虽如此,打开 PowerShell 命令行。那里
Import-Module 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\Tools\Microsoft.VisualStudio.DevShell.dll'
Install-Module VSSetup -Scope CurrentUser
Get-VSSetupInstance
用您的 VS 版本替换上面的 2019。您只需为 PowerShell 执行一次。剩下的就是每次需要构建 bcp
时。上面的 Get-VSSetupInstance
将打印有关您计算机上的 Visual Studio 实例的信息。写下您想使用的 InstanceId
。现在切换到 PowerShell 中的 boost 目录,然后:
Enter-VsDevShell InstanceId -DevCmdArguments '-arch=x64' -SkipAutomaticLocation
其中 InstanceId
是您从 Get-VSSetupInstance
获得的 ID。然后从相同的命令提示符
cd tools\build\src\engine
& .\build.bat
cd ..\..\..\bcp
..\build\src\engine\b2 address-model=64
cd ..\..
dist\bin\bcp fusion\include hana\functional spirit\home\x3 X:\some\path\boost