四则运算--c语言匹配,没有使用文法,多级优先级队列思想

四则运算-过程

  1. 把求 一串 四则运算表达式看做 【多条优先级队列】 , 高优先级的往下移动到其他列
  2. 队列的每个节点 由 一个【运算符】加【前参数】与【下参数】组成 ,下参数也可能是【高优先级表达式】
  3. 括号内的全部挂在的下参数
  4. 每个节点都是运算符指向运算符的流动
  5. 计算时,如果前参数与下参数都有直接计算,如果下参数是运算符则递归出值后在计算,直到队列尾
    如果前参数没有,则使用前面计算的值作为前参数。
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

*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值