📄 compiler.cpp
字号:
{
strcpy(sym,wsym[k]);//找到保留字,把sym置为相应的保留字值
}
else
{
strcpy(sym,"ident");//否则就把sym置为标识符
}
}
else if(ch>='0'&&ch<='9') //如果读出字符是数字
{
k=0; //数字位数置0
num=0; //数字置为0
strcpy(sym,"number");//置sym为number,表示这一次读到的是数字
do
{
num=10*num+(int)ch-'0';//num*10加上最近读出的字符ASCII减'0'的ASCII得到相应的数值
k++; //数字位数加1
getCh();
}while(ch>='0'&&ch<='9');
if(k>NMAX) //如果组成的数字位数大于最大允许的数字位数
{
error(30);//发出第30号错误
}
}
else if(ch==':')//如果读出的是冒号
{
getCh(); //再读取下一次字符
if(ch=='=')
{
strcpy(sym,"becomes");
getCh();
}
else
strcpy(sym,"nul");
}
else if(ch=='<')//如果读出的不是字母也不是数字也不是冒号
{
getCh();
if(ch=='=')
{
strcpy(sym,"leq");
getCh();
}
else if(ch=='>')
{
strcpy(sym,"neq");
getCh();
}
else
strcpy(sym,"lss");
}
else if (ch=='>')
{
getCh();
if(ch=='=')
{
strcpy(sym,"geq");
getCh();
}
else
strcpy(sym,"gtr");
}
else//如果读到不是字母也不是数字也不是冒号也不是小于号大于号
{
switch(ch)
{
case '+': strcpy(sym,"plus");
break;
case '-': strcpy(sym,"minus");
break;
case '*': strcpy(sym,"times");
break;
case '/': strcpy(sym,"slash");
break;
case '(': strcpy(sym,"lparen");
break;
case ')': strcpy(sym,"rparen");
break;
case '=': strcpy(sym,"eql");
break;
case ',': strcpy(sym,"comma");
break;
case '.': strcpy(sym,"period");
break;
//case '#': strcpy(sym,"neq");
// break;
case ';': strcpy(sym,"semicolon");
break;
}
getCh();
}
}
//参数p是要生成的一行代码的助记符
//参数q,r是代码的两个操作数
//该函数用于把生成的目标代码写入目标代码数组,供后面的解释器解释执行
void gen(enum fct p,int q,int r)
{
if(cx>CXMAX)//表示当前生成的代码行号大于允许的最大代码行数
{
cout<<"程序太长";
}
else
{
code[cx].f=p;
code[cx].l=q;
code[cx].a=r;
cx++; //移动cx指向下一个空位
}
}
//test:测试当前单词是否合法
//s1:当语法进入或退出某一语法单元时当前单词符合应属于的集合
//s2:在某一出错状态下,可恢复语法分析政党工作的补充单词集合
//n:出错信息编号,当当前符号不属于合法的s1集合时发出的出错信息
/*void test(symset s1,symset s2,int n)
{
if(s1.find(sym)==s1.end()) //如果当前符号不在s1中
{
error(n);
symset::iterator ii;
for(ii=s2.begin();ii!=s2.end();ii++)
s1.insert(*ii); //s1=s1+s2 把s2集合补充进s1集合
while(s1.find(sym)==s1.end()) //通过循环找到下一个合法的符号,以恢复语法分析工作
getsym();
}
//else
// return;
}//test end */
//检查str串是否在set结构体记录中,若在返回1,否则返回0
int in(char *str,struct node *set)
{
int i=0;
while(set->pa[i]!=NULL)
{
if(strcmp(str,set->pa[i])==0)
return 1;
else
i++;
}
return 0;
}
//将set1和set1中没有的set2的内容合成为一个node类型并返回(合并set1,set2)
struct node *add(struct node *set1,struct node *set2)
{
int i=0,j=0,k=0,cnt;
//定义pt,并申请空间
struct node *pt;
pt=(struct node *)malloc(sizeof(struct node));
for(cnt=0;cnt<32;cnt++)
{
pt->pa[cnt]=(char *)malloc(10*sizeof(char));
}
//将set1中内容拷贝到pt
while(set1->pa[i]!=NULL)
strcpy(pt->pa[j++],set1->pa[i++]);
//现在pt和set1中内容相同,但若set2中有与set1不同的内容,加入到pt中
while((set2->pa[k])!=NULL)
{
if(in(set2->pa[k],set1)==0)
strcpy(pt->pa[j++],set2->pa[k++]);
else
k++;
}
pt->pa[j]=NULL;
return(pt);
}
//test:测试当前单词是否合法
//p:当语法进入或退出某一语法单元时当前单词符合应属于的结构
//q:在某一出错状态下,可恢复语法分析政党工作的补充单词结构
//n:出错信息编号,当当前符号不属于合法的s1集合时发出的出错信息
void test(struct node *p,struct node *q,int n)
{
if(in(sym,p)==0) //如果当前符号不在p中
{
error(n);
p=add(p,q); //把s2补充进s1
while(in(sym,p)==0) //通过循环找到下一个合法的符号,以恢复语法分析工作
getsym();
}
}
void enter(enum object k)//登录符号表过程enter
{
tx++; //符号表指针指向一个新的空位
strcpy(table1[tx].name,id); //符号名字
table1[tx].kind=k; //符号类型
switch(k) //根据不同的类型进行不同的操作
{
case constant: //如果是常量名
if(num>AMAX) //在常量的数值大于允许的最大值的情况下
{
error(31); //抛出31号错误
num=0; //实际登录的数字以0代替
}
else
{
table1[tx].val=num; //如果是合法的数值就登录到符号表
}
break;
case variable: //如果是变量名
table1[tx].level=lev;//记下它所属的层次号
table1[tx].adr=dx; //记下它在当前层中的偏移量
dx++; //偏移量自增一,为下一次做好准备
break;
case procedur: //如果要登录的是过程名
table1[tx].level=lev;//记录这个过程所在层次
break;
}
} //enter end
//position函数:在符号表中查找指定符号所在位置
//参数:id要找的符号
//返回值:要找的符号在符号表中的位置,如果找不到就返回0
int position(char id[10])
{
int i;
strcpy(table1[0].name,id); //先把id放入符号表0号位置
i=tx; //从符号表中当前位置也即最后一个符号开始找
while(i>=0&&strcmp(table1[i].name,id)!=0)
i--; //如果当前的符号与要找的不一致,找前面一个
return i; //返回找到的位置号,如果没找到则一定正好为0
} //end position
//常量声明处理过程
void constdeclaration()
{
if(strcmp(sym,"ident")==0)//常量声明过程开始遇到的第一个符号必然应为标识符
{
getsym();//获取下一个token
if(strcmp(sym,"becomes")==0||strcmp(sym,"eql")==0) //如果是等号或赋值号
{
if(strcmp(sym,"becomes")==0)//如果是赋值号(常量声明中应应该是等号)
error(1); //抛出1号错误
//这里其实是自动进行了错误纠正使编译继续进行,把赋值号当作等号处理
getsym();
if(strcmp(sym,"number")==0)
{
enter(constant); //把这个常量登录到符号表
getsym(); //获取下一个token,为后面作准备
}
else
error(2); //如果等号后面接的不是数字,抛出2号错误
}
else
error(3); //如果常量标识符后接的不是等号或赋值号,抛出3号错误
}
else
error(4); //如果常量声明过程遇到的第一个符号不为标识符,抛出4号错误
}//constdeclaration end
//变量声明过程
void vardeclaration()
{
if(strcmp(sym,"ident")==0) //变量声明过程开始最到的第一个符号必然应为标识符
{
enter(variable); //将标识符登录到符号表中
getsym(); //获取下一个token,为后面作准备
}
else
error(4); //如果变量声明过程最到的第一个符号不是标识符,抛出4号错误
} //vardeclaration end
//函数listcode:列出当前一层类PCODE目标代码
/*void listcode(int *cx0)
{
int i=*cx0;
if(listswitch) //如果用户选择是要列出代码的情况下才列出代码
{
cout<<endl;
while(i<=cx-1) //从当前层代码开始位置到当前代码位置-1处,即为本分程序块
{
cout<<" "<<i<<" "<<mnemonic[(int)code[i].f]<<" "<<code[i].l<<" "<<code[i].a<<endl; //显示出第i行代码的助记符和L与A操作数
// fprintf(fa,"%2d %5s %3d %5d\n",i,mnemonic[(int)code[i].f],code[i].l,code[i].a); //同时把屏显打印到文件
i++;
}
cout<<endl<<endl;
}
}*/
void listcode(int *cx0)
{
//打印本层的伪代码
int i;
if(listswitch)
{
cout<<endl;
for(i=*cx0;i<=cx-1;i++)
{
printf("%2d %5s %3d %5d\n",i,mnemonic[(int)code[i].f],code[i].l,code[i].a);
fprintf(fa,"%2d %5s %3d %5d\n",i,mnemonic[(int)code[i].f],code[i].l,code[i].a);
}
printf("\n");
printf("\n");
}
}
//因子处理过程factor
//参数说明:fsys:如果出错可用来恢复语法分析的符号集合
void factor(struct node *fsys)
{
int i;
int m=0,n=0;
void expression(struct node *fsys);
struct node *tp;
char *tpset[]={"rparen",NULL};
tp=(struct node*)malloc(sizeof(struct node));
while(tpset[m]!=NULL)
tp->pa[n++]=tpset[m++];
tp->pa[n]=NULL;
test(facbegsys,fsys,24); //开始因子处理前,先检查当前token是否在facbegsys集合中
//如果不是合法的token,抛24号错误,并通过fsys集恢复使用权语法处理可以继续进行
while(in(sym,facbegsys)==1) //循环处理因子
{
if(strcmp(sym,"ident")==0) //如果最到的是标识符
{
i=position(id); //查符号表,找到当前标识符在符号表中的位置
if(i==0) //如果查符号表返回0,表示没有找到标识符
error(11); //抛出11号错误
else //如果在符号表中找到了当前标识符的位置,开始生成相应代码
{
switch(table1[i].kind)
{
case constant:
gen(lit,0,table1[i].val);//如果是常量,值为val,生成lit指令,把val放到栈顶
break;
case variable:
gen(lod,lev-table1[i].level,table1[i].adr); //如果是变量,生成lod指令,把位于距离当前层level的层的偏移地址为adr的变量放到栈顶
break;
case procedur:
error(21); //如果在因子处理中最到的标识符是过程名,抛出21号错误码
break;
}
}
getsym(); //获取下一个token,继续循环处理
}
else if(strcmp(sym,"number")==0) //当因子处理遇到数字时
{
if(num>AMAX) //如果数字的大小超过允许最大值AMAX
{
error(31); //抛出31号错
num=0; //把数字按0值处理
}
else
{
gen(lit,0,num);//生成lit指令,把这个数值字面常量放到栈顶
getsym();
}
}
else if(strcmp(sym,"lparen")==0) //如果最到的是左括号
{
getsym(); //获取下一个token
expression(add(tp,fsys)); //递归调用expression子程序分析一个子表达式
//子表达式分析完后,应最到右括号
if(strcmp(sym,"rparen")==0) //如果的确最到右括号
getsym(); //读取下一个token
else
error(22); //否则抛出22号错误
}
test(fsys,facbegsys,23); //一个因子处理完毕,最到的token应在fsys集合中
//如果不是,抛23号错误,并找到下一个因子的开始,使语法分析可以继续运行下去
}
}//factor end
//项处理过程term
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -