1. 程式人生 > >面向物件計算器(五)

面向物件計算器(五)

主要是為了更正之前的設計缺陷

1、算術表示式解析器的一個缺陷在於它的語法是右結合的。這意味著8-2+1被解析為8-(2+1)
2、可以通過更正語法
expresion := expresion ’+’ term
但這會導致無限迴圈(Expr呼叫Expr,Expr又呼叫Expr…)
3、一種解決方法:


更改後的類圖:


在程式中的具體實現為:

Node.h:

class MultipleNode : public Node
{
public:
	MultipleNode(Node* node)
	{
		AppendChild(node, true);
	}
	void AppendChild(Node* node, bool positive)
	{
		childs_.push_back(node);
		positives_.push_back(positive);
	}
	~MultipleNode();
protected:
	std::vector<Node*> childs_;
	std::vector<bool> positives_;
};


class SumNode : public MultipleNode
{
public:
	SumNode(Node* node)
		: MultipleNode(node) {}
	double Calc() const;
};


class ProductNode : public MultipleNode
{
public:
	ProductNode(Node* node)
		: MultipleNode(node) {}
	double Calc() const;
};
Node.cpp
MultipleNode::~MultipleNode()
{
	std::vector<Node*>::const_iterator it;
	for (it = childs_.begin(); it != childs_.end(); ++it)
	{
		delete *it;
	}
}

double SumNode::Calc() const
{
	double result = 0.0;
	std::vector<Node*>::const_iterator childIt = childs_.begin();
	std::vector<bool>::const_iterator positiveIt = positives_.begin();

	for (; childIt != childs_.end(); ++childIt, ++positiveIt)
	{
		assert(positiveIt != positives_.end());
		double val = (*childIt)->Calc();
		if (*positiveIt)
			result += val;
		else
			result -= val;
	}
	assert(positiveIt == positives_.end());

	return result;
}

double ProductNode::Calc() const
{
	double result = 1.0;
	std::vector<Node*>::const_iterator childIt = childs_.begin();
	std::vector<bool>::const_iterator positiveIt = positives_.begin();

	for (; childIt != childs_.end(); ++childIt, ++positiveIt)
	{
		assert(positiveIt != positives_.end());
		double val = (*childIt)->Calc();
		if (*positiveIt)
			result *= val;
		else if (val != 0.0)
			result /= val;
		else
		{
			std::cout<<"Division by zero."<<std::endl;
			return HUGE_VAL;
		}
			
	}
	assert(positiveIt == positives_.end());

	return result;
}


Parser.cpp:
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);
	//}
	if (token == TOKEN_PLUS || token == TOKEN_MINUS)
	{
		// Expr := Term { ('+' | '-') Term }
		MultipleNode* multipleNode = new SumNode(node);
		do 
		{
			scanner_.Accept();
			Node* nextNode = Term();
			multipleNode->AppendChild(nextNode, (token == TOKEN_PLUS));
			token = scanner_.Token();
		} while (token == TOKEN_PLUS || token == TOKEN_MINUS);
		node = multipleNode;
	}

	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);
	//}
	if (token == TOKEN_MULTIPLY || token == TOKEN_DIVIDE)
	{
		// Term := Factor { ('*' | '/') Factor }
		MultipleNode* multipleNode = new ProductNode(node);
		do 
		{
			scanner_.Accept();
			Node* nextNode = Factor();
			multipleNode->AppendChild(nextNode, (token == TOKEN_MULTIPLY));
			token = scanner_.Token();
		} while (token == TOKEN_MULTIPLY || token == TOKEN_DIVIDE);
		node = multipleNode;
	}

	return node;
}