📄 pl0.cpp
字号:
#include "pl0.h"
/**************************************************************************
* PL/0 语言编译程序,由江汉石油学院计算机系周云才根据清华大学出版社出版,
* 吕映芝,张素琴,蒋维杜编写的教材《编译原理》中第二章(PL/0编译程序的实现)
* 以及附录A中的代码改编而成。
* 代码版权由周云才拥有,使用者必须遵循以下约定:
* 可以免费使用此文件,但必须包含此声明。
* 可以修改、传播、打印、出版这里的源代码。
* 可以在任何软件工程中使用这里的源代码。
* 周云才对于由此源代码的使用而引起的任何问题没有任何责任。
* 周云才地址:湖北省荆州市江汉石油学院计算机系
* 邮编:434023
* 信箱:zyc262@163.net
* 电话: 0716-8431262
********************************************************************************************* */
// 错误字符串数组
string PL0::errStr[]={" ","error 0001: 常数说明中“=”写成“:=”",
"error 0002: 常数说明中的“=”后应为数字",
"error 0003: 常数说明中的标识符后应是“=”",
"error 0004: const,var,procedure后应为标识符",
"error 0005: 漏掉了‘,’或‘;’",
"error 0006: 过程说明后的符号不正确(应是语句开始符或过程开始符)",
"error 0007: 应是语句开始符",
"error 0008: 过程体内语句部分的后跟符不正确",
"error 0009: 程序皆为丢了句号‘.’",
"error 0010: 语句之间漏了‘;’",
"error 0011: 标识符没说明",
"error 0012: 赋值语句中,赋值号左部标识符属性应是变量",
"error 0013: 赋值语句左部标识符应是赋值号:=",
"error 0014: call后应为标识符",
"error 0015: call后标识符属性应为过程",
"error 0016: 条件语句中丢了then",
"error 0017: 丢了end或;",
"error 0018: while型循环语句中丢了do",
"error 0019: 语句后的标识符不正确",
"error 0020: 应为关系运算符",
"error 0021: 表达式内标识符属性不能是过程",
"error 0022: 表达式中漏掉了右括号‘)’",
"error 0023: 因子后的非法符号",
"error 0024: 表达式开始符不能是此符号",
"error 0025: 文件在不该结束的地方结束了",
"error 0026: 结束符出现在不该结束的地方",
"error 0027: ","error 0028: ","error 0029: ","error 0030: ",
"error 0031: 数越界",
"error 0032: read语句括号中标识符不是变量",
"error 0033: else附近错误" ,
"error 0034: repeat附近错误"};
// PL0构造函数
PL0::PL0(char* source,char*destination)
{
listswitch=true,sourceEnd=false;
strcpy(word[1],"begin"); // 初始化存储保留字
strcpy(word[2],"call");
strcpy(word[3],"const");
strcpy(word[4],"do");
strcpy(word[5],"else");
strcpy(word[6],"end");
strcpy(word[7],"if");
strcpy(word[8],"odd");
strcpy(word[9],"procedure");
strcpy(word[10],"read");
strcpy(word[11],"repeat");
strcpy(word[12],"then");
strcpy(word[13],"until");
strcpy(word[14],"var");
strcpy(word[15],"while");
strcpy(word[16],"write");
wsym[1]= BEGINSYM; wsym[2]= CALLSYM; // 初始化保留字表中每一个保留字对应的symbol类型
wsym[3]= CONSTSYM; wsym[4]= DOSYM;
wsym[5]= ELSESYM; wsym[6]= ENDSYM;
wsym[7]= IFSYM; wsym[8]= ODDSYM;
wsym[9]= PROCSYM; wsym[10]= READSYM;
wsym[11]= REPEATSYM; wsym[12]= THENSYM;
wsym[13]= UNTILSYM; wsym[14]= VARSYM;
wsym[15]= WHILESYM; wsym[16]= WRITESYM;
memset(code,0,sizeof(code));
memset(ssym,0,100*sizeof(symbol));
memset(table,0,sizeof(table));
memset(line,0,sizeof(line));
ssym['+']= PLUS; // 初始化一些符号对应的symbol类型表
ssym['-']= MINUS;
ssym['*']= TIMES;
ssym['/']= SLASH;
ssym['(']= LPAREN;
ssym[')']= RPAREN;
ssym['=']= EQL;
ssym[',']= COMMA;
ssym['.']= PERIOD;
ssym['#']= NEQ;
ssym['<']= LSS;
ssym['>']= GTR;
ssym[';']= SEMICOLON;
strcpy(mnemonic[LIT]," lit "); // 初始化类PCODE指令助记符表
strcpy(mnemonic[OPR]," opr ");
strcpy(mnemonic[LOD]," lod ");
strcpy(mnemonic[STO]," sto ");
strcpy(mnemonic[CAL]," cal ");
strcpy(mnemonic[INT]," int ");
strcpy(mnemonic[JMP]," jmp ");
strcpy(mnemonic[JPC]," jpc ");
declbegsys.insert(CONSTSYM),declbegsys.insert(VARSYM),declbegsys.insert(PROCSYM); // 初始化声明开始符号集合
statbegsys.insert(BEGINSYM),statbegsys.insert(CALLSYM),statbegsys.insert(IFSYM),statbegsys.insert(WHILESYM); // 初始化表达式开始符号集合
facbegsys.insert(IDENT),facbegsys.insert(NUMBER),facbegsys.insert(LPAREN); // 初始化项开始符号集合
err= 0;
cc= 0; // 行缓冲区指针
cx= 0; // 代码分配指针,代码生成模块总在cx所指位置生成新的代码
ll= 0; // 行缓冲区长度
ch= ' '; // last character read
kk= al; // 引入此变量是出于程序性能考虑
codeNo=0; // code line no.
fin=fopen(source,"r");
fout=fopen(destination,"w");
}
// 出错处理,打印出错位置和出错代码
void PL0::error(int n)
{
char s[10];
sprintf(s,"第 %d 行:",codeNo);
errorString.push_back(s+errStr[n]);
err= err+1;//error count
}//error end
// 词法分析,读取一个单词
void PL0::getsym()
{
if(sourceEnd)
return;
int i,j,k;
while (ch ==' '||ch==9)
getch(); // cls space and tab
if(isalpha(ch)) // id or reserved word
{
k=0;
memset(a,0,al+1);
// 检测一个单词长度
do{
if (k < al)
{
a[k]= ch;
k= k+1;
}
getch();
if(sourceEnd)
return;
}while(isalpha(ch)||isdigit(ch));
if(k >= kk)
kk = k;
else
{
do{
a[kk]= ' ';
kk= kk-1;
}while(kk > k);
}
strcpy(id,a);
i= 1;
j= norw;
// 判断是否是关键字(二分搜索)
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(isdigit(ch)) // number
{
k= 0;
num= 0;
sym= NUMBER;
do{
num= 10 * num + ch - '0';
k= k+1;
getch();
}while(isdigit(ch));
if(k > nmax)
error(30);
}
else if (ch == ':')
{
getch();
if( ch == '=')
{
sym= BECOMES;
getch();
}
else
sym= NUL;
}
else if(ch == '<') // extra stuff added to support <=
{
getch();
if (ch== '=')
{
sym= LEQ;
getch();
}
else
sym= LSS;
}
else if (ch == '>')
{
getch();
if( ch == '=')
{
sym= GEQ;
getch();
}
else
sym= GTR;
}
else // end of extra stuff
{
sym= ssym[ch]; // 其它符号的赋值
getch();
}
}
// 漏掉空格,读取一个字符
void PL0::getch()
{
if(cc == ll)
{
if(feof(fin))
{
if(sym!=PERIOD)
error(25);
sourceEnd=true;
return;
}
cc= 0;
fgets(line,lineLength,fin);
codeNo++;
ll=strlen(line);
if(line[ll-1]==10) ll--;
}
ch= line[cc];
cc= cc+1;
}
// 生成目标代码,并送入目标程序区
void PL0::gen(fct x,int y,int z)
{
if (cx > cxmax)
{
cout<<"Program too long\n";
return;
}
code[cx].f= x;
code[cx].l= y;
code[cx].a= z;
cx= cx+1;
}//gen end
// 测试当前单词符号是否合法
void PL0::test(symset s1,symset s2,int n)
{
if(sourceEnd) return;
if (s1.find(sym)==s1.end())
{
error(n);
symset::iterator it;
for(it=s2.begin();it!=s2.end();it++)
s1.insert(*it);//s1=s1+s2
while (s1.find(sym)==s1.end())
getsym();
}
}//test end
// 分程序分析处理过程
void PL0::block(int lev,int tx,symset fsys)
{
if(sourceEnd)
return;
int dx; // data allocation index
int tx0; // initial table index
int cx0; // initial code index
dx= 3; // 变量的个数
tx0= tx; // 表指针
table[tx].other.inOther.adr= cx;
gen(JMP,0,0);
if( lev>levmax)
error(32);
do{
if( sym == CONSTSYM) // 处理常量声明
{
getsym();
do{
constdeclaration(tx,dx,lev);
while (sym == COMMA)
{
getsym();
constdeclaration(tx,dx,lev);
}
if (sym ==SEMICOLON)
getsym();
else
error(5);
}while(sym==IDENT);
}
if( sym == VARSYM) // 处理变量声明
{
getsym();
do{
vardeclaration(tx,dx,lev);
while( sym == COMMA){
getsym();
vardeclaration(tx,dx,lev);
}
if( sym ==SEMICOLON)
getsym();
else
error(5);
}while(sym==IDENT);
}
while( sym ==PROCSYM) // 处理过程的声明
{
getsym();
if (sym ==IDENT)
{
enter(PROCEDURE,tx,dx,lev);
getsym();
}
else
error(4);
if( sym ==SEMICOLON)
getsym();
else
error(5);
symset tmp = fsys;
tmp.insert(SEMICOLON);
block(lev+1,tx,tmp);
if (sym == SEMICOLON){
getsym();
symset tmp = statbegsys;
for(int i= IDENT;i<=PROCSYM;i++)
tmp.insert((symbol)i);
test(tmp,fsys,6);
}
else
error(5);
}
symset tmp=statbegsys;
tmp.insert(IDENT);
test(tmp,declbegsys,7);
}while(declbegsys.find(sym)!=declbegsys.end());
code[table[tx0].other.inOther.adr].a= cx;
table[tx0].other.inOther.adr= cx; // start adr of code
table[tx0].other.inOther.size=dx;
cx0= cx;
gen(INT,0,dx);
symset tmp=statbegsys;
for(int i=SEMICOLON;i <= ENDSYM;i++)
tmp.insert((symbol)i);
statement(tmp,tx,lev);
gen(OPR,0,0); // return
symset s2;
test(fsys,s2,8);
listcode(cx0);
}// block end
// 登入名字表
void PL0::enter(obj0 k,int &tx,int &dx,int lev)
{
tx= tx+1;
strcpy(table[tx].name,id);
table[tx].kind=k;
switch(k)
{
case CONSTANT:
if(num>amax)
{
error(31);
num=0;
}
table[tx].other.val=num;
break;
case VARIABLE:
table[tx].other.inOther.level=lev;
table[tx].other.inOther.adr=dx;
dx++;
break;
case PROCEDURE:
table[tx].other.inOther.level=lev;
break;
case ARRAY:
table[tx].other.inOther.size = lev;
break;
}
}//enter end
// 查找标示符在名字表中的位置
int PL0::position(alfa id,int tx)//find identifier id in table
{
int i;
strcpy(table[0].name, id);
i= tx;
while (strcmp(table[i].name,id)!=0)i--;
return i;
}//position end
// 常量定义处理
void PL0::constdeclaration(int&tx,int&dx,int lev)
{
if(sym == IDENT)
{
getsym();
if(sym>=EQL&&sym<=BECOMES)
{
if( sym ==BECOMES)
error(1);
getsym();
if( sym == NUMBER)
{
enter(CONSTANT,tx,dx,lev);
getsym();
}
else
error(2);
}
else
error(3);
}
else
error(4);
}// constdeclaration end
// 变量说明处理
void PL0::vardeclaration(int&tx,int&dx,int lev)
{
if( sym == IDENT)
{
enter(VARIABLE,tx,dx,lev);
getsym();
}
else
error(4);
}//vardeclaration end
// 数组说明处理
void PL0::arraydeclaration(int&tx,int&dx,int lev)
{
int upscript=0,downscript=0;
getsym();
if(sym == NUMBER || sym == CONSTSYM)
{
if(num == 0)
{
upscript = num;
getsym();
}
else
error(32);
}
if(sym == COMMA)
getsym();
else
error(32);
if(sym == NUMBER || sym == CONSTSYM)
{
downscript = num;
getsym();
}
if(sym != RPAREN)
error(32);
else
{
enter(ARRAY,tx,dx,downscript+1);
getsym();
}
}
// 列出目标代码清单
void PL0::listcode(int cx0)//list code generated for this block
{
int i;
if(listswitch)
for (i= cx0;i<cx;i++)
cout<<" "<<i<<" "<<mnemonic[code[i].f]
<<" "<<code[i].l<<" "<<code[i].a<<endl;
}// listcode end
// 语句部分处理
void PL0::statement(symset fsys,int tx,int lev)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -