在c ++中解析数学表达式

Hal*_*mil 24 c++ tree parsing

我有一个关于解析树的问题:

我有一个字符串(math expresion estring),例如:(a+b)*c-(d-e)*f/g.我必须在树中解析该表达式:

class Exp{};
class Term: public Exp{
    int n_;
}

class Node: Public Exp{
    Exp* loperator_;
    Exp* roperator_;
    char operation; // +, -, *, /
}
Run Code Online (Sandbox Code Playgroud)

我可以用什么算法来构建一个代表上面表达式字符串的树?

Kos*_*Kos 10

使用分流码算法.维基百科的描述非常全面,我希望它足够了.

您还可以尝试编写正式语法,例如解析表达式语法,并使用工具生成解析器.该关于PEG的网站列出了用于PEG解析的3个C/C++文库.


Ani*_*han 5

(a+b)*c-(d-e)*f/g 是一个固定的表达式.

要轻松创建,请先将其转换为前缀表达式.

从示例中,前缀(A * B) + (C / D)+ (* A B) (/ C D)

     (+)            
     / \        
    /   \       
  (*)    (/)         
  / \   /  \        
 A   B C    D   

 ((A*B)+(C/D))  
Run Code Online (Sandbox Code Playgroud)

然后,您的树看起来有+作为其根节点.您可以继续填充左右子树,关于每个运算符.

此外,此链接详细解释了递归下降解析,并且可以实现.

  • 这个直接的翻译步骤有何帮助? (4认同)
  • 他必须解析中缀来构建前缀,所以这根本没有用. (2认同)

jah*_*haj 5

第一步是为您的表达式编写语法。对于这种简单情况,第二步是编写递归下降解析器,这是我推荐的算法。这是递归下降解析器的 wiki 页面,它有一个漂亮的 C 实现。

http://en.wikipedia.org/wiki/Recursive_descent_parser


BLU*_*IXY 5

#include <algorithm>
#include <iostream>
#include <string>
#include <cctype>
#include <iterator>

using namespace std;

class Exp{
public:
//  Exp(){}
    virtual void print(){}
    virtual void release(){}
};
class Term: public Exp {
    string val;
public:
    Term(string v):val(v){}
    void print(){
        cout << ' ' << val << ' ';
    }
    void release(){}
};

class Node: public Exp{
    Exp *l_exp;
    Exp *r_exp;
    char op; // +, -, *, /
public:
    Node(char op, Exp* left, Exp* right):op(op),l_exp(left), r_exp(right){}
    ~Node(){
    }
    void print(){
        cout << '(' << op << ' ';
        l_exp->print();
        r_exp->print();
        cout  << ')';
    }
    void release(){
        l_exp->release();
        r_exp->release();
        delete l_exp;
        delete r_exp;
    }
};

Exp* strToExp(string &str){
    int level = 0;//inside parentheses check
    //case + or -
    //most right '+' or '-' (but not inside '()') search and split
    for(int i=str.size()-1;i>=0;--i){
        char c = str[i];
        if(c == ')'){
            ++level;
            continue;
        }
        if(c == '('){
            --level;
            continue;
        }
        if(level>0) continue;
        if((c == '+' || c == '-') && i!=0 ){//if i==0 then s[0] is sign
            string left(str.substr(0,i));
            string right(str.substr(i+1));
            return new Node(c, strToExp(left), strToExp(right));
        }
    }
    //case * or /
    //most right '*' or '/' (but not inside '()') search and split
    for(int i=str.size()-1;i>=0;--i){
        char c = str[i];
        if(c == ')'){
            ++level;
            continue;
        }
        if(c == '('){
            --level;
            continue;
        }
        if(level>0) continue;
        if(c == '*' || c == '/'){
            string left(str.substr(0,i));
            string right(str.substr(i+1));
            return new Node(c, strToExp(left), strToExp(right));
        }
    }
    if(str[0]=='('){
    //case ()
    //pull out inside and to strToExp
        for(int i=0;i<str.size();++i){
            if(str[i]=='('){
                ++level;
                continue;
            }
            if(str[i]==')'){
                --level;
                if(level==0){
                    string exp(str.substr(1, i-1));
                    return strToExp(exp);
                }
                continue;
            }
        }
    } else
    //case value
        return new Term(str);
cerr << "Error:never execute point" << endl;
    return NULL;//never
}

int main(){
    string exp(" ( a + b ) * c - ( d - e ) * f / g");
    //remove space character
    exp.erase(remove_if(exp.begin(), exp.end(), ::isspace), exp.end());
    Exp *tree = strToExp(exp);
    tree->print();
    tree->release();
    delete tree;
}
//output:(- (* (+  a  b ) c )(/ (* (-  d  e ) f ) g ))
Run Code Online (Sandbox Code Playgroud)

  • 你需要比这个描述更多的东西吗? (2认同)