📄 compiler.cpp
字号:
void term(struct node *fsys)
{
char mulop[10];
int m=0;
int n=0;
struct node *tp;
char *tpset[]={"times","slash",NULL};
tp=(struct node *)malloc(sizeof(struct node));
while(tpset[m]!=NULL)
tp->pa[m++]=tpset[n++];
tp->pa[m]=NULL;
factor(add(tp,fsys)); //每一个项都应该由因子开始,因此调用factor子程序分析因子
while(in(sym,tp)==1) //一个因子后应当最到乘号或除号
{
strcpy(mulop,sym); //保存当前运算符
getsym(); //获取下一个token
factor(add(tp,fsys)); //运算符后应是一个因子,故调用factor子程序分析因子
if(strcmp(mulop,"times")==0)//如果刚才遇到乘号
gen(opr,0,4); //生成乘法指令
else
gen(opr,0,5); //不是乘号一定是除号,生成除法指令
}
}//term end
//算术表达式处理过程expression
void expression(struct node *fsys)
{
char addop[10];
int m=0,n=0;
struct node *tp;
char *tpset[]={"plus","minus",NULL};
tp=(struct node *)malloc(sizeof(struct node));
while(tpset[n]!=NULL)
tp->pa[m++]=tpset[n++];
tp->pa[m]=NULL;
if(in(sym,tp)==1) //一个表达式可能会由加号或减号开始,表示正负号
{
strcpy(addop,sym); //把当前的正号或负号保存起来,以便下面生成相应代码
getsym(); //获取一个token;
term(add(fsys,tp)); //正负号后面应该是一个项,调term子程序分析
if(strcmp(addop,"minus")==0) //如果保存下来的是负号
gen(opr,0,1); //生成一条1号操作指令:取反运算
//如果不是负号就是正号,正号不需要生成相应的指令
}
else
term(add(fsys,tp)); //如果不是由正负号开头,就应是一个项开头,调用term子程序分析项
while(in(sym,tp)==1) //项后应该是回法运算符+/-
{
strcpy(addop,sym); //把运算符保存下来
getsym(); //获取下一个token
term(add(fsys,tp)); //调用term子程序分析项
if(strcmp(addop,"plus")==0) //如果项与项之间的运算符是加号
gen(opr,0,2); //生成2号操作指令:加法
else
gen(opr,0,3); //生成3号操作指令:减法
}
}//expression end
//条件处理过程
void condition(struct node *fsys)
{
char relop[10]; //用于临时记录token(这里一定是一个二元逻辑运算符的内容)
int m=0,n=0;
struct node *tp;
char *tpset[]={"eql","neq","lss","leq","gtr","geq",NULL};
tp=(struct node*)malloc(sizeof(struct node));
while(tpset[n]!=NULL)
tp->pa[m++]=tpset[n++];
tp->pa[m]=NULL;
if(strcmp(sym,"oddsym")==0) //如果是odd运算符(一元)
{
getsym(); //获取下一个token
expression(fsys); //对odd的表达式进行处理计算
gen(opr,0,6); //生成6号操作指令:奇偶判断运算
}
else //如果不是odd运算符(那就一定是二元逻辑运算符)
{
expression(add(tp,fsys)); //对表达式左部进行处理计算
if(in(sym,tp)==0) //如果token不是逻辑运算符中的一个
error(20); //抛出20号错误
else
{
strcpy(relop,sym); //记录下当前的逻辑运算符
getsym(); //获取下一个token
expression(fsys); //对表达式右部进行处理计算
//如果刚才的运算符是下面的一种
if(strcmp(relop,"eql")==0)
gen(opr,0,8); //如果是等号,产生8号判等指令
if(strcmp(relop,"neq")==0)
gen(opr,0,9); //如果是不等号,产生9号判不等指令
if(strcmp(relop,"lss")==0)
gen(opr,0,10); //如果是小于号,产生10号判小指令
if(strcmp(relop,"geq")==0)
gen(opr,0,11); //如果是大于等于号,产生11号判不小于指令
if(strcmp(relop,"gtr")==0)
gen(opr,0,12); //如果是大于号,产生12号判大于指令
if(strcmp(relop,"leq")==0)
gen(opr,0,13); //如果是小于等于号,产生13号判不大于指令
}
}
}//condition end
//语句处理过程
void statement(struct node *fsys,int plev)
{
int m=0,n=0;
int i,cx1,cx2;
char *tempset1[]={"rparen","comma",NULL};
char *tempset2[]={"thensym","dosym",NULL};
char *tempset3[]={"semicolon","endsym",NULL};
char *tempset4[]={"semicolon",NULL};
char *tempset5[]={"dosym",NULL};
char *tempset6[]={NULL};
struct node *temp1,*temp2,*temp3,*temp4,*temp5,*temp6;
temp1=(struct node *)malloc(sizeof(struct node));
temp2=(struct node *)malloc(sizeof(struct node));
temp3=(struct node *)malloc(sizeof(struct node));
temp4=(struct node *)malloc(sizeof(struct node));
temp5=(struct node *)malloc(sizeof(struct node));
temp6=(struct node *)malloc(sizeof(struct node));
while(tempset1[n]!=NULL)
temp1->pa[m++]=tempset1[n++];
temp1->pa[m]=NULL;
m=0;
n=0;
while(tempset2[n]!=NULL)
temp2->pa[m++]=tempset2[n++];
temp2->pa[m]=NULL;
m=0;
n=0;
while(tempset3[n]!=NULL)
temp3->pa[m++]=tempset3[n++];
temp3->pa[m]=NULL;
m=0;
n=0;
while(tempset4[n]!=NULL)
temp4->pa[m++]=tempset4[n++];
temp4->pa[m]=NULL;
m=0;
n=0;
while(tempset5[n]!=NULL)
temp5->pa[m++]=tempset5[n++];
temp5->pa[m]=NULL;
m=0;
n=0;
while(tempset6[n]!=NULL)
temp6->pa[m++]=tempset6[n++];
temp6->pa[m]=NULL;
m=0;
n=0;
if(strcmp(sym,"ident")==0) //所谓语句可能是赋值语句,以标识符开头
{
i=position(id); //在符号表中查到该符号所在位置
if(i==0)
error(11); //如果没有找到,抛出11号错误
else
{
if(table1[i].kind!=variable) //如果在符号表中找到该标识符,但该标识符不是变量名
{
error(12); //
i=0;
}
}
getsym(); //获取下一个token,正常应为赋值符号
if(strcmp(sym,"becomes")==0) //如果的确为赋值符号
getsym(); //获取下一个token,正常应为一个表达式
else
error(13); //如果不是赋值号,抛出13号错误
expression(fsys); //处理表达式
if(i!=0) //如果不曾出错,i将不为0,i所指为当前语句左部标识符在符号表中的位置
gen(sto,plev-table1[i].level,table1[i].adr);//产生一行指把表达式值写往指定内存的sto目标代码
}
else if(strcmp(sym,"readsym")==0) //如果不是赋值语句,而是遇到了read语句
{
getsym(); //获取下一个token,正常情况下应为左括号
if(strcmp(sym,"lparen")!=0)
error(24); //如果read后跟的不是左括号,抛出34错误
else
{
do//循环不断生成代码直到read语句的参数表中的变量遍历完为止,这里最到不是逗号,应为右括号
{
getsym(); //token,正常应是一个变量名
if(strcmp(sym,"ident")==0)//如果确为一个标识符
i=position(id); //查符号表,找到它所在位置给i,找不到i会为0
else
i=0;
if(i==0)
error(35);
else
{
gen(opr,0,16);
gen(sto,plev-table1[i].level,table1[i].adr);
}
getsym();
}while(strcmp(sym,"comma")==0);
}
if(strcmp(sym,"rparen")!=0)
{
error(22);
while(in(sym,fsys)==0)
getsym();
}
else
getsym(); //如果read语句正常结束,得到下一个token,一般为分号,或end
}
else if(strcmp(sym,"writesym")==0) //如果最到了write语句
{
getsym(); //获取下一个token,应为左括号
if(strcmp(sym,"lparen")==0) //如果确为左括号
{
do //循环直到遇到的不再是逗号,这时应是右括号
{
getsym(); //获取下一个token,这里应是一个标识符
expression(add(temp1,fsys)); //调用expression过程分析表达式,用于出错恢复的集合中加上右括号和逗号
gen(opr,0,14); //生成14号指令,向屏幕输出
}while(strcmp(sym,"comma")==0);
if(strcmp(sym,"rparen")!=0) //如果不是右括号
error(33); //抛出33号错误
else
getsym();
}
gen(opr,0,15); //生成一个15号操作的目标代码,功能是输出一个换行
}
else if(strcmp(sym,"callsym")==0) //如果是call语句
{
getsym(); //获取token,应是过程名标识符
if(strcmp(sym,"ident")!=0) //如果call后面跟的不是标识符
error(14); //抛出14号错误
else
{
i=position(id); //从符号表中找出相应的标识符
if(i==0) //如果没找到
error(11); //抛出11号错误
else //如果找到标识符位于符号表第i位置
{
if(table1[i].kind==procedur)//如果这个标识符为一个过程名
gen(cal,plev-table1[i].level,table1[i].adr);//生cal目标代码,呼叫这个过程
else
error(15); //如果call后面跟的不是过程名,抛出15号错误
}
getsym(); //获取下一个token
}
}
else if(strcmp(sym,"ifsym")==0) //如果是if语句
{
getsym(); //获取下一个token,应是一个逻辑表达式
condition(add(temp2,fsys)); //对逻辑表达式进行分析计算,出错恢复集中加入then和do语句
if(strcmp(sym,"thensym")==0) //表达式后应最到then语句
getsym(); //获取then后的token,应是一语句
else
error(16); //如果if后没有then,抛出16号错误
cx1=cx; //记下当前代码分配指针位置
gen(jpc,0,0); //生成条件跳转指令,跳转位置暂时填0,分析完语句后再填写
statement(fsys,plev); //分析then后的语句
code[cx1].a=cx; //上一行指令(cx1所指的)的跳转位置应为当前cx所指位置
}
else if(strcmp(sym,"beginsym")==0) //如果遇到begin
{
getsym(); //获取下一个token
statement(add(temp3,fsys),plev); //对begin与end之间的语句进行分析处理
while(in(sym,add(temp4,statbegsys))==1)//如果分析完一句后遇到分号或语句开始循环分析下一句语句
{
if(strcmp(sym,"semicolon")==0) //如果语句是分号(可能是空语句)
getsym(); //获取下一个token继续分析
else
error(10); //如果语句与语句间没有分号,出10号错
statement(add(temp3,fsys),plev);//分析一个语句
}
if(strcmp(sym,"endsym")==0) //如果语句全分析完了,应该遇到end
getsym(); //的确是end ,读下一个token
else
error(17); //如果不是end,抛出17号错误
}
else if(strcmp(sym,"whilesym")==0) //如果遇到while语句
{
cx1=cx; //记下当前代码分配位置,这是while循环的开始位置
getsym(); //获取下一个token,应为一逻辑表达式
condition(add(temp5,fsys)); //对这个逻辑表达式进行分析计算
cx2=cx; //记下当前代码分配位置,这是while的do中的语句的开始位置 gen(jpc,0,0); //生成条件跳转指令,跳转位置暂时填0
gen(jpc,0,0); //生成条件跳转指令,跳转位置暂置0
if(strcmp(sym,"dosym")==0) //逻辑表达式后应为do语句
getsym(); //获取下一个token
else
error(18); //while后少do,抛出18号错误码
statement(fsys,plev); //分析do后的语句块
gen(jmp,0,cx1); //循环跳转到cx1位置,即再次进行逻辑判断
code[cx2].a=cx; //把刚才填0的跳转位置改成当前位置,完成while语句的处理
}
test(fsys,temp6,19); //到此一个语句处理完成,一定会遇到fsys集中的符号,如果没有遇到,就抛19号错误
}
void block(int plev,struct node *fsys)
{
int m=0,n=0;
int dx=3; //地址指示器给出每层局部量当前已分配到的相应位置
//置初始值为3的原因是:每一层最开始的位置有三个空间用于存放静态链SL,动态链DL和返回地址RA
int tx0=tx; //初始符号表指针指向当前层的符号在符号表中的开始位置
lev=plev;
static int cx0=0; //起始代码下标
table1[tx].adr=cx; //符号表当前位置记下层代码的开始位置
char *tempset1[]={"semicolon","endsym",NULL};
char *tempset2[]={"ident","procsym",NULL};
char *tempset3[]={"semicolon",NULL};
char *tempset4[]={"ident",NULL};
char *tempset5[]={NULL};
struct node *temp1,*temp2,*temp3,*temp4,*temp5;
temp1=(struct node *)malloc(sizeof(struct node));
temp2=(struct node *)malloc(sizeof(struct node));
temp3=(struct node *)malloc(sizeof(struct node));
temp4=(struct node *)malloc(sizeof(struct node));
temp5=(struct node *)malloc(sizeof(struct node));
// temp6=(struct node *)malloc(sizeof(struct node));
while(tempset1[n]!=NULL)
temp1->pa[m++]=tempset1[n++];
temp1->pa[m]=NULL;
m=0;
n=0;
while(tempset2[n]!=NULL)
temp2->pa[m++]=tempset2[n++];
temp2->pa[m]=NULL;
m=0;
n=0;
while(tempset3[n]!=NULL)
temp3->pa[m++]=tempset3[n++];
temp3->pa[m]=NULL;
m=0;
n=0;
while(tempset4[n]!=NULL)
temp4->pa[m++]=tempset4[n++];
temp4->pa[m]=NULL;
m=0;
n=0;
while(tempset5[n]!=NULL)
temp5->pa[m++]=tempset5[n++];
temp5->pa[m]=NULL;
m=0;
n=0;
gen(jmp,0,1); //产生一行跳转指令,跳转达位置暂时未知填0
if(plev>LEVMAX) //如果当前过程嵌套层数大于最大允许的套层数
error(32); //抛出32号错误
do
{
if(strcmp(sym,"constsym")==0)
{
getsym();
do
{
constdeclaration(); //声明以当前token为标识符的常量
while(strcmp(sym,"comma")==0) //如果最到了逗号则反复声明下一个常量
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -