您的位置:首页 > 编程语言 > C语言/C++

小型计算器A small software project

2017-02-05 17:09 435 查看

小型计算器

一个小型的软件项目,代码大概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;
}






内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息