您的位置:首页 > 编程语言 > C语言/C++

A Calculator Supports Parentheses Written in C

2016-02-13 04:24 337 查看
 The flow chart be:

 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 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 gernal 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
+
Notice :  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
-
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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言 編譯原理