数据结构表达式求值代码_编译原理学习笔记-编写简单的数学表达式计算器

按照老规矩,应该是先放示例图

dfc248e6c766e2ecb1d28bdfc596bddb.png

简单介绍后序表达式

一般我们以前数学课学习的数学表达式都是中序的,比如说一加一,则写法就是1+1

而在计算的时候,为了方便编写数学表达式求值的计算机程序,通常会输入后序表达式。如1+1的后缀表达式为1 1 -

举个更复杂的例子,比如今有中序表达式:

1 + (1 - 2) / 3

则它的后序表达式为:

1 2 - 3 / 1 +

为什么后序表达式会更方便编写计算的算法呢?

我们使用数据结构 - 栈 来进行我们的算法。至于什么是栈,请咨询数据结构老师吧。

将上述例子储存到栈中是这个样子的:

1550d5a54978f3d7bdc418a0ae34a43f.png

图中使用了两个栈,一个用来储存后序表达式,一个用来放置我们的计算结果。

后序表达式求值算法

话不多说,直接看图吧,每一个图表示一个步骤。

dc397172298ff7ecdd6946d3f1aa5d4c.png

6e0cc3bab64efe4b3fc729b108f757d5.png

676a940da007c113230f5b830313171e.png

c33bf7dcba11250b83785c75ab9e90e8.png

f9adc854a1abd45e2f4ffd9c3932acd7.png

e5004dd1437a3cee0ba3f94b784d932b.png

ef9da1aa457a679650da409df48042f4.png

8885606ed84c32746d61d86cfe739a2a.png

1cc9f4ea868f4937aa08be985b4189b8.png

0fe36d181e0b071b3bf03323144d841f.png

4bde941ebd0d1540e491f51848d02175.png

将中序表达式转换为后序表达式

那么我们的目标很明确了,就是编写一个算法,输入是中序表达式字符串,输出是后序表达式栈,之后再使用上述后序表达式求值算法,即可求出表达式的值。

递归下降语法分析器

该语法分析器会接受一个字符串输入,然后根据定义的数学表达式,输出后序表达式栈。

定义数学表达式

_Expr     -> _Term0    | _Expr + _Term0  | _Expr - _Term0
_Term0    -> _Term1    | _Term0 * _Term1 | _Term0 / _Term1
_Term1    -> _Term2    | _Term1 ^ _Term2
_Term2    -> _Real     | ( _Expr )       | _Func ( _Args )

_Real     -> _Positive | - _Positive     | + _Positive
_Positive -> _Interger | _Interger . _Interger
_Interger -> digital   | _Interger digital

_Func     -> letter    | _Func letter    | _Func digital
_Args     -> _Expr     | _Args , _Expr

根据定义编写函数

_Expr

//表达式
void _Expr()
{
    _Term0();
    while(true)
    {
        //在0级优先级的操作符中搜索是否有这个操作符
        auto find_opt = opts_0.find(*next);
        if(find_opt != string::npos)
        {
            auto op = opts_0[find_opt];
            _Match(op);
            _Term0();
            output += op;
            LexerValue lex;
            lex.o = op;
            theExp.exp.push(make_pair(LexerType::OPT, lex));
        }else if(*next == '.')
        {
            cout<<"Too many '.'!"<<endl;
            throw theExp;
        }else
        {
            return;
        }
    }
}

_Term0

//0级优先级二元操作符
void _Term0()
{
    _Term1();
    while(true)
    {
        //在1级优先级的操作符中搜索是否有这个操作符
        auto find_opt = opts_1.find(*next);
        if(find_opt != string::npos)
        {
            auto op = opts_1[find_opt];
            _Match(op);
            _Term1();
            output += op;
            LexerValue lex;
            lex.o = op;
            theExp.exp.push(make_pair(LexerType::OPT, lex));
        }else
        {
            return;
        } 
    }
}

_Term1

//1级优先级二元操作符
void _Term1()
{
    _Term2();
    while(true)
    {
        //在2级优先级的操作符中搜索是否有这个操作符
        auto find_opt = opts_2.find(*next);
        if(find_opt != string::npos)
        {
            auto op = opts_2[find_opt];
            _Match(op);
            _Term2();
            output += op;
            LexerValue lex;
            lex.o = op;
            theExp.exp.push(make_pair(LexerType::OPT, lex));
        }else
        {
            return;
        } 
    }
}

_Term2

//2级优先级二元操作符
void _Term2()
{
    if(IsDigit(*next) || (next + 1 != end && (*next == '-' || *next == '+') && IsDigit(*(next + 1))))
    {
        output += '<';
        auto b = output.size();
        _Real();
        string real(output.begin() + b, output.end());
        LexerValue lex;
        lex.r = StrToReal(real);
        theExp.exp.push(make_pair(LexerType::REAL, lex));
        output += '>';
    }else if(*next == '(')
    {
        _Match('(');
        _Expr();
        _Match(')');
    }else if(IsLetter(*next))
    {
        auto b = output.size();
        _Func();
        string func_name(output.begin() + b, output.end());
        output += '(';
        _Match('(');
        _Args();
        _Match(')');
        output += ')';
        LexerValue lex;
        lex.f = func_name;
        theExp.exp.push(make_pair(LexerType::FUNC, lex));
    }
}

_Real

//实数
void _Real()
{
    if(*next == '-')
    {
        _Match('-');
        output += '-';
        _Positive();
    }if(*next == '+')
    {
        _Match('+');
        _Positive();
    }
    else
    {
        _Positive();
    }
}

_Positive

//正数
void _Positive()
{
    _Interger();
    if(*next == '.')
    {
        output += '.';
        _Match('.');
        _Interger();
    }
}

_Interger

//正整数
void _Interger()
{
    while(IsDigit(*next))
    {
        output += *next;
        _Match(*next);
    }
}

_Func

//函数名
void _Func()
{
    if(IsLetter(*next))
    {
        char l = *next;
        output += l;
        _Match(l);

        while(IsLetter(*next) || IsDigit(*next))
        {
            output += *next;
            _Match(*next);
        }
    }
}

_Args

//函数的参数
void _Args()
{
    while(true)
    {
        _Expr();
        if(__Match(','))
        {
            output += ',';
        }else
        {
            break;
        }
    };
}

匹配函数

bool __Match(char t)
{
    while(*next == ' ')++next;
    if(*next == t)
    {
        do{
            ++next;
        }while(*next == ' ');
        return true;
    }
    return false;
}


void _Match(char t)
{
    if(!__Match(t))
    {
        theExp.exp = stack<Lexer>();
        cout<<"nMatch ( '"<<t<<"' with '"<<*next<<"' ) fail!"<<endl;
        throw theExp;
        return;
    }
}

运行示例

该程序不但能处理整数,还可以处理负数,浮点数以及在力所能及的范围内给出错误参考提示。

32dd3af3bd95964872a283a4bd36e701.png

我在定义数学表达式时让其支持根据函数名调用,可以实现一下奇怪的功能。比如下面这个设定随机数种子并获取一个0到99内的随机数。

18c348f557d5e0e5f40198e21e8b49b6.png

完整源代码

https://github.com/rayxuln/CodingNotebook/blob/master/ExpCalculator.cpp

参考资料

[1] 编译原理

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值