⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 althorm.h

📁 编译原理上机编写的
💻 H
字号:
///////////////////////////////////////////////////////////////////////////////
//	名称:可编程计算器
//	功能描述:
//	本计算器可以实现对诸如 3+(1+7)*6+4*((5+4))这样的表达式的计算,
//      目前仅限于带括号的 +, * 运算
//	实现描述:
//	本计算器的是在教材 pp.49, 文法 (3.8)基础上稍加修改后,
//      利用自上而下的递归程序实现。每个非终结符对应一个分析函数。
//		
//		修改后的文法如下所示,其中 e 代表空串
//
//		E-->TE'
//		E'-->+TE'|-TE'|e
//		T-->FT'
//		T'-->*FT'|/FT'|e
//		F-->(E)|num|+num|-num
//
//	程序中使用了一个词法分析函数 yylex,变量yylval代表最近的整数
//      记号的数值。'\0'对应着$符号,预示着输入串结束.
//		
///////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

// 这一段是极好的定义
#define ADD 0
#define MIN 1
#define MUL 2
#define DIV	3
#define LBRACE 4
#define RBRACE 5
#define NUM	6
#define END 7
#define OTHER 8

char input[200];	// 输入串。
int lookahead;
int pCur;
double yylval;
char last;
char before;
CString error;

// 函数声明
int yylex();
void Match(int t);
double T();
double E_();
double E();
double T_();
double F();

// 词法分析器,读入一个记号
int yylex()
{
	char num[20];
	int temp = 0;
	
	// 过滤掉空白
	while ( input[pCur]==' ' ) pCur++;
	
	// 如果是数字,那么把这个记号的数值计算出来放在 yylval 中
	while ((input[pCur] >= '0' && input[pCur] <= '9')||input[pCur]=='.'){
		num[temp++] = input[pCur++];
	}
	last = input[pCur];
	if(pCur == 0)
		before = '@';
	else
		before = input[pCur-1];
	if (temp >0) 
	{
		sscanf(num, "%lf", &yylval);
		return NUM;
	}
	// 其他记号的处理
	switch (input[pCur++])	// 注意:这里指针往前移了一位
	{
	case '+':	return ADD;
	case '-':	return MIN;
	case '*':	return MUL;
	case '/':	return DIV;
	case '(':	return LBRACE;
	case ')':	return RBRACE;
	case '\0':	return END;
	default:	return OTHER;
	}
}

// 匹配函数,若当前记号与参数相同,则读入下一个记号
void Match(int t)
{
	if (lookahead == t) 
		lookahead = yylex();
	else 
	{
		error = "括号不匹配,左括号和右括号必须成对出现!\n";
		throw error;
	}
}

// 处理 E-->TE'
double E()
{
	switch (lookahead)
	{
	case LBRACE:	// FIRST(E)={(,num,+,-}
	case NUM:
	case ADD:
	case MIN:
		return T() + E_();
	case END:
		error = "";
		error = error + "表达式不能以字符 " + before +" 结尾!\n表达式只能以右括号或数字结尾!\n";
		throw error;
		break;
	default:
		if(pCur == 1)
		{
			error = "";
			error = error + "表达式不能以字符 "+ last +" 开头!\n表达式只能以左括号或数字开头!\n";
			throw error;
		}
		else
		{
			error = "";
			error = error + "左括号后不能跟字符 "+ last +" !\n左括号后只能跟左括号或数字!\n";
			throw error;
		}
		
	}		
}

// 处理 E'-->+TE'|-TE'|e
double E_()
{
	switch (lookahead)
	{
	case ADD:			// FIRST(E')={+,-,e}
		Match(ADD); 
		if(lookahead==ADD || lookahead==MIN)
		{
			error = "";
			error = error + "表达式中操作符 "+ before +" 后的字符 "+ last +" 不合法!\n操作符 "+ before +" 后只能跟数字或者左括号!\n";
			throw error;
		}
		return T() + E_();
	case MIN:
		Match(MIN);
		if(lookahead==ADD || lookahead==MIN)
		{
			error = "";
			error = error + "表达式中操作符 "+ before +" 后的字符 "+ last +" 不合法!\n操作符 "+ before +" 后只能跟数字或者左括号!\n";
			throw error;
		}
		return -T() + E_();
	case RBRACE:	// E'-->e 的情况,这个时候需要处理 FOLLOW集合, FOLLOW(E')={), $}
	case END:
		return 0;
	default:
		error = "不可能发生的错误!";
		throw error; //这个错误一般不会发生,因为在他执行之前如果有错误的话一般会被发现。
	}	
}

// 处理 T-->FT'
double T()
{
	switch (lookahead)
	{
	case LBRACE:	// FIRST(T)={(,num,+,-}
	case NUM:
	case ADD:
	case MIN:
		return F()*T_();
	case END:
		error = "";
		error = error + "\n表达式不能以操作符 "+ before +" 结尾!\n";
		throw error;
	default:
		error = "";
		error = error + "表达式中操作符 "+ before +" 后的字符 "+ last +" 不合法!\n操作符 "+ before +" 后只能跟数字或者左括号!\n";
		throw error;
	}
}

// 处理 T'-->*FT'|/FT'|e
double T_()
{
	switch (lookahead)
	{
	case MUL:	// FIRST(T')={*,/,e}
		Match(MUL);
		if(lookahead==ADD || lookahead==MIN)
		{
			error = "";
			error = error + "表达式中操作符 "+ before +" 后的字符 "+ last +" 不合法!\n操作符 "+ before +" 后只能跟数字或者左括号!\n";
			throw error;
		}
		return F() * T_();
	case DIV:
		Match(DIV);
		if(lookahead==ADD || lookahead==MIN)
		{
			error = "";
			error = error + "表达式中操作符 "+ before +" 后的字符 "+ last +" 不合法!\n操作符 "+ before +" 后只能跟数字或者左括号!\n";
			throw error;
		}
		return 1/F() * T_();
	case ADD:	// T'-->e 的情况,这个时候需要处理 FOLLOW集合, FOLLOW(T')={+,-,),$}
	case MIN:
	case RBRACE:
	case END:
		return 1;
	case NUM:
		error = "右括号后不能直接跟数字,只能跟+、-、*、/操作符!";
		throw error;
	default:
		error = "";
		error = error + "字符 + before + 后不能跟字符 " + last + " !\n数字或右括号后只能跟+、-、*、/和右括号!\n";
		throw error;
	}		
}

// 处理 F-->(E)|num|+num|-num
double F()
{
	double temp;
	
	switch(lookahead)
	{
	case LBRACE:	// FIRST((E))={(}
		Match(LBRACE);
		temp = E();
		Match(RBRACE);
		return temp;
	case NUM:		// FIRST(num) = {num}
		temp = yylval;
		Match(NUM);
		return temp;
	case ADD:
		Match(ADD);
		return F();
	case MIN:
		Match(MIN);
		return -F();
	case END:
		error = "";
		error = error + "表达式不能以操作符 " + before + " 结尾!\n";
		throw error;
	default:
		error = "";
		error = error + "表达式中操作符 "+ before +" 后的字符 "+ last +" 不合法!\n操作符 "+ before +" 后只能跟数字或者左括号!\n";
		throw error;
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -