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

📄 yufafenxi.txt

📁 语法分析器是函数绘图语言解释器的核心
💻 TXT
字号:
struct ExprNode {	// 语法树节点类型
	enum Token_Type OpCode;	// 记号类别号PLUS, MINUS, MUL, DIV POWER, FUNC, CONSTID 等
	//记号类型
	union {
		struct { ExprNode *Left, *Right; } CaseOperator;		//二元运算符
		struct { ExprNode *Child; FuncPtr MathFuncPtr; } CaseFunc;	//数学函数
		double CaseConst;		//常数
		double *CaseParmPtr;	//参数T 
	} Content;
};
static void FetchToken () 
{//获取一个记号  
      	token = GetToken ();//通过词法分析器接口GetToken获取一个记号
if (token.type == ERRTOKEN)
     	SyntaxError(1); //若得到的记号是一个非法输入ERRTOKEN,则指出一个语法错误
} 
static void MatchToken (enum Token_Type The_Token) 
{//匹配记号
	if (token.type != The_Token) SyntaxError(2);//匹配当前的记号,匹配失败指出一个语法错误
	FetchToken();//匹配当前的记号,匹配成功获取下一个记号
} 
 
static void SyntaxError (int case_of) {
 //定义语法错误函数
	switch(case_of) {
		case 1: //若case_of为,则执行程序段
			ErrMsg (LineNo, "错误记号",   token.lexeme);//程序段
			break;//跳出循环
		case 2://若case_of为,则执行程序段
			ErrMsg (LineNo, "不是预期记号", token.lexeme);//程序段
			break;//跳出循环
		}
	}	
 
void PrintSyntaxTree(struct ExprNode* root, int indent) {//打印语法分析树
int temp;
	for (temp=1; temp<=indent; temp++) printf("\t"); //若temp<=indent则一直输出转义字符
	switch(root->OpCode) {//判断记号类别号
		case PLUS: //若记号类别是PLUS,则输出“+”,并退出循环
			printf("%s\n", "+"); break;
		case MINUS://若记号类别是MINUS,则输出“-”,并退出循环
			printf("%s\n", "-"); break;
		case MUL://若记号类别是MUL,则输出“*”,并退出循环
			printf("%s\n", "*"); break;
		case DIV://若记号类别是DIV,则输出“/”,并退出循环
			printf("%s\n", "/"); break;
		case POWER://若记号类别是POWER,则输出“**”,并退出循环
			printf("%s\n", "**"); break;
		case FUNC://若记号类别是FUNC,则输出语法树节点的数学函数,并退出循环
			printf("%x\n", root->Content.CaseFunc.MathFuncPtr); break;
		case CONST_ID://若记号类别是CONST_ID,则输出语法树的常量,并退出循环
			printf("%f\n", root->Content.CaseConst); break;
		case T://若记号类别是T,则输出参数T,并退出循环
			printf("%s\n", "T" ); break;
		default://若记号类别是其他记号,则输出“错误的树节点”信息,并正常退出程序
			printf("错误的树节点!\n"); 
			exit(0);
	}
	if(root->OpCode == CONST_ID || root->OpCode == T) return; //若记号类别是CONST_ID 或者是T,则返回空
	if(root->OpCode == FUNC) //若记号类别是FUNC,则打印语法分析树
		PrintSyntaxTree(root->Content.CaseFunc.Child, indent+1);
	else {//否则打印语法分析树的左节点和右节点
		PrintSyntaxTree(root->Content.CaseOperator.Left, indent+1);
		PrintSyntaxTree(root->Content.CaseOperator.Right, indent+1);
	}
}
 
void ErrMsg(unsigned LineNo, char *descrip, char *string ) {
	#ifdef PARSER_DEBUG       //PARSER_DEBUG已被#define定义则执行程序段,否则执行程序段
	printf("行号%5d:%s %s!\n", LineNo, descrip, string);//程序段,输出字符串所在行号信息
	#else
		char msg[256];//程序段
		memset(msg, 0, 256);//内存空间初始化
sprintf(msg, "行号%5d:%s %s!", LineNo, descrip, string);
	#endif
	#ifdef _VC_COMPILER //PARSER_DEBUG已被#define定义则执行程序段
		MessageBox(NULL, msg, "错误!", MB_OK);//程序段
	#endif
	#ifdef _BC_COMPILER//PARSER_DEBUG已被#define定义则执行程序段
		printf("%s\n", msg);//程序段
	#endif
	CloseScanner();//关闭词法分析器
	exit(1);//程序正常退出}
 
static void Program ()
{//定义递归下降分析
	enter("<程序>");
	while (token.type != NONTOKEN) {//若记号类别不是空记号
		Statement ();//调用Statement ()函数进行语法分析
		MatchToken (SEMICO);//调用匹配当前记号函数
	}
	back("<程序>");
}
 
static void Statement() {
	enter("<语句>");
	switch (token.type) {//判断记号类别
		case ORIGIN: //若记号类别是坐标平移ORIGIN,则调用OriginStatement()函数,并退出循环
			OriginStatement(); break;
		case SCALE: //若记号类别是比例设置SCALE,则调用ScaleStatement()函数,并退出循环
			ScaleStatement(); break;
		case ROT: //若记号类别是旋转角度ROT,则调用RotStatement()函数,并退出循环
			RotStatement(); break;
		case FOR: //若记号类别是循环绘图FOR,则调用ForStatement()函数,并退出循环
			ForStatement(); break;
		default: //若记号类别是其他记号,则调用打印语法分析器错误函数
			SyntaxError(2);
	}
	back("<语句>");
} 
 static void RotStatement (void) {//定义旋转角度函数的递归子程序
	struct ExprNode *tmp;
	enter("<旋转角度设置语句>");
	MatchToken (ROT);//匹配当前记号		
	MatchToken (IS);//匹配当前记号
	tmp = Expression();		
	#ifndef PARSER_DEBUG
		Rot_angle = GetExprValue(tmp); //获取旋转表达式语法树的值
		DelExprTree(tmp);//删除旋转表达式语法树的值
	#endif
	back("<旋转角度设置语句>");
}
 
static void OriginStatement (void) {//定义坐标平移函数的递归子程序
struct ExprNode *tmp;
	enter("<原点设置语句>");
	MatchToken (ORIGIN);//匹配当前记号		
	MatchToken (IS);	//匹配当前记号			
	MatchToken (L_BRACKET);	//匹配当前记号		
	tmp = Expression();			
	#ifndef PARSER_DEBUG
		Origin_x = GetExprValue(tmp);//获取X平移的值
		DelExprTree(tmp);//删除X平移表达式语法树的值
	#endif
	MatchToken (COMMA);	//匹配当前记号	
	tmp = Expression();			
	#ifndef PARSER_DEBUG
		Origin_y = GetExprValue(tmp); //获取Y平移的值
		DelExprTree(tmp);//删除Y平移表达式语法树的值
	#endif
	MatchToken (R_BRACKET);		//匹配当前记号
	back("<原点设置语句>");
} 
static void ForStatement (void) {//定义循环绘图语句的的递归子程序
#ifndef PARSER_DEBUG
double Start, End, Step; 
#endif
struct ExprNode *start_ptr, *end_ptr, *step_ptr,*x_ptr,*y_ptr; //定义各表达式语法树的根节点
	enter("<循环绘图语句>");
	MatchToken (FOR);	//调用匹配当前记号函数
	call_match("FOR");
	MatchToken(T); //调用匹配当前记号函数
	call_match("T");
	MatchToken (FROM); //调用匹配当前记号函数
	call_match("FROM");
	start_ptr = Expression(); //起点表示式的语法树
	#ifndef PARSER_DEBUG
		Start = GetExprValue(start_ptr);	//获取起点表达式语法树的值
		DelExprTree(start_ptr);				//删除起点表达式语法树的值
	#endif
	MatchToken (TO);//调用匹配当前记号函数
	call_match("TO");
	end_ptr = Expression(); //终点表达式的语法树
	#ifndef PARSER_DEBUG
		End = GetExprValue(end_ptr); //获取终点表达式语法树的值
		DelExprTree(end_ptr);	//删除终点表达式语法树的值	
	#endif
	MatchToken (STEP);//调用匹配当前记号函数
	call_match("STEP");
	step_ptr = Expression(); //步长表达式的语法树
	#ifndef PARSER_DEBUG
		Step = GetExprValue(step_ptr);	//获取步长表达式语法树的值
		DelExprTree(step_ptr);//删除步长表达式语法树的值			
	#endif
	MatchToken (DRAW);//调用匹配当前记号函数
	call_match("DRAW");
	MatchToken (L_BRACKET);//调用匹配当前记号函数
	call_match("(");
	x_ptr = Expression();//横坐标x表达式的语法树
	MatchToken(COMMA);//调用匹配当前记号函数
	call_match(",");
	y_ptr = Expression();//纵坐标y表达式的语法树
	MatchToken (R_BRACKET);//调用匹配当前记号函数
	call_match(")");
	#ifndef PARSER_DEBUG
		DrawLoop (Start, End, Step, x_ptr, y_ptr); 	
		DelExprTree(x_ptr); 
		DelExprTree(y_ptr); 
	#endif
	back("<循环绘图语句>");
}
 
static struct ExprNode* Expression() {//构造表达式的语法树
struct ExprNode *left, *right; //定义语法树的左、右节点指针
Token_Type token_tmp; //定义当前记号类别
	enter("<表达式>");
	left = Term(); //分析左操作数并且得到其语法树
	while (token.type == PLUS || token.type == MINUS) {
		token_tmp = token.type;//当记号类别是PLUS或是MINUS时,把PLUS或是MINUS附给当前记号token_tmp
		MatchToken(token_tmp);	//调用匹配当前记号
		right = Term();			//分析右操作数并且得到其语法树
		left = MakeExprNode(token_tmp, left, right);//构造运算的语法树并将结果作为左子数
	}
	Tree_trace(left); 
	back("<表达式>");
	return left; //返回最终表达式的语法树
}
static struct ExprNode *Term(){
struct ExprNode *left, *right;//定义语法树的左、右节点指针
Token_Type token_tmp;//定义当前记号类别
	left = Factor();	
	while (token.type==MUL || token.type==DIV) {
		token_tmp = token.type;
		MatchToken(token_tmp);
		right = Factor();
		left = MakeExprNode(token_tmp, left, right);//构造运算的语法树并将结果作为左子树
	}	
	return left;
}
 
static struct ExprNode * MakeExprNode(enum Token_Type opcode, ...) {
struct ExprNode *ExprPtr = new (struct ExprNode);//新建语法树ExprPtr
va_list ArgPtr;
	ExprPtr->OpCode = opcode; 
	va_start(ArgPtr, opcode);
   switch(opcode) {	//判断记号的类别构造不同的节点
		case CONST_ID: //构造常数节点,并退出循环
			ExprPtr->Content.CaseConst = (double)va_arg(ArgPtr, double);
			break;
		case T://构造参数节点,并退出循环
			ExprPtr->Content.CaseParmPtr = &Parameter;
			break;
	case FUNC://构造函数调用节点,并退出循环
	ExprPtr->Content.CaseFunc.MathFuncPtr = (FuncPtr)va_arg(ArgPtr, FuncPtr);
	ExprPtr->Content.CaseFunc.Child = (struct ExprNode *) va_arg(ArgPtr, struct ExprNode *);
			break;
	default://构造二元运算节点,并退出循环
	ExprPtr->Content.CaseOperator.Left = (struct ExprNode *)va_arg(ArgPtr, struct ExprNode *);	ExprPtr->Content.CaseOperator.Right = (struct ExprNode *)va_arg(ArgPtr, struct ExprNode *);
			break;
	}
	va_end(ArgPtr);
	return ExprPtr;//返回建立的语法树
}

⌨️ 快捷键说明

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