컴퓨터를 정리하다보니, 또 재미난 소스가 있어서 올려본다.
바로 이전 포스트 다항식 연산은 아주 간단한 과제였는데, 지금 보니 계산기를 만들어라는 과제도 있었던 것 같아서 찾아보니 역시나 있다.
내 기억에 이 과제를 하면서, "아! 계산기가 이렇게 복잡하게 동작하는거였어???" 하면서 힘들어했던 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);//변환된 수식출력
}
}
// 소스 코드 끝
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////