COMPILERPL0语言的示例语法描述Word格式.docx
- 文档编号:6440390
- 上传时间:2023-05-06
- 格式:DOCX
- 页数:54
- 大小:383.64KB
COMPILERPL0语言的示例语法描述Word格式.docx
《COMPILERPL0语言的示例语法描述Word格式.docx》由会员分享,可在线阅读,更多相关《COMPILERPL0语言的示例语法描述Word格式.docx(54页珍藏版)》请在冰点文库上搜索。
方括号表示其内的成分为任选项。
6)():
表示圆括号内的成分优先。
PL/0语言文法的EBNF表示为:
〈程序〉∷=〈分程序〉.
〈分程序〉∷=[〈常量说明部分〉][〈变量说明部分〉][〈过程说明部分〉]〈语句〉
〈常量说明部分〉∷=CONST〈常量定义〉{,〈常量定义〉};
〈常量定义〉∷=〈标识符〉=〈无符号整数〉
〈无符号整数〉∷=〈数字〉{〈数字〉}
〈变量说明部分〉∷=VAR〈标识符〉{,〈标识符〉};
〈标识符〉∷=〈字母〉{〈字母〉|〈数字〉}
〈过程说明部分〉∷=〈过程首部〉〈分程序〉{;
〈过程说明部分〉};
〈过程首部〉∷=PROCEDURE〈标识符〉;
〈语句〉∷=〈赋值语句〉|〈条件语句〉|〈当型循环语句〉|
〈过程调用语句〉|〈读语句〉|〈写语句〉|〈复合语句〉|〈空〉
〈赋值语句〉∷=〈标识符〉∶=〈表达式〉
〈复合语句〉∷=BEGIN〈语句〉{;
〈语句〉}END
〈条件〉∷=〈表达式〉〈关系运算符〉〈表达式〉|ODD〈表达式〉
〈表达式〉∷=[+|-]〈项〉{〈加法运算符〉〈项〉}
〈项〉∷=〈因子〉{〈乘法运算符〉〈因子〉}
〈因子〉∷=〈标识符〉|〈无符号整数〉|'
('
〈表达式〉'
)'
〈加法运算符〉∷=+|-
〈乘法运算符〉∷=*|/
〈关系运算符〉∷=#|=|<|<=|>|>=
〈条件语句〉∷=IF〈条件〉THEN〈语句〉
〈过程调用语句〉∷=CALL〈标识符〉
〈当型循环语句〉∷=WHILE〈条件〉DO〈语句〉
〈读语句〉∷=READ'
〈标识符〉{,〈标识符〉}'
〈写语句〉∷=WRITE'
〈表达式〉{,〈表达式〉}'
〈字母〉∷=a|b|…|X|Y|Z
〈数字〉∷=0|1|2|…|8|9
(b)PL/0语言的语法描述图
☐用椭圆和圆圈中的英文字表示终结符,用长方形内的中文字表示非终结符。
◆画语法图时要注意箭头方向和弧度,语法图中应该无直角,如图2.1给出的PL/0语法描述图。
沿语法图分析时不能走尖狐线。
图2.1(a)程序语法描述图p9
图2.1(b)分程序语法描述图p10
按照上图,不能将常量定义写在变量定义前面.
图2.1(c)语句语法描述图
可以改动上图,增加else语句
可以改动上图,使do语句可以处理多条语句.
图2.1(d)条件语法描述图
图2.1(e)表达式语法描述图
图2.1(f)项语法描述图
图2.1(g)因子语法描述图
附录:
源代码
pl0c.h
/*关键字个数*/
#definenorw13
/*名字表容量*/
#definetxmax100
/*所有的add1用于定义数组*/
#definetxmaxadd1101
/*number的最大位数*/
#definenmax14
/*符号的最大长度*/
#defineal10
/*地址上界*/
#defineamax2047
/*最大允许过程嵌套声明层数*/
#definelevmax3
/*最多的虚拟机代码数*/
#definecxmax200
#definecxmaxadd1201
/*当函数中会发生fatalerror时,返回-1告知调用它的函数,最终退出程序*/
#definegetsymdoif(-1==getsym())return-1
#definegetchdoif(-1==getch())return-1
#definetestdo(a,b,c)if(-1==test(a,b,c))return-1
#definegendo(a,b,c)if(-1==gen(a,b,c))return-1
#defineexpressiondo(a,b,c)if(-1==expression(a,b,c))return-1
#definefactordo(a,b,c)if(-1==factor(a,b,c))return-1
#definetermdo(a,b,c)if(-1==term(a,b,c))return-1
#defineconditiondo(a,b,c)if(-1==condition(a,b,c))return-1
#definestatementdo(a,b,c)if(-1==statement(a,b,c))return-1
#defineconstdeclarationdo(a,b,c)if(-1==constdeclaration(a,b,c))return-1
#definevardeclarationdo(a,b,c)if(-1==vardeclaration(a,b,c))return-1
typedefenum{false,true}bool;
/*符号*/
enumsymbol{nul,ident,number,plus,minus,times,slash,oddsym,eql,neq,lss,leq,gtr,geq,lparen,rparen,comma,semicolon,period,becomes,beginsym,endsym,ifsym,thensym,whilesym,writesym,readsym,dosym,callsym,constsym,varsym,procsym};
#definesymnum32
/*名字表中的类型*/
enumobject{constant,variable,procedur};
/*虚拟机代码*/
enumfct{lit,opr,lod,sto,cal,inte,jmp,jpc};
#definefctnum8
/*虚拟机代码结构*/
structinstruction
{
enumfctf;
/*虚拟机代码指令*/
intl;
/*引用层与声明层的层次差*/
inta;
/*根据f的不同而不同*/
};
FILE*fas;
/*输出名字表*/
FILE*fa;
/*输出虚拟机代码*/
FILE*fa1;
/*输出源文件及其各行对应的首地址*/
FILE*fa2;
/*输出结果*/
boollistswitch;
/*显示虚拟机代码与否*/
booltableswitch;
/*显示名字表与否*/
charch;
/*获取字符的缓冲区,getch使用*/
enumsymbolsym;
/*当前的符号*/
charid[al];
/*当前ident*/
intnum;
/*当前number*/
intcc,ll,kk;
/*getch使用的计数器,cc表示当前字符(ch)的位置*/
intcx;
/*虚拟机代码指针*/
charline[81];
/*读取行缓冲区*/
chara[al];
/*临时符号*/
structinstructioncode[cxmaxadd1];
/*存放虚拟机代码的数组*/
charword[norw][al];
/*保留字*/
enumsymbolwsym[norw];
/*保留字对应的符号值*/
enumsymbolssym[256];
/*单字符的符号值*/
charmnemonic[fctnum][5];
/*虚拟机代码指令名称*/
booldeclbegsys[symnum];
/*表示声明开始的符号集合*/
boolstatbegsys[symnum];
/*表示语句开始的符号集合*/
boolfacbegsys[symnum];
/*表示因子开始的符号集合*/
/*名字表结构*/
structtablestruct
charname[al];
/*名字*/
enumobjectkind;
/*类型:
const,varorprocedure*/
intval;
/*数值,仅const使用*/
intlevel;
/*所处层,仅const不使用*/
intadr;
/*地址,仅const不使用*/
intsize;
/*需要分配的数据区空间,仅procedure使用*/
structtablestructtable[txmaxadd1];
/*名字表*/
FILE*fin;
FILE*fout;
charfname[al];
interr;
/*错误计数器*/
voiderror(intn);
intgetsym();
intgetch();
voidinit();
intgen(enumfctx,inty,intz);
inttest(bool*s1,bool*s2,intn);
intinset(inte,bool*s);
intaddset(bool*sr,bool*s1,bool*s2,intn);
intsubset(bool*sr,bool*s1,bool*s2,intn);
intmulset(bool*sr,bool*s1,bool*s2,intn);
intblock(intlev,inttx,bool*fsys);
voidinterpret();
intfactor(bool*fsys,int*ptx,intlev);
intterm(bool*fsys,int*ptx,intlev);
intcondition(bool*fsys,int*ptx,intlev);
intexpression(bool*fsys,int*ptx,intlev);
intstatement(bool*fsys,int*ptx,intlev);
voidlistcode(intcx0);
intvardeclaration(int*ptx,intlev,int*pdx);
intconstdeclaration(int*ptx,intlev,int*pdx);
intpostion(char*idt,inttx);
voidenter(enumobjectk,int*ptx,intlev,int*pdx);
intbase(intl,int*s,intb);
pl0c.c
/*
Windows下c语言PL/0编译程序
在VisualC++6.0和VisualC.NET上运行通过
使用方法:
运行后输入PL/0源程序文件名
回答是否输出虚拟机代码
回答是否输出名字表
fa.tmp输出虚拟机代码
fa1.tmp输出源文件及其各行对应的首地址
fa2.tmp输出结果
fas.tmp输出名字表
*/
#include<
stdio.h>
#include"
pl0c.h"
string.h"
/*解释执行时使用的栈*/
#definestacksize500
intmain()
boolnxtlev[symnum];
init();
/*初始化*/
fas=fopen("
fas.tmp"
"
w"
);
fa1=fopen("
fa1.tmp"
printf("
Inputfile?
"
fprintf(fa1,"
scanf("
%s"
fname);
/*输入文件名*/
fin=fopen(fname,"
r"
if(fin)
{
fprintf(fa1,"
%s\n"
printf("
Listobjectcode?
(Y/N)"
/*是否输出虚拟机代码*/
scanf("
listswitch=(fname[0]=='
y'
||fname[0]=='
Y'
Listsymboltable?
/*是否输出名字表*/
tableswitch=(fname[0]=='
err=0;
cc=cx=ll=0;
ch='
'
;
kk=al-1;
if(-1!
=getsym())
{
fa=fopen("
fa.tmp"
fa2=fopen("
fa2.tmp"
addset(nxtlev,declbegsys,statbegsys,symnum);
nxtlev[period]=true;
if(-1==block(0,0,nxtlev))/*调用编译程序*/
{
fclose(fa);
fclose(fa1);
fclose(fin);
printf("
\n"
return0;
}
fclose(fa);
fclose(fa1);
if(sym!
=period)error(9);
if(err==0)interpret();
/*调用解释执行程序*/
else
Errorsinpl/0program"
}
fclose(fin);
}
else
Can'
topenfile!
fclose(fa1);
fclose(fas);
return0;
}
/*在适当的位置显示错误*/
voiderror(intn)
charspace[81];
memset(space,32,81);
space[cc-1]=0;
/*出错时当前符号已经读完,所以cc-1*/
****%s!
%d\n"
space,n);
err++;
/*词法分析,获取一个符号*/
intgetsym()
inti,j,k;
while(ch=='
||ch==10||ch==9)/*忽略空格、换行和TAB*/
getchdo;
if(ch>
='
a'
&
ch<
z'
)
{/*名字或保留字以a..z开头*/
k=0;
do
if(k<
al)
a[k]=ch;
k++;
getchdo;
while(ch>
||ch>
0'
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];
elsesym=ident;
/*搜索失败则,是名字或数字*/
if(ch>
{/*检测是否为数字:
以0..9开头*/
k=0;
num=0;
sym=number;
do
num=10*num+ch-'
getchdo;
while(ch>
/*获取数字的值*/
k--;
if(k>
nmax)error(30);
else
if(ch=='
'
)/*检测赋值符号*/
if(ch=='
{
sym=becomes;
getchdo;
}
else
sym=nul;
/*不能识别的符号*/
<
)/*检测小于或小于等于符号*/
if(ch=='
{
sym=leq;
getchdo;
}
else
sym=lss;
>
)/*检测大于或大于等于符号*/
if(ch=='
{
sym=geq;
getchdo;
}
else
sym=gtr;
sym=ssym[ch];
/*当符号不满足上述条件时,全部按照单字符符号处理*/
/*生成虚拟机代码*/
intgen(enumfctx,/*f*/
inty,/*l*/
intz/*a*/
)
if(cx>
cxmax)
Programtoolong"
/*程序过长*/
return-1;
code[cx].f=x;
code[cx].l=y;
code[cx].a=z;
cx++;
/*在某一部分(如一条语句,一个表达式)将要结束时时我们希望下一个符号属于某集合(该部分的后跟
符号),test负责这项监测,并且负责当监测不通过时的补救措施,程序在需要检测时指定当前需要的符
号集合和补救用的集合(如之前未完成部分的后跟符号),以及检测不通过时的错误号*/
inttest(bool*s1,/*我们需要的符号*/
bool*s2,/*如果不是我们需要的,则需要一个补救用的集合*/
intn)/*错误号*/
if(!
inset(sym,s1))
error(n);
/*当检测不通过时,不停获取符号,直到它属于需要的集合或补救的集合*/
while((!
inset(sym,s1))&
(!
inset(sym,s2)))
getsymdo;
/*编译程序主体*/
intblock(intlev,/*当前分程序所在层*/
inttx,/*名字表当前尾指针*/
bool*fsys/*当前模块后跟符号集合*/
inti;
intdx;
/*名字分配到的相对地址*/
inttx0;
/*保留初始tx*/
intcx0;
/*保留初始cx*/
/*在下级函数的参数中,符号集合均为值参,但由于使用数租实现,
传递进来的是指针,为防止下级函数改变上级函数的集合,开辟新的空间
传递给下级函数,之后所有的nxtlev都是这样*/
dx=3;
tx0=tx;
/*记录本层名字的初始位置*/
table[tx].adr=cx;
gendo(jmp,0,0);
if(lev>
levmax)error(32);
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- COMPILERPL0 语言 示例 语法 描述