Native/C

계산기 1차

aucd29 2013. 10. 2. 18:51
/***************************************************************************
*
*        Date        : 2005-04-29
*        Copyright    : aucd29
*        E-mail        : aucd29@daum.net
*
*         중위 -> 후위로 그리고 과정 보여주고 계산값 보여주고
*
***************************************************************************/

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

//
// definition
//
#define MAX_STACK_SIZE 100
#define MAX_EXPR_SIZE 100
#define MAX_NUM 10
typedef enum{
    lparen, rparen, plus, minus, times, divide, mod, eos, operand
} precedence;

//
// variant value
//
double stack[MAX_STACK_SIZE];
double postfix_stack[MAX_EXPR_SIZE];        // 연산을 위한..
char expr[MAX_EXPR_SIZE];
double num_stack[MAX_STACK_SIZE];

static int isp[] = {0, 19, 12, 12, 13, 13, 13, 0};
static int icp[] = {20, 19, 12, 12, 13, 13, 13, 0};
int postfix_top = -1;                        // 후위 연산을 위해

//
// function
//
double eval(void);
int get_token(char*, int*, int);
void postfix(void);
void getline(char *);
void print_token(int);
double rmstack(int *);
void add(int*, int);
void ToStr(char* ,int*);
void push(double);
double pop(void);
void eval(double op1, double op2, int token);

int main(int argc, char *argv[])
{
    //
    // 중위 표기식 입력 받고
    //
    getline(expr);

    //
    // 중위식을 후위식으로 바꾸고 프린트
    //
    postfix();

    return 0;
}

//
// 배열에 주소에 내용을 입력 받는다.
//
void getline(char *s)
{
    int c, i;

    for(i=0;(c=getchar()) !='\n'; ++i)
        if(c!=' ' && MAX_EXPR_SIZE>i) *s++ = c;
    s = '\0';
}

//
// 중위 표기를 후위표기로 변환한다.
//
void postfix(void)
{
    char symbol[MAX_NUM];    
    int token,tokenx;
    int n = 0;
    int top = 0;        // insert eos
    stack[0] = eos;
    int chk=0;

    for(token = get_token(symbol, &n, 1); token != eos; token = get_token(symbol, &n, 1))
    {
        if(token == operand)
        {
            printf("%s ", symbol);
            push(atof(symbol));
        }
        else if(token == rparen)
        {
            token = (int)rmstack(&top);                    
            rmstack(&top);                    // rmstack rparen;
            print_token(token);    
            eval(pop(),pop(),token);
        }
        else
        {
            //print_token(token);
            //
            // symbol 의 isp가 token의 icp보다 크거나 작으면 symbol을 제거하고 출력한다.
            //
            //printf("(t:%d)",top);
            while(isp[(int)stack[top]] >= icp[token])
            {
                tokenx = (int)rmstack(&top);    // 이것땜에 삽질 ㅡ.ㅡ;
                print_token(tokenx);
                eval(pop(),pop(),tokenx);
            }

            //printf("(add:%d)",token);
            add(&top, token);
        }
    }

    //printf("\n=======\n%lf,%lf,%lf\n",stack[top],stack[top-1],stack[top+1]);

    //printf("(t:%d)",top);
    while((token = (int)rmstack(&top)) != eos)
    {
        print_token(token);
        eval(pop(),pop(),token);
    }

    printf("\nResult : %lf",postfix_stack[postfix_top]);
    printf("\n");
}

int get_token(char* symbol, int* n, int recuv)
{
    char c = expr[(*n)++];
     /* if(*n-1==0 || get_token(symbol, n-1, 0) != operand)
        {
            *symbol++ = '-';
            ToStr(symbol, n+1);
            return operand;
        }
        else*/
    switch(c)
    {
    case '-':    return minus;
    case '(':    return lparen;
    case ')':    return rparen;
    case '+':    return plus;
    case '/':    return divide;
    case '*':    return times;
    case '%':    return mod;
    case '\0':    return eos;
    default:
        if(recuv)
        {
            *symbol++ = c;
            ToStr(symbol, n);
        }
        return operand;
    }
}

void ToStr(char* symbol,int* n)
{
    while(get_token(symbol, n, 0) == operand)
        *symbol++ = expr[*n-1];
    
    *symbol = '\0';
    --*n;
}

void print_token(int n)
{
    switch(n)
    {
    case minus:        printf("-"); break;
    case lparen:    printf("("); break;
    case rparen:    printf(")"); break;
    case plus:        printf("+"); break;
    case divide:    printf("/"); break;
    case times:        printf("*"); break;
    case mod:        printf("%");break;
    }
    printf(" ");
}

double rmstack(int* top)
{
    return stack[(*top)--];        // 리턴후 스텍 감소
}

void add(int* top, int token)
{
    stack[++*top] = token;        // 증가후 토큰 입력
}

//
// overloading
//
void add(int* top, double token)
{
    stack[++*top] = token;        // 증가후 토큰 입력
}

void push(double f)
{
    postfix_stack[++postfix_top] = f;
}

double pop(void)
{
    return postfix_stack[postfix_top--];
}

void eval(double op1, double op2, int token)
{
    //printf("\neval(%lf, %lf)\n", op1, op2);
    switch(token)
    {
    case plus:
        push(op1 + op2);
        break;
    case minus :    
        push(op1 - op2);
        break;
    case times :
        push(op1 * op2);
        break;
    case divide:
        push(op1 / op2);
        break;
    case mod :
        push((int)op1 % (int)op2);
        break;
    }

    /*int token;
    char symbol[MAX_NUM];
    double op1, op2;
    int n = 0;
    int top = -1;
    
    while((token = get_token(symbol, &n, 1)) != eos)
    {
        if(token == operand)
            add(&top, atof(symbol)); // push
        else
        {
            op2 = rmstack(&top);    // pop
            op1 = rmstack(&top);
            switch(token)
            {
            case plus:
                add(&top, op1 + op2);
                break;
            case minus :
                add(&top, op1 - op2);
                break;
            case times :
                add(&top, op1 * op2);
                break;
            case divide:
                add(&top, op1 / op2);
                break;
            case mod :
                add(&top, (int)op1 % (int)op2);
                break;
            }
        }
    }
    
    return rmstack(&top);*/
}