2013-03-06 59 views
1

为了简单起见,我将庸俗化整个问题。懒惰存储在载体中的表达式的评估

我正在使用布尔算术只使用运算符OR和AND(现在)。

我的布尔表达式存储在一个交替变量和运算符的向量中(类似[a,||,b]代表“a或b”)。

我想知道是否有可能链回我的载体,如果我写了:

std::vector<xxx> v = {true, &&, (, false, ||, true,)}; 
// result = true && (false || true) = true 
bool result = vector[0] vector[1] vector[2] vector[3] vector[4] vector[5] vector[6]; 

我知道算术评估算法存在(如分流码),但我想避免使用它们,而是使用C++评估器。 我想我可以重载操作符来处理简单的表达式,但只要括号显示我卡住了。

我很抱歉,如果这个问题已被问及回答,我只是不知道在我的搜索中使用什么关键字!

谢谢你在前进,哪怕只是一个线索将是不错:)

+0

好问题。我也需要这个答案。 – 2013-03-06 14:44:17

+0

或者不是+。这是XOR。 'true + true = false','true || true = true'。 – Puppy 2013-03-06 15:00:59

+0

@DeadMG:嗯真实+真实给我。我必须错过一些东西:/无论如何,我编辑我的问题使用&&和||。 – 2013-03-06 15:32:27

回答

0

像AxelOmega说各个方面 - 您可以使用boost::spirit。语法很简单:

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/qi_bool.hpp> 
#include <boost/spirit/include/phoenix.hpp> 

namespace qi = boost::spirit::qi; 

template <class Iterator> 
struct bool_grammar : qi::grammar<Iterator, bool(), qi::space_type> { 
     qi::rule<Iterator, bool(), qi::space_type> rGroup, rBool, rName, rOr, rAnd; 

     bool_grammar() : bool_grammar::base_type(rOr) { 
       rGroup = '(' >> rOr >> ')'; 
       rBool = qi::bool_ | rGroup; 
       rAnd = rBool[qi::_val = qi::_1] >> 
          *('&' >> rBool[qi::_val = qi::_val && qi::_1]); 
       rOr  = rAnd[qi::_val = qi::_1] >> 
          *('|' >> rAnd[qi::_val = qi::_val || qi::_1]); 
     } 
}; 

,你还需要一个函数来调用解析器和检查结果

bool parse(const std::string& value) { 
     bool_grammar<std::string::const_iterator> g; 
     std::string::const_iterator it = value.begin(); 
     std::string::const_iterator end = value.end(); 

     bool s; 
     if (qi::phrase_parse(it, end, g, qi::space, s) == false || it != end) { 
       // error 
     } 

     return s; 
} 

,现在刚刚合并vector成一个单一的string和使用parse功能:

parse("(true | false) & true | false") ; 

如果您对bool结果不感兴趣,也可以将合成属性更改为某个自定义类,而您将w蚂蚁创建一个可以操纵的树。

+0

它工作得很好谢谢你的详细解答! – 2013-03-06 19:06:13

0

一个解决办法是重载,操作。但是这会在处理圆括号时给你带来问题。通常你不会通过线性解析表达式来找到正确的结果。

表示表达式的正常方式是树状。然后遍历树来计算最终的值。遍历通常使用递归完成。

所以它的两个分阶段

1:构建树

2:递归计算表达式树

如果你想让它表示为图形,看看boost::graph

+0

谢谢你的回答! 我也认为重载,或者+会在括号中产生问题。忘了提及它(将编辑)。 我确实可以使用树来表示我的表情,但我想避免这种情况:) – 2013-03-06 14:54:53

+0

或者看看使用'boost :: spirit'正确解析表达式。我用它与计算堆栈一起在运行时评估小型表达式。但是,不要回避图表,图表是解决许多计算问题的朋友。如果我可能会问,为什么你不想用树? – AxelOmega 2013-03-06 15:05:23

+0

我会看看它谢谢。我只是想知道是否有可能在C++中做我想要的来学习新的“技巧”。它看起来并不可能,尽管如此,我可能会选择我的计划B,调车场或其他算法。 – 2013-03-06 15:20:25

1

首先,你不能真的在vector任何类型中存储原始的C++操作符或语法元素,所以(,*等都出来了。

您可以将它们保存为文本,但:

std::vector<std::string> expression = { "2", "+", "3" }; 

然而,这是不可能使用“C++的评估”是什么; C++是一种编译语言,因此不可能在运行时使用相同的逻辑(从技术上讲,它可能通过像LLVM这样的东西,但它肯定会是一种矫枉过正)。在这种情况下,您最好使用自定义评估程序。

在编译时使用TMP也可能,但我不确定这是你想要的。

+0

谢谢你的答案! 我知道我不能将运营商直接存储在我的矢量中,为了清晰起见,我简化了我的问题。我打算使用自定义对象和操作符,但我最想忽略的是如何在我的向量中“链接”元素,就像我上面给出的例子。 – 2013-03-06 14:57:50

+0

在这种情况下,最好只是像'double evaluate(vector const&expression)'我猜。 – 2013-03-06 14:59:24

+0

但它需要一个算术评估算法,不是吗? :) – 2013-03-06 15:02:03

2

您可以使用表达式模板来执行此操作。你的一些布尔文字将不得不像bool_(true)那样用合适的操作符创建自定义对象,但除此之外,它就像你真的使用C++一样。

当然,仅仅使用lambda或者为此编写一个函数通常会更简单,除非您需要在运行时或类似的内容中对内置树进行内省/修改。

+0

它看起来像我需要的东西。它显然允许我正在寻找的懒惰评估。谢谢! – 2013-03-06 15:54:29

1

您可以使用C++源代码生成一个文件,编译并运行它。事情是这样的:

std::vector<xxx> v = {true, *, (, false, +, true,)}; 
std::ofstream src("temp.cpp"); 
src << 
    "#include <iostream>\n" 
    "int main() {\n" 
    "bool result = "; 
for (auto i: v) 
    src << i << ' '; 
src << 
    ";\n" 
    "std::cout << result;\n" 
    "}\n"; 
src.close(); 
system("g++ temp.cpp -o temp"); 
system("temp"); 

我忽略一样的权限,临时文件名,输出重定向等

+0

谢谢!挺有趣的!这对于我需要做的事情来说太慢了。至少我学到了一些东西,再次感谢:) – 2013-03-06 15:24:11