정말 오랫만에 C / C++ 코딩을 하게 되었다.

long long 보다 큰, 아니 long 보다 큰 자료형을 거의 쓸일이 없었는데, 최근 불어닥치고 있는 소프트웨어 능력 평가로 인해 정말 오랫만에 C/C++로 코딩을 하고 있다.


문제자체는 쉬운데, 큰 정수를 다뤄야 하는 부분도 있어서 곰곰히 생각해보다가 매우 간단하게 long long의 곱셉이 가능하도록 급하게 만들어봤다.


999의 9승을 계산하는 긴급하게 만든 코드이므로 최적화나 다양한 테스트를 해보지는 못한 코드이다.



#include <stdio.h>

#define MAX_MODULO 100000000LL


typedef struct _BigNumber {
	long long quad;
	long long head;
	long long tail;
} BigNumber;

void toString(BigNumber a) {
	if (a.quad != 0) {
		printf("%lld", a.quad);		
		printf("%08lld", a.head);	
		printf("%08lld\n", a.tail);
	}else if (a.head != 0) {
		printf("%lld", a.head);
		printf("%08lld\n", a.tail);
	}else {
		printf("%lld\n", a.tail);
	}	
}

BigNumber multiply(BigNumber a, BigNumber b) {	
	BigNumber result;	
	result.quad = a.head*b.head + a.quad*b.tail + b.quad*a.tail;
	result.head = a.head * b.tail + a.tail * b.head;
	result.tail = a.tail*b.tail;	
	result.head += result.tail / MAX_MODULO;
	result.tail = result.tail % MAX_MODULO;
	result.quad += result.head / MAX_MODULO;
	result.head = result.head % MAX_MODULO;
	return result;
}

BigNumber add(BigNumber a, BigNumber b) {
	BigNumber result;
	result.quad = a.quad + b.quad;
	result.head = a.head + b.head;
	result.tail = a.tail + b.tail;
	result.head += result.tail / MAX_MODULO;
	result.tail = result.tail % MAX_MODULO;
	result.quad += result.head / MAX_MODULO;
	result.head = result.head % MAX_MODULO;
	return result;
}

BigNumber power(BigNumber a, int b) {
	BigNumber result;
	result.quad = a.quad;
	result.head = a.head;
	result.tail = a.tail;

	if (b == 0){
		result.quad = 0;
		result.head = 0;
		result.tail = 1;
		return result;
	}		

	if (b == 1) {
		return result;
	}

	for (int i = 1; i < b; i++) {
		result = multiply(result, a);		

	}
	return result;
}

int main() {
	BigNumber test;
	test.quad = 0;
	test.head = 0;
	test.tail = 999;
	toString(power(test, 9));
	return 0;
}


블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,

iOS용 게임을 개발할때 coco2d를 사용했었는데, 잠깐 한들여다본 사이에 cocos2d-x라는 것이 나와서 모든 플래폼에서 게임을 개발할수 있게 아예 cpp로 소스를 전부다 만들어놓은것이 나와있었다.


iOS용은 Objective-C로 되어 있었기 때문에 그냥 빌드할때 프로젝트만 추가해서 빌드하면되었는데, 윈도우에서 Android용 게임을 한번 개발해볼까 하고 cocos2d를 설치할려고 하니 개발환경 설치도 ... 하나의 일이된것 같다. 그래서 정리해둔다...


준비물(정말 아래대로 준비해둬야 한다.) - eclipse,JDK, Android SDK는 설치되어 있다는 가정하에 ..

1. Cygwin(Windows 환경하에서 Linux Build환경을 사용하기 위해서 설치필요)

 -  http://cygwin.com/install.html에서 Setup.exe를 다운받고 실행시키면 된다. 설치 패키지중 Devel,Editor 패키지정도는 install로 바꿔서 설치




2. Customized Android NDK (Native Development Kit)(기본 NDK가 아닌 stl을 지원하는 Crystax의 NDK를 반드시 설치해야 한다.) 

 - http://www.crystax.net/ko/android/ndk/7#download

 - 최신 버전으로 다운받고 압축 풀어두면 됨(이걸 모르고 기본 NDK로 cocos2d-x  빌드하려고 무려 3시간을 낭비 했다 ㅠ.ㅠ)

 - 그리고 빌드중 계속 stl , std:: link에러가 나오면 반드시 prog.android\jni\Application.mk 파일을 열어서 아래와 같이 수정해줘야 한다.

    APP_STL := gnustl_static  -->  APP_STL := stlport_static


3. cocos2d-x  다운로드후 압축 풀기 

 - http://www.cocos2d-x.org/projects/cocos2d-x/wiki/Download


압축을 다 해제하고, 설치를 끝낸 후 디렉토리의 모습







준비는 이제 다 끝났으니, 본격적으로 cocos2d를 사용하기 위해서는 환경설정도 맞춰줘야 되고, cygwin 설정 그리고 project설정을 맞춰줘야 한다.해보자

1. windows에 path 추가

 - 환경변수 설정에서 path에 다음두개를 추가해두기.

 -  D:\Android\android-sdks\tools;D:\cygwin\usr\include


2. cygwin terminal을 열어서 .bashrc 수정

 export PATH=$PATH:/cygdrive/d/Android/android-ndk-r7-crystax-5

 export ANDROID_NDK_ROOT=/cygdrive/d/Android/android-ndk-r7-crystax-5

 export NDK_ROOT=/cygdrive/d/Android/android-ndk-r7-crystax-5   --> 이건 프로젝트 생성하면 설정되지만, 그냥 추가해둠.


3. 수정된 .bashrc 반영

 source ~/.bashrc


4. cocos2d-x 프로젝트 설정 수정

D:\Android\cocos2dx\cocos2d-2.0-x-2.0.4\create-android-project.bat 파일이 안드로이드용 프로젝트를 생성해주는 스크립트(열어서 환경설정변경)

:: modify it to work under your environment  

set _CYGBIN=D:\cygwin\bin

if not exist "%_CYGBIN%" echo Couldn't find Cygwin at "%_CYGBIN%" & pause & exit 4


:: modify it to work under your environment

set _ANDROIDTOOLS=D:\Android\android-sdks\tools

if not exist "%_ANDROIDTOOLS%" echo Couldn't find android sdk tools at "%_ANDROIDTOOLS%" & pause & exit 5


:: modify it to work under your environment

set _NDKROOT=D:\Android\android-ndk-r7-crystax-5


5. Windows cmd 열어서 cocos2d-x 용 안드로이드 프로젝트 생성.

D:\Android\cocos2dx\cocos2d-2.0-x-2.0.4\create-android-project.bat을 실행하면 됨.

자신이 추가해둔 sdk 에 따라서 생성할수 프로젝트 들이 나오는데 그중에 하나를 선택하면 됨 예를 들면 아래 처럼하면 됨



6. cygwin에서 shared library 빌드하기.

자신이 생성한 프로젝트 디렉토리로 가서 build 하기(helloworld로 프로젝트를 만들었다면 아래와 같이 하면 됨)




7. eclipse 에서 작업하기
eclipse에서 위에서 생성한 helloworld 프로젝트를 열면 됨.
에러가 나는 경우는 Java Compiler 가 맞지 않을 경우와 cocos2d-x 라이브러리가 없을때인데 아래와 같이 해결하면 된다.

Java Compiler는 1.6으로 맞춰주고 ....



cocos2d Library가 없다고 에러가 나면.... 아래 lib 폴더를 복사해서 아래 eclipse의 패키지처럼되게 넣으면 된다.






실행해보면~~~~~ 이렇게 나온다. 이제 준비끝.... 아흑,.. 삽질을 좀 했다.



iOS게임으로 만들었던 BlueOcean을 Android에 그대로 포팅해봐야 겠다.

'코딩하고 > C,C++' 카테고리의 다른 글

큰 정수 계산하기  (0) 2016.03.27
OS - Page Fault Simulation(FIFO,LRU,Optimal)  (0) 2012.10.21
자료구조 - 계산기 만들기  (10) 2012.10.12
C언어로 만든 객체  (0) 2012.10.11
자료구조 - 다항식 연산하기  (2) 2012.10.10
블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,

학부시절 운영체제 수업을 들었던 기억이 가물 가물한데,...

LRU 알고리즘이 갑자기 생각나서 수업 자료들을 뒤지는 중 시뮬레이션 소스를 발견하였다. 

10년 정도 지나고 나서 보니, 대체 왜 이런식으로 코딩을 했을까 하고 생각도 들긴하지만, 그때 당시 열심히 공부했었구나 싶기도 하다.



/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 2002년 11월 20일                                                       
// 운영체제론 Report #2                                                 
// PageFault Simulation.                                               
// Algorithm : FIFO                                                       
//                 Optimal                                                       
//                 LRU                                                            
// Compiler : MS Visual C++ 6.0                                                                                        
// Test : Pentium III 866Mhz, 512Mb SDRAM, VIA694 Board                                                  
// 실행 시 유의 사항 : 윈도우즈에서 실행 시킬 경우 도스명령창이 뜨는데 그때 그 창의 속성을 너비 84이상으로 할것       
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <stdio.h>  // 표준 입출력함수를 사용하기 위해서 포함시킴
#include <stdlib.h> // rand()를 사용하기 위해서 포함시킴
#include <time.h>   // rand()의 seed를 time을 사용하기 위해서 포함시킴 
#include <malloc.h> // 메모리 할당함수인 malloc 함수의 사용을 위해

#define MAX_FRAME 10 // 프레임의 수를 최대 10로 설정
                     // 페이지가 1~7까지라서 7이면 충분하지만, test를 위해 여유 있게 10으로 함.

#define MAX_REF_SIZE 60    // reference string의 길이를 60으로 한다. 
#define default_of_frame 3 //frame의 수를 default 값으로 3으로 한다.
int ref_string[MAX_REF_SIZE];  // reference string의 길이를 60으로 한다.
int frame[MAX_FRAME]={0};      // FIFO와 Optimal 방식에서 사용될 frame 배열(초기화 시킴)
int number_of_frame=0;         // 입력 받을 프레임의 수
int cfifo=0;    //fifo 방식의 pagefault 발생횟수
int coptimal=0; //optimal 방식의 pagefault 발생횟수
int clru=0;     //LRU 방식의 pagefault 발생횟수

typedef struct stack_dlist *stack_ptr; //LRU방식에서 사용될 이중연결 리스트 구조체 선언
typedef struct stack_dlist{
	stack_ptr uplink;    
	stack_ptr downlink;
	int data;
	};
stack_ptr top=NULL;    // 일종의 stack형식이므로 top값을 지정
stack_ptr bottom=NULL; // 접근 편리를 위해 bottom값을 지정(pagefault 때에는 bottom에 있는 값을 victim으로 한다.

void init(); // reference string 만들기, 프레임의 수 입력 받기 ,screen 만들기, 각 함수 호출하기
void fifo();    // fifo replacement 방식을 구현한 함수
void optimal(); // optimal replacement 방식을 구현한 함수
void lru();     // LRU replacement 방식을 구현한 함수
short int pagefault(int);     // pagefault를 검사하는 함수
short int lru_pagefault(int); // LRU 방식에서 pagefault 검사하는 함수
int flength(int,int); // optimal 에서 현재위치 i에서 프레임의 각 원소들이 얼마나 멀리 있는지 검사하는 함수

void main(void)
{
	init();	
	
}

void init()
{
	int number=0; // 프레임의 수를 저장한다.
	int i=0;      // loop에 사용될 변수
	char *cnumber;// frame 의 갯수를 입력받아서 저장할 포인터
	cnumber=(char *)malloc(3*sizeof(char)); // 크기를 3으로한다.
	
	printf("Number of Frame (Maximum value is %d, Default value is %d) : ",MAX_FRAME,default_of_frame);
	gets(cnumber); // frame의 수를 사용자로부터 입력받아서 number변수에 저장한다.
	
	if(cnumber[0]==NULL) //default값으로 대치한다.
	{
		number=default_of_frame;
	}
	
	else // 문자열을 정수형으로 변환한다.
	{
		number=atoi(cnumber);
	}

	if((number > 0) && (number < MAX_FRAME+1)) 
	{
		number_of_frame=number;
	}	

	else //범위에 벗어나는 입력이 들어 왔을경우 디폴트 값으로 한다.
	{
		number_of_frame=default_of_frame;	
	}
	
	// 화면을 구성한다.
	printf("\nNumber of Frame : %d   PageFault: F",number_of_frame);
	printf("\n┌────┬──────────────────────────────┬───┐");
	printf("\n│ Method │Reference String                                            │Counts│");
	printf("\n│        │");
	srand( (unsigned)time( NULL ) ); // 랜덤하게 Reference String을 만들것이므로 rand()의 seed를 넣어준다.

	for(i=0;i<MAX_REF_SIZE;i++) // Reference String의 길이를 MAX_REF_SIZE로 해서 만든다.
	{			
		ref_string[i]=rand()%7+1;
		printf("%d",ref_string[i]);
	}
	printf("│      │");
	printf("\n");
	
	printf("├────┼──────────────────────────────┼───┤");
	printf("\n");	

	printf("│FIFO    │");
	fifo(); // fifo함수 호출
	
	if(cfifo>9) // fifo카운터의 자릿수가 두 자리 일 때
	{
		printf("│  %d  │",cfifo);
	}
	else // fifo카운터의 자릿수가 한 자리 일 때
	{
		printf("│  %d   │",cfifo);
	}
	
	printf("\n");
	printf("├────┼──────────────────────────────┼───┤");
	printf("\n");

	for(i=0;i<MAX_FRAME;i++) // frame을 0으로 초기화 시킨다.(fifo에서 사용했던 프레임의 내용을 제거)
	{
		frame[i]=0;
	}
	printf("│Optimal │");
	optimal();
	
	if(coptimal>9) // optimal 카운터의 자릿수가 두 자리 일 때
	{
		printf("│  %d  │",coptimal);
	}
	else // optimal 카운터의 자릿수가 한 자리 일 때
	{
		printf("│  %d   │",coptimal);
	}
	
	printf("\n");
	printf("├────┼──────────────────────────────┼───┤");
	printf("\n");

	printf("│LRU     │");
	lru(); // LRU함수 호출
	if(clru>9) // LRU 카운터의 자릿수가 두 자리 일 때
	{
		printf("│  %d  │",clru);
	}
	else // LRU 카운터의 자릿수가 한 자리 일 때
	{
		printf("│  %d   │",clru);
	}
	
	printf("\n└────┴──────────────────────────────┴───┘");
	printf("\n");
}




void fifo()
{
	int i=0,f=0;
	
	for(i=0;i<MAX_REF_SIZE;i++)
	{
		if(pagefault(ref_string[i])) // pagefault발생하면
		{
			cfifo++; // 그 카운터를 증가시키고
			frame[f]=ref_string[i]; // replacement한다.
			printf("F"); // pagefault가 발생했다는 표시한다.
			f=(f+1)%number_of_frame; // frame의 인덱스를 프레임의 수에 맞게 바꾼다.(fifo)			
		}
		else
		{
			printf(" "); // 아무일도 없다.

		}		
	}
}
void optimal()
{
	int i=0,f=0,k=0;
	int length[MAX_FRAME]={0}; // 프레임내의 어떤 원소의 위치가 어디 인지를 저장하는 변수	
	int max=0; // 가장 늦게 나오는 프레임인덱스를 저장하게 된다.

	for(i=0;i<MAX_REF_SIZE;i++)
	{
		max=0;
		if(pagefault(ref_string[i])) // pagefault발생하면
		{
			coptimal++;//카운터 증가
			if(frame[f]==-1)//frame에 비어 있는 공간이 있으면 그냥 넣어도 됨,처음에는 프레임이 비어 있음
			{				
				frame[f]=ref_string[i];				
				f=f+1;
			}
			else// frame에 빈 공간이 없을때, 프레임에 있는 item들이 다음의 refrence string에서 어디에 위치하는지 알아보고
				// 가장 늦게 나오는 item을 replacement한다.
			{
				for(k=0;k<number_of_frame;k++)// 각 아이템들이 지금 위치에서 얼마나 멀리 떨어져 있는지 검사
				{
					length[k]=flength(i,k); 
				}
				for(k=0;k<number_of_frame-1;k++)
				{
					if(length[max]<length[k+1])  // 가장 늦게 나오는 원소를 replacement하기 위해서 골라 낸다.
					{
						max=k+1;
					}
				}
				frame[max]=ref_string[i]; // replacement
			}			
			printf("F");

		}

		else
		{
			printf(" ");
		}		
	}

	
}

void lru() 
{
	int i=0,stack_count=0;	
	
	for(i=0;i<MAX_REF_SIZE;i++)
	{
		if(lru_pagefault(ref_string[i])) // pagefault발생하면
		{
			clru++;// 카운터 증가
			
			if(number_of_frame==1)// 만약에 프레임의 수가 1 이라면
			{
				stack_ptr temp=(stack_ptr)malloc(sizeof(stack_dlist)); // 임시 노드를 하나 선언한다.
				
				temp->downlink=NULL; // 프레임 노드가 하나만 있으므로 replacement는 그 data만 바꾸면 된다.
				temp->uplink=NULL;
				temp->data=ref_string[i];				
				top=temp;
				bottom=temp;
			}

			else if(stack_count<number_of_frame) // 스택이 비어 있다면(프레임에 빈공간이 있다면)
			{
				stack_ptr temp=(stack_ptr)malloc(sizeof(stack_dlist));	// 임시 노드 선언			
				
				stack_count++;// 스택 카운터를 증가시킨다.

				temp->downlink=top;// 이중연결 리스트 구조 이므로
				temp->uplink=NULL; // 이중연결 리스트 구조 이므로 (리포트에 따로 정리)

				if(top) // 노드가 하나라도 존재하면
				{
					top->uplink=temp; //존재하는 노드의 uplink를 새로운 노드로 포인팅한다.
				}
				temp->data=ref_string[i];// 데이터 저장				
				top=temp; // top를 새로운 노드로 한다.
				if(!bottom) // 노드의 밑부분의 노드를 bottom으로 한다.
				{
					bottom=temp;
				}				
			}
			else // 프레임에 빈공간이 없을 경우
			{
				stack_ptr temp=(stack_ptr)malloc(sizeof(stack_dlist));				
				
				temp=bottom; // 교과서에 나온대로 제일 밑의 노드를 희생량으로 삼는다.
				
				// 링크의 조정(자료구조 책에 나옴)
				temp->uplink->downlink=temp->downlink;
				bottom=temp->uplink;

				temp->data=ref_string[i];
				
				temp->downlink=top;
				temp->uplink=top->uplink;
				top->uplink=temp;

				top=temp;						
			}
			printf("F");
		}

		else
		{
			printf(" ");
		}		
	}

}

short int pagefault(int item) 
{
	int i=0;
	short int flag=1; // pagefault가 발생하면 1

	for(i=0;i<number_of_frame;i++)
	{
		if(frame[i]==item)
			flag=0;	// 그렇지 않으면 0		
	}	
	return flag;
}

int flength(int now,int item_pos) // 현재 위치에서 얼마나 떨어져 있는지 검사
{
	int i=0;
	
	i=now+1;
	
	while(i<MAX_REF_SIZE)
	{
		if(ref_string[i]==frame[item_pos])
		{
			return i;			
		}
		i++;
	}
	return MAX_REF_SIZE+1;
}
short int lru_pagefault(int item) // LRU 의 pagefault검사
{
	int flag=1;
	stack_ptr temp=(stack_ptr)malloc(sizeof(stack_dlist));
	stack_ptr position=(stack_ptr)malloc(sizeof(stack_dlist));
		
	position=top;
	temp=top;
	
	while(position!=NULL) // 리스트에서 데이터를 찾는 방식과 같음
	{
		if(position->data==item)// 프레임에 지금 들어온 페이지가 존재하면 그 노드를 top으로하고 링크를 조정한다.
		{
			temp=position;
			flag=0; // pagefault발생 안함	
			if((temp->uplink)&&(temp->downlink)) // 노드가 리스트의 중간에 있을 경우(top나 bottom이 아닐경우)
			{
				temp->uplink->downlink=temp->downlink;
				temp->downlink->uplink=temp->uplink;
				
				temp->downlink=top;
			    temp->uplink=top->uplink;
			    
				top->uplink=temp;
        		top=temp;
			}			
			else if(!(temp->downlink)&&temp->uplink) // 노드가 bottom에 있을 경우(노드가 하나만 있다면 안된다)
			{								
				temp->uplink->downlink=temp->downlink;
				bottom=temp->uplink;

				temp->uplink=top->uplink;
				top->uplink=temp;
				
				temp->downlink=top;
				
				top=temp;						
			}			
		}			
		position=position->downlink;//리스트의 처음부터 끝까지 다 스캔해서 페이지를 검색.	
	}	
	return flag; 


}

'코딩하고 > C,C++' 카테고리의 다른 글

큰 정수 계산하기  (0) 2016.03.27
cocosdx 사용해서 게임 개발하기 -1-  (0) 2012.11.19
자료구조 - 계산기 만들기  (10) 2012.10.12
C언어로 만든 객체  (0) 2012.10.11
자료구조 - 다항식 연산하기  (2) 2012.10.10
블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,

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


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


내 기억에 이 과제를 하면서, "아! 계산기가 이렇게 복잡하게 동작하는거였어???" 하면서 힘들어했던 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);//변환된 수식출력
			
	}
}
// 소스 코드 끝
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

'코딩하고 > C,C++' 카테고리의 다른 글

cocosdx 사용해서 게임 개발하기 -1-  (0) 2012.11.19
OS - Page Fault Simulation(FIFO,LRU,Optimal)  (0) 2012.10.21
C언어로 만든 객체  (0) 2012.10.11
자료구조 - 다항식 연산하기  (2) 2012.10.10
ls 명령어 구현하기.  (2) 2012.10.09
블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,

오늘도 어제에 이어 문서파일들을 정리하는 중인데, class_c라는 파일이 있어 열어보니.


학부 시절, C언어로 객체를 구현해서 오라는 과제가 있어서 만들어봤던 마린 클래스 소스였다.


현업하면서 BREW 라는 플래폼을 사용할때 C언어로 객체를 구현했길래 그 안을 들여다 보니.. 그방법이 똑같았다. ^.^



//함수형 포인터를 이용해서 클래스를 흉내내어 본다.
//구현해볼 클래스는 '마린' 클래스인데, CMarine구조체에 보면 7개의 속성등을 선언해뒀고,
//그 것들을 조정하는 함수를 14개의 함수형 포인터로 선언해두었으며,
//각각의 상태를 출력해주는 함수도 같이 포함되어 있다.

#include <stdio.h>
#include <stdlib.h>

#define ON 1 //스팀팩의 사용여부를 나타는 값.
#define OFF 0

//구조체 선언한다.(클래스처럼 사용하기 위한 구조체)
struct CMarine
{
	//상태를 저장하는 변수를 선언한다.
	int m_nLife;
	int m_nSpeed;
	int m_nStimPack; /*1 stimpack on, 0 otherwise.*/
	int m_nAttackDamage;
	int m_nAttackRange;
	int m_nWeaponUpLv;
	int m_nArmorUpLv;

	//상태를 셋팅하는 함수를 각각 함수형 포인터로 선언한다.
	void (*SetLife)(CMarine *pMarine,int Life);
	void (*SetSpeed)(CMarine *pMarine,int Speed);
	void (*SetStimPack)(CMarine *pMarine,int StimPack);
	void (*SetAttackDamage)(CMarine *pMarine,int AttackDamage);
	void (*SetAttackRange)(CMarine *pMarine,int AttackRange);
	void (*SetWeaponUpLv)(CMarine *pMarine,int WeaponUpLv);
	void (*SetArmorUpLv)(CMarine *pMarine,int ArmorUpLv);

	//각각의 상태를 출력해주는 함수를 각각 함수형 포인터로 선언한다.
	void (*PrintStatus)(CMarine *pMarine);

	//각각의 저장된 값을 불러오는 함수를 각각 함수형 포인터로 선언한다.
	int (*GetLife)(CMarine *pMarine);
	int (*GetSpeed)(CMarine *pMarine);
	int (*GetStimPack)(CMarine *pMarine);
	int (*GetAttackDamage)(CMarine *pMarine);
	int (*GetAttackRange)(CMarine *pMarine);
	int (*GetWeaponUpLv)(CMarine *pMarine);
	int (*GetArmorUpLv)(CMarine *pMarine);
};
//클래스처럼 사용할 수 있는 구조체의 정의 끝.

//각 함수들을 구현해준다.
void SetLife(CMarine *pMarine, int Life){
	pMarine->m_nLife=Life;
}

void SetSpeed(CMarine *pMarine,int Speed){
	pMarine->m_nSpeed=Speed;
}

void SetStimPack(CMarine *pMarine,int StimPack){
	pMarine->m_nStimPack=StimPack;
}

void SetAttackDamage(CMarine *pMarine,int AttackDamage){
	pMarine->m_nAttackDamage=AttackDamage;
}

void SetAttackRange(CMarine *pMarine,int AttackRange){
	pMarine->m_nAttackRange=AttackRange;
}

void SetWeaponUpLv(CMarine *pMarine,int WeaponUpLv){
	pMarine->m_nWeaponUpLv=WeaponUpLv;
}

void SetArmorUpLv(CMarine *pMarine,int ArmorUpLv){
	pMarine->m_nArmorUpLv=ArmorUpLv;
}

int GetLife(CMarine *pMarine){
	return pMarine->m_nLife;
}

int GetSpeed(CMarine *pMarine){
	return pMarine->m_nSpeed;
}

int GetStimPack(CMarine *pMarine){
	return pMarine->m_nStimPack;
}

int GetAttackDamage(CMarine *pMarine){
	return pMarine->m_nAttackDamage;
}

int GetAttackRange(CMarine *pMarine){
	return pMarine->m_nAttackRange;
}

int GetWeaponUpLv(CMarine *pMarine){
	return pMarine->m_nWeaponUpLv;
}

int GetArmorUpLv(CMarine *pMarine){
	return pMarine->m_nArmorUpLv;
}

CMarine *NewCMarine();//생성자 함수이다.(초기값을 설정해주고.메모리를 할당 받는다.)
void DestroyCMaine(CMarine *);//소멸자 함수.(메모리 반환)
void PrintStatus(CMarine *);//상태를 출력해 주는 함수.

int main(){
	CMarine *pMarine=NewCMarine();//생성자로 클래스를 하나 만든다.
	pMarine->PrintStatus(pMarine);//초기 상태를 출력한다.
	
	//값을 세팅해준다.
	pMarine->SetLife(pMarine,40);
	pMarine->SetSpeed(pMarine,10);
	pMarine->SetAttackDamage(pMarine,6);
	pMarine->SetAttackRange(pMarine,4);

	//세팅할 때 GetXXXXX함수를 사용해서 저장된 값을 불러온 다음 업그레이드 한다.
	pMarine->SetArmorUpLv(pMarine,(pMarine->GetArmorUpLv(pMarine))+1);
	pMarine->SetWeaponUpLv(pMarine,(pMarine->GetWeaponUpLv(pMarine))+1);
	pMarine->SetStimPack(pMarine,ON);

	//셋팅후의 상태를 출력한다.
	pMarine->PrintStatus(pMarine);
	DestroyCMaine(pMarine);//메모리 반환(소멸자 함수를 명시적으로 호출한다.)
	return 0;//에러 없음
}

//상태를 출력해주는 함수(변수를 바로 접근할 수도 있지만, GetXXXXX함수들을 이용한다.
void PrintStatus(CMarine *pMarine){
	printf("_______Status Information_______\n");
	printf("Life :\t %d\n",pMarine->GetLife(pMarine));
	printf("Speed :\t %d\n",pMarine->GetSpeed(pMarine));
	printf("Attack Damage :\t %d\n",pMarine->GetAttackDamage(pMarine));
	printf("Attack Range :\t %d\n",pMarine->GetAttackRange(pMarine));
	printf("Armor Upgrade Level :\t %d\n",pMarine->GetArmorUpLv(pMarine));
	printf("Weapon Upgrade Level :\t %d\n",pMarine->GetWeaponUpLv(pMarine));
	printf("Stim Pack :\t %s\n",pMarine->GetStimPack(pMarine)==1 ? "ON":"OFF");
	printf("________________________________\n");
}

//생성자 함수의 구현.
CMarine *NewCMarine(){
	//메모리 할당
	CMarine *pMarine=(CMarine *)malloc(sizeof(CMarine));

	//각함수의 주소를 저장한다.(포인터로 접근하게 함)
	pMarine->SetArmorUpLv=SetArmorUpLv;
	pMarine->GetArmorUpLv=GetArmorUpLv;
	pMarine->SetAttackDamage=SetAttackDamage;
	pMarine->GetAttackDamage=GetAttackDamage;
	pMarine->SetAttackRange=SetAttackRange;
	pMarine->GetAttackRange=GetAttackRange;
	pMarine->SetLife=SetLife;
	pMarine->GetLife=GetLife;
	pMarine->SetSpeed=SetSpeed;
	pMarine->GetSpeed=GetSpeed;
	pMarine->SetStimPack=SetStimPack;
	pMarine->GetStimPack=GetStimPack;
	pMarine->SetWeaponUpLv=SetWeaponUpLv;
	pMarine->GetWeaponUpLv=GetWeaponUpLv;
	pMarine->PrintStatus=PrintStatus;

	//초기값 설정준다.
	pMarine->m_nArmorUpLv=0;
	pMarine->m_nAttackDamage=0;
	pMarine->m_nAttackRange=0;
	pMarine->m_nLife=0;
	pMarine->m_nSpeed=0;
	pMarine->m_nStimPack=0;
	pMarine->m_nWeaponUpLv=0;

	return pMarine;
}

//소멸자 함수
void DestroyCMaine(CMarine *pMarine){
	free(pMarine);//메모리 반환
}
블로그 이미지

커뉴

이 세상에서 꿈 이상으로 확실한 것을, 인간은 가지고 있는 것일까?

,