43 c++ 面向对象版表达式计算器Parser

      







基本代码完善:

   递归实现表达式树:

  main.cpp

  

#include <iostream>
#include <string>
#include "Scanner.h"
#include "Parser.h"
using namespace std;
int main(void)
{
	STATUS status=STATUS_OK;
	do
	{
		cout<<"> ";
		string buf;
		getline(cin,buf);//输入一行表达式,放到buf 中。
		//cout<<buf<<endl;//输出
		Scanner scanner(buf);//扫描表达式
		Parser parser(scanner);
		parser.Parse();//解析
		cout<< parser.Calculate()<<endl;  //解析完毕,计算
	}while(status!=STATUS_QUIT);
	return 0;
}

parser.h

#ifndef _PARSER_H_
#define _PARSER_H_
class Scanner;
class Node;//前项声明
enum STATUS{
	STATUS_OK,
	
	STATUS_ERROR,

	STATUS_QUIT
};
class Parser
{
	//这里是引用的方式来使用Scanner 或者指针的方式,没有必要这么快就包含头文件,可以用前项声明。
	//这样的话,头文件会比较小,cpp 中多次包含了,就会使得可执行文件增大
public:
	Parser(Scanner& scanner);
	void Parse();
	Node* Expr();//表达式
	Node* Term();//项
	Node* Factory();//因式
	double Calculate() const;
private:
	Scanner& scanner_;
	Node* tree_;//生成一棵表达式树
	STATUS status_;
};
#endif

parser.cpp

#include "Parser.h"
#include "Scanner.h"
#include "Node.h"
#include <cassert>
#include <iostream>

//引用在初始化列表中进行初始化
Parser::Parser(Scanner& scanner):scanner_(scanner),tree_(0)//0 就是null
{

}
void Parser::Parse()
{
	tree_=Expr();//解析是否是一个表达式  返回一个Node
}
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::Factory()
{
	Node* node=0;
	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:抛出异常
			cout<<"not a valid experssion"<<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(Factory());
	}else
	{
		status_=STATUS_ERROR;
		//Todo:抛出异常
			cout<<"not a valid experession"<<endl;
			node=0;
	}
	return node;
}
Node* Parser::Term()
{
	Node* node=Factory();
	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;
}
//加const 和不加const 是可以构成重载的。
double Parser::Calculate() const
{
	assert(tree_!=0);
	return tree_->Calc();
}


scanner.cpp

#include "Scanner.h"
#include <cctype>

Scanner::Scanner(const 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);//&p 是指针的指针 指针指向了第一个不是数字的位置
		//然后根据&p 得到cur_pos 的位置  指针的位置减去首地址
		//curPos_  是一个整数  要将地址转换成数字
		curPos_=p-&buf_[0];
		break;
	case '\\0':case '\n':case '\r':case EOF:
		token_=TOKEN_END;//表达式结束
		break;
	default:
		token_=TOKEN_ERROR;
		break;
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值