스택을 이용한 계산기 프로그램
글쓴이: 여리왕자 / 작성시간: 화, 2006/05/16 - 1:20오전
스택(배열)을 이용한 중위 연산식을 후위 연산식으로 변환한 후 그 값을 계산하는 프로그램입니다....
장장 5시간을 붙잡고 있다가.... 결국 질문을 올립니다.
일단 소스를 올리자면....
#include <stdio.h> #include <stdlib.h> #define MAX_STACK_SIZE 100 #define MAX_EXPR_SIZE 100 char expr[MAX_EXPR_SIZE] = "(((8/2)-3)+(4*2))"; typedef enum {rparen, lparen, plus, minus, times, divide, eos, operand} input_char ; static input_char stack[MAX_STACK_SIZE]; int action[7][7] ={ /*?? ) ? (? + - *? /? eos */ /*? ) */ {-1, 2, 1, 1, 1, 1, -1}, /*? ( */ {-1, 0, 0, 0, 0, 0, 0}, /* input */ /* + */ {-1, 0, 1, 1, 1, 1, 0}, /* -? */ {-1, 0, 1, 1, 1, 1, 0}, /* *? */ {-1, 0, 0, 0, 1, 1, 0}, /* /? */ {-1, 0, 0, 0, 1, 1, 0}, /* eos */ {-1,-1, 1, 1, 1, 1, 3} }; static int top = -1; // - 후위 표기식 변환 함수 void push( int *, input_char ); input_char pop( int *); void postfix( void ); input_char get_token(char *, int * ); int stack_top( int ); void print_token( input_char ); int eval( void ); input_char get_next_token( char *, int * ); int main( void ){ int top = -1; printf("fostfix: %s\n\n", expr); postfix(); printf("\n\nresult: %d", eval()); system( "pause" ); return 0; } void postfix(void) { int n = 0; /* 입력 문자열의 위치 */ char symbol; int done; input_char token; push(&top, eos); /* 스택의 초기 상태 */ token = get_token(&symbol, &n); done = 0; /* false */ while (!done) { if (token == operand) { printf("%c ", symbol); token = get_token(&symbol, &n); } else { switch (action[token][stack_top(top)]) { case -1: /* 오류 */ break; case 0: push(&top, token); // push token = get_token(&symbol, &n); break; case 1: /* pop, print, .... */ print_token(pop(&top)); break; case 2: /* pop */ pop(&top); /* delete lparen */ token = get_token(&symbol, &n); break; case 3: /* done */ done = 1; /* true */ } /* end of switch */ } } /* end of while */ } void push( int *in, input_char data ) { if (*in >= MAX_STACK_SIZE - 1) { /* 스택 포화 상태 */ fprintf(stderr, "Stack full"); exit(1); } stack[++*in] = data; } input_char pop(int *out) { if (*out < 0) { fprintf(stderr, "Stack Empty\n" ); return eos; // 스택에 존재하지 않는 코드를 반환 } //printf("[pop= %d]\n ", stack[*out]); return stack[(*out)--]; } input_char get_token(char *symbol, int *n) { *symbol = expr[(*n)++]; switch (*symbol) { case '(' : return lparen; case ')' : return rparen; case '+' : return plus; case '-' : return minus; case '/' : return divide; case '*' : return times; case '\0': return eos; default : return operand; } } int stack_top( int top) { if (top < 0 ) { fprintf(stderr, "Stack Empty"); return -1; } return stack[top]; } void print_token( input_char in ) { switch ( in ) { case lparen : printf("%c ", '(' ); break; case rparen : printf("%c ", ')' ); break; case plus : printf("%c ", '+' ); break; case minus : printf("%c ", '-'); break; case divide : printf("%c ", '/'); break; case times : printf("%c ", '*'); break; } } int eval( void ) { input_char token; char symbol; int op1, op2; int n=0; token = get_next_token( &symbol, &n ); while ( token != eos ) { if ( token == operand ) push( &top, (input_char)atoi( &symbol ) ); else { op2 = pop( &top ); op1 = pop( &top ); switch ( token ) { case plus : push( &top, (input_char)(op1 + op2)) ; break; case minus : push( &top, (input_char)(op1 - op2) ); break; case times : push( &top, (input_char)(op1 * op2) ); break; case divide : push( &top, (input_char)(op1 / op2) ); break; } } token = get_next_token( &symbol, &n ); } return pop( &top ); } input_char get_next_token( char *symbol, int *n ) { *symbol = expr[ (*n)++ ]; switch ( *symbol ) { case '+' : return plus; case '-' : return minus; case '/' : return divide; case '*' : return times; case '\0' : return eos; default : return operand; } }
일단 소스는 여기까지 입니다...
원래 있던 소스들을 껴맞추구... 제가 수정하고, 만들고 하면서 많이 변환되었습니다...
중위에서 후위 변환식으로는 변환이 되는데, 계산하는 함수인... eval() 이 먹히지 않는듯 합니다...
중간에 op1 과 op2 에 들어가는 값을 따로 프린트 해보았는데... 한쪽값에 0 이 들어가는게 이상한듯 하구요....
그리고 eval 함수에는 op1과 op2의 연산 결과값을 열거형인 input_char 형으로 타입캐스팅 해버렸는데요...
순전히 제 생각으로 해놓은겁니다... push 함수를 그대로 이용하려니 저렇게 캐스팅 하지 않으니 컴파일러가 에러를 내더군요... ㅜㅜ
근데 저렇게 캐스팅 해버리면... 열거형으로 인식해서 case 문을 통한 비교연산을 하지 않을까 싶은데요...
도무지 모르겠습니다....
아놔.... 열심히 하는데, 쉽지가 않네요.... 역시 프로그래머의 길은 멀고도 힘들어.... ㅜㅜ
고수님들~~~ 도와 주세요~~~ 충고의 말씀~~~ 한마디 쏴주세요~~~~ ^^*
File attachments:
첨부 | 파일 크기 |
---|---|
![]() | 4.08 KB |
Forums:
에...
에...
스택을 이용한... 계산기니깐..
일단 스택이 제대로 되어있어야 겠죠?
스택이 재대로 되어있나 확인하세요.
스택동작이 틀린듯..
소스 올리실때 정리좀 하고 올리시길.. 보기 힘들어서 다들 몰라라 합니다.
일렬로 쭉...이라니..
postfix()의 역할이 없는 것 같은데요.
이 소스에서 postfix()는 화면에 프린트해 주는 것 이외에 아무런 역할이 없는 것 같습니다.
postfix() 실행이 끝나고 나면 top = -1 이고 stack은 초기화되어 있습니다.
eval()의 원래 의도가 postfix()로 stack에 뭔가 채워넣은 내용을 사용하려는 것이라고도
postfix()는 원래 화면에 프린트만 하는 역할이고 eval()이 독자적으로 실행되는 것이라고도
생각할 수 없습니다. 전자라면 postfix()의 역할이 완전히 오류이고
후자라면 get_next_token()으로 여전히 stack이 아닌 expr에서 읽어들이는데다가
괄호( '(', ')' )의 처리가 빠져있는 점이 말이 되지 않습니다.
아무래도 eval() 자체의 코드만을 놓고 보면 postfix()에서 expr의 내용을 후위연산식으로
수정한 것으로 가정하는 듯 합니다. 하지만 postfix() 에 expr의 내용을 수정하는 코드는
존재하지 않습니다.
따라서 postfix()에서 printf()로 화면에 보여줄 것이 아니라
sprintf() 등을 사용해서 그 내용을 가지고 새로운 문자열을 만든 후에
그 내용을 eval()이 사용하도록 하는 편이 좋을 것 같습니다.
또다른 문제로는...
get_token()이건 get_next_token()이건 두 자리 숫자를 입력받을 수 있지 않습니다.
postfix()의 경우에는 두 자리 숫자가 들어오더라도 단순히 숫자 두 개를 화면에 프린트하면
그만이었기 때문에 이렇게 처리해도 아무 문제가 없었습니다만, eval()은 이 숫자를
값으로 인식하고 계산을 해야 하므로 이런 식으로 character 1개씩을 받아서 처리하는 것은
맞지 않습니다. 이 부분도 수정을 하셔야 할 것 같습니다.
eval()에서는 stack에 숫자값들을 집어넣고 있는데, 사실 postfix()에서는 integer값을
stack에 넣고 계산에 사용할 의도가 전혀 없었던 것 같습니다. 따라서 stack은
input_char type으로 되어 있고, integer 값을 입력하기에는 맞지 않습니다.
하지만 내부적으로는 enum 자체가 integer로 구현되어 있을 것이므로 이 부분은 실행 오류 없이
무사히 넘어갈 수 있을 것 같습니다. 의미상으로는 맞지 않습니다만.
댓글 달기