The flow chart
Read Input -> Get Tokens -> Infix To Postfix -> Evaluate -> Output Result
GetToken : Check if there is syntax know or not.
Infix To Postfix: Check if there perenthesis be balance or not.
Evaluate: Check if there is operator or operand be 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 PrintTokenPropertyArray(int n, struct TokenProperty *pTokenArray)
{
int i;
for (i = 0; i < n; i++) {
switch (pTokenArray[i].tokenType)
{
case Unknown:
printf("Unknown\n");
break;
case ExpressionEnd:
printf("ExpressionEnd\n");
break;
case Operator:
printf("Operator, ");
switch (pTokenArray[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", pTokenArray[i].intValue);
break;
case OperandFloat:
printf("OperandFloat, %f\n", pTokenArray[i].floatValue);
break;
default:
return -1;
}/*switch tokenType*/
}/*for */
printf("\n");
return 0;
}/*PrintTokenPropertyArray*/
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 TokenArrayInfixToPostfix(int nInfixToken, struct TokenProperty *pTokenArray)
{
struct TokenProperty *pTokenInfixArray;
struct TokenProperty *pTokenPostfixArray;
struct TokenProperty *pCurrentToken;
unsigned char precedence[MAX_STR_LEN];
int i;
int ii;
int top;
struct TokenProperty *pOperatorTokenStack;
pTokenInfixArray = pTokenArray;
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));
pTokenPostfixArray =
(struct TokenProperty*)malloc(nInfixToken*sizeof(struct TokenProperty));
memset(pTokenPostfixArray, 0, nInfixToken*sizeof(struct TokenProperty));
pCurrentToken = &pTokenInfixArray[0];
top = -1;
ii = 0;
for (i = 0; i < nInfixToken; i++)
{
enum TokenType tokenType;
tokenType = pCurrentToken->tokenType;
switch (tokenType)
{
case OperandInteger:
case OperandFloat:
memcpy(&pTokenPostfixArray[ii],
pCurrentToken, sizeof(struct TokenProperty));
ii += 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 <= top )
{
/*if the operatorStackTop one's precedence subdues current's,
ouput the operatorStackTop one to postfix stack */
if (OP_LPAREN != pOperatorTokenStack[top].operatorType)
{
if (precedence[pOperatorTokenStack[top].operatorType]
> precedence[pCurrentToken->operatorType])
{
memcpy(&pTokenPostfixArray[ii],
&pOperatorTokenStack[top],
sizeof(struct TokenProperty));
ii += 1;
top -= 1;
}/*if */
}/*keep ( in the stack */
}/*stack is not empty*/
top += 1;
memcpy(&pOperatorTokenStack[top], pCurrentToken,
sizeof(struct TokenProperty));
break;
case OP_LPAREN:
top += 1;
memcpy(&pOperatorTokenStack[top], pCurrentToken,
sizeof(struct TokenProperty));
break;
case OP_RPAREN:
while ( OP_LPAREN !=
pOperatorTokenStack[top].operatorType)
{
if (0 > top)
{
printf("error : ( could not be found! \n");
return -3;
}/*not balance*/
memcpy(&pTokenPostfixArray[ii],
&pOperatorTokenStack[top],
sizeof(struct TokenProperty));
ii += 1;
top -= 1;
}/*while parenthesis is balance*/
top -= 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 <= top)
{
if (OP_LPAREN == pOperatorTokenStack[top].operatorType)
{
printf("error : ) could not be found! \n");
return -3;
}/*not balance*/
memcpy(&pTokenPostfixArray[ii], &pOperatorTokenStack[top],
sizeof(struct TokenProperty));
ii += 1;
top -= 1;
}/*while*/
memcpy(pTokenArray, pTokenPostfixArray, ii*sizeof(struct TokenProperty));
free(pTokenPostfixArray); pTokenPostfixArray = NULL;
return ii;
}/*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 EvaluatePostfix(int nPostfixToken, struct TokenProperty *pTokenPostfixArray,
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 == pTokenPostfixArray[i].tokenType)
{
pTokenPostfixArray[i].tokenType = OperandFloat;
pTokenPostfixArray[i].floatValue
= (double)pTokenPostfixArray[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 (pTokenPostfixArray[i].tokenType)
{
case OperandFloat:
top += 1;
pOperandStack[top].floatType
= pTokenPostfixArray[i].floatValue;
break;
case OperandInteger:
top += 1;
pOperandStack[top].integerType
= pTokenPostfixArray[i].intValue;
break;
case Operator:
{
union evaluateType a, b, c;
if (OP_RPAREN == pTokenPostfixArray[i].operatorType
|| OP_LPAREN == pTokenPostfixArray[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 (pTokenPostfixArray[i].operatorType)
{
case OP_UNKOWN:
printf("Unknown operator %c\n",
pTokenPostfixArray[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", pTokenPostfixArray[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 *pTokenArray;
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);
pTokenArray =
(struct TokenProperty*)malloc(
(nToken + CONFIRMED_SIZE)*sizeof(struct TokenProperty));
memset(pTokenArray, 0, (nToken + CONFIRMED_SIZE)*sizeof(struct TokenProperty));
nToken = GetTokens(&inputStr[0], strLen, pTokenArray);
if (0 > nToken)
return -1;
nToken = TokenArrayInfixToPostfix(nToken, pTokenArray);
if (0 > nToken)
return -2;
//PrintTokenPropertyArray(nToken, pTokenArray);
if (0 > EvaluatePostfix(nToken, pTokenArray, &isFloat, &result))
return -3;
free(pTokenArray); pTokenArray = 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