面向对象版计算器(一)

表达式计算器设计

在这里插入图片描述

表达式树

类设计

在这里插入图片描述

新的继承体系

在这里插入图片描述
在这里插入图片描述

//Node.h
#pragma once
#ifndef _NODE_H_
#define _NODE_H_


class Node
{
public:
	virtual double Calc() const = 0;
	virtual ~Node() {};
};
class NumberNode :public Node
{
public:
	NumberNode(double number) :number_(number) {}
	double Calc() const;
private:
	const double number_;
};
class BinaryNode : public Node
{
public:
	BinaryNode(Node* left, Node* right) :left_(left), right_(right) {}
	~BinaryNode();
protected:
	Node* const left_;
	Node* const right_;
};
class UnaryNode :public Node
{
public:
	UnaryNode(Node* child):child_(child){}
	~UnaryNode();
protected:
	Node* const child_;
};
class AddNode :public BinaryNode
{
public:
	AddNode(Node* left, Node* right) :BinaryNode(left, right) {}
	double Calc() const;
};
class SubNode :public BinaryNode
{
public:
	SubNode(Node* left, Node* right) :BinaryNode(left, right) {}
	double Calc() const;
};
class MultiplyNode :public BinaryNode
{
public:
	MultiplyNode(Node* left, Node* right) :BinaryNode(left, right) {}
	double Calc() const;
};
class DivideNode :public BinaryNode
{
public:
	DivideNode(Node* left, Node* right) :BinaryNode(left, right) {}
	double Calc() const;
};
class UMinusNode :public UnaryNode
{
public:
	UMinusNode(Node* child):UnaryNode(child){}
	double Calc() const;
};
#endif // !_NODE_H_

//Node.cpp
#include "Node.h"
#include "iostream"
#include <cmath>
double NumberNode::Calc() const
{
	return number_;
}
UnaryNode::~UnaryNode()
{
	delete child_;
}
BinaryNode::~BinaryNode()
{
	delete left_;
	delete right_;
}
double AddNode::Calc() const
{
	return left_->Calc() + right_->Calc();
}
double SubNode::Calc() const
{
	return left_->Calc() - right_->Calc();
}
double MultiplyNode::Calc() const
{
	return left_->Calc() * right_->Calc();
}
double DivideNode::Calc() const
{
	double divisor = right_->Calc();
	if (divisor != 0.0)
	{
		return left_->Calc() / right_->Calc();
	}
	else {
		std::cout << "Error:Divisor by zero" << std::endl;
		return HUGE_VAL;
	}
}
double UMinusNode::Calc() const
{
	return -child_->Calc();
}


分清值语义与对象语义

  • 值语义是指对象的拷贝与原对象无关。拷贝之后就与原对象脱离关系,彼此独立互不影响。比如说int,c++中的内置类型都是值语义,我们前面学过的三个标准库类型:string,vector,map也是值语义
  • 对象语义指的是面向对象意义下的对象
    • 对象拷贝是禁止的(Noncopyable)。
    • 一个对象被系统标准的复制方式复制后,与被复制的对象之间依然共享底层资源,对任何一个的改变都将改变另一个
  • 值语义对象生命期容易控制
  • 对象语义对象生命不容易控制(通过智能指针来解决)。智能指针实际上是将对象语义转换为值语义
  • 值语义与对象语义是分析模型决定的,语言的语法技巧用来匹配模型。
    在这里插入图片描述
    智能指针:
    auto_ptr:所有权独占,不能共享,但是可以转移
    sharde_ptr:所有权共享,内部维护了一个引用计数,+1,-1
    weak_ptr:弱指针,他要与sharde_ptr配合使用,循环引用
    scoped_ptr:与auto_ptr类似,所有权独占,不能共享,但是也不可以转移
    RAII:资源获取即初始化
    值语义对象的析构是确定的。

表达式解析

  • expression :=
    • term ‘+’ expression
    • term ‘-’ expression
    • term

  • term :=
    • factor ‘*’ term
    • factor ‘/’ term
    • factor

  • factor :=
    • number
    • identifier
    • ‘_’ factor
    • ‘(‘expression’)’
  • 表达式
    • 是一个后面有加号或减号的项,加号或减号的后面又有另一个表达式
    • 如果表达式不含任何加号或减号,它等于此项
    • 表达式也可以为一个项加一个等于号,再加一个表达式
  • 一个项是
    • 被另一个项乘或除的因子
    • 如果一个项不包含任何乘或除运算符,它等于此因子
  • 一个因子可以是
    • 一个数字
    • 一个对应于某变量的标识符
    • 后面带有一个因子的减号(一元减)
    • 小括号中的整个表达式
      在这里插入图片描述

Scanner类的实现

在这里插入图片描述

  • 字符串转double
    double strtod(const char *nptr,char **endptr);
//scanner.h
#pragma once
#include <iostream>
#include <string>
enum EToken
{
	TOKEN_END,
	TOKEN_ERROR,
	TOKEN_NUMBER,
	TOKEN_PLUS,
	TOKEN_MINUS,
	TOKEN_MULTIPLY,
	TOKEN_DIVIDE,
	TOKEN_LPARENTHESIS,
	TOKEN_RPARENTHESIS,
	TOKEN_IDENTIFUER,
	TOKEN_ASSIGN
};
class Scanner
{
public:
	Scanner(const std::string& buf);
	void Accept();
	double Number() const;
	EToken Token() const;
private:
	void SkipWhite();
	const std::string buf_;
	unsigned int curPos_;
	EToken token_;
	double number_;
};
//scanner.cpp
#include "Scanner.h"
#include <cctype>
Scanner::Scanner(const std::string& buf): buf_(buf),curPos_(0)
{
	Accept();
}
double Scanner::Number() const
{
	return number_;
}
EToken Scanner::Token() const
{
	return token_;
}
void Scanner::SkipWhite()
{
	while (isspace(buf_[curPos_]))
		++curPos_;
}
void Scanner::Accept()
{
	SkipWhite();
	switch (buf_[curPos_])
	{
	case '+':
		token_ = TOKEN_PLUS;
		++curPos_;
		break;
	case '-':
		token_ = TOKEN_MINUS;
		++curPos_;
		break;
	case '*':
		token_ = TOKEN_MULTIPLY;
		++curPos_;
		break;
	case '/':
		token_ = TOKEN_DIVIDE;
		++curPos_;
		break;
	case '(':
		token_ = TOKEN_LPARENTHESIS;
		++curPos_;
		break;
	case ')':
		token_ = TOKEN_RPARENTHESIS;
		++curPos_;
		break;
	case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.':
		token_ = TOKEN_NUMBER;
		char* p;
		number_ = strtod(&buf_[curPos_], &p);
		curPos_ = p - &buf_[0];
		break;
	case '\0': case '\n': case '\r': case EOF:
		token_ = TOKEN_END;
		break;
	default:
		token_ = TOKEN_ERROR;
		break;
	}
}

Parser类的实现

在这里插入图片描述

Expression :表达式,Term:项,Factor :因式

  • Expression is Term + Expression
  • or Term - Expression
  • or Term = Expression
  • or just Term

  • Term is Factor * Term
  • or Factor / Term
  • or just Factor

  • Factor is Number
  • or Identifier
  • or Identifier(Expression)
  • or -Factor
  • or (Expresion)
//parser.h
#pragma once
#include "Scanner.h"
#include "Node.h"
enum STATUS
{
	STATUS_OK,
	STATUS_ERROR,
	STATUS_QUIT
};
class Parser
{
public:
	Parser(Scanner& scanner);
	void Parse();
	Node* Expr();
	Node* Term();
	Node* Factor();
	double Calculate() const;
private:
	Scanner& scanner_;
	Node* tree_;
	STATUS status_;
};
//parser.cpp
#include "Parser.h"
#include <cassert>
Parser::Parser(Scanner& scanner) :scanner_(scanner),tree_(0)
{

}
void Parser::Parse()
{
	tree_ = Expr();
}
Node* Parser::Expr()
{
	Node* node = Term();
	EToken token = scanner_.Token();
	if (token == TOKEN_PLUS)
	{
		scanner_.Accept();
		Node* nodeRight = Expr();
		node = new AddNode(node, nodeRight);
	}
	else if(token == TOKEN_MINUS){
		scanner_.Accept();
		Node* nodeRight = Expr();
		node = new SubNode(node, nodeRight);
	}
	return node;
}
Node* Parser::Term()
{
	Node* node = Factor();
	EToken token = scanner_.Token();
	if (token == TOKEN_MULTIPLY)
	{
		scanner_.Accept();
		Node* nodeRight = Term();
		node = new MultiplyNode(node, nodeRight);
	}
	else if (token == TOKEN_DIVIDE) {
		scanner_.Accept();
		Node* nodeRight = Term();
		node = new DivideNode(node, nodeRight);
	}
	return node;
}
Node* Parser::Factor()
{
	Node* node;
	EToken token = scanner_.Token();
	if (token == TOKEN_LPARENTHESIS)
	{
		scanner_.Accept();//accept'('
		node = Expr();
		if (scanner_.Token() == TOKEN_RPARENTHESIS)
		{
			scanner_.Accept();//accept')'
		}
		else {
			status_ = STATUS_ERROR;
			// TODO:抛出异常
			std::cout << "MISSING RPARENTHESIS" << std::endl;
			node = 0;
		}
	}
	else if(token == TOKEN_NUMBER){
		node = new NumberNode(scanner_.Number());
		scanner_.Accept();
	}
	else if (token == TOKEN_MINUS)
	{
		scanner_.Accept(); // accept minus
		node = new UMinusNode(Factor());
	}
	else {
		status_ = STATUS_ERROR;
		// TODO:抛出异常
		std::cout << "not a balid expression" << std::endl;
		node = 0;
	}
	return node;
}
double Parser::Calculate() const
{
	assert(tree_!=NULL);
	return tree_->Calc();
}

结果

//main.cpp
#include<iostream>
#include<string>
#include"Parser.h"
int main()
{
	STATUS status = STATUS_OK;
	do
	{
		std::cout << "> ";
		std::string buf;
		std::getline(std::cin, buf);
		//std::cout << buf << std::endl;
		Scanner scanner(buf);
		Parser parser(scanner);
		parser.Parse();
		std::cout<<parser.Calculate()<<std::endl;
	} while (status != STATUS_QUIT);
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值