表达式计算器设计
表达式树
类设计
新的继承体系
//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);
}