1. 程式人生 > >C++程式設計語言 計算器原始碼

C++程式設計語言 計算器原始碼

首先是課本最早出現的原始碼,可以執行

#include "pch.h"
#include <iostream>
#include<string>
#include<cctype>
#include<map>
#include<sstream>

using namespace std;

enum Token_value{

	NAME,NUMBER,END,
	PLUS='+',MINUS='-',MUL='*',DIV='/',
	PRINT=';',ASSIGN='=',LP='(',RP=')'

};
Token_value curr_tok = PRINT;

int no_of_errors;
double term(bool get);
string string_value;
double number_value;

double error(const string&s)
{
	no_of_errors++;
	cout << "error" << s << '\n';
	return 1;
}

Token_value get_token()
{
	char ch = 0;
	cin >> ch;
	switch (ch) {
	case 0:
		return curr_tok = END;
	case';':
	case'*':
	case'/':
	case'+':
	case'-':
	case'(':
	case')':
	case'=':
		return curr_tok = Token_value(ch);
	case'0':case'1':case'2':case'3':case'4':case'5':
	case'6':case'7':case'8':case'9':case'.':
		cin.putback(ch);
		cin >> number_value;
	default:
		if (isalpha(ch)) {
			string_value = ch;
			while (cin.get(ch) && isalnum(ch));
			string_value.push_back(ch);
			return curr_tok = NAME;
		}
		error("bad token");
		return curr_tok = PRINT;
		return curr_tok = NUMBER;
	}
}

double expr(bool get) {
	double left = term(get);
	for(;;)
		switch (curr_tok)
		{
		case PLUS:
			left += term(true);
			break;
		case MINUS:
			left -= term(true);
			break;
		default:
			return left;
		}
}


double prim(bool get) {
	if (get) get_token();
	switch (curr_tok)
	{
	case NUMBER:
	{
		double v = number_value;
		get_token();
		return v;
	}
	case NAME:
	{
		double&v = number_value;
		if (get_token() == ASSIGN)
			v = expr(true);
		return v;
	}
	case MINUS:
		return -prim(true);
	case LP:
	{
		double e = expr(true);
		if (curr_tok != RP)
			return error(")needed");
		get_token();
		return e;
	}
	default:
		return error("引數缺少");
	}
}

double term(bool get) {
	double left = prim(get);
	for(;;)
		switch (curr_tok) {
		case MUL:
			left *= prim(true);
			break;
		case DIV:
			if (double d = prim(true)) {
				left /= d;
				break;
			}
			return error("divide by 0");
		default:
			return left;
		}

}

istream* input;
int main(int argc,char* argv[] )
{
	switch (argc)
	{
		case 1:
		{
			input = &cin;
			break;
		}	
		case 2:
		{
			input = new istringstream(argv[1]);
			break;
		}
		
		default:
			error("too many!");
			return 1;
	}
	
	while (*input)
	{
		get_token();
		if (curr_tok == END)break;
		if (curr_tok == PRINT) continue;
		cout << expr(false) << '\n';
	}
	if (input != &cin)
		delete input;
	
	return no_of_errors;
}

加入名稱空間以及異常處理內容後的終極版本

#include "pch.h"
#include <iostream>
#include<string>
#include<cctype>
#include<map>
#include<sstream>

using namespace std;

namespace Error {

	struct Zero_divide
	{

	};
	struct Syntax_error {
		const char*p;
		Syntax_error(const char*q) { p = q; }
	};
	struct Range_error {
		int i;
		Range_error(int ii) { i = ii; }
	};
}


namespace Parser {
	using namespace Error;
	double expr(bool get);
	double prim(bool get);
	double term(bool get);


}

namespace Lexer {
	enum Token_value {

		NAME, NUMBER, END,
		PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
		PRINT = ';', ASSIGN = '=', LP = '(', RP = ')'

	};
	Token_value curr_tok = PRINT;

	Token_value get_token();
	string string_value;
	double number_value;

};





double Parser::expr(bool get) {
	using Lexer::curr_tok;
	using Lexer::PLUS;
	using Lexer::MINUS;


	double left = term(get);
	for (;;)
		switch (curr_tok)
		{
		case PLUS:
			left += term(true);
			break;
		case MINUS:
			left -= term(true);
			break;
		default:
			return left;
		}
}






double Parser::prim(bool get) {
	if (get) Lexer::get_token();
	switch (Lexer::curr_tok)
	{
	case Lexer::NUMBER:
	{
		double v = Lexer::number_value;
		Lexer::get_token();
		return v;
	}
	case Lexer::NAME:
	{
		double&v = Lexer::number_value;
		if (Lexer::get_token() == Lexer::ASSIGN)
			v = expr(true);
		return v;
	}
	case Lexer::MINUS:
		return -prim(true);
	case Lexer::LP:
	{
		double e = expr(true);
		if (Lexer::curr_tok != Lexer::RP)
			throw Error::Syntax_error("引數缺少");
		Lexer::get_token();
		return e;
	}
	default:
		throw Error::Syntax_error("引數缺少");
	}
}

double Parser::term(bool get) {
	double left = prim(get);
	for (;;)
		switch (Lexer::curr_tok) {
		case Lexer::MUL:
			left *= prim(true);
			break;
		case Lexer::DIV:
			if (double d = prim(true)) {
				left /= d;
				break;
			}
			throw Error::Zero_divide();
		default:
			return left;
		}

}


Lexer::Token_value Lexer::get_token()
	{
		char ch = 0;
		cin >> ch;
		switch (ch) {
		case 0:
			return curr_tok = END;
		case';':
		case'*':
		case'/':
		case'+':
		case'-':
		case'(':
		case')':
		case'=':
			return curr_tok = Token_value(ch);
		case'0':case'1':case'2':case'3':case'4':case'5':
		case'6':case'7':case'8':case'9':case'.':
			cin.putback(ch);
			cin >> number_value;
			return curr_tok = NUMBER;
		default:
			if (isalpha(ch)) {
				string_value = ch;
				while (cin.get(ch) && isalnum(ch));
				string_value.push_back(ch);
				return curr_tok = NAME;
			}
			throw Error::Syntax_error("bad token");
			return curr_tok = PRINT;
			return curr_tok = NUMBER;
		}
	}


//驅動模組。
namespace Driver {
	int no_of_errors;
	istream* input;
	void skip();
}
void Driver::skip() {
	//skip函式將繼續讀取輸入知道遇到換行或者分號時,返回。
	no_of_errors++;

	while (*input) {
		char ch;
		input->get(ch);

		switch (ch) {
		case'\n':
		case';':
			return;
		}
	}
}





int main(int argc, char* argv[])

	{
	try {
		switch (argc)
		{
		case 1:
		{
			Driver::input = &cin;
			break;
		}
		case 2:
		{
			Driver::input = new istringstream(argv[1]);
			break;
		}

		default:
			throw Error::Range_error(1);
		}
	}
	catch (Error::Range_error) {
		cout << "too many";
		Lexer::curr_tok = Lexer::PRINT;
	}
	/*using namespace Lexer;
	using namespace Parser;
	while (*Driver::input)
		try{
			get_token();
			if (curr_tok == END)break;
			if (curr_tok == PRINT) continue;
			cout << expr(false) << '\n';
		}
		catch(Error::Zero_divide){
			cerr << "不可除以零。\n";
			if (Lexer::curr_tok != Lexer::PRINT)Driver::skip();
			//skip()將嘗試把程式恢復到一個可以執行的情形。
		}
		catch(Error::Syntax_error e){
			cerr << "格式錯誤。" << e.p << '\n';
			if (Lexer::curr_tok != Lexer::PRINT)Driver::skip();
		}
		if (Driver::input != &cin)
			delete Driver::input;
		//釋放空間。

		return Driver::no_of_errors;*/

	bool in_error = false;
	//這種處理方式會導致錯誤的輸入依然殘留,所以還會報錯,不夠優秀。
	while (*Driver::input) {
		try {
			Lexer::get_token();
			if (Lexer::curr_tok == Lexer::END)break;
			if (Lexer::curr_tok == Lexer::PRINT) {
				in_error = false;
				continue;
			}
			if (in_error == false)cout << Parser::expr(false) << '\n';
		}
		catch (Error::Zero_divide) {
			cerr << "嘗試除以零\n";
			in_error = true;
		}
		catch (Error::Syntax_error e) {
			cerr << "格式錯誤:" << e.p << '\n';
			in_error = true;
			cout << "error引數被順利更改\n";
		}
		if (Driver::input != &cin)
			delete Driver::input;
		//釋放空間。

		return Driver::no_of_errors; 

	}
	}