基于C++计算器,中序表达式,后序表达式,波兰表达式

要求

  1. 采用多个头文件、多个实现文件的方式实现完整程序(使得源代码的物理结构和逻辑结构保持一致);
  2. 输入中每遇到一个分号或回车(‘\n’)就认为一个完整表达式结束,并将该完整表达式记作一行。在处理过程中累计行数(和行号);
  3. 对于输入中存在的错误,除了提示错误现象外,还需提示相应的出错行号(即表达式的序号)。
  4. 必须支持命令行参数,以指明从何处读取所有表达式。
  • 命令行参数中的第2项开始,指定0~多个输入文件之路径。输入文件就是普通的文本文件,其中预先输入了若干表达式,内容及格式 均与来自标准输入的完全相同。
  • 若命令行参数未指明输入文件,则程序从标准输入设备(cin)读取表达式。
  • 若命令行指明了1~N个输入文件,则程序依次从这些文件读入表达式,并按照读到的顺序依次处理他们。

代码文件说明

每一个类都由头文件和源文件组成。

calch.h文件

#pragma once

#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <cmath>

#include "calc.h"
#include "datahandler.h"
#include "eval.h"
#include "lexer.h"
#include "sym.h"
#include "filenotfound.h"
#include "illegalname.h"
#include "evalerror.h"

我把所有的头文件在这个文件中一次引用,之后后面的代码每一个头文件都要引用这个头文件。

主函数文件

#include "calch.h"

using namespace std;
using namespace calculator;

int main(int argc, char* argv[])
{
	calc mycalc(argc, argv);
	system("pause");
	return 0;
}

calc

头文件

#pragma once

#include "calch.h"

namespace calculator
{
	class calc
	{
	public:
		calc(int argc, char * argv[]);
	};
}

源文件

#include "calc.h"

using namespace calculator;
using namespace std;

datahandler dh;
sym symbol_table;

calc::calc(int argc, char* argv[])
{
	try
	{
		dh.init(argc, argv);
	}
	catch (filenotfound e)
	{
		cout << e.what() << endl;
	}
	
	vector<string> lines = dh.getLines();
	int pos = 1;
	for (vector<string>::iterator it = lines.begin(); it < lines.end(); ++it)
	{
		laxer mylaxer(*it, pos);
		try
		{
			mylaxer.getcalc();
		}
		catch (evalerror e)
		{
			cout << e.what() << endl;
		}
		catch (illegalname e)
		{
			cout << e.what() << endl;
		}
		++pos;
	}
}

datahandler

头文件

#pragma once

#include "calch.h"

namespace calculator
{
	class datahandler
	{
	public:
		~datahandler();

		void init(int argc, char * argv[]);
		void handlekeybordinput();
		void handlefileinput();
		void handlechar(char c);
		void output2keybord();
		std::vector<std::string> getLines();

	private:
		std::vector<std::string> lines;
		std::ifstream infile;
		std::string tempstr;
	};
}

源文件

#include "datahandler.h"

using namespace std;
using namespace calculator;

datahandler::~datahandler()
{
	std::vector<std::string>().swap(lines);
	tempstr.clear();
	infile.close();
}

void datahandler::init(int argc, char * argv[])
{
	if (argc == 1)
		handlekeybordinput();
	else
	{
		string filename;
		for (int i = 1; i < argc; i++)
		{
			filename = argv[i];
			infile.open(filename);
			if (!infile.is_open())
				throw filenotfound(filename);
			else
				handlefileinput();
		}
	}
}

void datahandler::handlekeybordinput()
{
	cin >> noskipws;
	char c;
	while (cin >> c)
		handlechar(c);
}

void datahandler::handlefileinput()
{
	char c;
	infile >> noskipws;
	int pos = 0;
	while (!infile.eof())
	{
		infile >> c;
		handlechar(c);
	}	
}

void datahandler::handlechar(char c)
{
	switch (c)
	{
	case ' ':
		break;
	case ';':
		if (tempstr.empty())
			break;
		tempstr.append(1, c);
		lines.push_back(this->tempstr);
		tempstr.clear();
		break;
	case '\n':
		if (tempstr.empty())
			break;
		lines.push_back(this->tempstr);
		tempstr.clear();
		break;
	default:
		tempstr.append(1, c);
		break;
	}	
}

void datahandler::output2keybord()
{
	int pos = 1;
	for (vector<string>::iterator it = lines.begin(); it < lines.end(); ++it)
	{
		cout << pos << "\t" << (*it) << endl;
		++pos;
	}
}

vector<std::string> datahandler::getLines()
{
	return lines;
}

eval

头文件

#pragma once

#include "calch.h"

namespace calculator
{
	class eval
	{
		typedef struct Reverse_Polish_Expression
		{
			Reverse_Polish_Expression(double num)
			{
				data.num = num;
				this->symbol = true;
			}
			Reverse_Polish_Expression(char ch)
			{
				data.op = ch;
				this->symbol = false;
			}

			union data
			{
				double num = 0.0;
				char op;
			}data;
			bool symbol;
		}RPE;
	public:
		eval();
		~eval();

		double calc(std::string line);
		double itercalc(std::string::iterator & begin, std::string::iterator & end);
		void parenthesis_matching(std::string str);
		void ophandler(char op, std::stack<char>& opStack, std::stack<RPE>& num);
		bool isNumber(char ch);
		bool ispartofNumber(char ch);
		bool isOperator(char ch);
		bool isLetter(char ch);
		void symbolhandler(std::string::iterator & it, std::stack<RPE> & num);
		void tranNum(std::string::iterator & it, std::stack<RPE>& num);
		void residueOphandler(std::stack<char>& opStack, std::stack<RPE>& number);
		void reverseStack(std::stack<RPE>& number);
		double RPEhandler(std::stack<RPE>& number);

	private:
		std::string line;
		std::map<char, int> priority;
		std::set<char> op;
	};
}

源文件

#include "eval.h"

using namespace std;
using namespace calculator;

extern sym symbol_table;

eval::eval()
{
	priority['+'] = 1;
	priority['-'] = 1;
	priority['*'] = 2;
	priority['/'] = 2;
	priority['^'] = 3;
	op.insert('+');
	op.insert('-');
	op.insert('*');
	op.insert('/');
	op.insert('^');
}

eval::~eval()
{
	line.clear();
	priority.clear();
	op.clear();
}

double eval::calc(string line)
{
	if (*(line.end() - 1) == ';')
		this->line = line.substr(0, line.length() - 1);
	else
		this->line = line;
	parenthesis_matching(this->line);
	string::iterator itbegin = this->line.begin();
	string::iterator itend = this->line.end();
	return itercalc(itbegin, itend);
}

double eval::itercalc(string::iterator &begin, string::iterator &end)
{
	stack<RPE> num;
	stack<char> opStack;
	bool lasttoken = true;

	for (; begin < end; ++begin)
	{
		if (*begin == '(')
		{
			int n = 1;
			++begin;
			string::iterator nextbegin = begin;
			for (; begin < end; ++begin)
				if (*begin == ')')
				{
					--n;
					if (n == 0)
					{
						num.push(RPE(itercalc(nextbegin, begin)));
						break;
					}
				}
				else if (*begin == '(')
				{
					++n;
				}
			lasttoken = false;
			if (begin >= end)
				break;
		}
		if (lasttoken && ispartofNumber(*begin))
		{
			tranNum(begin, num);
			lasttoken = false;
		}
		else
		{
			if (isOperator(*begin))
			{
				if (lasttoken)
					throw "Operator error.";
				ophandler(*begin, opStack, num);
				lasttoken = true;
			}
			else if (isLetter(*begin))
			{
				symbolhandler(begin, num);
				lasttoken = false;
			}
			else if (*begin == ')')
				continue;
			else
				throw "Unknown operation.";
		}
	}
	if (lasttoken)
		throw "Operator error.";
	residueOphandler(opStack, num);
	reverseStack(num);
	return RPEhandler(num);
}

void eval::parenthesis_matching(string str)
{
	int n = 0;
	for (string::iterator it = str.begin(); it < str.end(); ++it)
	{
		if (*it == '(')
			++n;
		if (*it == ')')
		{
			if (n > 0)
				--n;
			else
				throw "Parenthesis unmatching.";
		}
	}
	if (n != 0)
		throw "Parenthesis unmatching.";
}

void eval::ophandler(char op, stack<char> &opStack, stack<RPE> &num)
{
	while (!opStack.empty() && priority[op] <= priority[opStack.top()])
	{
		num.push(RPE(opStack.top()));
		opStack.pop();
	}
	opStack.push(op);
}

void eval::symbolhandler(string::iterator &it, stack<RPE> &num)
{
	string tempstr;
	tempstr.append(1, *it);
	for (++it; it < line.end(); ++it)
		if (isLetter(*it) || isNumber(*it))
			tempstr.append(1, *it);
		else
			break;
	try
	{
		num.push(RPE(symbol_table.find(tempstr)));
	}
	catch (const char* str)
	{
		throw str;
	}
	--it;
}

void eval::tranNum(string::iterator &it, stack<RPE> &num)
{
	string tempstr;
	double n;
	if (ispartofNumber(*it))
		tempstr.append(1, *it);
	++it;
	for (; it < line.end(); ++it)
		if (isNumber(*it) || *it == '.')
			tempstr.append(1, *it);
		else
			break;
	if (!isNumber(tempstr[0]) && tempstr[0] != '-')
		throw "Operator error.";
	stringstream ss(tempstr);
	ss >> n;
	num.push(RPE(n));
	--it;
}

void eval::residueOphandler(stack<char> &opStack, stack<RPE> &number)
{
	while (!opStack.empty())
	{
		number.push(RPE(opStack.top()));
		opStack.pop();
	}
}

void eval::reverseStack(stack<RPE> &number)
{
	queue<RPE> queue;
	while (!number.empty())
	{
		queue.push(number.top());
		number.pop();
	}
	while (!queue.empty())
	{
		number.push(queue.front());
		queue.pop();
	}
}

double eval::RPEhandler(stack<RPE> &number)
{
	stack<double> result;
	char tempOp;
	double tempnum1, tempnum2;
	while (!number.empty())
	{
		if (number.top().symbol)
		{
			result.push(number.top().data.num);
			number.pop();
		}
		else
		{
			tempOp = number.top().data.op;
			number.pop();
			if (result.size() < 2)
				throw "Operator error.";
			tempnum2 = result.top();
			result.pop();
			tempnum1 = result.top();
			result.pop();
			switch (tempOp)
			{
			case '+':
				result.push(tempnum1 + tempnum2);
				break;
			case '-':
				result.push(tempnum1 - tempnum2);
				break;
			case '*':
				result.push(tempnum1 * tempnum2);
				break;
			case '/':
				result.push(tempnum1 / tempnum2);
				break;
			case '^':
				result.push(pow(tempnum1, tempnum2));
				break;
			default:
				throw "Operator error.";
			}
		}
	}
	if (!number.empty())
		throw "Operator error.";
	if (isinf(result.top()) || isnan(result.top()))
		throw "Divide 0 is not allow.";
	if (result.size() != 1)
		throw "Number error.";
	return result.top();
}

bool eval::isNumber(char ch)
{
	return ch >= '0' && ch <= '9';
}

bool eval::ispartofNumber(char ch)
{
	return isNumber(ch) || ch == '.' || ch == '-' || ch == '+';
}

bool eval::isOperator(char ch)
{
	return op.count(ch) != 0;
}

bool eval::isLetter(char ch)
{
	return ((ch >= 'a'&&ch <= 'z') || (ch >= 'A'&&ch <= 'Z'));
}

evalerror

头文件

#pragma once

#include "calch.h"

namespace calculator
{
	class evalerror
	{
	public:
		evalerror(std::string except, int Line);
		~evalerror();

		std::string what();

	private:
		std::string except;
	};
}

源文件

#include "evalerror.h"

using namespace std;
using namespace calculator;

evalerror::evalerror(string except, int Line)
{
	this->except = "EVALERROR ERROR: " + except + " Line " + to_string(Line);
}

evalerror::~evalerror()
{
	except.clear();
}

string evalerror::what()
{
	return except;
}

filenotfound

头文件

#pragma once

#include "calch.h"

namespace calculator
{
	class filenotfound
	{
	public:
		filenotfound(std::string except);
		~filenotfound();

		std::string what();

	private:
		std::string except;
	};
}

源文件

#include "filenotfound.h"

using namespace calculator;
using namespace std;

filenotfound::filenotfound(string except)
{
	this->except = "FILENOTFOUND ERROR: " + except;
}

filenotfound::~filenotfound()
{
	except.clear();
}

string filenotfound::what()
{
	return except;
}

illegalname

头文件

namespace calculator
{
	class illegalname
	{
	public:
		illegalname(std::string except, int Line);
		~illegalname();

		std::string what();

	private:
		std::string except;
	};
}

源文件

#include "illegalname.h"

using namespace std;
using namespace calculator;

illegalname::illegalname(string except, int Line)
{
	this->except = "ILLEGALNAME ERROR: " + except + " Line " + to_string(Line);
}

illegalname::~illegalname()
{
	except.clear();
}

string illegalname::what()
{
	return except;
}

lexer

头文件

namespace calculator
{
	class lexer
	{
		enum ChooseSymbol
		{
			num, symbol, token
		};
	public:
		lexer(std::string line, int Lnum);
		~lexer();

		void getcalc();
		void symbolhandle(std::string str);
		bool isLetter(const char ch);
		bool isNumber(const char ch);

	private:
		int Lnum;
		double ans;
		std::vector<std::string> s;
		std::string line;
		enum ChooseSymbol cs;
	};
}

源文件

#include "lexer.h"

using namespace calculator;
using namespace std;

extern sym symbol_table;
eval myeval;

lexer::lexer(string line, int Lnum)
{
	this->line = line;
	this->Lnum = Lnum;
}

lexer::~lexer()
{
	s.clear();
	line.clear();
}

void lexer::getcalc()
{
	int equalpos = line.find("=");
	bool flag = *(line.end() - 1) == ';';
	if (equalpos > -1)
	{
		try
		{
			ans = myeval.calc(line.substr(equalpos + 1));
		}
		catch (const char* str)
		{
			throw evalerror(str, Lnum);
		}
		try
		{
			symbolhandle(line.substr(0, equalpos));
		}
		catch (const char* str)
		{
			throw illegalname(str, Lnum);
		}
		if (!flag)
			cout << line.substr(0, equalpos) << " = " << ans << endl;
	}
	else
	{
		try
		{
			if (flag)
				ans = myeval.calc(line.substr(0, line.length() - 1));
			else
				ans = myeval.calc(line);
		}
		catch (const char* str)
		{
			throw evalerror(str, Lnum);
		}
		symbol_table.add("ans", ans);
		if (!flag)
			cout << "ans = " << ans << endl;
	}
}

void lexer::symbolhandle(string str)
{
	string tempsym;
	string::iterator it = str.begin();
	if (!isLetter(*it))
		throw "Not conform to the standard.";
	for (; it < str.end(); ++it)
		if (!(isLetter(*it) || isNumber(*it)))
			throw "Not conform to the standard.";
		else
			tempsym.append(1, *it);
	symbol_table.add(tempsym, ans);
}

bool lexer::isLetter(const char ch)
{
	return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}

bool lexer::isNumber(const char ch)
{
	return (ch >= '0' && ch <= '9');
}

sym

头文件

#pragma once

#include "calch.h"

namespace calculator
{
	class sym
	{
	public:
		sym();
		~sym();

		void add(std::string symbol, double num);
		double find(std::string symbol);

	private:
		std::map<std::string, double>table;
	};
}

源文件

#include "sym.h"

using namespace calculator;

sym::sym()
{
	table["e"] = 2.71828182845904523536;
	table["pi"] = 3.14159265358979323846;
}

sym::~sym()
{
	table.clear();
}

void sym::add(std::string symbol, double num)
{
	table[symbol] = num;
}

double sym::find(std::string symbol)
{
	if (table.count(symbol) == 0)
		throw "No such symbol.";
	return table[symbol];
}

代码说明

数据结构:eval.h中定义了逆波兰表达式所需的节点,其中包含一个联合体data与symbol,data为了表示数据,symbol用于区分数字与符号。

typedef struct Reverse_Polish_Expression
{
	Reverse_Polish_Expression(double num)
	{
		data.num = num;
		this->symbol = true;
	}
	Reverse_Polish_Expression(char ch)
	{
		data.op = ch;
		this->symbol = false;
	}

	union data
	{
		double num = 0.0;
		char op;
	}data;
	bool symbol;
}RPE;

算法1 int main()
作 用:主控函数,也实现对题目所需其他内容的测试。
参 数:int argc, char* argv[]:命令行参数
返回值:总是返回0。
计算过程:
创建calc类,名为mycalc。

类1 calc类
算法1.1 构造器calc::calc()
作 用:构造计算器,处理各类跑出的异常。
参 数:int argc, char* argv[]:命令行参数
返回值:无
计算过程:
(1) try/catch语句,调用数据处理类,该类调用算法2.1,处理filenotfound错误。
(2) 调用数据处理类,该类调用算法2.2,返回值赋值给lines。
(3) 循环遍历lines,读取lines中每一元素。
(4) try/catch语句,将lines中元素给语法分析类,该类调用算法3.2,处理evalerror与illegalname错误。

类2 datahandler类
算法2.1 void datahandler::init(int argc, char * argv[])
作 用:初始化状态,判断数据来源。
参 数:int argc, char * argv[]:命令行参数
返回值:无
计算过程:
(1) 判断argc为1,调用算法2.3。
(2) 判断argc不为1,循环遍历argv,将其当做文件名处理,如果文件找不到,抛出异常filenotfound;否则调用算法2.4。

算法2.2 vectorstd::string datahandler::getLines()
作 用:返回私有成员lines
参 数:无
返回值:lines
计算过程:
返回私有成员lines。

算法2.3 void datahandler::handlekeybordinput()
作 用:处理键盘输入
参 数:无
返回值:无
计算过程:
(1) 将cin模式调为不跳过结束符。
(2) 每次读入一个字符,并调用算法2.5。

算法2.4 void datahandler::handlefileinput()
作 用:处理文件输入
参 数:无
返回值:无
计算过程:
(1) 将文件内容按字符输入,不调过结束符。
(2) 每次读入一个字符,并调用算法2.5。

算法2.5 void datahandler::handlechar(char c)
作 用:处理一个字符
参 数:char c:传入字符
返回值:无
计算过程:
(1) 如果c是空格就退出。
(2) 如果c是‘;’,如果tempstr为空,则退出;否则,就将其接在tempstr后面,之后在lines中加入tempstr。
(3) 如果c是‘\n’,如果tempstr为空,则退出;否则,在lines中加入tempstr。
(4) 如果c都不满足上述条件,就将其接在tempstr后面。

类3 laxer类
算法3.1 构造器laxer::laxer(string line, int Lnum)
作 用:为成员变量赋值
参 数:
string line:一行
int Lnum:行号
返回值:无
计算过程:
为成员变量赋值

算法3.2 void laxer::getcalc()
作 用:进行语法分析
参 数:无
返回值:无
计算过程:
(1) 找到成员变量line中的‘=’,以此作为分隔,前面为新增符号,后面为表达式。
(2) 判断语句结尾是否有‘;’,有则为真,将结果赋值给flag。
(3) 判断‘=’位置,如果有,则调用算法4.2计算表达式的值并赋值给ans,并处理异常,之后调用算法3.3,处理赋值;如果没有,则调用算法4.2计算表达式的值并赋值给ans,并处理异常,之后将值放入符号表中ans项。
(4) 判断flag,如果为真,输出结果,符号为自定义符号,如果为假,则输出符号ans的值。

算法3.3 void laxer::symbolhandle(string str)
作 用:处理符号,检查是否为不符合规定的符号。
参 数:string str:符号
返回值:无
计算过程:
(1) 先检查符号的第一位,不为字母,则抛出异常。
(2) 后面如果出现不为字母或数字的字符,则抛出异常。
(3) 如果符合标准,则将该符号加入符号表,并将赋值为ans的值。

算法3.4 bool laxer::isLetter(const char ch)
作 用:判断是否为字母
参 数:const char ch:传入字符
返回值:(ch >= ‘a’ && ch <= ‘z’) || (ch >= ‘A’ && ch <= ‘Z’)
计算过程:
判断传入字符是否为字母。

算法3.5 bool laxer::isNumber(const char ch)
作 用:判断是否为数字
参 数:const char ch:传入字符
返回值:(ch >= ‘0’ && ch <= ‘9’)
计算过程:
判断传入字符是否为数字。

类4 eval类
算法4.1 构造器eval::eval()
作 用:初始化成员变量
参 数:无
返回值:无
计算过程:
初始化成员变量,为各个运算符分配优先级。

算法4.2 double eval::calc(string line)
作 用:计算表达式值,将表达式看做由很多括号括起来的子式,之后迭代计算。
参 数:string line:表达式
返回值:表达式的值
计算过程:
(1) 判断表达式后是否有‘;’,有就去掉。
(2) 调用算法4.3,检查括号是否匹配。
(3) 调用算法4.4。

算法4.3 void eval::parenthesis_matching(string str)
作 用:判断括号是否匹配
参 数:string str:表达式
返回值:无
计算过程:
(1) 使用一个整数n。
(2) 每次遇到‘(’,n就累加1,每次遇到‘)’,判断是否小于0,是就抛出异常,不是n就减1。
(3) 结束循环后,检查n是否为0,不是就抛出异常。

算法4.4 double eval::itercalc(string::iterator &begin, string::iterator &end)
作 用:计算一个算术子式,即计算一个无括号算式。
参 数:string::iterator &begin:算术子式的开头
string::iterator &end:算术子式的结尾
返回值:算术子式的值
计算过程:
使用逆波兰表达式计算算术子式。
(1) 使用栈,第一个栈为运算符栈,其中使用结构为结构体RPE,第二个栈为操作符栈。
(2) 扫描整个字符串,读入为数字或者符号,则压入运算符栈,读入为操作符,则按照逆波兰表达式的规则压入运算符栈或者操作符栈,这里运算符栈结构为结构体RPE,使用symbol来区分是操作符还是数字。
(3) 在扫描过程中,发现‘(’,则把这个括号当做起始位置,向后找到与之对应的‘)’,之后将其中的式子当做子式,调用算法4.4,进行下一轮循环,将迭代结果压入运算符栈中。
(4) 最外层的迭代返回整个式子的结果。

算法4.5 void eval::ophandler(char op, stack &opStack, stack &num)
作 用:处理操作符
参 数:
char op:操作符
stack &opStack:操作符栈
stack &num:运算符栈
返回值:无
计算过程:
解决逆波兰表达式中运算符优先级问题。

算法4.6 void eval::symbolhandler(string::iterator &it, stack &num)
作 用:处理符号
参 数:
string::iterator &it:符号在字符串中出现的开始位置
stack &num:运算符栈
返回值:无
计算过程:
检测符号,将符号转换为数字并压入运算符栈,没有该运算符则抛出异常。

算法4.7 void eval::tranNum(string::iterator &it, stack &num)
作 用:处理数字
参 数:
string::iterator &it:数字在字符串中出现位置
stack &num:运算符栈
返回值:无
计算过程:
检测数字,将字符串转换为数字并压入运算符栈。

算法4.8 void eval::residueOphandler(stack &opStack, stack &number)
作 用:将操作符栈剩余的操作符压入运算符栈
参 数:
stack &opStack:操作符栈
stack &number:运算符栈
返回值:无
计算过程:
将操作符栈剩余的操作符压入运算符栈

算法4.9 void eval::reverseStack(stack &number)
作 用:翻转运算符栈
参 数:
stack &number:运算符栈
返回值:无
计算过程:
用队列将运算符栈翻转

算法4.10 double eval::RPEhandler(stack &number)
作 用:处理逆波兰表达式
参 数:
stack &number:运算符栈
返回值:逆波兰表达式计算结果
计算过程:
(1) 建立一个结果栈,从运算符栈中弹出项,如果为数字,则直接压入结果栈,如果是符号,则从结果栈中弹出两个数字,进行运算后压入结果栈中。
(2) 判断操作数栈是否为空,不为空抛出异常。
(3) 判断结果栈栈顶是否为inf,是则抛出异常。
(4) 判断结果栈大小是否为1,不是则抛出异常。
(5) 返回结果栈顶。

算法4.11 bool eval::isNumber(char ch)
作 用:判断是否为数字,
参 数:
char ch:输入字符,
返回值:true则为是,false则为否,
计算过程:
判断是否为数字,

算法4.12 bool eval::ispartofNumber(char ch)
作 用:判断是否为一个数字的一部分,
参 数:
char ch:输入字符,
返回值:true则为是,false则为否,
计算过程:
判断是否为一个数字的一部分,

算法4.13 bool eval::isOperator(char ch)
作 用:判断是否为操作符,
参 数:
char ch:输入字符,
返回值:true则为是,false则为否,
计算过程:
判断是否为操作符,

算法4.14 bool eval::isLetter(char ch)
作 用:判断是否为字母。
参 数:
char ch:输入字符。
返回值:true则为是,false则为否。
计算过程:
判断是否为字母。

类5 sym类
算法5.1 构造器sym::sym()
作 用:初始化符号表。
参 数:无
返回值:无
计算过程:
初始化符号表。

算法5.2 void sym::add(std::string symbol, double num)
作 用:向符号表中添加元素。
参 数:
std::string symbol:符号。
double num:符号的值。
返回值:无
计算过程:
在符号表中插入键为symbol,值为num的项。

算法5.3 double sym::find(std::string symbol)
作 用:在符号表里查找一个元素。
参 数:
std::string symbol:需要查找的元素的键值。
返回值:键的值
计算过程:
先查找是否有该元素,如果没有就抛出异常,有就返回键的值。

类6 evalerror类
算法6.1 构造器evalerror::evalerror(string except, int Line)
作 用:初始化类
参 数:
string except:抛出异常的内容。
int Line:行号。
返回值:无
计算过程:
初始化成员

算法6.2 string evalerror::what()
作 用:返回错误内容。
参 数:无
返回值:错误内容
计算过程:
返回错误内容。

类7 filenotfound类
算法7.1 构造器filenotfound::filenotfound(string except)
作 用:初始化类
参 数:
string except:抛出异常的内容。
int Line:行号。
返回值:无
计算过程:
初始化成员

算法7.2 string filenotfound::what()
作 用:返回错误内容。
参 数:无
返回值:错误内容
计算过程:
返回错误内容。

类8 illegalname类
算法8.1 构造器illegalname::illegalname(string except, int Line)
作 用:初始化类
参 数:
string except:抛出异常的内容。
int Line:行号。
返回值:无
计算过程:
初始化成员

算法8.2 string illegalname::what()
作 用:返回错误内容。
参 数:无
返回值:错误内容
计算过程:
返回错误内容。

测试结果

输入1

b=7
c=21
a=3
a^2
A^2
9abc=5+6;
9/0
1/0-1/0
a*(2+3)
^1+1
1**2
1&+2
1(2+3*)
^Z

输出1

b = 7
c = 21
a = 3
ans = 9
EVALERROR ERROR: No such symbol. Line 5
ILLEGALNAME ERROR: Not conform to the standard. Line 6
EVALERROR ERROR: Divide 0 is not allow. Line 7
EVALERROR ERROR: Divide 0 is not allow. Line 8
ans = 15
EVALERROR ERROR: Operator error. Line 10
EVALERROR ERROR: Operator error. Line 11
EVALERROR ERROR: Unknown operation. Line 12
EVALERROR ERROR: Operator error. Line 13

输入2

a=4;b=3;c=a+b;d=haha
a
b
c
^Z

输出2

EVALERROR ERROR: No such symbol. Line 4
ans = 4
ans = 3
ans = 7

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FishPotatoChen

谢谢您的支持,我会更努力的~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值