编译原理c语言--词法语法分析--简单四则运算计算器 (支持算符优先级与括号)--生成语法树然后计算结果

本文深入探讨了使用C语言实现表达式的解析过程,包括词法分析、语法分析以及抽象语法树的构建。通过具体示例,文章详细讲解了如何将输入字符串转换为一系列标记,再通过递归下降解析器构建抽象语法树,最终进行表达式的求值。

在windows 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
{
	PLUS, MINUS, MUL, DIV, 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 PLUS:
		printf("PLUS");
		break;
	case MINUS:
		printf("MINUS");
		break;
	case MUL:
		printf("MUL");
		break;
	case DIV:
		printf("DIV");
		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, PLUS, '+');
			continue;
		case '-':
			tokenone(&tokencurr, MINUS, '-');
			continue;
		case '*':
			tokenone(&tokencurr, MUL, '*');
			continue;
		case '/':
			tokenone(&tokencurr, DIV, '/');
			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* left; // when this is op node
	struct node* right;
} node;

node* newnode()
{
	node* nodenew = malloc(sizeof(node));

	nodenew->val  = NULL;
	nodenew->left = NULL;
	nodenew->right = NULL;

	return nodenew;
}

// syntax directed translation, each grammar is a function
/*
expr   : term ((PLUS | MINUS) term)*
term   : factor ((MUL | DIV) factor)*
factor : INTEGER | LPAREN expr RPAREN
*/

token* tokenp;  //token list index pointer
node* factor();
node* term();
node* expr();

node* factor()
{
	if (tokenp->tokentype == INTEGER)  // find num
	{
		node* one = newnode();
		one->val = tokenp;
		tokenp = tokenp->next;//skip num
		return one;
	}
	else if (tokenp->tokentype == LPAREN) //find (), to recursive descent parse
	{
		tokenp = tokenp->next;//skip LP
		node* one = expr(); // recursive, exit if the token is RPARENT, otherwise if match other token like integer or +-/* will be still in the recursive
		tokenp = tokenp->next; //skip RP
		return one;
	}
}
node* term()
{
	node* one = factor();
	
	while (tokenp!=NULL && (tokenp->tokentype == MUL || tokenp->tokentype == DIV))
	{
		node* op = newnode();
		op->val = tokenp;
		op->left = one;
		tokenp = tokenp->next;  //skip * or /
		op->right = factor();
		one = op;
	}
	
	return one;
}
node* expr()
{
	node* one = term();

	/*
	e.g. 1+2+3+4
	this will first create
	  +
	  /\
	 1  2
	then, add + 3 at the top, 
	     +
		/\
	   +  3
	  /\
	 1  2
	1+2*3 like
	   +
	   /\
      1   *
	      /\
		 2  3
    because plus->right = term(), and term is 2*3
	*/
	while (tokenp!=NULL && (tokenp->tokentype == PLUS || tokenp->tokentype == MINUS))
	{
		node* op = newnode();
		op->val = tokenp;
		op->left = one;
		tokenp = tokenp->next; //skip + or -
		op->right = term();
		one = op;
	}
	
	return one;
}

//low order in the bottom of tree
//same order from bottom left to top right tree
node* ast(token* tokenlist)
{
	tokenp = tokenlist;
	return expr();
}

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;
	}
}

//the node is oprator +-/*
int isop(int tokentype)
{
	if (tokentype == PLUS
		|| tokentype == MINUS
		|| tokentype == MUL
		|| tokentype == DIV)
	{
		return 1;
	}
	return 0;
}
//postorder traversal 
int eval(node* nodelist)
{
	int left=0, right=0;
	if (isop(nodelist->val->tokentype))
	{

		if (isop(nodelist->left->val->tokentype))
		{
			left=eval(nodelist->left);
		}
		if (isop(nodelist->right->val->tokentype))
		{
			right=eval(nodelist->right);
		}
	}
	//if nodelist->left->val->val is not a integer, like +-*/, not a integer ascii atoi will return 0
	return calc(atoi(nodelist->left->val->val)+left, atoi(nodelist->right->val->val)+right, nodelist->val->val[0]);

}
int main()
{
	char input[128];
	getline(input, 128);

	token* tokenlist = tokenize(input);
	printtoken(tokenlist);

	node* nodelist = ast(tokenlist);
	
	int res = eval(nodelist);
	printf("res:%d\n", res);
	return 0;
}

/*
1+2+3+4*5*6*7-8-9  tree view
                 -
				/ \
			    -  9
			   / \
			  +  8
			 /  \
		   +     *
          /\     /\
		 +  3   *  7
		/\     /\
	   1  2   *  6
	          /\
			 4  5

first 1+2,then +3, then + with plus->right = term() to get all 4*5*6*7
first 4*5,then *6,*7, then add the node to +
then -8, -9
*/
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值