반응형
프로그래밍 처음 시작하면서 짠코드입니다. 허접하니 알아서 보시길;;
아무래도 컴파일은 될것입니다. VS5.0 콘솔 프로젝트로 테스트완료
- 예제파일 : 공학용계산기.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#define MAX_EXPR_SIZE 100
#define MAX_MYSTACK_SIZE 50
typedef enum
{lparen,rparen,plus,minus,times,devide,mod,eos,operand,sign_m,sign_p,my_sin,my_cos,my_tan} precendence;
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13
static int isp[] = {0, 19, 12, 12, 13, 13, 13, 0, 0, 0, 0, 0, 0}; // 스택에 있을때 isp[8],isp[9]=21 최고수준유지..
static int icp[] = {20, 19, 12, 12, 13, 13, 13, 0, 21, 21, 21, 21, 21}; // 스택에 들어갈때
//# & 연산자는 스택엔 무조건 저장했다가.. 다른연산자 만나면 무조건 꺼낸다.
char expr[MAX_EXPR_SIZE];
double stack[MAX_MYSTACK_SIZE]; // 스택선언.. 동적할당은 않는다.
int top; // 스택 tp 선언.. stack_init()으로 초기화.. -1
/* 원형 선언..*/
void stack_init();
void push(double);
double pop();
precendence get_token(char*);
char printf_token(int);
void postfix(char*,char*); //중위 표현 으로..
double eval(char*); //후위 표현 으로 컨버팅... 정수만..
void tri_funtion(char*,char*); //삼각 함수를 압축 따로 계산..
double my_sin_fct(char*);
double my_cos_fct(char*);
double my_tan_fct(char*);
int main(void)
{
int i=0;
char input_char;
/* 입력 문자열 */
char expr_temp[MAX_EXPR_SIZE];
printf("수식입력하시오\n");
while((input_char=getchar()) != '\n') //문자열 입력받음..
expr[i++]=input_char;
expr[i]='\0'; // 마지막에 널문자.
tri_funtion(expr,expr_temp); // 일단 삼각 함수 모두 계산하여 정수 중위표현만 넘긴다.
printf("변환 확인:%s\n",expr_temp);
postfix(expr_temp,expr_temp);
printf("후위표현..%s\n", expr_temp);
eval(expr_temp);
printf("최종결과:%f\n",eval(expr_temp));
// printf("sin30=%f",sin(30*3.141592/180));
return 0;
}
/*----------stack funtion-----------------*/
void push(double temp)
{
stack[++top]=temp;
}
void stack_init()
{
top = -1;
}
double pop()
{
return stack[top--];
}
/*----------------------------------------*/
/*-------convert data---------------------*/
precendence get_token(char* input)
{
switch(*input){
case '(' : return lparen;
case ')' : return rparen;
case '+' : return plus;
case '-' : return minus;
case '*' : return times;
case '/' : return devide;
case '%' : return mod;
//----------------------------------------//
case '&' : return sign_m;
case '#' : return sign_p;
//----------------------------------------//
case 's' : return my_sin;
case 'c' : return my_cos;
case 't' : return my_tan;
//----------------------------------------//
case '\0' : return eos;
default : return operand;
}
}
char printf_token(int precendence)
{
switch(precendence){
//----------------------------------------//
case sign_m : return '&'; // * -1
case sign_p : return '#'; // * 1
//----------------------------------------//
case my_sin : return 's';
case my_cos : return 'c';
case my_tan : return 't';
//----------------------------------------//
case plus : return '+';
case minus : return '-';
case times : return '*';
case devide : return '/';
default : return '%';
}
}
void postfix(char* input,char* output) //후위 표현으로 바꾼 string을.. strcpy(input,output);
{
precendence token;
int j=0, k=0, sign=0, flag=1;
char temp_num[100];
stack_init(); // 스택 초기화
push(eos); // stack의 첫번째 요소에..eos
while((token = get_token(input+j))!=eos)
{
sign=0; //sign 초기화..
//-------minus sign 판별..---- 수식 / 부호 => 0 /1 --------//
if((token==minus))
{
if(j==0 && (get_token(input+j+1)==minus)) // 처음 - - 이면..
sign=-1;
else if((get_token(input+j-1)!=operand) && (get_token(input+j+1)==operand)) // 수식 - 숫자 일때..
sign=1; //부호인 경우는 오로지 한개다....
else if((get_token(input+j-1)==rparen) && (get_token(input+j+1)!=operand)) // ) - 수식..
sign=0;
else if((get_token(input+j-1)!=operand) && (get_token(input+j+1)==lparen)) // 수식 - ( 이면..
sign=-1; //좌 괄호 앞은 *-1 이다.
else if((get_token(input+j-1)==rparen) && (get_token(input+j-1)!=operand)) // 수식 - ( 이면..
sign=-1; //좌 괄호 앞은 *-1 이다
else if((get_token(input+j-1)!=operand) && isalpha(*(input+j+1))) // 수식 - sin 이면..
sign=-1;
else if((get_token(input+j-1)!=operand) && (get_token(input+j+1)==minus)) // 수식 - - 이면..
sign=-1; // 수식 사이의 -는 *-1 이다.
else // 숫자 - 숫자
sign=0;
}
//----------------------------------------------------------//
//--------plus sign 판별..---- 수식 / 부호 => 0 /1 --------//
if((token==plus))
{
if(j==0 && (get_token(input+j+1)==plus)) // 처음 + + 이면..
sign=-2;
else if((get_token(input+j-1)!=operand) && isalpha(*(input+j+1))) // ) - 문자 이면..
sign=-2;
else if((get_token(input+j-1)==rparen) && (get_token(input+j+1)!=operand)) // ) - 수식..
sign=0;
else if((get_token(input+j-1)!=operand) && isalpha(*(input+j+1))) // 수식 - sin 이면..
sign=-2;
else if((get_token(input+j-1)!=operand) && (get_token(input+j+1)==operand)) // 수식 + 숫자 일때..
sign=1; //부호..
else if((get_token(input+j-1)!=operand) && (get_token(input+j+1)==lparen)) // 수식 + ( 이면..
sign=0;
else if((get_token(input+j-1)!=operand) && (get_token(input+j+1)==plus)) // 수식 + + 이면..
sign=-2;
else //숫자 + 숫자
sign=0;
}
//----------------------------------------------------------//
// printf("sign=%d\n",sign);
if(sign==-3) // 에러 플래그 띄울까?
{
printf("input error!!!!\n");
exit(1);
}
else if(sign==-2)
{
j++;
push(sign_p);
continue;
}
else if(sign==-1) // * -1 처리..
{
j++;
push(sign_m); // -() 처리.. 스택저장하고 루프끝냄.. &&..
continue;
}
else if(sign==0) // 해당인덱스가 부호가 아닐때.. 원래대로 처리..
{
if (token == operand)
{
*(temp_num+k++) = *(input+j);
if(!isdigit(*(input+j+1)) && (*(input+j+1)!='.') && !isalpha(*(input+j+1)) && (stack[top]==9||stack[top]==8) ) // # & 가 숫자 앞에 있을경우 끄집는다.
{ // 뒤에가 소숫점, 숫자, 문자가 아닐경우.. 숫자 종료..
while(stack[top]==9 || stack[top]==8) // 좌괄호 나올때까지.. pop()..
{
*(temp_num+k++)=' ';
*(temp_num+k++) = printf_token((int)pop());
*(temp_num+k++)=' ';
}
}
}
else if (token == rparen) // 우괄호..
{
while(stack[top]!=lparen) // 좌괄호 나올때까지.. pop()..
{
*(temp_num+k++)=' ';
*(temp_num+k++) = printf_token((int)pop());
}
pop(); // 좌골호 또한. pop
//----좌괄호 옆에 삼각함수 있으면 끄집어 내라.------//
if(stack[top]==my_sin)
{
*(temp_num+k++)=' ';
*(temp_num+k++) = printf_token((int)pop());
}
if(stack[top]==my_cos)
{
*(temp_num+k++)=' ';
*(temp_num+k++) = printf_token((int)pop());
}
if(stack[top]==my_tan)
{
*(temp_num+k++)=' ';
*(temp_num+k++) = printf_token((int)pop());
}
//---------------------------------------------------//
}
else
{
if((get_token(input+j-1)==operand) && (token==lparen)) //숫자() 곱셈치환..
{
push(times);
}
if((get_token(input+j-1)!=lparen) && !isalpha(*(input+j)) && (stack[top]==9||stack[top]==8) ) // # & 가 숫자 앞에 있을경우 끄집는다.
{ // 뒤에가 소숫점, 숫자, 문자가 아닐경우.. 숫자 종료..
while(stack[top]==9 || stack[top]==8) // 좌괄호 나올때까지.. pop()..
{
*(temp_num+k++)=' ';
*(temp_num+k++) = printf_token((int)pop());
*(temp_num+k++)=' ';
}
}
while(isp[(int)stack[top]]>=icp[token]) //현재 스택포인터와 들어갈 자료 비교.
{
*(temp_num+k++)=' ';
*(temp_num+k++) = printf_token((int)pop());
}
push(token);
*(temp_num+k++)=' '; // 숫자 끝나면 공백 넣어라.
}
}
else // 해당인덱스가 부호 일때.. 그냥 프린트..
{
*(temp_num+k++) = *(input+j);
sign=0; // 부처리후 다시 초기화..
}
j++;
}
while((token = (int)pop())!=eos)//스택에 나머지있는거 다 출력
{
*(temp_num+k++)=' ';
*(temp_num+k++) = printf_token(token);
}
*(temp_num+k++)=' '; // 후위 표현 연산뒤 강제로 공백삽입
temp_num[k]='\0';
strcpy(output,temp_num);
}
double eval(char* postfix)
{
int i=0,j=0;
char temp_num[10]; // atof 쓰기위한 임시 배열..
int flag=0;
double op1,op2;
stack_init(); //stack을 쓰기 위한 다시 초기화.
while(*(postfix+i)!='\0')
{
//printf("현재 스택값 : %f \n",stack[top]);
//----- 일반 숫자열계산. --------------------------------------------------------------//
if(*(postfix+i)==' ')
{
i++; // 일단 공백 제거..
continue; // 인덱스는 바로 옮긴다.
}
else if(isdigit(*(postfix+i+1))) // 뒤에가 숫자면.. 부호이므로... atof 변환하여 스택저장.
{
while((*(postfix+i)!=' '))
{
temp_num[j++]=*(postfix+i++);
}
temp_num[j]='\0'; // temp_num을 마무리
push(atof(temp_num)); // push 하여 스택에 저장..
j=0; // temp_num을 다시 초기화 해서 쓴다.
}
else if(isdigit(*(postfix+i))) // 해당 인덱스하 한자리 숫자일경우..
{
while(*(postfix+i)!=' ')
temp_num[j++]=*(postfix+i++);
temp_num[j]='\0'; // temp_num을 마무리
push(atof(temp_num)); // push 하여 스택에 저장..
j=0; // temp_num을 다시 초기화 해서 쓴다.
}
else if(*(postfix+i)=='&') // -( ) 처리..
stack[top] = stack[top] * -1;
else if(*(postfix+i)=='#') // +( ) 처리..
stack[top] = stack[top] * 1;
else if(*(postfix+i)=='s')
stack[top] = sin(stack[top]*3.141592/180);
else if(*(postfix+i)=='c')
stack[top] = cos(stack[top]*3.141592/180);
else if(*(postfix+i)=='t')
stack[top] = tan(stack[top]*3.141592/180);
else
{
op2 = pop();
op1 = pop();
switch(get_token(postfix+i))
{
case plus :
{
push(op1 + op2);
break;
}
case minus :
{
push(op1 - op2);
break;
}
case times :
{
push(op1 * op2);
break;
}
case devide :
{
push(op1 / op2);
break;
}
case mod :
{
push((int)op1 % (int)op2);
break;
}
}
}
//------------------------------------------------------------------------------//
i++; // 무사히 한번돌면 인덱스 증가. 단 공백은 바로.. continue
}
// printf("최종결과:%f",stack[top]); // stack에 최종남아있는것이 값.
return stack[top];
}
void tri_funtion(char* input,char* output)
{
char tri_result[MAX_EXPR_SIZE];
char temp_arr[10]; // s c t 임시 검사용..
int i=0, j=0, z=0;
while(*(input+i)!='\0')
{
// tri_result[z++] = *(*(input+i));
if(isalpha(*(input+i))!=0) // 숫자,문자=0 // 대문자=1 // 소문자=2 //문자일경우.. 루프..
{
char char_sin[] = {"sin"};
char char_cos[] = {"cos"};
char char_tan[] = {"tan"};
//--------- s c t 검사후 문자열 변환.. ------------------//
for(j=0;j<3;j++) // 삼각함수 문자열 저장..() 했을때..
temp_arr[j]=*(input+i+j);
temp_arr[j]='\0';
if(!strncmp(temp_arr,char_sin,3))
{
tri_result[z++] = 's';
i+=3; // 만약 sin 들어오면.. 인덱스 3 옮기고 루프 종료.
continue;
}
else if (!strncmp(temp_arr,char_cos,3))
{
tri_result[z++] = 'c';
i+=3; // 만약 cos 들어오면.. 인덱스 3 옮기고 루프 종료.
continue;
}
else if (!strncmp(temp_arr,char_tan,3))
{
tri_result[z++] = 't';
i+=3; // 만약 tan 들어오면.. 인덱스 3 옮기고 루프 종료.
continue;
}
else
{
printf("input data is error"); // 잘못된 데이터면 프로그램 강제종료.
exit(1);
}
}
//--------- s c t 검사후 문자열 변환.. ------------------//
else
tri_result[z++] = *(input+i);
i++;
}
tri_result[z]='\0';
// printf("test:%s\n",tri_result);
strcpy(output,tri_result);
}
/*
double my_sin_fct(char* input)
{
char temp_tri_sin[50];
double result;
postfix(input,temp_tri_sin); // 들어온 스트링을 후위 표현으로 계산후..
eval(temp_tri_sin); // 그 인자를 연산하여..
result = sin(eval(temp_tri_sin)*3.141592/180); // 최종 사인값으로..
return result;
}
double my_cos_fct(char* input)
{
char temp_tri_cos[50];
double result;
postfix(input,temp_tri_cos); // 들어온 스트링을 후위 표현으로 계산후..
eval(temp_tri_cos); // 그 인자를 연산하여..
result = cos(eval(temp_tri_cos)*3.141592/180); // 최종 사인값으로..
return result;
}
double my_tan_fct(char* input)
{
char temp_tri_tan[50];
double result;
postfix(input,temp_tri_tan); // 들어온 스트링을 후위 표현으로 계산후..
eval(temp_tri_tan); // 그 인자를 연산하여..
result = tan(eval(temp_tri_tan)*3.141592/180); // 최종 사인값으로..
return result;
}
*/
반응형