○逆ポーランド法みたいな電卓

VisualC++ 6.0で作成しました

計算式をそのまま入力すると計算してくれる計算機です
たとえば、
1+(1+1)*2
など、入力すると計算結果が出力されます
ちゃんと演算子の優先順位を判断して計算を行います

プログラムと実行ファイル

#pragma warning( disable : 4786 )
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector> 
#include <stack>

//文字列の複製
void strcpy(char*a,char*b){
	while(*a++=*b++);
}

//文字列のスペースをすべて取り除く
void trim(char*str){
	if(' '==*str) strcpy(str,str+1);
	if(*str++) trim(str);
}

//文字列をトークンごとに切り出し
void token(char*str,std::vector<std::string>*data){
	char pos;
	std::string strpos="";
	while(pos=*str++){
		switch (pos){
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			strpos=strpos+pos;
			break;
		case '+':
			if(strpos!="") data->push_back(strpos);
			strpos="";
			data->push_back("+");
			break;
		case '-':
			if(strpos!="") data->push_back(strpos);
			strpos="";
			data->push_back("-");
			break;
		case '*':
			if(strpos!="") data->push_back(strpos);
			strpos="";
			data->push_back("*");
			break;
		case '/':
			if(strpos!="") data->push_back(strpos);
			strpos="";
			data->push_back("/");
			break;
		case '(':
			if(strpos!="") data->push_back(strpos);
			strpos="";
			data->push_back("(");
			break;
		case ')':
			if(strpos!="") data->push_back(strpos);
			strpos="";
			data->push_back(")");
			break;
		default:
			break;
		}
	}
	if(strpos!="") data->push_back(strpos);
}

//トークンであるか確認
bool isToken(std::string str){
	if(str=="+" || str=="-" || str=="*" || str=="/") return true;
	return false;
}

//トークンの整形する
void tokenAna(std::vector<std::string>*in,std::vector<std::string>*out){
	if(isToken((*in)[0])){
		(*in)[1]=(*in)[0]+(*in)[1];
	}else{
		out->push_back((*in)[0]);
	}

	for(int i=1;i<in->size();i++) {
		if(isToken((*in)[i])){
			if(isToken((*in)[i-1])){
				(*in)[i+1]=(*in)[i]+(*in)[i+1];
			}else{
				if((*in)[i-1]=="("){
					(*in)[i+1]=(*in)[i]+(*in)[i+1];
				}else{
					out->push_back((*in)[i]);
				}
			}
		}else{
			out->push_back((*in)[i]);
		}
	}
}



//逆ポーランド法に変換するための演算子の優先順位を決定
int Priority(const char*str){
	if(0==strcmp(str,"+")) return 10;
	if(0==strcmp(str,"-")) return 10;
	if(0==strcmp(str,"*")) return 20;
	if(0==strcmp(str,"/")) return 20;
	return 0;
}

//数式を逆ポーランド法に変換
void Analyzer(std::vector<std::string>*data,std::vector<std::string>*out,int*i){
	std::stack<const char*> stack;

	for(;*i<data->size();(*i)++){
		if((*data)[*i]=="+" || (*data)[*i]=="-" || (*data)[*i]=="*" || (*data)[*i]=="/"){
			while(stack.empty()==false && //false : スタックに値がある
				!(Priority((*data)[*i].c_str())>Priority(stack.top()))){ 
					const char*str=stack.top();//最後尾の値の取得
					stack.pop();//最後尾の値の削除
					out->push_back(str);
			}
			stack.push((*data)[*i].c_str());//値の追加
		}else{
			if((*data)[*i]=="("){
				*i=*i+1;
				Analyzer(data,out,i);
			}else{
				if((*data)[*i]==")"){
					goto end;
				}else{
					out->push_back((*data)[*i]);
				}
			}
		}
	}
end:
	while(stack.empty()==false){//false : スタックに値がある
		const char*str=stack.top();//最後尾の値の取得
		stack.pop();//最後尾の値の削除
		out->push_back(str);
	}
}

//逆ポーランド法表記の計算式を計算
double calc(std::vector<std::string>*out){
	int c=out->size();
	std::stack<double> stack;
	double j,k;
	for(int i=0;i<c;i++){
			if((*out)[i]== "+"){
				j=stack.top();
				stack.pop();
				k=stack.top();
				stack.pop();
				stack.push(k+j);
			}else if((*out)[i]=="-"){
				j=stack.top();
				stack.pop();
				k=stack.top();
				stack.pop();
				stack.push(k-j);
			}else if((*out)[i]=="*"){
				j=stack.top();
				stack.pop();
				k=stack.top();
				stack.pop();
				stack.push(k*j);
			}else if((*out)[i]=="/"){
				j=stack.top();
				stack.pop();
				k=stack.top();
				stack.pop();
				stack.push(k/j);
			}else{
				stack.push(atof((*out)[i].c_str()));
			}
		}
	return stack.top();
}

int main(){
	printf("%s\n","((-10+-20)*((30+40))+1)*2 [Enter] の様に入力してください");
	printf("--------------------------------------\n");
	while(1){
		std::vector<std::string> data;
		std::vector<std::string> out;

		//文字列として入力
		char str[1024];
		scanf("%s",str);
		trim(str);
		token(str,&data);
		
		std::vector<std::string> data2;
		tokenAna(&data,&data2);

		{printf("トークン切り出し結果 : ");for(int a=0;a<data2.size();a++) printf("%s ",data2[a].c_str());}
		
		int c=0;
		Analyzer(&data2,&out,&c);

		{printf("\n逆ポーランド法に変換 : ");for(int a=0;a<out.size();a++) printf("%s ",out[a].c_str());}
		printf("\n計算結果 : ");printf("%g\n",calc(&out));
		printf("--------------------------------------\n");
	}
	getchar();
	return 0;
}




▲トップページ > プログラミングの実験