2016年1月31日 星期日

A Calculator Supports Parentheses Writtren in C




 The flow chart be:

 Read Input  -> Get Tokens -> Infix To Postfix -> Evaluate -> Output Result



GetToken : Check if there are the known syntaxes or not.

Infix To Postfix: Check if the parentheses are balance or not.

Evaluate: Check if there is the operator or operand being dangle or not.


My Code:

/*
ref :
 http://www.paulgriffiths.net/program/c/calc1.php
 http://openhome.cc/Gossip/AlgorithmGossip/InFixPostfix.htm //tranditional chinese
*/


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

#include <ctype.h>
#include <math.h>

#define _FORCE_FLOATING_ARITHMETIC

#ifndef FALSE
 #define FALSE       (0)
 #define TRUE       (1)
#endif

#define MAX_STR_LEN       (256)

enum TokenType
{
 Unknown,
 ExpressionEnd,
 Operator,
 OperandInteger, OperandFloat
};

enum OperatorType
{
 OP_UNKOWN = 0, OP_PLUS, OP_MINUS, OP_MULTIPLY, OP_DIVIDE,
 OP_POWER, OP_MOD, OP_LPAREN, OP_RPAREN, 
};

typedef struct TokenProperty {
 enum TokenType tokenType;

 union
 {
  long long intValue;
  double floatValue;
  struct
  {
   enum OperatorType operatorType;
   char unknownSymbol;
  };
 };/*union*/
}TokenProperty;


int GetTokenNumber(char *pStr, int bufferSize)
{
 int number;
 char *pMovBuf;

 number = 0;
 pMovBuf = pStr;
 while ((pMovBuf - pStr) < bufferSize)
 {
  char *pTemp;

  if ('\0' == *pMovBuf || '\n' == *pMovBuf || EOF == *pMovBuf)
  {
   number++;
   break;
  }/*if end */

  if (isspace(*pMovBuf))
   pMovBuf++;

  pTemp = pMovBuf;

  strtold(pMovBuf, &pTemp);

  if (pMovBuf == pTemp
   || *pTemp == 'e' || *pTemp == 'E'
#if(0)
   || *pTemp == 'f' || *pTemp == 'F'
#endif
   )
  {
   pTemp++;
  }/*if strtold valid or float suffix*/

  pMovBuf = pTemp;
  number++;
 }/*while 0 < bufferSize*/

 return number;
}/*GetTokenNumber*/


int PrintTokenProperty(int n, struct TokenProperty *pTokens)
{
 int i;

 for (i = 0; i < n; i++) {
  switch (pTokens[i].tokenType)
  {
  case Unknown:
   printf("Unknown\n");
   break;
  case ExpressionEnd:
   printf("ExpressionEnd\n");
   break;
  case Operator:
   printf("Operator, ");
   switch (pTokens[i].operatorType)
   {
   case OP_UNKOWN:
    printf("OP_UNKOWN \n");
    break;

   case OP_PLUS:
    printf("OP_PLUS \n");
    break;
   
   case OP_MINUS:
    printf("OP_MINUS \n");
    break;

   case OP_MULTIPLY:
    printf("OP_MULTIPLY \n");
    break;

   case OP_DIVIDE:
    printf("OP_DIVIDE \n");
    break;

   case OP_POWER:
    printf("OP_POWER \n");
    break;

   case OP_MOD:
    printf("OP_MOD \n");
    break;

   case OP_LPAREN:
    printf("OP_LPAREN \n");
    break;

   case OP_RPAREN:
    printf("OP_RPAREN \n");
    break;

   default:
    return -2;
   }/*switch operatorType*/
   break;
  case OperandInteger:
   printf("OperandInteger, %lld\n", pTokens[i].intValue);
   break;
  case OperandFloat:
   printf("OperandFloat, %f\n", pTokens[i].floatValue);
   break;
  default:
   return -1;
  }/*switch tokenType*/

 }/*for */
 printf("\n");
 return 0;
}/*PrintTokenProperty*/


int GetNextToken(char *pStr, int strSize, struct TokenProperty *pToken, int *pCostedStrLen)
{
 int tokenLen;
 char *pMovBuf;

 tokenLen = 0;
 pMovBuf = pStr;


 if ('\0' == *pMovBuf || '\n' == *pMovBuf || EOF == *pMovBuf)
 {
  pToken->tokenType = ExpressionEnd;
  pMovBuf++;
  goto Flag_End_GetToken;
 }/*if*/

 while (*pMovBuf && isspace(*pMovBuf))
  pMovBuf++;

 if (FALSE != isdigit(*pMovBuf))
 {
  /*  Token is an operand  */
  int isFloat;
  isFloat = FALSE;

  {
   long long intValue;
   char *pTemp;

   intValue = strtoll(pMovBuf, &pTemp, 0);
   if (*pTemp == '.'
    || *pTemp == 'e' || *pTemp == 'E'
#if(0)
    || *pTemp == 'f' || *pTemp == 'F'
#endif
    )
   {
    isFloat = TRUE;
   }
   else
   {
    pToken->tokenType = OperandInteger;
    pToken->intValue = intValue;
    pMovBuf = pTemp;
   }/*is float*/
  }/*local variable*/

  if (FALSE != isFloat)
  {
   pToken->floatValue = strtod(pMovBuf, &pMovBuf);
   pToken->tokenType = OperandFloat;
#if(0)
   if ('f' == *pMovBuf || 'F' == *pMovBuf)
    pMovBuf++;
#endif
  }/*FALSE == isFloat*/

  goto Flag_End_GetToken;
 }/* operand */


 {
  /*Token is an operator*/  
  char symbol;
  symbol = *pMovBuf;
  pToken->tokenType = Operator;

  switch (symbol)
  {
  case '+':
   pToken->operatorType = OP_PLUS;
   break;
  case '-':
   pToken->operatorType = OP_MINUS;
   break;
  case '*':
   pToken->operatorType = OP_MULTIPLY;
   break;
  case '/':
   pToken->operatorType = OP_DIVIDE;
   break;

  case '^':
   pToken->operatorType = OP_POWER;
   break;
  case '%':
   pToken->operatorType = OP_MOD;
   break;

  case '(':
   pToken->operatorType = OP_LPAREN;
   break;

  case ')':
   pToken->operatorType = OP_RPAREN;
   break;

  default:
   pToken->operatorType = OP_UNKOWN;
   pToken->unknownSymbol = symbol;
   break;
  }/*switch*/

  pToken->tokenType = Operator;
  pMovBuf++;
 }/*operator */

Flag_End_GetToken:

 tokenLen = (int)(pMovBuf - pStr);
 *pCostedStrLen = tokenLen;

 return tokenLen;
}/*GetToken*/


int GetTokens(char *pStr, int strLen, struct TokenProperty *pTokenArray)
{
 int costedSize;
 int k;
 char *pMovBuf; 

 pMovBuf = pStr; 

 k = 0;

 while (0 < strLen)
 {
  GetNextToken(pMovBuf, strLen, &pTokenArray[k], &costedSize);

  pMovBuf += costedSize;
  strLen -= costedSize;
  k++;  
 }/*while 0 < strLen*/


 {/*check if there is unknownSymbol*/
  int i;    
  for (i = 0; i < k; i++)
  {
   if (Operator == pTokenArray[i].tokenType &&
    OP_UNKOWN == pTokenArray[i].operatorType)
   {
    printf("Error : character %c unknown\n",
     pTokenArray[i].unknownSymbol);

    return -1;
   }/*if */

  }/*for i*/
  
 }/*local variable*/

#ifndef _DEBUG
 /*check if there is grammatical error*/
 {
  int i;
  struct TokenProperty previousToken;

  memcpy(&previousToken, &pTokenArray[0],
   sizeof(struct TokenProperty));

  for (i = 1; i < k; i++)
  {   
   switch (pTokenArray[i].tokenType)
   {
   case Operator:
    if (Operator == previousToken.tokenType
     && OP_LPAREN != previousToken.operatorType
     && OP_RPAREN != previousToken.operatorType)
    {
     printf("error : two operator have been"
      " put together !\n");
     return -2;
    }
    break;
   case OperandFloat:
   case OperandInteger:
    if (OperandFloat == previousToken.tokenType
     || OperandInteger == previousToken.tokenType)
    {
     printf("error : two operend have been" 
      " put together !\n");
     return -3;
    }
    break;
   }/*switch*/

   memcpy(&previousToken, &pTokenArray[i],
    sizeof(struct TokenProperty));
  }/*for i*/
 }/*local variable*/ 

#endif /*_DEBUG*/

 return k;
}/*GetTokens*/


int InfixArrayToPostfixStack(int nInfixToken, struct TokenProperty *pTokens)
{
 struct TokenProperty *pTokenInfixArray;
 struct TokenProperty *pTokenPostfixStack;

 struct TokenProperty *pCurrentToken;

 unsigned char precedence[MAX_STR_LEN];
 int i;
 int nPostfixToken;
 int operatorStackTop;

 struct TokenProperty *pOperatorTokenStack;
 
 
 pTokenInfixArray = pTokens;

 if (0 >= nInfixToken)
  return -1;

 { /*initialize the precedence array*/

  memset(&precedence[0], 0, MAX_STR_LEN);
  precedence[OP_PLUS] = 1; precedence[OP_MINUS] = 1;
  precedence[OP_MULTIPLY] = 2; precedence[OP_DIVIDE] = 2;
  precedence[OP_POWER] = 3; precedence[OP_DIVIDE] = 2;

  precedence[OP_LPAREN] = 255; precedence[OP_RPAREN] = 254;
  precedence[OP_UNKOWN] = 0;
 }/*local block*/

 pOperatorTokenStack =
  (struct TokenProperty*)malloc((nInfixToken)*sizeof(struct TokenProperty));
 memset(pOperatorTokenStack, 0, (nInfixToken)*sizeof(struct TokenProperty));

 pTokenPostfixStack =
  (struct TokenProperty*)malloc(nInfixToken*sizeof(struct TokenProperty)); 
 memset(pTokenPostfixStack, 0, nInfixToken*sizeof(struct TokenProperty));

 pCurrentToken = &pTokenInfixArray[0];
 
 operatorStackTop = -1;
 nPostfixToken = 0;

 for (i = 0; i < nInfixToken; i++)
 {
  enum TokenType tokenType;
  tokenType = pCurrentToken->tokenType;

  switch (tokenType)
  {  
  case OperandInteger:
  case OperandFloat:
   memcpy(&pTokenPostfixStack[nPostfixToken],
    pCurrentToken, sizeof(struct TokenProperty));
   nPostfixToken += 1;
   break;
  case Operator:
   switch (pCurrentToken->operatorType)
   {
   case OP_UNKOWN:
    printf("Unknown operator %c\n", pCurrentToken->unknownSymbol);
    return -2;

   case OP_PLUS:
   case OP_MINUS:
   case OP_MULTIPLY:
   case OP_DIVIDE:
   case OP_POWER:
   case OP_MOD:
    if (0 <= operatorStackTop)
    {
     
     /*if there is no parenthesis to force current operator 
      subduing previous operator*/
     if (OP_LPAREN !=
      pOperatorTokenStack[operatorStackTop].operatorType)
     {
      enum OperatorType operatorStackTopType;
      operatorStackTopType 
       = pOperatorTokenStack[operatorStackTop].operatorType;

      /*if previous operator subdues current operator,
      ouput the operatorStackTop one to postfix stack */

      if (precedence[pCurrentToken->operatorType] <
       precedence[operatorStackTopType])
      {

       memcpy(&pTokenPostfixStack[nPostfixToken],
        &pOperatorTokenStack[operatorStackTop],
        sizeof(struct TokenProperty));
       nPostfixToken += 1;
       operatorStackTop -= 1;
      }/*if */
     }/*keep ( in the stack */
    }/*stack is not empty*/

    operatorStackTop += 1;
    memcpy(&pOperatorTokenStack[operatorStackTop], pCurrentToken,
     sizeof(struct TokenProperty));
    break;

   case OP_LPAREN:
    operatorStackTop += 1;
    memcpy(&pOperatorTokenStack[operatorStackTop], pCurrentToken,
     sizeof(struct TokenProperty));
    break;

   case OP_RPAREN:
    while ( OP_LPAREN != 
     pOperatorTokenStack[operatorStackTop].operatorType)
    {
     if (0 > operatorStackTop)
     {
      printf("error : ( could not be found! \n");
      return -3;
     }/*not balance*/

     memcpy(&pTokenPostfixStack[nPostfixToken],
      &pOperatorTokenStack[operatorStackTop],
      sizeof(struct TokenProperty));

     nPostfixToken += 1;
     operatorStackTop -= 1;
    }/*while parenthesis is balance*/

    operatorStackTop -= 1;
    break;

   default:
    break;
   }/*switch*/

   break;
  case Unknown:
   //printf("unknow token type %d");
   return -2;
  }/*switch*/

  pCurrentToken++;
 }/*while ExpressionEnd != pCurrentToken->tokenType*/
 

 /*inverse output to postfix stack*/
 while (0 <= operatorStackTop)
 {
  
  if (OP_LPAREN == pOperatorTokenStack[operatorStackTop].operatorType)
  {
   printf("error : ) could not be found! \n");
   return -3;
  }/*not balance*/
  
  memcpy(&pTokenPostfixStack[nPostfixToken], 
   &pOperatorTokenStack[operatorStackTop], sizeof(struct TokenProperty)); 
  nPostfixToken += 1;
  operatorStackTop -= 1;
 }/*while*/
 
 memcpy(pTokens, pTokenPostfixStack, nPostfixToken*sizeof(struct TokenProperty));

 free(pTokenPostfixStack); pTokenPostfixStack = NULL;

 return nPostfixToken;
}/*TokenArrayInfixToPostfix*/


long long ipow(int base, int exp)
{
 long long result = 1;

 while (exp)
 {
  if (exp & 1)
   result *= base;
  base *= base;
  exp >>= 1;
 }

 return result;
}/*ipow*/


union evaluateType
{
 long long integerType;
 double floatType;
};


int EvaluatePostfixStack(int nPostfixToken, struct TokenProperty *pTokenPostfixStack,
 int *pIsFloat, union evaluateType *pResult)
{
 int i;
 int isThereFloat;
 isThereFloat = FALSE;
 union evaluateType *pOperandStack;
 int top;

#ifdef _FORCE_FLOATING_ARITHMETIC
 isThereFloat = TRUE;
#else
 for (i = 0; i < nPostfixToken; i++)
 {
  if (OperandFloat == pTokenPostfixArray[i].tokenType)
  {
   isThereFloat = TRUE;
   break;
  }/*if*/  
 }/*for i*/
#endif

 if (FALSE != isThereFloat)
 {
  for (i = 0; i < nPostfixToken; i++)
  {
   if (OperandInteger == pTokenPostfixStack[i].tokenType)
   {
    pTokenPostfixStack[i].tokenType = OperandFloat;
    pTokenPostfixStack[i].floatValue
     = (double)pTokenPostfixStack[i].intValue;
   }/*if */
  }/*for i*/
 }/*if FALSE != isThereFloat*/


 pOperandStack = 
  (union evaluateType*)malloc(nPostfixToken*sizeof(union evaluateType));

 top = -1;
 
 for (i = 0; i < nPostfixToken; i++)
 {
  switch (pTokenPostfixStack[i].tokenType)
  {
  case OperandFloat:
   top += 1;
   pOperandStack[top].floatType
    = pTokenPostfixStack[i].floatValue;
   break;

  case OperandInteger:
   top += 1;
   pOperandStack[top].integerType
    = pTokenPostfixStack[i].intValue;
   break;

  case Operator:
   {
    union evaluateType a, b, c;

    if (OP_RPAREN == pTokenPostfixStack[i].operatorType
     || OP_LPAREN == pTokenPostfixStack[i].operatorType)
    {
     break;
    }/*ingore parenthesis*/

    if (0 > top)
    {
     printf("error,  deficiency of operand!");
     return -4;
    }

    if (FALSE == isThereFloat)
     b.integerType = pOperandStack[top].integerType;
    else
     b.floatType = pOperandStack[top].floatType;

    top -= 1;


    if (0 > top)
    {
     
     printf("error, lacking operand !");
     return -3;
    }
    if (FALSE == isThereFloat)
     a.integerType = pOperandStack[top].integerType;
    else
     a.floatType = pOperandStack[top].floatType;

    top -= 1;

    switch (pTokenPostfixStack[i].operatorType)
    {
    case OP_UNKOWN:
     printf("Unknown operator %c\n", 
      pTokenPostfixStack[i].unknownSymbol);
     return -2;
    
    case OP_PLUS:
     if (FALSE == isThereFloat)
      c.integerType = a.integerType + b.integerType;
     else
      c.floatType = a.floatType + b.floatType;
     break;

    case OP_MINUS:
     if (FALSE == isThereFloat)
      c.integerType = a.integerType - b.integerType;
     else
      c.floatType = a.floatType - b.floatType;
     break;

    case OP_MULTIPLY:
     if (FALSE == isThereFloat)
      c.integerType = a.integerType * b.integerType;
     else
      c.floatType = a.floatType * b.floatType;
     break;

    case OP_DIVIDE:

     if (FALSE == isThereFloat)
      c.integerType = a.integerType / b.integerType;
     else
      c.floatType = a.floatType / b.floatType;
     break;

    case OP_POWER:
     if (FALSE == isThereFloat)
      c.integerType 
      = ipow((int)a.integerType, (int)b.integerType);
     else
      c.floatType = pow(a.floatType, b.floatType);
     break;

    case OP_MOD:
     if (FALSE == isThereFloat)
      c.integerType = a.integerType % b.integerType;
     else
      c.floatType = fmod(a.floatType, b.floatType);
     break;
    
    default:
     break;
    }/*switch (pTokenPostfixArray[i].operatorType)*/

    top += 1;
    pOperandStack[top] = c;
   }/*Operator*/   
   break;

  case Unknown:
   printf("Unknown operator %c\n", pTokenPostfixStack[i].unknownSymbol);
   return -1;
   break;

  case ExpressionEnd:   
   break;
  default:
   break;
  }/*switch*/
    
 }/*for i */
 
 *pIsFloat = isThereFloat;
 *pResult = pOperandStack[0];

 free(pOperandStack); pOperandStack = NULL;

 if (0 != top)
 {
  printf("error, lacking operator between two operands  !");
  return -5;
 }/*if not only top exists*/ 

 return 0;
}/*EvaluatePostfix*/

#define CONFIRMED_SIZE      (4) // for Expression End


int main(int argc, char *argv)
{
 char inputStr[MAX_STR_LEN];
 int strLen;

 struct TokenProperty *pTokens;
 int nToken;

 int isFloat;
 union evaluateType result;

 memset(&inputStr[0], 0, MAX_STR_LEN);

 printf("input your expression:\n");

 fgets(&inputStr[0], MAX_STR_LEN, stdin);
 strLen = (int)strlen(&inputStr[0]);

 nToken = GetTokenNumber(&inputStr[0], strLen);

 pTokens =
  (struct TokenProperty*)malloc(
   (nToken + CONFIRMED_SIZE)*sizeof(struct TokenProperty));

 memset(pTokens, 0, (nToken + CONFIRMED_SIZE)*sizeof(struct TokenProperty));

 nToken = GetTokens(&inputStr[0], strLen, pTokens);
 if (0 > nToken)
  return -1;

 nToken = InfixArrayToPostfixStack(nToken, pTokens);
 if (0 > nToken)
  return -2;

 PrintTokenProperty(nToken, pTokens);

 if (0 > EvaluatePostfixStack(nToken, pTokens, &isFloat, &result))
   return -3;

 free(pTokens); pTokens = NULL;
 
 if (FALSE == isFloat)
  printf(" = %lld\n", result.integerType);
 else
  printf(" = %f\n", result.floatType);

 return 0;
}/*main*/

Run the code:


input your expression:
(1 +2)^2.5/(2*0.2)
 = 38.971143


Explaination:

The code is straightforward, the postfix stack has been adopted in here:

the concept of postfix stack is :


零.  create a temporary stack to store opeators.

example :

a + b + c :
 


a
b
c


+
+

The combination of the two stack be :


a
b
c
+
+




一. The operator is put more late, the precedence would be more high in nature. It is the general rule to make the postfix stack.


example :

 a + b - c


a
b
c
-
+




二. While precedence  of previous operator is higher than current's, put previous operator into postfix stack.

example :

 a  * b  + c


a
b
*
c
+

Explanation : the precedence  of multiplication is higher that addition. Once while the addition would be put into opation stack, I should move the multiplication (the previous one in the operator stack ) into the postfix stack first.




三. While there is a right parenthesis, move all the opeators from the opeartor stack into the postfix stack until encountering a left parenthesis:

example :

(a^b * c) - d


a
b
^
c
*
d
-

Explanation : The power opeator would be put in the postfix stack in first by the rule 二, and the multiplication would be store in the operator stack for further processing; Once the rght  parenthesis has been enoutered, the multiplication would be move into the postfix stack from the operator stack.


Above is my  cognition of postfix stack algorithm, I hope it is useful for you.




沒有留言:

張貼留言