📄 yufafenxi.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 + -