123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- #include "stdafx.h"
- #include <stdlib.h>
- #include <math.h>
- #include <float.h>
- #include "MathExpression.h"
- namespace expInterpreter {
- const int expr_str_err_N = 5;
- const char *expr_str_err[] =
- {
- "unknown error.", // error code 0
- "unexcepted end.", // error code 1
- "operator error.", // error code 2
- "input data error.", // error code 3
- "expression too long." // error code 4
- };
- const int compute_err_N = 5;
- const char *compute_err[] =
- {
- "unknown error.", // error code 0
- "compute data error.", // error code 1
- "input data error.", // error code 2
- "devided by zero.", // error code 3
- "pow return non." // error code 4
- };
- // 从字符串的start位置开始读一个元素放入atom,返回结束位置,若解析结束,返回-1
- int read_atom(Atom *atom, const char *exprStr, int start);
- // 从字符串尝试读取一个数字,返回结束位置,若解析结束,返回start
- int read_digit(double *result, const char *exprStr, int start);
- // 判断是否为数字符号
- inline bool isEmpty(char ch);
- // 判断是否为数字符号
- inline bool isDigit(char ch);
- // 判断是否为运算符
- inline bool isSymbol(char ch);
- // 判断是否为变量
- inline bool isVariable(char ch);
- // 获取Atom的字符表示
- char atom_symbol(Atom *atom);
- // 判断符号是否合法
- enum BL { F = 0, T = 1 }; // T true,F false
- BL legel_Atom(Atom *atom1, Atom *atom2);
- BL legel_Atom(char ch1, char ch2);
- enum CR { A = 0, B = 1, D = 2, E = 3 }; // A大于,B小于,D相等,E错误
- // 判断符号优先级
- CR compare_symbol(char ch1, char ch2);
- // 表达式的最大长度
- const int Expression::poland_MAX = 255;
- Expression::Expression()
- {
- this->poland = new Atom[poland_MAX];
- this->poland[0].type = ATOM_END;
- this->poland_N = 0;
- this->var = new double[26];
- for (unsigned int i = 0; i < 26; i++)
- {
- this->var[i] = 1; // 初始化所有变量为1
- }
- }
- Expression::~Expression()
- {
- delete[] this->poland;
- delete[] this->var;
- }
- int Expression::SetExprStr(const char *exprStr)
- {
- Atom Bak, Now;
- this->poland_N = 0;
- char symbol_stack[poland_MAX];
- int symbol_stack_N = 0;
- symbol_stack[symbol_stack_N++] = '#';
- Bak.type = ATOM_END;
- int index = 0;
- int error_code = 0;
- while (symbol_stack_N)
- {
- if (index < 0) // 解析式是否结束
- {
- error_code = 1;
- goto error_return;
- }
- index = read_atom(&Now, exprStr, index);
- if (!legel_Atom(&Bak, &Now)) // 判断是否合法
- {
- if (Now.type == ATOM_SYMBOL && Now.value.symbol == '-') // 尝试一元运算符的多义
- {
- Now.value.symbol = '~';
- if (!legel_Atom(&Bak, &Now))
- {
- error_code = 2;
- goto error_return;
- }
- }
- else
- {
- error_code = 2;
- goto error_return;
- }
- }
- switch (Now.type) // 根据类别计算
- {
- case ATOM_ERROR:
- error_code = 3;
- goto error_return;
- break;
- case ATOM_SYMBOL: // 运算符号,包括结束符号
- case ATOM_END:
- {
- bool poped = true;
- char ch = atom_symbol(&Now);
- while (poped)
- {
- switch (compare_symbol(symbol_stack[symbol_stack_N - 1], ch)) // 比较当前运算符和符号栈顶的优先级
- {
- case A: // 上一个符号优先级高,先完成上一个运算符的运算
- this->poland[this->poland_N].type = ATOM_SYMBOL;
- this->poland[this->poland_N].value.symbol = symbol_stack[symbol_stack_N - 1];
- this->poland_N++;
- if (this->poland_N >= poland_MAX)
- {
- error_code = 4;
- goto error_return;
- }
- symbol_stack_N--;
- poped = true;
- break;
- case B: // 这次的优先级高,则压入符号栈,等待处理
- symbol_stack[symbol_stack_N++] = ch;
- poped = false;
- break;
- case D: // 优先级相等,例如'('和')',同时弹出
- symbol_stack_N--;
- poped = false;
- break;
- case E: // 优先级出错
- error_code = 2;
- goto error_return;
- }
- }
- }
- break;
- case ATOM_CONSTANT: // 变量或常量,自己压入逆波兰式
- case ATOM_VARIABLE:
- this->poland[this->poland_N++] = Now;
- if (this->poland_N >= poland_MAX)
- {
- error_code = 4;
- goto error_return;
- }
- break;
- }
- Bak = Now;
- }
- this->poland[this->poland_N].type = ATOM_END;
- return 0;
- error_return:
- return error_code;
- }
- const char *Expression::GetExprErrorStr(int err)
- {
- return err < 1 ?
- expr_str_err[0] :
- err >= expr_str_err_N ?
- expr_str_err[0] :
- expr_str_err[err];
- }
- const char *Expression::GetResultErrorStr(int err)
- {
- return err < 1 ?
- compute_err[0] :
- err >= compute_err_N ?
- compute_err[0] :
- compute_err[err];
- }
- void Expression::SetVar(char x, double value)
- {
- if (!isVariable(x)) return;
- x |= 0x20; // 将变量转换为小写
- this->var[x - 'a'] = value;
- }
- int Expression::GetResult(double *result)
- {
- double digit[poland_MAX]; // 逆波兰式的辅助堆栈
- int digit_N = 0;
- int index = 0;
- int error_code = 0;
- for (index = 0; index < this->poland_N; index++)
- {
- switch (this->poland[index].type)
- {
- case ATOM_ERROR:
- error_code = 2;
- goto error_return;
- break;
- case ATOM_SYMBOL:
- switch (this->poland[index].value.symbol)
- {
- case '+':
- if (digit_N < 2)
- {
- error_code = 1;
- goto error_return;
- }
- digit[digit_N - 2] = digit[digit_N - 2] + digit[digit_N - 1];
- digit_N--;
- break;
- case '-':
- if (digit_N < 2)
- {
- error_code = 1;
- goto error_return;
- }
- digit[digit_N - 2] = digit[digit_N - 2] - digit[digit_N - 1];
- digit_N--;
- break;
- case '*':
- if (digit_N < 2)
- {
- error_code = 1;
- goto error_return;
- }
- digit[digit_N - 2] = digit[digit_N - 2] * digit[digit_N - 1];
- digit_N--;
- break;
- case '/':
- if (digit_N < 2)
- {
- error_code = 1;
- goto error_return;
- }
- digit[digit_N - 2] = digit[digit_N - 2] / digit[digit_N - 1];
- digit_N--;
- if (!_finite(digit[digit_N - 1]))
- {
- error_code = 3;
- goto error_return;
- }
- break;
- case '^':
- if (digit_N < 2)
- {
- error_code = 1;
- goto error_return;
- }
- digit[digit_N - 2] = pow(digit[digit_N - 2], digit[digit_N - 1]);
- digit_N--;
- if (_isnan(digit[digit_N - 1]))
- {
- error_code = 4;
- goto error_return;
- }
- break;
- case '~':
- if (digit_N < 1)
- {
- error_code = 1;
- goto error_return;
- }
- digit[digit_N - 1] = -digit[digit_N - 1];
- break;
- }
- break;
- case ATOM_CONSTANT:
- digit[digit_N++] = this->poland[index].value.constant;
- break;
- case ATOM_VARIABLE:
- digit[digit_N++] = this->var[this->poland[index].value.variable - 'a'];
- break;
- case ATOM_END:
- break;
- }
- }
- if (digit_N != 1)
- {
- error_code = 1;
- goto error_return;
- }
- else
- {
- *result = digit[0];
- return 0;
- }
- error_return:
- return error_code;
- }
- const Atom *Expression::GetPoland()
- {
- return this->poland;
- }
- // 兼容矩阵
- BL legel_matrix[10][10] =
- {
- // + - * / ^ ( ) i ~ #
- F, F, F, F, F, T, F, T, T, F, // +
- F, F, F, F, F, T, F, T, T, F, // -
- F, F, F, F, F, T, F, T, T, F, // *
- F, F, F, F, F, T, F, T, T, F, // /
- F, F, F, F, F, T, F, T, T, F, // ^
- F, F, F, F, F, T, F, T, T, F, // (
- T, T, T, T, T, F, T, F, F, T, // )
- T, T, T, T, T, F, T, F, F, T, // i
- F, F, F, F, F, T, F, T, F, F, // ~
- F, F, F, F, F, T, F, T, T, F, // #
- };
- // 兼容矩阵下标值
- char legel_matrix_ch[10] = { '+', '-', '*', '/', '^', '(', ')', 'i', '~', '#', };
- // 优先级矩阵
- CR cmp_matrix[9][9] =
- {
- // + - * / ^ ( ) ~ #
- A, A, B, B, B, B, A, B, A, // +
- A, A, B, B, B, B, A, B, A, // -
- A, A, A, A, B, B, A, B, A, // *
- A, A, A, A, B, B, A, B, A, // /
- A, A, A, A, A, B, A, B, A, // ^
- B, B, B, B, B, B, D, B, E, // (
- E, E, E, E, E, E, E, E, E, // )
- A, A, A, A, A, B, A, A, A, // ~
- B, B, B, B, B, B, E, B, D, // #
- };
- // 优先级矩阵下标值
- char cmp_matrix_ch[9] = { '+', '-', '*', '/', '^', '(', ')', '~', '#', };
- BL legel_Atom(char ch1, char ch2)
- {
- int index1 = 0;
- while (legel_matrix_ch[index1] != ch1 && index1 < 10) index1++;
- if (index1 == 10) return F;
- int index2 = 0;
- while (legel_matrix_ch[index2] != ch2 && index2 < 10) index2++;
- if (index2 == 10) return F;
- return legel_matrix[index1][index2];
- }
- char atom_symbol(Atom *atom)
- {
- switch (atom->type)
- {
- case ATOM_ERROR:
- return -1;
- case ATOM_SYMBOL:
- return atom->value.symbol;
- case ATOM_CONSTANT:
- case ATOM_VARIABLE:
- return 'i';
- case ATOM_END:
- return '#';
- }
- return -1;
- }
- BL legel_Atom(Atom *atom1, Atom *atom2)
- {
- char ch1 = atom_symbol(atom1);
- if (ch1 < 0) return F;
- char ch2 = atom_symbol(atom2);
- if (ch2 < 0) return F;
- return legel_Atom(ch1, ch2);
- }
- CR compare_symbol(char ch1, char ch2)
- {
- int index1 = 0;
- while (cmp_matrix_ch[index1] != ch1 && index1 < 9) index1++;
- if (index1 == 9) return E;
- int index2 = 0;
- while (cmp_matrix_ch[index2] != ch2 && index2 < 9) index2++;
- if (index2 == 9) return E;
- return cmp_matrix[index1][index2];
- }
- int read_atom(Atom *atom, const char *exprStr, int start)
- {
- while (isEmpty(exprStr[start])) start++;
- if (exprStr[start] == '\0')
- {
- atom->type = ATOM_END;
- return -1;
- }
- if (isVariable(exprStr[start]))
- {
- atom->type = ATOM_VARIABLE;
- atom->value.variable = exprStr[start] | 0x20; // 变量长度只为1,转换为小写
- start++;
- }
- else if (isSymbol(exprStr[start]))
- {
- atom->type = ATOM_SYMBOL;
- atom->value.symbol = exprStr[start];
- start++;
- }
- else if (isDigit(exprStr[start])) // 是数字时,调用库函数读入一个实数
- {
- double digit;
- start = read_digit(&digit, exprStr, start);
- atom->type = ATOM_CONSTANT;
- atom->value.constant = digit;
- }
- else
- {
- atom->type = ATOM_ERROR;
- start++;
- }
- return start;
- }
- int read_digit(double *result, const char *exprStr, int start) // 利用库函数读入一个实数
- {
- int len = 0;
- while (isDigit(exprStr[start + len])) len++;
- *result = atof(exprStr + start);
- start += len;
- return start;
- }
- inline bool isEmpty(char ch)
- {
- return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
- }
- inline bool isDigit(char ch)
- {
- return (ch == '.' || (ch >= '0' && ch <= '9'));
- }
- const int sml_N = 7;
- const char sml[] = { '+', '-', '*', '/', '^', '(', ')' };
- inline bool isSymbol(char ch)
- {
- for (unsigned int i = 0; i < sml_N; i++)
- {
- if (ch == sml[i])
- return true;
- }
- return false;
- }
- inline bool isVariable(char ch)
- {
- return ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'));
- }
- }
|