본문 바로가기

Native/C

계산기 (음수연산.. 진행중)

// 중위 -> 후위로 그리고 과정 보여주고 계산값 보여주고
// -10*----5
// -10*-(-9.1--(--0.8--0.1))

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

//
// defintion
//
#define MAX_STACK_SIZE 100
#define MAX_EXPR_SIZE 100
typedef enum{
    lparen, rparen, plus, minus, times, divide, mod, eos, operand, blank, minus_val,minus_val2
}precedence;

//
// variant value
//
int stack[MAX_STACK_SIZE];
double dbl_stack[MAX_STACK_SIZE];
char expr[MAX_EXPR_SIZE];

char post_expr[MAX_EXPR_SIZE];
int post_i=0;
//int minus_chk = 0;        // 지워도 될듯?
int rtnM;

static int isp[] = {0, 19, 12, 12, 13, 13, 13, 0};
static int icp[] = {20, 19, 12, 12, 13, 13, 13, 0};

//
// function
//
void add(int*, int);
char put_token(int n);
double eval(void);
precedence get_token(char *, int*);
void postfix(void);
void getline(char *);
void print_token(int);
int rmstack(int *);
double pop(int* top);

int main(int argc, char *argv[])
{
    int ires;
    double dres;

    //
    // 중위 표기식 입력 받고
    //
    getline(expr);

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

    printf("\n==== PostFix ===\n%s\n================\n",post_expr);
    //
    // 후위 표기식인걸 계산하자.
    //
    dres = eval();
    ires = (int)dres;

    if((dres-ires)>0)
        printf("%lf",dres);
    else
        printf("%d",ires);

    printf("\n");

    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;
    precedence token;
    int token2=0;
    int n = 0, j=0;
    int top = 0;        // insert eos
    stack[0] = eos;


    for(token = get_token(&symbol, &n); token != eos; token = get_token(&symbol, &n))
    {
        if(token == minus_val)
        {
            post_expr[post_i++] = symbol;
            post_expr[post_i++] = '1';
            post_expr[post_i++] = ' ';
            add(&top, times);
        }
        /*else if(token == minus_val2)
        {
            printf("%c",symbol);
            post_expr[post_i++] = symbol;
            while((token = get_token(&symbol, &n)) == operand)
            {
                printf("%c",symbol);
                post_expr[post_i++] = symbol;
            }
            post_expr[post_i++] = ' ';
            minus_chk = 0;
            //post_expr[post_i++] = '*';
            //post_expr[post_i++] = ' ';
        }*/
        else if(token == operand)
        {
            //if(!rtnM || rtnM>1)
            //{
            printf("%c",symbol);
            post_expr[post_i++] = symbol;
            printf("%d",n);
            while((token = get_token(&symbol, &n)) == operand)
            {
                printf("%c",symbol);
                post_expr[post_i++] = symbol;
            }
            --n;

            post_expr[post_i++] = ' ';
        //    }

            if(rtnM)
            {
                for(j=0;j<rtnM;++j)
                {
                    post_expr[post_i++] = '-';
                    post_expr[post_i++] = '1';
                    post_expr[post_i++] = ' ';
                }

                for(j=0;j<rtnM;++j)
                {
                    post_expr[post_i++] = '*';
                    post_expr[post_i++] = ' ';
                }

                rtnM = 0;
            }
            printf(" ");
        }
        else if(token == rparen)
        {
            token2 = rmstack(&top);
            print_token(token2);
            post_expr[post_i++] = put_token(token2);
            post_expr[post_i++] = ' ';
            rmstack(&top);
        }
        else
        {
            // symbol 의 isp가 token의 icp보다 크거나 작으면 symbol을 제거하고 출력한다.
            while(isp[stack[top]] >= icp[token])
            {
                token2 = rmstack(&top);
                print_token(token2);
                post_expr[post_i++] = put_token(token2);
                post_expr[post_i++] = ' ';
            }
            add(&top, token);
        }
    }

    while((token = (precedence)rmstack(&top)) != eos)
    {
        print_token(token);
        post_expr[post_i++] = put_token(token);
        post_expr[post_i++] = ' ';
    }

    post_expr[--post_i] = '\0';
    printf("\n");
}

int CountMark(int *n)
{
    int i;
    for(i=0;'-'==expr[(*n)++];++i);

    return i;
}


precedence get_token(char* symbol, int* n)
{
    *symbol = expr[(*n)++];
    switch(*symbol)
    {
    case '-':
        if(*n==1)
            return operand;
        else if(expr[(*n)]=='(')
        {
            return minus_val;
        }
        else if(expr[*n] == '-'|| !isdigit(expr[(*n-2)]))
        {
            rtnM = CountMark(n);
            --*n;
            return operand;
        }
        /*else if(expr[*n] != '-' && minus_chk)
        {
            return minus_val2;
        }*/
        else
        {
            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:     return operand;
    }
}

precedence get_token2(char* symbol, int* n)
{
    *symbol = post_expr[(*n)++];
    switch(*symbol)
    {
    case '-':
        if(*n==1)
            return operand;
        else if(isdigit(post_expr[*n]))
        {
            return minus_val;
        }
        else
        {
            return minus;
        }
    case '(':    return lparen;
    case ')':    return rparen;
    case '+':    return plus;
    case '/':    return divide;
    case '*':    return times;
    case '%':    return mod;
    case '\0': return eos;
    case ' ':     return blank;
    default:     return operand;
    }
}

void print_token(int n)
{
    printf("%c ",put_token(n));
}

char put_token(int n)
{
    switch(n)
    {
    case minus:     return '-';
    case lparen:    return '(';
    case rparen:    return ')';
    case plus:     return '+';
    case divide:    return '/';
    case times:     return '*';
    case mod:     return '%';
    case eos:     return '\0';
    }
}

int rmstack(int* top)
{
    return stack[(*top)--];
}

double pop(int* top)
{
    return dbl_stack[(*top)--];
}

void add(int* top, int token)
{
    stack[++*top] = token;
}

//
// overloading
//
void add(int* top, double token)
{
    dbl_stack[++*top] = token;
}

double eval(void)
{
    precedence token;
    char symbol;
    double op1, op2;
    int n = 0;
    int top = -1;
    char szLine[100];
    int cnt=0;

    while((token = get_token2(&symbol, &n)) != eos)
    {
        if(token == blank) continue;

        if(token == minus_val)
        {
            szLine[cnt++] = symbol;
            while((token = get_token2(&symbol, &n)) != blank)
            {
                szLine[cnt++] = symbol;
            }
            szLine[cnt] = '\0';
            add(&top, atof(szLine));
            cnt = 0;
        }
        else if(token == operand)
        {
            szLine[cnt++] = symbol;
            while((token = get_token2(&symbol, &n)) != blank)
            {
                szLine[cnt++] = symbol;
            }
            szLine[cnt] = '\0';
            add(&top, atof(szLine));
            cnt = 0;
        }
        else
        {
            op2 = pop(&top); // delete stack
            op1 = pop(&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 pop(&top);    // return result
}

'Native > C' 카테고리의 다른 글

계산기 (음수연산 완료)  (0) 2013.10.02
계산기 (음수계산 진행중2)  (0) 2013.10.02
계산기 수정판 (소수점연산 + 일반)  (0) 2013.10.02
계산기 오류1차  (0) 2013.10.02
계산기 1차  (0) 2013.10.02