小型计算器A small software project

小型计算器

一个小型的软件项目,代码大概1000行左右,包括了很多知识(继承、多态、前向声明、虚函数、动态内存、引用、指针等等),从头到尾写完花了些时间,但觉得很受用。
(1)计算器程序的目的是接受用户提供的算术表达式(例:1+2*3),求其值显示结果。
(2)每个算术表达式由解析器分析,将输入的算法表达式(一串字符)转换成一个算术树。
(3)算术树(一种数据结构):算术表达式可以转换为一个二叉树结构。
如:(a+b×(c-d))-e/f
二叉树结构为:
这里写图片描述

解析器语法

解析式寻找一个表达式,语法定义如下:
1. An expression is(一个表达式是)
a. 一个后面有加号或减号的项,加号或减号后面是另一个表达式。例:表达式2-3,2是一个项(后面是减号),3是一个表达式。
b. 如果表达式不含有加号、减号,它等于项。
(例:上例中的3是一个表达式,它也是一个项)

2. A term is(一个项是)
a. 被另一个项乘除的因子。
(例:表达式1+2*3,2*3是一个表达式,满足1b条件,2*3是一个项,满足2a条件,2是一个因子)
b.项如果不包含乘除,它等于此因子。

3. A factor can be(一个因子是)
a. 数字
b. 对应某变量的标识符
c. 后面带有一个因子的减号
d. 小括号中的整个表达式

配合实例理解解析器的语法定义:
1+x*(2-y)
这里写图片描述

具体实现

计算器由以下几个对象组成:
(1)扫描器,扫描用户输入的字符串。
(2)符号表,使计算器可以处理符号变量,如(x=1,变量x代表1)
(3)存储器,让计算器具有记忆能力,可以保存用户自定义变量的值。
(4)函数表,让计算器事先具有一些函数(如sin、cos、log、exp)
(5)结点,对应算术树的每个结点(使用继承实现)。关于结点的简化版本参看C++多态
(6)解析器,实现算数表达式的解析。

代码:只给出主函数、解析器代码,剩下的代码可以从github下载。
计算器Github
主函数 calculator.cpp

#include"SymbolTable.h"
#include"FunctionTable.h"
#include"Store.h"
#include"Scanner.h"
#include"Parser.h"
const int maxBuf = 100;
const int maxSymbols = 40;

int main()
{
    char buf[maxBuf];
    //状态位
    Status status;
    //符号表
    SymbolTable symTab(maxSymbols);
    //函数表
    FunctionTable funTab(symTab, funArr);   
    //存储器
    Store store(maxSymbols, symTab);
    do
    {
        std::cout << "> ";
        std::cin.getline(buf, maxBuf);
        //扫描器
        Scanner scanner(buf);
        //解析器
        Parser parser(scanner, store, funTab, symTab);
        status = parser.Eval();
    } while (status != stQuit);
    return 0;
}

解析器 Parser.h

#ifndef PARSER_H
#define PARSER_H
class Node;
class Scanner;
class SymbolTable;
class Store;
class FunctionTable;
//枚举:状态
enum Status
{
    stOK,
    stQuit,
    stError
};
//解析器类
class Parser
{
public:
    Parser(Scanner & scanner,
        Store& store,
        FunctionTable& funTab,
        SymbolTable & symTab);
    ~Parser();
    Status Eval();
private:
    void Parse();
    Node* Expr();
    Node* Term();
    Node* Factor();
    void Execute();

    Scanner & _scanner;//扫描器
    SymbolTable & _symTab;//符号表
    Node* _pTree;//算术树
    Status _status;//状态位
    Store& _store;//存储器
    FunctionTable& _funTab;//函数表
};


#endif

Parser.cpp

#include "Parser.h"
#include<iostream>
#include"Store.h"
#include"Node.h"
#include"FunctionTable.h"
#include"SymbolTable.h" 
#include"Scanner.h"
#include"AddNode.h"
#include "AssignNode.h"
#include"SubNode.h"
#include"MultNode.h"
#include"DivideNode.h"
#include"NumNode.h"
#include"FunNode.h"
#include"VarNode.h"
#include"UMinusNode.h"

Parser::~Parser()
{
    delete _pTree;
}       
Parser::Parser(Scanner & scanner,
    Store& store,
    FunctionTable& funTab,
    SymbolTable & symTab)
    :_scanner(scanner),
    _pTree(0),
    _status(stOK),
    _funTab(funTab),
    _store(store),
    _symTab(symTab)
{
    std::cout << "Parser Created" << std::endl;
}
//解析记号
Status Parser::Eval()
{
    Parse();
    if (_status == stOK)
        Execute();
    else
        _status == stQuit;
    return _status;
    //for (EToken token = _scanner.Token();
    //  token != tEnd;
    //  _scanner.Accept())
    //{
    //  token = _scanner.Token();
    //  switch (token)
    //  {
    //  case tMult:
    //      std::cout << "Times" << std::endl;
    //      break;
    //  case tPlus:
    //      std::cout << "Plus" << std::endl;
    //      break;
    //  case tNumber:
    //      std::cout << "Number: " << _scanner.Number() << std::endl;
    //      break;
    //  case tEnd:
    //      std::cout << "End" << std::endl;
    //      return stQuit;
    //  case tError:
    //      std::cout << "Error" << std::endl;
    //      return stQuit;
    //  default:
    //      std::cout << "Error: bad token" << std::endl;
    //      return stQuit;
    //  }
    //}
    //return stOK;
}
void Parser::Execute()
{
    if (_pTree)
    {
        double result = _pTree->Calc();
        std::cout << " " << result << std::endl;
    }
}
void Parser::Parse()
{
    _pTree = Expr();
}
//表达式
Node* Parser::Expr()
{
    Node* pNode = Term();
    EToken token = _scanner.Token();
    //加
    if (token == tPlus)
    {
        //识别下一个记号
        _scanner.Accept();
        Node* pRight = Expr();
        pNode = new AddNode(pNode, pRight);
    }
    //减
    else if (token==tMinus)
    {
        _scanner.Accept();
        Node* pRight = Expr();
        pNode = new SubNode(pNode, pRight);
    }
    //赋值
    else if (token == tAssign)
    {
        _scanner.Accept();
        Node* pRight = Expr();
        //左值
        if (pNode->IsLvalue())
        {
            pNode = new AssignNode(pNode, pRight);
        }
        else
        {
            _status = stError;
            delete pNode;
            pNode = Expr();
        }
    }
    return pNode;
}
//项
Node* Parser::Term()
{
    Node* pNode = Factor();
    //Term is Factor * Term
    if (_scanner.Token() == tMult)
    {
        _scanner.Accept();
        Node* pRight = Term();
        pNode = new MultNode(pNode, pRight);
    }
    //Term is Factor/Term
    else if (_scanner.Token()==tDivide)
    {
        _scanner.Accept();
        Node* pRight = Term();
        pNode = new DivideNode(pNode, pRight);
    }
    //Term is Factor
    return pNode;
}
//因子
Node* Parser::Factor()
{
    Node* pNode;
    EToken token = _scanner.Token();
    //左括号
    if (token == tLParen)
    {
        _scanner.Accept();//accept '('
        pNode = Expr();
        if (_scanner.Token() != tRParen)
            _status = stError;
        _scanner.Accept();//accept ')'
    }
    //数字
    else if (token == tNumber)
    {
        pNode = new NumNode(_scanner.Number());
        _scanner.Accept();
    }
    //符号变量
    else if (token == tIdent)
    {
        char strSymbol[maxSymLen + 1];
        int lenSym = maxSymLen;
        //复制symbol到strSymbol
        _scanner.GetSymbolName(strSymbol, lenSym);
        int id = _symTab.Find(strSymbol);
        _scanner.Accept();
        //函数调用 如sin(x)
        if (_scanner.Token() == tLParen)
        {
            _scanner.Accept();
            pNode = Expr();
            if (_scanner.Token() == tRParen)
                _scanner.Accept();
            else
                _status = stError;
            if (id != idNotFound && id < _funTab.Size())
            {
                //函数结点
                pNode = new FunNode(_funTab.GetFun(id), pNode);
            }
            else
            {
                std::cout << "Unknow function\"";
                std::cout << strSymbol << "\"\n";
            }
        }
        else
        {
            if (id == idNotFound)
                id = _symTab.ForcAdd(strSymbol, lenSym);
            pNode = new VarNode(id, _store);
        }
    }
    //一元减
    else if (token == tMinus)
    {
        _scanner.Accept();
        pNode = new UMinusNode(Factor());

    }
    else
    {
        _scanner.Accept();
        _status = stError;
        pNode = 0;
    }
    return pNode;
}

这里写图片描述
这里写图片描述
这里写图片描述

相关系列

基于堆栈的计算器

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林多

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值