247 lines
4.9 KiB
C++
247 lines
4.9 KiB
C++
#include "stackApp.h"
|
|
#include <stdlib.h>
|
|
#include <string>
|
|
|
|
/*-----------build-in functions----------*/
|
|
int readNumber(char* &expr);
|
|
int fac(int n);
|
|
inline char orderBetween(char optr1, char optr2);
|
|
int findOptr(char optr);
|
|
double cal(char optr, double opnd);
|
|
double cal(double opnd1, char optr, double opnd2);
|
|
void append(char* &des, char c);
|
|
|
|
/*
|
|
* @brief : convert a decimal digit n to any base(2 <= base <= 36)
|
|
* @args :
|
|
* @return: return the result in the form of char*
|
|
*/
|
|
char* convert(__int64 n, int base){
|
|
Stack<char> charStack;
|
|
while(n != 0){
|
|
charStack.push(digits[n % base]);
|
|
n /= base;
|
|
}
|
|
char* res = new char[charStack.getSize() + 1];
|
|
int pos = 0;
|
|
while (!charStack.empty()) res[pos++] = charStack.pop();
|
|
res[pos] = '\0';
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
* @brief : to judge if an expression of matches
|
|
* @args : exp
|
|
* @return: return true if matches
|
|
*/
|
|
bool paren(const char exp[]){
|
|
Stack<char> parenStack;
|
|
char currParen;
|
|
for(int ix = 0; (currParen = exp[ix]) != '\0'; ++ix){
|
|
switch(currParen){
|
|
case '(':
|
|
case '[':
|
|
case '{':
|
|
parenStack.push(currParen);
|
|
break;
|
|
|
|
case ')':
|
|
if (parenStack.empty()) return false;
|
|
if (parenStack.pop() != '(') return false;
|
|
break;
|
|
|
|
case ']':
|
|
if (parenStack.empty()) return false;
|
|
if (parenStack.pop() != '[') return false;
|
|
break;
|
|
|
|
case '}':
|
|
if (parenStack.empty()) return false;
|
|
if (parenStack.pop() != '{') return false;
|
|
break;
|
|
}
|
|
}
|
|
return parenStack.empty()? true : false;
|
|
}
|
|
|
|
/*
|
|
* @brief : to compute the value of an infix expression
|
|
* @args : infixExpr
|
|
* @return: return the value in double
|
|
* @others: only consider valid infix expression
|
|
*/
|
|
double evaluate(char* infixExpr){
|
|
Stack<double> opnd;
|
|
Stack<char> optr;
|
|
double opnd1, opnd2;
|
|
optr.push('\0');
|
|
while(!optr.empty()){
|
|
if (isdigit(*infixExpr)) opnd.push(readNumber(infixExpr));
|
|
else{
|
|
if (*infixExpr == ' ' || *infixExpr == '\t') { // skip white spaces
|
|
++infixExpr;
|
|
continue;
|
|
}
|
|
|
|
switch(orderBetween(optr.top(), *infixExpr)){
|
|
case '>':
|
|
if (optr.top() == '!') opnd.push(cal(optr.pop(), opnd.pop()));
|
|
else{
|
|
opnd2 = opnd.pop();
|
|
opnd1 = opnd.pop();
|
|
opnd.push(cal(opnd1, optr.pop(), opnd2));
|
|
}
|
|
break;
|
|
|
|
case '<':
|
|
optr.push(*infixExpr++);
|
|
break;
|
|
|
|
case '=':
|
|
infixExpr++;
|
|
optr.pop();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return opnd.pop();
|
|
}
|
|
|
|
/*
|
|
* @brief : to convert an infix expression to a postfix one
|
|
* @args : infixExpr
|
|
* @return: return the converted postfix expression
|
|
* @others: only consider valid infix expression
|
|
*/
|
|
char* toPostfix(char* infixExpr){
|
|
char* postfixExpr = "";
|
|
Stack<char> optr;
|
|
optr.push('\0');
|
|
while(!optr.empty()){
|
|
if (isdigit(*infixExpr)) append(postfixExpr, *infixExpr++);
|
|
else{
|
|
if (*infixExpr == ' ' || *infixExpr == '\t') { // skip white spaces
|
|
++infixExpr;
|
|
continue;
|
|
}
|
|
switch(orderBetween(optr.top(), *infixExpr)){
|
|
case '>':
|
|
append(postfixExpr, optr.pop());
|
|
break;
|
|
|
|
case '<':
|
|
optr.push(*infixExpr++);
|
|
break;
|
|
|
|
case '=':
|
|
optr.pop();
|
|
++infixExpr;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return postfixExpr;
|
|
}
|
|
/*
|
|
* @brief : to generate a very long expression in the pattern '1+0*1^(1+0*1^(1+0*1^(......)'
|
|
* @args : number of brackets in the expression
|
|
* @return: pointer to the long expression
|
|
*/
|
|
char* generateLongExpr(int n){
|
|
char* expr = new char[8 * n + 8];
|
|
int pos = 0;
|
|
for(int ix = 0; ix != n; ix++, pos += 7)
|
|
memcpy(expr + pos, "1+0*1^(", 7);
|
|
expr[pos++] = '1';
|
|
for (int ix = 0; ix != n; ++ix)
|
|
expr[pos++] = ')';
|
|
expr[pos] = '\0';
|
|
return expr;
|
|
}
|
|
|
|
/*-----------build-in functions----------*/
|
|
int readNumber(char* &expr){
|
|
int res = 0;
|
|
while(isdigit(*expr)){
|
|
res = res * 10 + *expr - '0';
|
|
expr++;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
inline char orderBetween(char optr1, char optr2){
|
|
return pri[findOptr(optr1)][findOptr(optr2)];
|
|
}
|
|
|
|
int findOptr(char optr){
|
|
if (optr == '+') return 0;
|
|
if (optr == '-') return 1;
|
|
if (optr == '*') return 2;
|
|
if (optr == '/') return 3;
|
|
if (optr == '^') return 4;
|
|
if (optr == '!') return 5;
|
|
if (optr == '(') return 6;
|
|
if (optr == ')') return 7;
|
|
if (optr == '\0') return 8;
|
|
}
|
|
|
|
int fac(int n){
|
|
int res = 1;
|
|
for (; n != 0; res *= n, n--);
|
|
return res;
|
|
}
|
|
|
|
double cal(char optr, double opnd){
|
|
double res = 0.0;
|
|
switch(optr){
|
|
case '!':
|
|
res = fac(opnd);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
double cal(double opnd1, char optr, double opnd2) {
|
|
double res = 0.0;
|
|
switch (optr){
|
|
case '+':
|
|
res = opnd1 + opnd2;
|
|
break;
|
|
|
|
case '-':
|
|
res = opnd1 - opnd2;
|
|
break;
|
|
|
|
case '*':
|
|
res = opnd1 * opnd2;
|
|
break;
|
|
|
|
case '/':
|
|
res = opnd1 / opnd2;
|
|
break;
|
|
|
|
case '^':
|
|
res = pow(opnd1, opnd2);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
* @brief : to append a char to an array of char, even if the array is already full
|
|
* @args : char* des, char c
|
|
* @return: void
|
|
* @others: the array can automatically expand itself when needed
|
|
*/
|
|
void append(char* &des, char c){
|
|
int n = strlen(des);
|
|
char* tmp = des;
|
|
des = new char[n + 2];
|
|
sprintf(des, "%s%c\0", tmp, c);
|
|
}
|