컴퓨터를 정리하다보니, 또 재미난 소스가 있어서 올려본다.


바로 이전 포스트 다항식 연산은 아주 간단한 과제였는데, 지금 보니 계산기를 만들어라는 과제도 있었던 것 같아서 찾아보니 역시나 있다.


내 기억에 이 과제를 하면서, "아! 계산기가 이렇게 복잡하게 동작하는거였어???" 하면서 힘들어했던 10년전의 내모습이 떠오른다 ㅎㅎㅎ


저 깨알 같은 주석들..., 주석이 코드보다 더 많다 ㅎㅎㅎㅎ



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 제작기간 : 2002.10.9 ~ 2002.10.13                                                                          
// 사용가능 연산자 : {"!","&&","||","==","!=","<",">","<=",">=","^","*","/","%","+","-","@"},(,)   
// 지원가능한 수식의 길이 : 80으로 설정됨(수정가능)                                                   
// 특이사항: 수식 오류 검사                                                                                     
// 지원 operand : -9에서 9까지(수정가능)                                                                 
// 입력 : c:\data 파일                                                                              
// 사용언어 및 컴파일러 : Visual C++ Enterprise,(C언어 구조 사용)                                                       
// 테스트 환경 : Intel Pentium3 866MHz                                                                                 
//               512MB Memory                                                                                           
// Test 내용 : Report파일 첨부                                                                                         
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <stdio.h>  //기본 입출력 함수사용을 위해
#include <string.h> //스트링 조작 함수사용을 위해
#include <stdlib.h> //atoi() 입력받은 문자를 정수로 변환하기 위한 함수사용을 위해
#include <math.h>   //pow()사용을 위해

#define MAX_EQS_SIZE 80  //입력받는 수식의 최대길이를 80으로 설정한다.
                         //예를 들어 9*1-8+1*(-1)은 12가 된다.
#define DATAFILE "C:\\data" //입력 파일을 정의
#define OPERATOR 1   //OPERATOR 라는 값을 1로 설정(스택 연산시에 쓰기 위해 )
#define OPERAND 0    //OPERAND 라는 값을 0으로 설정(스택 연산시에 쓰기 위해)

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//전역변수 변수선언부

static char operator_priority_table[16][3]={"!","&&","||","==","!=","<",">","<=",">=","^","*","/","%","+","-","@"};
 //메모리의 낭비가 있더라도 ,길이가 2인 연산자가 있어서 배열로 선언 했음.
 //15개의 연산자 우선순위 선언(@:연산자우선순위끝)
 //논리,비교,산술연산자들의 우선순위대로 배열에 저장(비주얼씨 도움말참조)
 //부정부호 (-) 따로 처리
 //지수연산은 연산 방향 right --> left 을 고려해서 처리할것
 //나중에 새로운 연산자를 추가 할경우에는 우선순위를 고려하여서 추가하고, 배열의 1차원 크기를 조정해줄것.
static char can_be_first[3]={'(','-','!'}; //수식의 처음에 올수 있는 operator들을 정의, '-'가 제일 처음오면 부호로 처리
static char can_be_last[1]={')'};          //수식의 마지막에 올수 있는 operator를 정의
static char can_be_after_operator[2]={'(','!'};   //operator 뒤에 올수 있는 operator 정의,
                                                  //그리고 이들은 operand뒤에는 올수없다.

char output[MAX_EQS_SIZE];             //변환된 수식 저장
int output_flag=0; //결과 식을 출력할지 안할지 셋팅 0:출력안함 ,1:출력(마지막 스텝에서 1로 셋팅)

char eqs[MAX_EQS_SIZE];                //수식을 저장하기 위한 문자열변수를 선언한다.
char operator_stack[MAX_EQS_SIZE][3];  //operator의 스택을 선언
int operand_stack[MAX_EQS_SIZE];       //operand의 스택을 선언
int top_of_operator_stack=-1;          //operator스택의 top선언
int top_of_operand_stack=-1;           //operand스택의 top선언
int top_operand=0;                     //top_operand 선언
int temp_operand=0;                    //오퍼랜드 임시 저장을 위해
char top_operator[3]={""};             //top_operator 선언
char top_new_operand[6]={""};          //계산된 결과 값을 새로운 오퍼랜드함수에 저장하기 위해서.	
int pairs_Gualho=0;            //괄호의 짝이 맞아야 한다.

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//함수 선언부

void process(); //operand 두개를 operator로 계산하는 함수
int is_next_correct_operator(char,char) ; //operand 다음에 오는 연산자가 올바른 것인지 검사 
void correct_operator(char,char); //operator뒤에 다른 operator가 올때 바른 연산자인지 검사 (can_be_after_operator참조
int is_operand(char);             //operand인지 검사 1:true 0:false
int is_operator(char *);          //operator인지 검사 1:true 0:false
int empty(int);                 //스택이 비었는지 검사    입력:operator_stack은 1,operand_stack은 0 : empty=1
int full(int);                  //스택이 가득 찾는지 검사 입력:operator_stack은 1,operand_stack은 0 : full=1
void scan_eqs();                //수식을 스캔하는 루틴
void error_eqs(int);                       // 수식의 오류메세지 출력 입력이 1이면 오류 없음,무시, 그렇지 않으면 오류 있음
int compare_operator(char *isp,char *icp); //  2 isp,icp우선순위가 같다.
                                           //  0: isp가 우선순위가 높다.
                                           //  1: icp가 우선순위가 높다.
void compute(int sign,char *token);//토큰을 가지고 계산하는 함수. sign에는 토큰이 '-'일때 부호인지 연산자인지 지정.
                                   //process호출
                                   //특별한 경우 를 검사 ('^','(',')','!')이런 경우에는 다른 조치를 취한후 process호출
int pop_operand();     //operand를 팝하는 함수
char *pop_operator();  //operator를 팝하는 함수
void push(char *token,int type); //푸시 함수 type는 operand인지 operator인지 지정
void print_status(int);          //스택의 상태, 결과값, postfix output을 출력하는 함수
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                                       
//main()의 시작
//파일을 열어서 수식을 입력받아서 배열에 저장한다.
//수식의 끝을 알려주는 '#'를 만듬.
//scan_eqs함수 호출

void main()
{
	int i=0;                 //수식의 배열 위치를 가리키기 위한 변수선언
	FILE *data;              //파일으로 부터 입력을 받기 위해서 파일 포인터 선언.

	if((data=fopen(DATAFILE,"r"))==NULL){      //지정 위치의 파일을 열지 못 할 경우에 에러 메세지 출력
		printf("\n파일을 열수가 없습니다.\n");  
		exit(0);
	}
    
	while(!(feof(data))) //파일로 부터 수식을 입력받는다.
	{
	    
		eqs[i]=fgetc(data);//파일의 수식들을 문자 하나 하나씩 입력받아서 배열에 저장한다.
	    if(eqs[i]==' ') //공백이 있을경우에는 i의 값을 하나 줄여주는 트릭을 사용해서 공백을 제거한다.
			i--;
		i++;
	}
	fclose(data);//파일을 닫는다.이제는 파일이 더이상 필요없으므로.
	eqs[i-1]='#'; //End of String의 값을 #로 셋팅함
	eqs[i]=NULL;  //문자열의 끝에 널문자를 추가해준다.
	printf("\n입력받은 수식은 %s 입니다.\n",eqs);//입력받은 수식을 확인하기 위해서.
	scan_eqs();  //infix수식을 postfix로 변화하고 계산한후 결과를 출력함수를 호출한다.	
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//scan_eqs()정의
//토큰을 분리해서 compute()함수
//처음에 올수 있는 연산자인지 검사하고,마지막에 올수 있는 함수 인지 검사
//올바른 연산자인지 검사
//올바른 operand 인지 검사
void scan_eqs()//한번의 스캔으로 ibfix->postfix변환,연산 수행
{
	char token[3]={""};//토큰을 저장할 공간 마련 길이가 3인 문자열 변수
	int i=0,j=0,flag=0;//i는 배열에 저장된 수식을 읽어오기 위한것, flag는 수식의 오류를 검사 1:오류 없음,0:오류 있음
    

	token[0]=eqs[0]; //수식의 처음에 올수 있는 수식을 확인해서 오류 확인을 위해서.처음 토큰을 검사한다.
	j=0;
	while(j!=(sizeof(can_be_first)/sizeof(can_be_first[0])))//처음에 올수있는 연산자갯수만큼 루트
	{
		if(token[0]==can_be_first[j])//처음에 올수 있는 연산자일경우는 오류없음
		{
			flag=1;
		}
		else if(is_operand(token[0]))//operand일경우도 오류 없음
		{
			flag=1;
		}
		j++;
    }
	
	error_eqs(flag);//에러 있는지 없는지 확인후 에러메세지 출력
    
	while(flag&&(!(eqs[i]=='#')))//토큰 분리 루프
	{	
		int sign=0;    //토큰이 '-'가 왔을때 부호표시 인지 연산자인지 구분
		switch(eqs[i]) //Operator를 만드는 과정 오페레이터들의 길이가 1이 아닌것도 있으므로 스트링으로 통일해서 만든다.
                       //Str_Operand를 만드는 과정도 같이 포함 		
		               //오류 체크 과정도 포함 
					   //연산자가 올수 있는 규칙에따라서 오류를 검사한다.
			{
			     case '!'://!연산자의 경우 두가지가 있다 NOT(!),!= 그러므로 바로 뒤의 입력값도 확인 해볼것
					 {
						 token[0]='!';
						 if((eqs[i+1])=='=')
						 {
							 token[1]='=';
							 token[2]=0;
							 i++;
						 }
						 else
						 { 
							 token[1]=0;
							 token[2]=0;
						 }
						 correct_operator(eqs[i],eqs[i+1]);
						 break;			
						 
					 }
				 
				 case '&'://&&연산자 분리
					 {
						 token[0]='&';
						 if((eqs[i+1])=='&')
						 {
							 token[1]='&';
							 token[2]=0;
							 i++;
						 }
						 else
						 { 
							 error_eqs(0); 
						 }
						 correct_operator(eqs[i],eqs[i+1]);
						 break;
					 }
					 
				 case '|'://'||'연산자 분리
					 {
						 token[0]='|';
						 if((eqs[i+1])=='|')
						 {
							 token[1]='|';
							 token[2]=0;
							 i++;
						 }
						 else
						 { 
							 error_eqs(0); 
						 }
						 correct_operator(eqs[i],eqs[i+1]);
						 break;
					 }


				 case '='://'=='연산자 분리
					 {
						 token[0]='=';
						 if((eqs[i+1])=='=')
						 {
							 token[1]='=';
							 token[2]=0;
							 i++;
						 }
						 else
						 { 
							 error_eqs(0); 
						 }
						 correct_operator(eqs[i],eqs[i+1]);
						 break;
					 }

				 case '>'://'>','>='연산자 구분 및 분리
					 {
						 token[0]='>';
						 if((eqs[i+1])=='=')
						 {
							 token[1]='=';
							 token[2]=0;
							 i++;
						 }
						 else
						 { 
							 token[1]=0;
							 token[2]=0;
						 }
						 correct_operator(eqs[i],eqs[i+1]);
						 break;
					 }

				 case '<'://'<','<='연산자 구분 및 분리
					 {
						 token[0]='<';
						 if((eqs[i+1])=='=')
						 {
							 token[1]='=';
							 token[2]=0;
							 i++;
						 }
						 else
						 { 
							 token[1]=0;
							 token[2]=0;
						 }			
						 correct_operator(eqs[i],eqs[i+1]);
						 break;
					 }

				 case '+'://'+'연산자 분리
					 {
						 token[0]='+';
						 token[1]=0;
						 token[2]=0;
						 correct_operator(eqs[i],eqs[i+1]);
						 break;
					 }

				 case '-'://'-'연산자 분리
					 {
						 token[0]='-';
						 token[1]=0;
						 token[2]=0;
						 correct_operator(eqs[i],eqs[i+1]);
						 
						 if(((i==0)&&(is_operand(eqs[i+1])))||((i>0)&&(eqs[i-1]=='(')))
							 //'-'가 수식의 제일 처음에 오거나 괄호안에 오게 되면 음수로 표현
							 //다음의 나오는 토큰은 operand일때 token을 합쳐서 음수로 만듬 
						 {
							 token[1]=eqs[i+1];
							 token[2]=0;
							 sign=1;
							 i++;
						 }						 
						 break;
					 }

				 case '*'://'*'연산자 분리
					 {
						 token[0]='*';
						 token[1]=0;
						 token[2]=0;
						 correct_operator(eqs[i],eqs[i+1]);
						 break;
					 }

				 case '/'://'/'연산자 분리
					 {
						 token[0]='/';
						 token[1]=0;
						 token[2]=0;
						 correct_operator(eqs[i],eqs[i+1]);
						 break;
					 }

				 case '%'://'%'연산자 분리
					 {
						 token[0]='%';
						 token[1]=0;
						 token[2]=0;
						 correct_operator(eqs[i],eqs[i+1]);
						 break;
					 }

				 case '^'://'^'연산자 분리
					 {
						 token[0]='^';
						 token[1]=0;
						 token[2]=0;
						 correct_operator(eqs[i],eqs[i+1]);
						 break;
					 }

				 case '('://'('연산자 분리
					 {
						 token[0]='(';
						 token[1]=0;
						 token[2]=0;
						 correct_operator(eqs[i],eqs[i+1]);
						 break;
					 }

				 case ')'://')'연산자 분리
					 {
						 token[0]=')';
						 token[1]=0;
						 token[2]=0;
						 
						 break;
					 }//of case
				 default://operand 분리
					 {
						 if(is_operand(eqs[i]))//operand가 들어오면
						 {
							 token[0]=eqs[i];
							 token[1]=0;
							 token[2]=0;
							 
							 if((is_operand(eqs[i+1]))||(!(is_next_correct_operator(eqs[i+1],eqs[i+2]))))
								 //operand는 두개가 연달아서 들어 올수 없으므로
								 //operand 다음에는 '('연산자와 '!'연산자만 올수 있다.
							 {
								 error_eqs(0);			 
							 }							 
						 }//of if						 
					 }//of default

	

			}//of switch

	        compute(sign,token);//연산 수행(sign은 음수 일경우를 나타내는 플래그이다.)
			printf("\nTOKEN STEP %d : %s ",i+1,token);//토큰 스텝을 출력
			print_status(i);//상태 출력			
			i++;
	}//of while
	
	token[0]=eqs[i-1]; //수식의 마지막에 올수 있는 수식을 확인해서 오류 확인을 위해서.마지막 토큰을 검사한다.
	j=0;
	flag=0;
	while(j!=(sizeof(can_be_last)/sizeof(can_be_last[0])))//마지막에 올수 있는 연산자의 갯수만큼 루프
	{
		if(token[0]==can_be_last[j])//마지막에 올수 있는 연산자의 경우에는 오류 없음
		{
			flag=1;
		}

		else if((token[0]<='9')&&(token[0]>='0'))//마지막에 operand가 와도 오류 없음
		{
			flag=1;
		}
		j++;
    }
	error_eqs(flag);//이상유무플래그 확인 후 에러 메세지 출력

	compute(0,"#");//마지막 eos토큰을 넣어 준다
	printf("\nTOKEN STEP %d : %s ",i+1,"#");//마지막에 나오는 결과 값은 다르게 표현함으로
	output_flag=1;//아웃풋의 내용을 출력하기 위한 플래그를 킨다.
	print_status(i);//마지막 상태 즉,결과 값과 변환 된 식을 출력한다.	    
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//process()정의

void process() //operand 두개를 operator로 계산하는 함수(compute함수에 의해서 호출 됨)
{
	int result=0;//연산 결과 값이 저장될 변수
	
	if(!empty(OPERAND))//operand가 있을때만 연산 수행
	{			
		top_operand=pop_operand();//연산을 하기 위해서 최소 하나의 operand가 필요하므로

		switch(top_operator[0])  //연산자가 선택
		{
			case '>': //>=연산자,>연산자
				{
					temp_operand=pop_operand();//두개의 operand가 필요한 연산자는 하나 더 뽑아 낸다.
					if(top_operator[1]=='=')
						result=(temp_operand>=top_operand);
					else						
						result=(temp_operand>top_operand);
					break;
				}

			case '<'://<=연산자,<연산자
				{
					temp_operand=pop_operand();//두개의 operand가 필요한 연산자는 하나 더 뽑아 낸다.
					if(top_operator[1]=='=')
						result=(temp_operand<=top_operand);
					else
						result=(temp_operand<top_operand);
					break;
				}
			case '!': //!=연산자,!연산자
				{
					if(top_operator[1]=='=')
					{
						temp_operand=pop_operand();//두개의 operand가 필요한 연산자는 하나 더 뽑아 낸다.
						result=(temp_operand!=top_operand);
					}
					else
					{						
						result=(!top_operand);
					}
					break;
				}
			case '=': //==연산자
				{
					
					if(top_operator[1]=='=')
					{
						temp_operand=pop_operand();//두개의 operand가 필요한 연산자는 하나 더 뽑아 낸다.
						result=(temp_operand==top_operand);
					}
					else
						result=0;
					break;
				}
			
			case '&': //&&연산자
				{
					if(top_operator[1]=='&')
					{
						temp_operand=pop_operand();//두개의 operand가 필요한 연산자는 하나 더 뽑아 낸다.
						result=(temp_operand&&top_operand);
					}
					else
						result=0;
					break;
				}
				
			case '|': //||연산자
				{
					if(top_operator[1]=='|')
					{
						temp_operand=pop_operand();//두개의 operand가 필요한 연산자는 하나 더 뽑아 낸다.
						result=(temp_operand||top_operand);
					}
					else
						result=0;
					break;
				}

			case '^'://지수연산
				{
					temp_operand=pop_operand();//두개의 operand가 필요한 연산자는 하나 더 뽑아 낸다.
					result=(int )pow(temp_operand,top_operand);
					break;
				}
			
			case '+'://더하기
				{
					temp_operand=pop_operand();//두개의 operand가 필요한 연산자는 하나 더 뽑아 낸다.
					result=(temp_operand+top_operand);
					break;				
				}
            
			case '-'://빼기
				{
					temp_operand=pop_operand();//두개의 operand가 필요한 연산자는 하나 더 뽑아 낸다.
					result=(temp_operand,top_operand);
					break;
				}
			case '*'://곱하기
				{
					temp_operand=pop_operand();//두개의 operand가 필요한 연산자는 하나 더 뽑아 낸다.
					result=(temp_operand*top_operand);
					break;
				}
			case '/'://나누기				
				{
					if(top_operand==0)//0으로 나눌수 없으므로
					{
						printf("\n0으로 나눌수 없습니다.");
						exit(0);
					}
					else
					{
						temp_operand=pop_operand();//두개의 operand가 필요한 연산자는 하나 더 뽑아 낸다.
						result=(temp_operand/top_operand);						
					}
					break;
				}
			case '%'://나머지 연산
				{
					if(top_operand==0)//0으로 나눌수 없으므로
					{
						printf("\n0으로 나눌수 없습니다.");
						exit(0);
					}
					else
					{			
						temp_operand=pop_operand();//두개의 operand가 필요한 연산자는 하나 더 뽑아 낸다.
						result=(temp_operand%top_operand);						
					}
					break;				
				}
			default://아무것도 아니면 그냥 0을 리턴한다.(결과 값이 이상하게 나옴)
				result=0;				
		}//of switch
		itoa(result,top_new_operand,10);//정수를 문자열로 변환후 푸시한다.
		                                //푸시함수는 인자를 문자열(포인터)만 받을수 있기때문)
		push(top_new_operand,OPERAND);  //결과 값을 푸시
	}	

	else//operand가 없을경우에는 다시 top_roperator를 푸시 한다.
	{
		push(top_operator,OPERATOR);
	}
	
	
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//compute()정의

void compute(int sign,char *token)//push,pop를 결정,process함수 호출
{
	if(token[0]=='#')//EOS가 들어 오면 operand스택에 이있는 값을 모두 꺼내서 연산 수행한다.
	{
		if(pairs_Gualho!=0)//괄호의 짝이 맞지 않으면 오류.
		{
			error_eqs(0);
		}	
		
		else
		{
			while(!empty(OPERATOR))//operator스택이 비지 않을때까지
			{
				strcpy(top_operator,pop_operator());//operator를 뽑아 낸다.
				strcat(output,top_operator);//output에 저장한다.최종 변환된 연산 식을 만들기 위해서
				process();//연산수행
			}
		}

	}	

	else if(sign==1)//음수일경우에는
	{
		push(token,OPERAND);//음수를 스택에 저장
	}
	
	else if('('==token[0])//'('가 오면 스택에 저장,괄호의 짝이 잘 이루어 졌나 확인하기 괄호의 카운트를 증가
	{
		strcat(output,token);//output에 저장한다.최종 변환된 연산 식을 만들기 위해서
		push(token,OPERATOR);//operator스택에 저장
		pairs_Gualho++;//괄호의 갯수 1증가
	}

	else if(is_operand(token[0]))//operand가 들어 올 경우
	{
		push(token,OPERAND);//operand를 스택에 저장한다.
		strcat(output,token);//output에 저장한다.최종 변환된 연산 식을 만들기 위해서
	}
	
	else if(is_operator(token))//operator의경우
	{
		
		if((empty(OPERATOR))||(empty(OPERAND)))//operator 스택이 비어있으면,제일 처음 오는 연산자 이므로 저장한다.
		{
			push(token,OPERATOR);//operator 스택에 삽입			
		}
		
		else
		{
			strcpy(top_operator,pop_operator());//operator 하나 뽑아 낸다.			
			if((token[0]!=')')&&(top_operator[0]=='('))	//토큰이 ')'가 아니고,operator이 '(' 일때는	
			{
				push(top_operator,OPERATOR);//operator을 푸시
				push(token,OPERATOR);//토큰을 푸시
			}			
			
			else if('^'==token[0])//'^'연산자일경우(연산 방향이 다름)
			{
				if(((compare_operator(top_operator,token))==2)||((compare_operator(top_operator,token))==1))
					//'^"의 우선순위가 같거나 높을때
				{
					push(top_operator,OPERATOR);
					push(token,OPERATOR);
				}
				
				else if((compare_operator(top_operator,token))==0)//토큰 우선순위가 낮을때
				{
					while((compare_operator(top_operator,token))==0)//토큰과 operator의 우선순위가 같을때까지만
					{						
						if(top_operator[0]=='(')//'('이 top_operator 일경우에는
						{
							break;//루프 종료
						}
							
						strcat(output,top_operator);//output에 저장한다.최종 변환된 연산 식을 만들기 위해서
						process();//연산 수행
						
						if(!empty(OPERATOR))//operator 스택이 비지 않았앗다면
						{
							strcpy(top_operator,pop_operator());//연산자 하나를 또 뽑아낸다
						}
						else
						{
							break;//루프 종료
						}
					}					
					push(top_operator,OPERATOR);//뽑아 내었던 연산자를 다시 푸시하고.
					push(token,OPERATOR);//토큰도 푸시한다.
				}					
				
			}

			else if(')'==token[0])//')'일경우
			{
				pairs_Gualho--;	//괄호의 갯수를 하나 줄인다.짝이 하나 들어 왔으므로
				
			
				while(!(top_operator[0]=='('))//'('를 만날때까지
				{
					if((top_operator[0]=='!')&&(top_operator[1]==0))//!연산자 일경우 !연산 수행
					{
						strcat(output,top_operator);//output에 저장한다.최종 변환된 연산 식을 만들기 위해서
						process();//연산 수행
						push(token,OPERATOR);//토큰을 푸시한다
					}//아니면 그냥 무시하고 지나감.					
					
					else
					{
						strcat(output,top_operator);//output에 저장한다.최종 변환된 연산 식을 만들기 위해서
						process();//연산 수행					
					}
					
					strcpy(top_operator,pop_operator());//연산자 하나를 뽑아 낸다			
				}
				strcat(output,token);//output에 저장한다.최종 변환된 연산 식을 만들기 위해서
				
			}
			
			else//위에서 정의 된 특별한 경우가 아닐경우에는
			{
				if(((compare_operator(top_operator,token))==0)||((compare_operator(top_operator,token))==2))
					//우선순위가 isp가 높거나, 같을때
				{   
					while((!empty(OPERAND))&&(compare_operator(top_operator,token))!=1)
						//operand가 있고,토큰의 우선순위가 낮지 않을때까지
					{	
						strcat(output,top_operator);//output에 저장한다.최종 변환된 연산 식을 만들기 위해서
						if((compare_operator(top_operator,token))==1)//우선순위가 icp가 높을때(루프문이므로)
						{
							push(top_operator,OPERATOR);//연산자를 다시 푸시							
							break;
						}

						process();//연산 수행
						
						if(empty(OPERATOR))//연산자가 없으면 루프 종료
						{							
							break;
						}
						else 
						{	
							strcpy(top_operator,pop_operator());//연산자를 하나 뽑아 낸다
							if(top_operator[0]=='(')//연산자가 '('인 경우에는
							{
								push(top_operator,OPERATOR);//다시 넣고 루프 종료								
								break;
							}
							
						}						
					}				
					push(token,OPERATOR);//토큰 삽입
				}
				else if((compare_operator(top_operator,token))==1)//우선순위가 icp(토큰)가 높을때
				{
					push(top_operator,OPERATOR);//뽑아내었던 연산자를 넣고
					push(token,OPERATOR);//토큰도 넣는다
				}
				
			}
			
		}
		
	}
	
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//is_next_correct_operator()정의
//리턴값 : 1: 올바름
//         0:올바르지 않음
int is_next_correct_operator(char next_token,char next_token_2)
{
	int j=0;
	while(j!=(sizeof(can_be_after_operator)/sizeof(can_be_after_operator[0])))
		//operand 다음에 올수없는 operator갯수만큼 루프
	{
		if((next_token=='!')&&(next_token_2=='='))//operand 다음에 "!="연산자는 올수 있으므로
			return 1;		
		else if(next_token==can_be_after_operator[j])//operand 다름에 올수 없는 operator일경우는 오류
			return 0;
		j++;
    }
	
	return 1;



}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//compare_operator()정의
//리턴값 : 0:isp우선순쉬가 높다.
//         1:isp 우선순위가 낮다.
//         2:isp 우선순위와 icp우선순위가 같다.
//         3:오류
int compare_operator(char *isp,char *icp)
{
	int result=0;
	int i=0;
	int pri_isp=0,pri_icp=0;
	
	if((isp[0]==icp[0])&&(isp[1]==icp[1]))//같은 연산자일경우(모든 연산자가 고유의 우선순위를 가지고 있다.)
		return 2;
	else
	{
		while((operator_priority_table[i][0])!='@')//연산자 우선순위 테이블을 참조해서 두 연산자의 우선순위 를 정함
		{
			if(isp[0]==operator_priority_table[i][0])
			{
				if(isp[1]==operator_priority_table[i][1])
				{
					pri_isp=i;
				}
			}
			else if(icp[0]==operator_priority_table[i][0])
			{
				if(icp[1]==operator_priority_table[i][1])
				{
					pri_icp=i;
				}
			}
			i++;
			
		}
	}
	//숫자가 작은것이 우선 순위가 높다.
	if(pri_isp<pri_icp)
		result=0;
	else if(pri_isp>pri_icp)
		result=1;
	else
	{
		result=3;
		error_eqs(1);
	}

	return result;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//correct_operator()정의
//리턴값 : 없음
//플래그 사용으로 올바른 연산자이면 오류 없음,그렇지 않으면 에러 메세지 출력후 종료

void correct_operator(char oper,char next_token)
{
	int j=0,flag=0;
	if((oper=='(')&&(next_token=='-'))//다음에 오는 연산자를 비교하기 위해서
		flag=1;

	else 
	{
		while(j!=(sizeof(can_be_after_operator)/sizeof(can_be_after_operator[0])))
			//operator 다음에 올수있는 operator갯수만큼 루프
		{
			if(next_token==can_be_after_operator[j])//operator 다름에 올수 있는 operator일경우는 오류없음
			{
				flag=1;
			}

			else if(is_operand(next_token))//operand일경우도 오류 없음
			{
				flag=1;
			}			
			j++;
		}
	}
	error_eqs(flag);

}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//is_operator()정의
//리턴값 : 0:연산자 아님
//         1:연산자
int is_operator(char token[])
{
	int i=0;
	while((operator_priority_table[i][0])!='@') //operator배열에서 끝까지
	{
		if((token[0]==operator_priority_table[i][0])||token[0])
		{
			return 1;
		}
		i++;
	}
	return 0;
		

}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//is_operand()정의
//리턴값 : 0:operand 아님
//         1:operand
int is_operand(char token)
{
	if((token<='9')&&(token>='0'))
		return 1;
	else
		return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//error_eqs()정의
//에러메세지 출력후 종료
void error_eqs(int flag)
{
	if(!flag)//플래그가 0이면 에러
	{
    	 printf("\n잘못된 표현식입니다.");
	     exit(0);
	}
}
	

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//empty()정의
//리턴값 : 0:비었음
//         1:안비었음
int empty(int stack)//stack값에 따라 operand스택인지,operator 스택인지 구분
{
	if((stack==OPERATOR)&&(top_of_operator_stack==(-1)))
		return 1;
    else if((stack==OPERAND)&&(top_of_operand_stack==(-1)))
		return 1;
	else return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//full()정의
//리턴값 : 0:가득참
//         1:가득차지 않음

int full(int stack)//stack값에 따라 operand스택인지,operator 스택인지 구분
{
	if((stack==OPERATOR)&&(top_of_operator_stack==(MAX_EQS_SIZE)))
		return 1;
    else if((stack==OPERAND)&&(top_of_operand_stack==(MAX_EQS_SIZE)))
		return 1;
	else return 0;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//pop_operand()정의
//리턴값 : top_operand

int pop_operand()
{
    int i=0;
	if(!empty(OPERAND))
	{
		i=operand_stack[top_of_operand_stack];
		top_of_operand_stack--;
	    return	i;
	}
    else
	{
		printf("\n operand 스택이 비었습니다.");
		exit(0);
		return -1;
	}
	
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//pop_operator()정의
//리턴값 : top_operator 
char *pop_operator()
{
	char *top=(char *)malloc(3*sizeof(char));
	if(!empty(OPERATOR))
	{
		strcpy(top,operator_stack[top_of_operator_stack]);
	    top_of_operator_stack--;
		return top;
	}
	else
	{
		printf("\n operator 스택이 비었습니다.");
		exit(0);
		return "ept";
	}


}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//push()정의
//스택의 타입에 따라 푸시 실행

void push(char *token,int type)
{
	if(type==OPERAND)//operand일경우에는
		{
			
			if(!full(OPERAND))//operand스택이 가득차지 않았으면 
			{
				int operand=0;
				operand=atoi(token);//토큰을 정수형 operand로 바꾸고 
				top_of_operand_stack++;//operand스택의 top을 중가 시켜줌
				operand_stack[top_of_operand_stack]=operand;//스택에 저장
				
			}
			else 
			{
				printf("\n operand 스택이 가득 찾습니다.");
				exit(0);
			}
		}
	if(type==OPERATOR)//operator일 경우에는
		{
			if(!full(OPERATOR))//operator스택이 가득차지 않았으면
			{
				top_of_operator_stack++;//operator스택의 top을 증가시켜줌
				strcpy(operator_stack[top_of_operator_stack],token);//스택에 저장
			}
			else 
			{
				printf("\n operator 스택이 가득 찾습니다.");
				exit(0);
			}
		}

}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//print_status()정의
//각 스탭의 상태 출력
void print_status(int j)
{
	int i=0,temp=0;
	if(output_flag==0)//마지막 단계가 아니라면 지금 스텝의 각 스택의 상태를 출력 
	{
		temp=top_of_operand_stack;//임시 변수에 top을 저장한다
		printf("\n   : operand  stack: ",j+1);
		while(temp!=(-1))//스택의 모두를 읽어 들여서 출력(top의 값의 변화를 주지 않기 위해 임시 변수 사용
		{
			printf("  %d",operand_stack[i]);
			temp--;
			i++;
		}
		
		printf("\n");
		
		temp=top_of_operator_stack;//임시 변수에 top을 저장한다
		i=0;		
		printf("   : operator stack: ");
		while(temp!=(-1))//스택의 모두를 읽어 들여서 출력(top의 값의 변화를 주지 않기 위해 임시 변수 사용
		{
			printf("  %s",operator_stack[i]);
			temp--;
			i++;
		}
	}
	else//마지막 단계일때는 출력 형식을 바꿔야 되기때문에
	{
		printf("\n   : RESULT: ");
		printf("  %d\n",operand_stack[i]);//결과값 출력				
		printf("   : OUTPUT: ");
		printf("  %s\n",output);//변환된 수식출력
			
	}
}
// 소스 코드 끝
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

저작자 표시
신고
  1. jkrm 2012.10.13 17:12 신고

    C언어 기반으로 만들어서 그런지 많은 소스가 대량 사용 되었네요 ;;

  2. jkrm 2012.10.13 17:12 신고

    C언어 기반으로 만들어서 그런지 많은 소스가 대량 사용 되었네요 ;;

    • rekun,ekun 커뉴 2012.10.14 20:31 신고

      맞습니다.
      10년전에 만들때 오직 C로만 자료구조 수업을 진행했기 때문에..
      보시면 스택자료구조 실습하는 과제였습니다.

  3. zzapcoder 2013.08.01 02:00 신고

    천줄... ㄷㄷㄷ.....

    • rekun,ekun 커뉴 2013.08.01 08:14 신고

      ㅎㅎㅎ 학부 시절 자료 구조 수업때 하던거라서...
      Test Case를 주고 그 Case가 무조건 돌아가야지만 되는 과제였던것 같습니다. ㅎㅎㅎ

  4. dd 2015.03.06 06:47 신고

    음수 -9 에서 더 내려갈려면 어떻게해야되나요?

    • dd 2015.03.06 11:04 신고

      그리고 소숫점은 어떻게표현하나요

    • rekun,ekun 커뉴 2015.03.07 22:19 신고

      push 하는 부분을 보면 atoi를 사용하고 있기 때문에, 문자하나를 정수로 변환하고 있습니다. push 하는 부분을 용도에 맞게 수정하셔서 사용하시면 됩니다.

  5. dd 2015.03.08 10:15 신고

    하나만 더질문할게요. 2자리수의 정수는 이 코드에서는 불가능한가요?

+ Recent posts

티스토리 툴바