基于词法分析的中缀表达式计算

基于词法分析的中缀表达式计算

         前面我们对中缀表达式的词法处理进行了讲解并给出了程序示例《四则运算的词法分析》,之前我们也对中缀表达式的计算进行了一系列的分析,诸如《检测中缀表达式的合法性》。在之前的中缀表达式的计算中,我们是利用了空白符来间隔操作符和操作数,这属于一种硬分割。

         本文我们利用上一篇中对中缀表达式进行词法分析,进而通过中缀表达式转换为后缀表达式,进而计算后缀表达式来实现基于词法分析的中缀表达式计算。

         程序的处理过程主要是包括3个部分:

         1.对中缀表达式进行词法分析

         2.中缀表达式转化为后缀表达式

         3.后缀表达式的计算

         我们的程序也是按照以上三个步骤进行的,具体的程序如下:

// 基于词法分析的中缀表达式计算

#include <iostream>

#include <sstream>

#include <vector>

#include <string>

#include <stack>

#include <map>

#include <cassert>

using namespace std;



string& replace_all_distinct(string& str, const string& src, const string& des)

{

    for (string::size_type i = 0; i != string::npos; i += des.size())

    {

        i = str.find(src, i);

        if (i != string::npos)

        {

            str.replace(i, src.size(), des);

        }

        else

        {

            break;

        }

    }

    return str;

}



string& n_replace(string& str, const vector<string>& src, const vector<string>& des)

{

    assert(src.size() > 0 && src.size() == des.size());

    for (vector<string>::size_type i = 0; i != src.size(); ++i)

    {

        replace_all_distinct(str, src[i], des[i]);

    }

    return str;

}



void get_infix(vector<string>& inf, const vector<string>& src, const vector<string>& des)

{

    inf.clear();

    string line;

    getline(cin, line);

    

    n_replace(line, src, des);

    

    istringstream sin(line);

    string tmp;

    while (sin >> tmp)

    {

        inf.push_back(tmp);

    }

}



// 加入词法分析 BEGIN

struct TI

{

    string token;

    int    id;

};



bool is_blank(char ch)

{

    return ch == ' ' || ch == '    ';

}



void get_exp(string& exp)

{

    getline(cin, exp);

}



void init_keys(map<string, int>& keys)

{

    keys.clear();

    keys["+"] = 1;

    keys["-"] = 2;

    keys["*"] = 3;

    keys["/"] = 4;

    keys["("] = 5;

    keys[")"] = 6;

    keys["__NUM__"] = 7;

}



void lex(const string& exp, vector<TI>& to_id, const map<string, int>& keys)

{

    to_id.clear();

    char ch;

    for (string::size_type pos = 0; pos < exp.size(); /* ++pos */)

    {

        TI ti;

        ch = exp[pos];



        if (is_blank(ch))

        {

            ++pos;

            continue;

        }

        if (ch >= '0' && ch <= '9' || ch == '.')

        {

            ti.token += ch;

            ++pos;

            if (pos >= exp.size())

            {

                ti.id = keys.size();

                to_id.push_back(ti);

                return;

            }

            ch = exp[pos];

            while (ch >= '0' && ch <= '9' || ch == '.')

            {

                ti.token += ch;

                ++pos;

                if (pos >= exp.size())

                {

                    ti.id = keys.size();

                    to_id.push_back(ti);

                    return;

                }

                ch = exp[pos];

            }

            ti.id = keys.size();

            to_id.push_back(ti);

        }

        else

        {

            map<string, int>::const_iterator cit;

            switch (ch)

            {

            case '+':

            case '-':

            case '*':

            case '/':

            case '(':

            case ')':

                ti.token += ch;

                cit = keys.find(ti.token);

                if (cit == keys.end())

                {

                    cout << "test" << endl;

                }

                ti.id = cit->second;

                to_id.push_back(ti);

                ++pos;

                break;



            default:

                // ti.token += string("Unknown:") + ch;

                ti.token += string("未知字符:") + ch;

                ti.id = -1;

                to_id.push_back(ti);

                ++pos;

                break;

            }

        }

    }

}



// 基于词法分析读取中缀表达式

void get_infix_lex(vector<string>&inf, const map<string, int>& keys)

{

    inf.clear();

    string line;

    getline(cin, line);

    vector<TI> to_id;

    lex(line, to_id, keys);

    for (vector<TI>::size_type i = 0; i != to_id.size(); ++i)

    {

        inf.push_back(to_id[i].token);

    }

}



// 加入词法分析 END





void show(const vector<string>& hs)

{

    for (vector<string>::size_type i = 0; i != hs.size(); ++i)

    {

        cout << hs[i] << ' ';

    }

    cout << endl;

}



void init_op(map<string, int>& ops)

{

    ops.clear();

    ops["+"] = 100;

    ops["-"] = 100;

    ops["*"] = 200;

    ops["/"] = 200;

    ops["("] = 1000;

    ops[")"] = 0;

}



bool is_operator(const string& hs, const map<string, int>& ops)

{

    map<string, int>::const_iterator cit = ops.find(hs);

    if (cit != ops.end())

    {

        return true;

    }

    else

    {

        return false;

    }

}



// 判断操作数是否合法

bool op_legal(const string& str, int& ill_id)

{

    assert(str.size() > 0);

    string::size_type i = 0;

    if (str[i] == '+' || str[i] == '-')

    {

        ++i;

        if (i == str.size())

        {

            ill_id = 3001;

            return false;

        }

    }

    int dot_num = 0;

    for (; i != str.size(); ++i)

    {

        // if (isdigit(static_cast<int>(str[i])))

        if (str[i] >= '0' && str[i] <= '9')

        {

            ;

        }

        else if (str[i] == '.')

        {

            ++dot_num;

        }

        else

        {

            ill_id = 3002;

            return false;

        }

    }

    if (dot_num > 1)

    {

        ill_id = 3003;

        return false;

    }

    return true;

}



void in2post(const vector<string>& inf, vector<string>& postf, map<string, int>& ops, bool& leg, int& ill_id)

{

    if (inf.size() == 0)

    {

        leg = false;

        ill_id = 6001;

        return;

    }

    

    postf.clear();

    stack<string> op_st;

    // 记录左括号和右括号之间的数量关系

    int brac = 0;

    int op_op = 0;

    

    for (vector<string>::size_type i = 0; i != inf.size(); ++i)

    {

        if (!is_operator(inf[i], ops))

        {

            // 判断是否是正确的操作数

            int tmp = 0;

            if (!op_legal(inf[i], tmp))

            {

                leg = false;

                ill_id = tmp;

                return;

            }

            ++op_op;

            if (op_op > 1)

            {

                leg = false;

                ill_id = 5001;

                return;

            }

            postf.push_back(inf[i]);

        }

        else

        {

            if (inf[i] == "(")

            {

                ++brac;

                op_st.push(inf[i]);

            }

            else if (inf[i] == ")")

            {

                --brac;

                if (brac < 0)

                {

                    leg = false;

                    ill_id = 4001;

                    return;

                }

                while (!op_st.empty())

                {

                    if (op_st.top() == "(")

                    {

                        op_st.pop();

                        break;

                    }

                    else

                    {

                        postf.push_back(op_st.top());

                        op_st.pop();

                    }

                }

            }

            else // 若为其他运算符

            {

                --op_op;                

                if (op_op < 0)

                {

                    leg = false;

                    ill_id = 5002;

                    return;

                }

                

                if (op_st.empty()) // 若为空栈,则直接入栈

                {

                    op_st.push(inf[i]);

                }

                else

                {

                    if (ops[inf[i]] > ops[op_st.top()])

                    {

                        // 如果当前操作符优先级高于站定操作符优先级

                        // 则直接入栈

                        op_st.push(inf[i]);

                    }

                    else

                    {

                        // 否则弹出栈中优先级大于等于当前操作符优先级

                        // 的操作符,并最后将当前操作符压栈

                        while (!op_st.empty() && ops[op_st.top()] >= ops[inf[i]] && op_st.top() != "(")

                        {

                            postf.push_back(op_st.top());

                            op_st.pop();

                        }

                        op_st.push(inf[i]);

                    }

                }

            }

        }

    }

    if (brac > 0)

    {

        leg = false;

        ill_id = 4002;

        return;

    }

    if (op_op != 1)

    {

        leg = false;

        ill_id = 5003;

        return;

    }

    

    while (!op_st.empty())

    {

        postf.push_back(op_st.top());

        op_st.pop();

    }

    leg = true;

    return;

}



double cal_post(const vector<string>& postf, const map<string, int>& ops, bool& leg, int& ill_id)

{

    stack<double> or_st;

    double operand = 0.0, a = 0.0, b = 0.0, c = 0.0;

    for (vector<string>::size_type i = 0; i != postf.size(); ++i)

    {

        if (!is_operator(postf[i], ops))

        {

            operand = static_cast<double>(atof(postf[i].c_str()));

            or_st.push(operand);

        }

        else

        {

            switch (postf[i][0])

            {

            case '+':

                // 检测后缀表达式的合法性:操作数是否足够

                if (or_st.size() < 2)

                {

                    leg = false;

                    ill_id = 1001;

                    return -10000000000000.0;

                }

                b = or_st.top();

                or_st.pop();

                a = or_st.top();

                or_st.pop();

                c = a + b;

                or_st.push(c);

                break;

            case '-':

                // 检测后缀表达式的合法性:操作数是否足够

                if (or_st.size() < 2)

                {

                    leg = false;

                    ill_id = 1002;

                    return -10000000000000.0;

                }

                b = or_st.top();

                or_st.pop();

                a = or_st.top();

                or_st.pop();

                c = a - b;

                or_st.push(c);

                break;

            case '*':

                // 检测后缀表达式的合法性:操作数是否足够

                if (or_st.size() < 2)

                {

                    leg = false;

                    ill_id = 1003;

                    return -10000000000000.0;

                }

                b = or_st.top();

                or_st.pop();

                a = or_st.top();

                or_st.pop();

                c = a * b;

                or_st.push(c);

                break;

            case '/':

                // 检测后缀表达式的合法性:操作数是否足够

                if (or_st.size() < 2)

                {

                    leg = false;

                    ill_id = 1004;

                    return -10000000000000.0;

                }

                b = or_st.top();

                or_st.pop();

                a = or_st.top();

                or_st.pop();

                c = a / b;

                or_st.push(c);

                break;

            default:

                break;

            }

        }

    }

    if (or_st.size() == 1)

    {

        leg = true;

        return or_st.top();

    }

    else // 检测后缀表达式的合法性:操作数是否有多余

    {

        leg = false;

        ill_id = 2001;

        return -10000000000000.0;

    }

}



void init_src_des(vector<string>& src, vector<string>& des)

{

    src.push_back("+");

    src.push_back("-");

    src.push_back("*");

    src.push_back("/");

    src.push_back("(");

    src.push_back(")");

    

    des.push_back(" + ");

    des.push_back(" - ");

    des.push_back(" * ");

    des.push_back(" / ");

    des.push_back(" ( ");

    des.push_back(" ) ");

}



// 将中缀表达式转换后缀表达式和计算后缀表达式封装合并

double cal_inf(const vector<string>& inf, map<string, int>& ops, bool& leg_trans, bool& leg_cal, int& ill_id)

{

    leg_trans = true;

    ill_id = 0;

    vector<string> postf;

    in2post(inf, postf, ops, leg_trans, ill_id);

    if (leg_trans)

    {

        show(postf);

    }

    else

    {

        cout << "Trans illegal: " << ill_id << '!' << endl << endl;

        return -10000000000000.0;

    }

    

    leg_cal = true;

    ill_id = 0;

    double ret = cal_post(postf, ops, leg_cal, ill_id);

    if (leg_cal)

    {

        return ret;

    }

    else

    {

        cout << "Cal illegal: " << ill_id << '!' << endl << endl;

        return -10000000000000.0;

    }

}



int main()

{

    map<string, int> ops;

    init_op(ops);

    vector<string> inf;

    

    vector<string> src, des;

    init_src_des(src, des);

    



    map<string, int> keys;

    init_keys(keys);



    while (1)

    {

        // 原来读取后缀表达式的方法(加空格处理)

        // get_infix(inf, src, des);

        

        get_infix_lex(inf, keys);



        bool leg_trans = true;

        bool leg_cal   = true;

        int  ill_id    = 0;

        double ret = cal_inf(inf, ops, leg_trans, leg_cal, ill_id);

        if (leg_trans && leg_cal)

        {

            cout << ret << endl << endl;

        }

    }

    return 0;

}

基于词法分析的中缀表达式计算

 

         目前我们关于四则运算表达式的计算到此结束。主要分为3大块:

         1.对输入的中缀表达式进行词法分析

         2.将中缀表达式转换为后缀表达式

         3.计算后缀表达式

         四则运算的相关处理已基本介绍完毕。接下来会涉及一些前缀表达式、中缀表达式、后缀表达式之间的一些相互转换。

         关于中缀表达式的计算我们是利用了两个栈——操作符栈和操作数栈进行的。对于中缀表达式另外的计算方法有待我们以后进一步探讨。

你可能感兴趣的:(表达式)