《编译原理》实验指导书
k++;
} getchdo;
}
while(ch>='a'&&ch<='z'||ch>='0'&&ch<='9'); a[k]=0; strcpy(id,a); i=0; j=norw-1;
do /* 搜索当前符号是否为保留字 */ { k=(i+j)/2;
if(strcmp(id,word[k])<=0)j=k-1; if(strcmp(id,word[k])>=0)i=k+1; }
while(i<=j);
if(i-1>j)sym=wsym[k]; else sym=ident; /* 搜索失败则,是名字或数字 */
} else { if(ch>='0'&&ch<='9') {
/* 检测是否为数字:以0..9开头 */
k=0; num=0; sym=number; do { num=10*num+ch-'0'; k++; getchdo;
}
while(ch>='0'&&ch<='9'); /* 获取数字的值 */ k--;
if(k>nmax)error(30);
} else { if(ch==':') /* 检测赋值符号 */
{ getchdo; if(ch=='=') { sym=becomes;
getchdo;
《编译原理》课程组 20 of 37
《编译原理》实验指导书
} else { }
if(ch=='<') { } else { }
if(ch=='>') { } else { }
sym=ssym[ch]; getchdo;
/* 当符号不满足上述条件时,全部按照单字符符号
getchdo; if(ch=='=') { } else { }
sym=gtr; sym=geq; getchdo;
/* 检测大于或大于等于符号 */
getchdo; if(ch=='=') { } else { }
sym=lss; sym=leq; getchdo;
/* 检测小于或小于等于符号 */
} else { }
sym=nul; /* 不能识别的符号 */
处理 */
《编译原理》课程组 21 of 37
《编译原理》实验指导书
}
/* 编译程序主体 */
int block(int lev, /* 当前分程序所在层 */ {
dx=3; tx0=tx;
/* 记录本层名字的初始位置 */
table[tx].adr=cx; gendo(jmp,0,0);
if(lev>levmax)error(32); do {
if(sym==constsym) /* 收到常量声明符号,开始处理常量声明 */ { {
}
while(sym==ident);
constdeclarationdo(&tx,lev,&dx); /* dx的值会被constdeclaration改变,使用指while(sym==comma) { }
if(sym==semicolon) { }
else error(5);
getsymdo; getsymdo;
constdeclarationdo(&tx,lev,&dx);
getsymdo; do
int i;
int dx; /* 名字分配到的相对地址 */ int tx0; /* 保留初始tx */ int cx0; /* 保留初始cx */
bool nxtlev[symnum]; /* 在下级函数的参数中,符号集合均为值参,但由于使用数租实现,
传递进来的是指针,为防止下级函数改变上级函数的集合,开辟新的空间 传递给下级函数,之后所有的nxtlev都是这样 */
int tx, /* 名字表当前尾指针 */ bool* fsys /* 当前模块后跟符号集合 */ ) } return 0;
}
针 */
《编译原理》课程组 22 of 37
《编译原理》实验指导书
}
if(sym==varsym)
/* 收到变量声明符号,开始处理变量声明 */
{ getsymdo; do { vardeclarationdo(&tx,lev,&dx); while(sym==comma) { getsymdo;
vardeclarationdo(&tx,lev,&dx);
}
if(sym==semicolon) { getsymdo; }
else error(5);
}
while(sym==ident);
}
while(sym==procsym) /* 收到过程声明符号,开始处理过程声明 */ { getsymdo; if(sym==ident) { enter(procedur,&tx,lev,&dx); /* 记录过程名字 */
getsymdo;
}
else error(4); /* procedure后应为标识符 */
if(sym==semicolon)
{ getsymdo;
}
else error(5);
/* 漏掉了分号 */
memcpy(nxtlev,fsys,sizeof(bool)*symnum); nxtlev[semicolon]=true;
if(-1==block(lev+1,tx,nxtlev))return -1; /* 递归调用 */ if(sym==semicolon) { getsymdo;
memcpy(nxtlev,statbegsys,sizeof(bool)*symnum); nxtlev[ident]=true; nxtlev[procsym]=true;
testdo(nxtlev,fsys,6); 《编译原理》课程组 23 of 37
《编译原理》实验指导书
}
/* 初始化 */ void init() {
int i;
/* 设置单字符符号 */
for(i=0;i<=255;i++)ssym[i]=nul; ssym['+']=plus; ssym['-']=minus; ssym['*']=times; ssym['/']=slash; ssym['(']=lparen; ssym[')']=rparen; ssym['=']=eql; ssym[',']=comma; ssym['.']=period; ssym['#']=neq; ssym[';']=semicolon; /* 设置保留字名字 */ }
while(inset(sym,declbegsys));
/* 直到没有声明符号 */
code[table[tx0].adr].a=cx; /* 开始生成当前过程代码 */ table[tx0].adr=cx; /* 当前过程代码地址 */ table[tx0].size=dx; cx0=cx;
gendo(inte,0,dx); /* 生成分配内存代码 */
/* 语句后跟符号为分号或end */
memcpy(nxtlev,fsys,sizeof(bool)*symnum); /* 每个后跟符号集和都包含上层后跟符号集和,以nxtlev[semicolon]=true; nxtlev[endsym]=true;
statementdo(nxtlev,&tx,lev); gendo(opr,0,0);
/* 每个过程出口都要使用的释放数据段指令 */
memset(nxtlev,0,sizeof(bool)*symnum); /*分程序没有补救集合 */ testdo(fsys,nxtlev,8); /* 检测后跟符号正确性 */ listcode(cx0); return 0;
/* 输出代码 */
/* 声明部分中每增加一条声明都会给dx增加1,声明部分已经结束,dx就
}
memcpy(nxtlev,statbegsys,sizeof(bool)*symnum); nxtlev[ident]=true;
testdo(nxtlev,declbegsys,7);
}
else error(5);
/* 漏掉了分号 */
是当前过程数据的size */
便补救 */
《编译原理》课程组 24 of 37