STACKÀ» »ç¿ëÇÏÁö ¾Ê´Â »çÄ¢¿¬»ê °è»ê±â

 

ÀÛ¼º: ±èÁøÈ«

¿¬»êÀÇ ¿ì¼±¼øÀ§¸¦ À§ÇØ Á¦ÇѾøÀÌ °ýÈ£¸¦ »ç¿ëÇÒ ¼ö ÀÖ´Ù.

 

 

/*

 *             A CALCULATOR

 *

 *             Coded by kim jin hong

 */

 

 

 

#include <stdio.h>

#include <stdlib.h>

 

#define MAXDATA                                       300   /* maximum readable characters */

 

#define ID_VALUE                            0

#define ID_OPENPARENTHESIS  1

#define ID_CLOSEPARENTHESIS     2

#define ID_ADD                  3

#define ID_SUBTRACT             4

#define ID_MULTIPLY             5

#define ID_DIVIDE               6

 

#define P_AS                                       1   /* signal for ADD or SUBTRACT */

#define  P_MD                                       2   /* signal for MULTIPLY or DIVIDE */

#define P_UP                                       100 /* weight for priority */

 

struct datatype {                   /* standard united data type */

  int level;                        /* priority of token */

  int id;                           /* token name */

  double data;                      /* a data; I used only double type */

} token[MAXDATA];

 

int itemn=0;                        /* total item number */

 

 

int nlength(char *);                /* return length of the value */

void cpy(char *, char *, int, int); /* copy string */

int isnumber(char);                 /* return true if the item is a value */

void classify(char *);              /* classify all the items */

void error(int);                    /* print error msg and quit if error occured */

void setuplevel(void);              /* set up priorities all of the items */

void cpytoken(struct datatype *, struct datatype); /* copy a token */

void eliminatep(void);              /* eliminate all parenthesises from the token[] */

int selectmaxlevel(void);           /* select an item which has the highest priority */

double calculate(void);             /* return double-type calculated data */

void eliminatespace(char *);        /* eliminate white-space in the string */

void process(char *);               /* call all processes before call calculate() */

void getline(char *);               /* get one line from console */

void checksides(int);               /* cause error if both side of the item aren't VALUE */

 

void main(int argc, int *argv[])

{

  char str[MAXDATA];

  int t;

 

  /* you can input your expressions(with no white-space) in the parameter */

  if (argc < 2) {

    printf("INPUT YOUR EXPRESSIONS (MAXIMUM %d ITEMS ALLOWED)\n", MAXDATA);

    getline(str);

    process(str);

  } else process(argv[1]);

}

 

void getline(char *str)

{

  char c;

  int idx=0;

 

  while ((c=getchar()) != '\n' && idx < MAXDATA)

    str[idx++]=c;

 

  str[idx]=NULL;

}

 

void process(char *str)

{

  eliminatespace(str);

  classify(str);

  setuplevel();

  eliminatep();

  printf("RESULT: %f\n", calculate());

}

 

int nlength(char *str)

{

  int cnt=0;

 

  if ((*str == '-') || (*str == '+')) {

    cnt++;

    str++;

  }

 

  while (1) {

    if ((*str >= '0' && *str <= '9') || (*str == '.')) cnt++;

    else break;

 

    str++;

  }

 

  return cnt;

}

 

void cpy(char *dst, char *src, int from, int to)

{

  int t;

 

  for (t=from; t<=to; t++)

    dst[t-from]=src[t];

  dst[t]=NULL;

}

 

int isnumber(char c)

{

  if (c >= '0' && c <= '9' || c == '.') return 1;

  return 0;

}

 

void classify(char *str)

{

  int idx=0, nlen;

  char buf[30];       /* temporarily need */

 

  while (*str != NULL) {

    switch (*str) {

      case '(':

                          token[itemn].id=ID_OPENPARENTHESIS;

                          itemn++;

                          str++;

                          break;

      case ')':

                          token[itemn].id=ID_CLOSEPARENTHESIS;

                          itemn++;

                          str++;

                          break;

      case '+':

                          token[itemn].id=ID_ADD;

                          itemn++;

                          str++;

                          break;

      case '-':

                          token[itemn].id=ID_SUBTRACT;

                          itemn++;

                          str++;

                          break;

      case '*':

                          token[itemn].id=ID_MULTIPLY;

                          itemn++;

                          str++;

                          break;

      case '/':

                          token[itemn].id=ID_DIVIDE;

                          itemn++;

                          str++;

                          break;

      default:

                /* cause error if found nonuse token */

                          if (!isnumber(*str)) error(3);

 

                          /* cause error if found these exprs., '1(2)': this should be '1*(2)'

                          if (isnumber(*str) && *(str-1)==')' || *(str+1)=='(')

                             error(3);

 

                /* check about the value has unary operation */

                          if ( (*(str-1) == '-' || *(str-1) == '+') && (!isnumber(*(str-2)))

                               && (*(str-2) != ')')) {

                                itemn--;

                                str--;

                          }

 

                          nlen=nlength(str);

                          cpy(buf, str, 0, nlen-1);

                          token[itemn].id=ID_VALUE;

                          token[itemn].data=atof(buf);

                          itemn++;

                          str+=nlen;

                          break;

    }

 

    idx++;

  }

 

  /* cause error, if total item number below 3 */

  if (itemn < 3) error(2);

 

  /* cause error if last item is not VALUE */

  if (token[itemn-1].id == ID_ADD || token[itemn-1].id == ID_SUBTRACT ||

      token[itemn-1].id == ID_MULTIPLY || token[itemn-1].id == ID_DIVIDE)

      error(3);

}

 

void error(int en)

{

  switch(en) {

    case 0:printf("Fatal error: Divide by zero!\n"); break;

    case 1:printf("Syntax error: Not matched parenthesis.\n"); break;

    case 2:printf("Syntax error: Not enough expression.\n"); break;

    case 3:printf("Syntax error: Not allowed expression.\n"); break;

  }

 

  exit(1);  /* exit. we can't process further more */

}

 

void setuplevel()

{

  int t, curprior=0;

 

  for (t=0; t<itemn; t++) {

    switch(token[t].id) {

      case ID_OPENPARENTHESIS:

                curprior+=P_UP;

                break;

      case ID_CLOSEPARENTHESIS:

                curprior-=P_UP;

                break;

    }

 

    token[t].level=curprior;

 

    switch(token[t].id) {

      case ID_ADD             :

      case ID_SUBTRACT        :token[t].level+=P_AS; break;

      case ID_MULTIPLY        :

      case ID_DIVIDE          :token[t].level+=P_MD; break;

      default                                :token[t].level=0; break;

    }

  }

 

  /* if curprior is not zero, that means parenthesises in the token[]

     are not matched */

  if (curprior != 0) error(1);

}

 

void cpytoken(struct datatype *dst, struct datatype src)

{

  dst->level=src.level;

  dst->id=src.id;

  dst->data=src.data;

}

 

void eliminatep()

{

  int t, nitemn=0;

 

  for (t=0; t<itemn; t++)

    if (token[t].id != ID_OPENPARENTHESIS &&

             token[t].id != ID_CLOSEPARENTHESIS) {

      cpytoken(&token[nitemn], token[t]);

      nitemn++;

    }

 

  itemn=nitemn;

}

 

int selectmaxlevel()

{

  int t, m=0;

 

  for (t=1; t<itemn; t++)

    if (token[m].level < token[t].level) m=t;

 

  return m;

}

 

void checksides(int m)

{

  if (m == 0 || token[m-1].id != ID_VALUE ||

      token[m+1].id != ID_VALUE) error(3);

}

 

double calculate()

{

  double acc=0.0;

  int maxlevel, t;

 

  /* if total item number is below 3... */

  if (itemn < 3) error(2);

 

  while (itemn > 1) {

    maxlevel=selectmaxlevel();

    checksides(maxlevel);

 

    switch(token[maxlevel].id) {

      case ID_ADD:

                          acc=token[maxlevel-1].data + token[maxlevel+1].data;

                          break;

      case ID_SUBTRACT:

                          acc=token[maxlevel-1].data - token[maxlevel+1].data;

                          break;

      case ID_MULTIPLY:

                          acc=token[maxlevel-1].data * token[maxlevel+1].data;

                          break;

      case ID_DIVIDE:

                          if (token[maxlevel+1].data == 0.0) error(0);

                          acc=token[maxlevel-1].data / token[maxlevel+1].data;

                          break;

    }

 

    token[maxlevel-1].data=acc;

    token[maxlevel-1].level=0;

    token[maxlevel-1].id=ID_VALUE;

    itemn-=2;

 

    for (t=maxlevel; t<itemn; t++)

      cpytoken(&token[t], token[t+2]);

 

  }

 

  return acc;

}

 

void eliminatespace(char *str)

{

  char buf[MAXDATA];

  char *ptr=str;

  int idx=0;

 

  while (*str != NULL) {

    if (*str != ' ') {

      buf[idx]=*str;

      idx++;

    }

 

    str++;

  }

 

  buf[idx]=NULL;

  cpy(ptr, buf, 0, idx-1);

}