编译原理实验题目解析Word文件下载.docx
《编译原理实验题目解析Word文件下载.docx》由会员分享,可在线阅读,更多相关《编译原理实验题目解析Word文件下载.docx(33页珍藏版)》请在冰豆网上搜索。
2、建立一个全局头文件,将本设计所需要用到的系统头文件的打开、一些必要的宏定义和全局变量的声明信息放在该全局头文件中;
3、将本设计所有文件加入一个工程文件。
六、分析与讨论
1、如何修改错误处理模块,使得编译器在发现错误后能跳过出错语句,继续进行语法分析;
2、试使用手工构造和自动生成相结合的方法来完成本课程设计;
3、仔细研读附录C有关“PL/0语言词法分析器的手工构造和自动生成”的设计内容,并通过借鉴PL/0语言词法分析器的设计方法和具体实现技术,对本课程设计的综合设计进行优化。
题目二 说明语句的词法分析器
了解的基本构造原理,掌握词法分析程序的手工构造及自动构造方法。
根据PASCAL语言的说明语句形式,用手工及自动方法构造一个对说明语句进行词法分析的程序。
该程序能对从键盘输入或从文件读入的形如:
“constcount=10,sum=81.5,char1=’f’,string1=”hj”,max=169;
”
的常量说明串进行处理,分析常量说明串中各常量名、常量类型及常量值,并统计各种类型常量个数。
1、输入的常量说明串,要求最后以分号作结束标志;
2、根据输入串或读入的文本文件中第一个单词是否为“const”判断输入串或文本文件是否为常量说明内容;
3、识别输入串或打开的文本文件中的常量名。
常量名必须是标识符,定义为字母开头,后跟若干个字母,数字或下划线;
4、根据各常量名紧跟等号“=”后面的内容判断常量的类型。
其中:
字符型常量定义为放在单引号内的一个字符;
字符串常量定义为放在双引号内所有内容;
整型常量定义为带或不带+、-号,不以0开头的若干数字的组合;
实型常量定义为带或不带+、-号,不以0开头的若干数字加上小数点再后跟若干数字的组合;
5、统计并输出串或文件中包含的各种类型的常量个数;
6、以二元组(类型,值)的形式输出各常量的类型和值;
7、根据常量说明串置于高级语言源程序中时可能出现的错误情况,模仿高级语言编译器对不同错误情况做出相应处理。
1、输入如下正确的常量说明串:
constcount=10,sum=81.5,char1=‘f’,max=169,str1=“h*542..4S!
AAsj”,char2=‘@’,str2=“aa!
+h”;
输出:
count(integer,10)
sum(float,81.5)
char1(char,‘f’)
max(integer,169)
str1(string,“h*542..4S!
AAsj”)
char2(char,‘@’)
str2(string,“aa!
+h”)
int_num=2;
char_num=2;
string_num=2;
float_num=1.
2、输入类似如下的保留字const错误的常量说明串:
Aconsttcount=10,sum=81.5,char1=‘f’;
输出类似下面的错误提示信息:
Itisnotaconstantdeclarationstatement!
Pleaseinputastringagain!
3、输入类似如下含常量名或常量值错误的常量说明串:
constcount=10,12sum=81.5,char1=‘ff’,max=0016;
12sum(Wrong!
Itisnotaidentifier!
)
char1(Wrong!
Therearemorethanonecharin‘’.)
max(Wrong!
Theintegercan’tbestartedwith‘0’.)
int_num=1;
char_num=0;
string_num=0;
float_num=0.
4、其他类型的错误处理情况(略)。
本课程设计重点有三个:
一是作为常量名的标识符的识别;
二是如何根据“=”后出现的内容来判断常量类型;
三是对各种错误的处理。
难点是对整型和实型常量的判断必须综合考虑多种可能情况。
提示:
1、用指针或数组与指针相结合来处理输入的常量说明串;
2、对整型和实型常量处理时,重点考虑常数中‘0’的位置。
1、若考虑用E或e的科学计数法来表示整数和实数,应该如何实现?
2、若考虑布尔型常量,且规定其值只能为true或false,应该如何实现?
3、如何对手工构造的词法分析程序做进一步的优化,以提高代码质量和运行效率?
题目三 基于预测分析方法的表达式语法分析器
了解预测分析器的基本构成及用自顶向下的预测法对表达式进行语法分析的方法,掌握预测语法分析程序的手工构造方法。
已知文法G[S]:
S->
AT
A->
BU
T->
+AT|$
U->
*BU|$
B->
(S)|m
其中,$表示空串。
对该文法构造预测分析表,并手工构造预测分析程序,对输入串m+m*m#进行语法分析,并根据栈的变化状态输出分析过程。
三、设计要求:
1、判断上述文法G[S]是否LL
(1)文法,若不是,将其转变为LL
(1)文法;
2、对转变后的LL
(1)文法建立预测分析表;
3、根据清华大学出版、吕映之等编著的编译原理教材教材第五章Page88的图5.11手工构造预测分析程序;
4、用预测分析程序对键盘输入串m+m*m#进行语法分析,并根据栈的变化状态输出给定串的具体分析过程。
从键盘输入串:
m+m*m#;
用预测分析法分析符号串m+m*m#的过程
Step
Stack
String
Rule
1
#S
m+m*m#
10
#TUm
m*m#
M匹配
2
#TA
11
#TU
*m#
*BU
3
#TUB
m
12
#TUB*
*匹配
4
13
m#
5
+m*m#
$
14
6
#T
+AT
15
#
7
#TA+
+匹配
16
8
17
接受
9
本课程设计重点有两个:
一是如何用适当的数据结构实现预测分析表存储和使用;
二是如何实现各规则右部串的逆序入栈处理。
建议:
使用结构体数组。
1、若输入串不是指定文法的句子,会出现什么情况?
2、总结预测语法分析程序的设计和实现的一般方法。
题目四 基于算符优先分析方法的表达式语法分析器
了解用算符优先法对表达进行语法分析的方法,编程实现算符优先表达式语法分析器。
对简单表达式文法构造算符优先分析器。
1、对下列简单表达式文法G[E’
]构造算符优先关系表。
E’→#E#
E→E+T|T
T→T*F|F
F→P/F|P
P→(E)|i
2、根据算符优先关系表,使用栈结构来实现算符优先分析:
设置两个栈:
存放运算符的OPTR栈和存放操作数或运算结果的OPND栈。
具体算法描述如下:
(1)首先置操作数OPND栈为空栈,将#入运算符OPTR栈。
(2)依次读入表达式中每个单词,若是操作数则进OPND栈,若是运算符则转(3)。
(3)当前设读入的运算符为θ2,查找算符优先关系表,比较θ2与OPTR栈顶元素θ1:
若θ1<
θ2,则θ2进OPTR栈,转
(2);
若θ1=θ2,如θ2为#,则分析成功,否则OPTR栈顶元素θ1出栈,并转
(2);
若θ1>θ2,则出栈OPND栈顶元素存放到b,又出栈其新栈顶元素存放到a,再出栈OPTR栈顶元素至t,进行运算r=atb(t为运算符),并将结果r存入栈OPND后转
(2);
(4)若θ1和θ2之间无优先关系,则报错。
1、从键盘输入表达式,利用算符优先法求出其值,如输入表达式有错,则给出报错提示。
表达式以“#”结尾。
1、从键盘输入表达式串:
10+15*4#
70
2、从键盘输入表达式串:
10+*15+
Theexpressioniserror!
1、构造算符优先关系表如下:
+
-
*
/
(
i
>
<
=
2、参考严蔚敏等编著、清华大学出版社出版的C语言版《数据结构》P52-P54的表达式求值算法。
题目五 递归下降分析法
掌握递归下降分析法的基本原理,掌握预测符集的求法,掌握递归下降分析程序的构造方法。
假设文法中有如下的产生式A1|2|…|n,则应按如下方法编写语法分析子程序
procedureA()
beginiftokenPredict(A1)thenθ
(1)else
iftokenPredict(A2)thenθ
(2)else
……
iftokenPredict(An)thenθ(n)else
error()
end
其中对i=X1X2…Xn,θ(i)=θ’(X1);
θ’(X2);
…;
θ’(Xn);
●如果XiVN,θ’(Xi)=Xi
●如果XiVT,θ’(Xi)=Match(Xi)
●如果Xi=,θ’(λ)=skip(空语句)
理解递归下降语法分析方法的主要原理,理解递归下降分析法对文法的要求,熟练掌握Predict集合的求法,熟练掌握文法变换算法(消除左递归和消除公共前缀)。
四、提示:
1.基本原理
递归下降法是语法分析中最易懂的一种方法。
它的主要原理是,对每个非终极符按其产生式结构构造相应语法分析子程序,其中终极符产生匹配命令,而非终极符则产生过程调用命令。
因为文法递归相应子程序也递归,所以称这种方法为递归子程序下降法或递归下降法。
其中子程序的结构与产生式结构几乎是一致的。
2.文法要求
递归下降法要满足的条件:
假设A的全部产生式为Aα1|α2|……|αn,则必须满足如下条件才能保证可以唯一的选择合适的产生式
predict(Aαi)∩predict(Aαj)=Φ,当i≠j.
五、实验步骤
1.求SNL文法中每个产生式Predict集合
Predict(Aβ)=First(β),
当First(β)
=(First(β)-{})∪Follow(A),当First(β)
根据Predict集合的定义求SNL的文法中每个产生式的Predict集合,判断是否满足递归下降法分析条件,若不满足用消除左递归和消除公共前缀等文法等价变化算法对文法进行变换,使其满足递归下降法的要求。
2.构造递归下降语法分析程序
采用了递归子程序方法进行语法分析,对文法中的每个非终极符号按其产生式结构产生相应的语法分析子程序,完成相应的识别任务。
其中终结符产生匹配命令,非终结符则产生调用命令。
每次进入子程序之前都预先读入一个单词。
因为使用了递归下降方法,所以程序结构和层次清晰明了,易于手工实现,且时空效率较高。
实际的语法分析工作,从调用总程序的分析子程序开始,根据产生式进行递归调用各个分析子程序。
附录A部分课程设计题目参考源程序
A.1基于语法制导翻译的表达式转换编译器参考源程序
/****全局头文件myglobal.h,用于存放需加载的头文件、宏定义、全局变量****/
#include<
stdio.h>
string.h>
ctype.h>
/*加载字符测试函数*/
#defineBUFSIZE128/*定义缓冲区大小*/
#defineNONE-1
#defineEOSTR‘\0’
#defineNUM256
#defineDIV257
#defineMOD258
#defineID259
#defineDONE260
inttokenval;
/*定义单词属性值*/
intlineno;
structtable{/*定义符号表结构*/
char*lexptr;
inttoken;
};
structtablesymtable[];
/*定义符号表*/
/****************词法分析程序lex.c*******************/
#include“global.h”
charlexbuf[BUFSIZE];
intlineno=1;
inttokenval=NONE;
intlex()/*词法分析函数*/
{
intt;
while
(1){
t=getchar();
if(t==’’||t==’\t’)
;
/*滤掉空格*/
elseif(t==’\n’)
lineno++;
elseif(isdigit(t))
ungetc(t,stdin);
scanf(“%d”,&
tokenval);
returnNUM;
}
elseif(isalpha(t))
intp,b=0;
while(isalnum(t))
{
lexbuf[b]=t;
b=b+1;
if(b>
BUFSIZE)
error(“compilererror!
”);
lexbuf[b]=EOSTR;
if(t!
=EOF)
p=lookup(lexbuf);
if(p==0)
p=insert(lexbuf,ID);
tokenval=p;
returnsysmtable[p].token;
elseif(t==EOF)
returnDONE;
else
tokenval=NONE;
returnt;
}
/****************语法分析程序paserx.c*******************/
intlookahead;
voidparse()
{lookahead=lex();
while(lookahead!
=DONE)
express();
match(‘;
’);
voidexpress()
voidterm();
while
(1)
switch(lookahead)
case‘+’:
case‘-’:
t=lookahead;
match(lookahead);
term();
emit(t,NONE);
continue;
default:
return;
voidterm()
intt;
voidfactor();
case‘*’:
case‘/’:
caseDIV:
caseMOD:
factor();
voidfactor()
case‘(’:
match(‘(’);
match(‘)’);
break;
caseNUM:
emit(NUM,tokenval);
match(NUM);
caseID:
emit(ID,tokenval);
match(ID);
error(“syntaxerror”);
voidmatch(intt)
if(lookahead==t)
lookahead=lex();
elseerror(“syntaxerror”);
/****************输出程序emitter.c*********************/
voidemit(intt,inttval)
{
switch(t)
printf(“%c\n”,t);
caseDIV:
printf(“DIV\n”);
caseMOD:
printf(“MOD\n”);
printf(“%d\n”,tval);
caseID:
printf(“%s\n”,symtable[tval].lexptr);
printf(“token%d,tokenval%d\n”,t,tval);
/****************符号表处理程序symbol.c*********************/
#defineSTRMAX999
#defineSYMMAX100
charlexemes[STRMAX];
intlasrchar=-1;
structentrysymtable[SYMMAX];
intlastentry=0;
intlookup(char*s)
intp;
for(p=lastentry;
p>
0;
p--)
if(strcmp(symtable[p].lexptr,s)==0)
returnp;
return0;
intinsert(char*s,inttok)
intlen;
len=strlen(s);
if(lastentry+1>
=SYMMAX)
error(“symboltablefull”);
if(lastchar+len+1>
=STRMAX)
error(“lexemesarrayfull”);
lastentry=lastentry+1;
symtable[lastentry].token=tok;
symtable[lastentry].lexptr=&
lexemes[lastchar+1];
lastchar=lastchar+len+1;
strcpy(symtable[lastentry].lexptr,s);
returnlastentry;
/************在符号表中填入关键字程序init.c********************/
structentrykeywords[]={“div”,DIV,“mod”,MOD,0,0}
voidinit()
structentry*p;
for(p=keywords;
p->
token;
p++)
insert(p->
lexptr,p->
token);
/**********************错误处理程序error.c*************************/
voiderror(char*m)
fprintd(stderr,“line%d:
%s\n”,lineno,m);
exit
(1);
/********************