四则运算-过程
- 把求 一串 四则运算表达式看做 【多条优先级队列】 , 高优先级的往下移动到其他列
- 队列的每个节点 由 一个【运算符】加【前参数】与【下参数】组成 ,下参数也可能是【高优先级表达式】
- 括号内的全部挂在的下参数
- 每个节点都是运算符指向运算符的流动
- 计算时,如果前参数与下参数都有直接计算,如果下参数是运算符则递归出值后在计算,直到队列尾
如果前参数没有,则使用前面计算的值作为前参数。
2+3 表示如下,一个运算符为中心,运算符指向其他运算符,参数数字为叶子节点
2 +
3
1+2+3+4表示如下
1 + + +
2 3 4
1+2+3*4*5*6-7-8表示如下, 2后面 + 向下指向 *, 表示优先级切换,之后的*跟在后面, -7 又切换回原来优先级队列
1 + + - -
2 3* * * 7 8
4 5 6
10-5+(2+1)*3-4表示如下
10- + -
5 2+ * 4
1 3
vs2015 测试代码
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
// console get line input
void getline(char* input, int inputsize) {
int len = inputsize;
int idx = 0;
input[idx] = '\0';
while (1)
{
char c = fgetc(stdin);
if (c == EOF)
break;
if (c == '\n')
{
input[idx++] = '\0';
break;
}
else {
input[idx++] = c;
}
if (idx >= len - 1)
{
input[idx++] = '\0';
break;
}
}
}
// lexical analysis section
enum tokentype
{
OPERATOR, LPAREN, RPAREN, INTEGER
};
typedef struct token {
int tokentype;
char val[16];
struct token* prev;
struct token* next;
} token;
token* newtoken()
{
token* tokennew = malloc(sizeof(token));
tokennew->next = NULL;
tokennew->prev = NULL;
tokennew->val[0] = '\0';
return tokennew;
}
void tokenmoveon(token** tokencurr)
{
(*tokencurr)->next = newtoken();
(*tokencurr)->next->next = NULL;
(*tokencurr)->next->prev = (*tokencurr);
(*tokencurr) = (*tokencurr)->next;
}
void printtoknetype(int type)
{
switch (type)
{
case OPERATOR:
printf("OPERATOR");
break;
case LPAREN:
printf("LPAREN");
break;
case RPAREN:
printf("RPAREN");
break;
case INTEGER:
printf("INTEGER");
break;
default:
break;
}
}
void printtoken(token* thead)
{
token* p;
p = thead;
printf("tokne:\n");
while (p != NULL)
{
printtoknetype(p->tokentype);
printf(":[%s] ", p->val);
p = p->next;
}
printf("\n");
}
void tokenone(token** tokencurr, int tokentype, char op)
{
(*tokencurr)->tokentype = tokentype;
(*tokencurr)->val[0] = op;
(*tokencurr)->val[1] = '\0';
tokenmoveon(tokencurr);
}
token* tokenize(char* str)
{
if (!*str) printf("no token\n");
token* thead;
token* tokencurr = newtoken();
thead = tokencurr;
int i, idx = 0;
char word[16];
for (i = 0; i < strlen(str); i++) {
char next = str[i + 1];
switch (str[i])
{
case ' ':
continue;
case '\0':
break;
case '+': //after + will be num (after num will be a op) or (
tokenone(&tokencurr, OPERATOR, '+');
continue;
case '-':
tokenone(&tokencurr, OPERATOR, '-');
continue;
case '*':
tokenone(&tokencurr, OPERATOR, '*');
continue;
case '/':
tokenone(&tokencurr, OPERATOR, '/');
continue;
case '(':
tokenone(&tokencurr, LPAREN, '(');
continue;
case ')':
tokenone(&tokencurr, RPAREN, ')');
continue;
default:
word[idx++] = str[i]; // digit num
if (!isdigit(next)) // finish num
{
word[idx] = '\0';
strcpy(tokencurr->val, word);
idx = 0;
tokencurr->tokentype = INTEGER;
tokenmoveon(&tokencurr);
}
continue;
}
}
//delete last token, is null token, because we tokenmoveon create token node first
tokencurr = tokencurr->prev;
free(tokencurr->next);
tokencurr->next = NULL;
return thead;
}
// syntax analysis section
typedef struct node {
token* val; //op or num token, num node is leaf
struct node* prev; // when this is op node,prev is num
struct node* next; // when this is op node,next is op
struct node* up; //when lower order op, go back to up lien
struct node* down; // down is num or op has higher order
} node;
node* newnode()
{
node* nodenew = malloc(sizeof(node));
nodenew->val = NULL;
nodenew->prev = NULL;
nodenew->next = NULL;
nodenew->up = NULL;
nodenew->down = NULL;
return nodenew;
}
//compare op1(current op) op2(next op) order, lower higher or same, op1i-op2i
int oporder(char op1c, char op2c)
{
int op1i = 0;
int op2i = 0;
switch (op1c)
{
case '+':
case '-':
op1i = 1;
break;
case '*':
case '/':
op1i = 2;
break;
default:
break;
}
switch (op2c)
{
case '+':
case '-':
op2i = 1;
break;
case '*':
case '/':
op2i = 2;
break;
default:
break;
}
return op1i - op2i;
}
token* tokenp; //token list index pointer
void settokenmark(token** tokencurr, token** tokennext, token** tokenthird, token** tokenfourth)
{
if ((*tokencurr)->next != NULL)
{
(*tokennext) = (*tokencurr)->next;
if ((*tokennext)->next != NULL)
{
(*tokenthird) = (*tokennext)->next;
if ((*tokenthird)->next != NULL)
{
(*tokenfourth) = (*tokenthird)->next;
}
else {
(*tokenfourth) = NULL;
}
}
else {
(*tokenthird) = NULL;
}
}
else {
(*tokennext) = NULL;
}
}
node* ast()
{
node* nodep = newnode();
node* nhead=nodep;
token* tokencurr = tokenp;//current token
token* tokennext; //token after current
token* tokenthird; //token third next to current
token* tokenfourth; //token fourth next to current
while (tokenp!=NULL && tokenp->tokentype!=RPAREN)
{
tokencurr = tokenp;
settokenmark(&tokencurr, &tokennext, &tokenthird, &tokenfourth);
if (tokennext == NULL || tokennext->tokentype==RPAREN)//last token or the end of ()
{
node* num = newnode();
num->val = tokencurr;
nodep->down = num;
tokenp = tokennext;
continue;
}
else if (tokencurr->tokentype == LPAREN)
{
tokenp = tokenp->next;
if (nodep->val == NULL) // ( start from the begining
{
nodep = ast();
// make the op after () at the same line, because () on the top line
tokenp = tokenp->next; // skip rparen
if (tokenp == NULL) continue;
if (tokenp != NULL && tokenp->tokentype == OPERATOR)
{
node* op = newnode();
op->val = tokenp;
nodep->next = op;
nodep = op;
tokenp = tokencurr;
}
}
else
{
nodep->down = ast();
tokenp = tokenp->next; // skip rparen
if (tokenp == NULL) continue; //no more after )
tokencurr = tokenp; //don't know the lenght of (), reset tokenmark
settokenmark(&tokencurr, &tokennext, &tokenthird, &tokenfourth);
if (tokencurr != NULL && tokencurr->tokentype == OPERATOR)
{
if (oporder(nodep->val->val[0], tokencurr->val[0]) == 0) //the op after () has low or same order of the op before (), just next to nodep
{
node* op = newnode();
op->val = tokenp;
nodep->next = op;
nodep = op;
tokenp = tokencurr->next;
}
else if(oporder(nodep->val->val[0], tokencurr->val[0]) < 0) // after() the op has higher order, should stick to () line
{
//step into ()line, set each of () line the value of up, until the last one
node* up;
up = nodep;
nodep = nodep->down;
while (nodep->next!=NULL)
{
nodep->up = nodep;
nodep = nodep->next;
}
nodep->up = nodep;
node* op = newnode();
op->val = tokenp;
nodep->next = op; // stick to the last
nodep = op;
tokenp = tokencurr->next;
}
else if (oporder(nodep->val->val[0], tokencurr->val[0]) > 0) // after() the op has low order, should up to the low order
{
node* op = newnode();
op->val = tokenp;
if (nodep->up == NULL) // already at the top line
{
nodep->next = op;
}
else
{
nodep->up->next = op;
}
nodep = op;
tokenp = tokencurr->next;
}
}
}
continue;
}
else if (nodep->val==NULL) // very first, start
{
node* num = newnode();
num->val = tokencurr;
node* op = newnode();
op->prev = num; //num
op->val = tokennext;
nodep = op; //pointer to op node
nhead = nodep; // node head pointer init
tokenp = tokenthird;
continue;
}
else if (oporder(nodep->val->val[0],tokennext->val[0])==0) // same or lower op order, folllow the befor, no need to the same line
{
node* num = newnode();
num->val = tokencurr;
nodep->down = num;
node* op = newnode();
op->val = tokennext;
op->up = nodep->up;
nodep->next= op; //pointer to op node
nodep = op;
tokenp = tokenthird;
continue;
}
else if (oporder(nodep->val->val[0], tokennext->val[0])<0) // higher op order
{
node* num = newnode();
num->val = tokencurr;
node* op = newnode();
op->val = tokennext;
op->prev = num;
op->up = nodep;
nodep->down = op;
nodep = op;
tokenp = tokenthird;
continue;
}
else if (oporder(nodep->val->val[0], tokennext->val[0]) > 0) // low op order, move to low order line, up
{
node* num = newnode();
num->val = tokencurr;
nodep->down = num;
node* op = newnode();
op->val = tokennext;
if (nodep->up == NULL)
{
nodep->next = op;
}
else
{
nodep->up->next = op; // move up, to low order line
}
nodep = op;
tokenp = tokenthird;
continue;
}
}
return nhead;
}
int calc(int a, int b, char op)
{
switch (op)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
return a / b;
}
}
//nodelist traversal
int eval(node* nodelist)
{
int res = 0;
while (nodelist!=NULL)
{
int left = 0, right = 0;
if (nodelist->prev == NULL)
{
left = res;
}
else
{
left = atoi(nodelist->prev->val->val);
}
if (nodelist->down->val->tokentype==OPERATOR)
{
right = eval(nodelist->down);
}
else
{
right = atoi(nodelist->down->val->val);
}
res = calc(left, right, nodelist->val->val[0]);
nodelist = nodelist->next;
}
return res;
}
int main()
{
char input[128];
getline(input, 128);
token* tokenlist = tokenize(input);
printtoken(tokenlist);
tokenp = tokenlist;
node* nodelist = ast();
int res = eval(nodelist);
printf("res:%d\n", res);
return 0;
}
/*
1+2+3+4*5*6*7-8-9 line view
1+ + + - -
2 3 8 9
4* * *
5 6 7
*/