实验一
1、程序设计思路
在预处理处理程序的基础上,扩充程序,增加行注释。
首先,行注释以“\”开始,以回车“\n”结束。参照星注释的源代码。其次,要区分行注释与星注释,即星注释(指的是/* */ )注释中包含行注释,行注释无效;行注释后有星注释,星注释无效。所以设计一个标记变量p,标记行注释。
2、 实现过程
输入的当前字符cur_c 等于''\"且old_c等于"\",如果满足这样的条件,就将 in_comment改为ture,进入行注释。并且标记p=1。继续运行,当输入字符cur_c="\n"且p=1,表示行注释离开,将in_comment改为false。
3、源程序关键代码
加粗的为自己修改的代码。
#include <fstream.h>
#include <iostream.h>
void pro_process(char *);
void main( ) //测试驱动程序
{//定义扫描缓冲区
char buf[4048]={'\0'}; //缓冲区清0
//调用预处理程序
pro_process(buf);
//在屏幕上显示扫描缓冲区的内容
cout<<buf<<endl;}
void pro_process(char *buf) //预处理程序
{ ifstream cinf("source.txt",ios::in);
int i=0,p=0; //计数器
char old_c='\0',cur_c; //前一个字符,当前字符。
bool in_comment=false; //false表示当前字符未处于注释中。
while(cinf.read(&cur_c,sizeof(char))){ //从文件读一个字符
switch(in_comment){
case false:
if(old_c=='/' && cur_c=='*'){ //进入多行注释
i--; //去除已存入扫描缓冲区的字符'/'
in_comment=true;
}
else{
if(old_c=='/' && cur_c=='/'){ //进入行注释
i--;p=1; //去除已存入扫描缓冲区的字符'/'
in_comment=true;
}
else {
if(old_c=='\\' && cur_c=='\n') //发现续行
i--; //去除已存入扫描缓冲区的字符'\'
else {
if(cur_c>='A' && cur_c<='Z')//大写变小写
cur_c+=32;
if(cur_c =='\t' || cur_c =='\n') //空格取代TAB换行
cur_c=' ';
buf[i++]=cur_c ;}}}
break;
case true:
if((old_c=='*' && cur_c=='/')) //离开注释
in_comment=false;
if(cur_c=='\n'&&p==1) in_comment=false;
}//end of switch
old_c= cur_c; //保留前一个字符
}//end of while
buf[i++]='#'; //在源程序尾部添加字符'#'
}
4、结果的输入与输出
Source.txt
Begin/*S=2*3.14*R*R+2*3.14*
R*H*/
Real R,h,s;
s=2*3\
14*r*(r+++h) kmoiulEnd
运行结果如下:
实验二
1、程序设计思路:
编写一个自动机(DFA)识别程序,判断一个字符序列是否为一个DFA所识别。
首先在试验一的基础上,对输入的字符序列进行预处理,然后在输入字符,看其是否能被指定的DFA识别。构造DNA状态转换矩阵,由输入的字符,确定其是否有后继状态,即是否能被识别。
2、实现过程
DFA的主要函数是: scanner(char *);
核心代码如下:
while(buf[i]==' ')i++;
{int cur_state=0;
while(DFA[cur_state][col(buf[i])]){//存在后继状态
cur_state=DFA[cur_state][col(buf[i])];//进入下一状态
if(buf[++i]=='\0')break;//指向下一字符,判缓冲区内字符是否处理完。}
3、源程序关键代码
#include <iostream.h>
#include <fstream.h>
#include <string.h>
#include <stdlib.h>
#include <conio.h>
const short WORDLEN=20;
struct code_val{
char code;char val[WORDLEN];
};
//单词编码表
const char code[]="{}ac=+$*,;()#";
//DFA列字符
const char COL_CHAR[]="a0=+*,;()# ";
//状态转换矩阵(DFA)
const int DFA[][11]={//strlen("a0=+*,;()# ")=11
{1,2,3,4,5,6,7,8,9,10,0},{11,11},0,12},{0},{0,0,0,13},{0},{0},{0},{0},{0},{0},{11,11}, {0,12},{0}
};
//预处理函数原型
void pro_process(char *);
//扫描函数原型
code_val scanner(char *);
//主函数
void main()
{ char buf[4048]={'\0'};//扫描缓冲区
//预处理
pro_process(buf);//显示buf
cout<<buf<<endl;
//单词识别
code_val t;//临时变量
do{
t=scanner(buf);//调用一次扫描器获得一个单词二元式
cout<<t.code<<'\t'<<t.val<<endl;//在屏幕显示单词二元式
}while(t.code!='#');
cout<<"End of lexical analysis!"<<endl;
getch();
}
int col(char);//转换函数
char search_table(char[]);//查单词二元式编码表函数
struct code_val scanner(char *buf)//扫描函数,每调用一次,返回一个单词的二元式。
{
static int i=0;//buf指针
struct code_val t={'\0',"NUL"};//临时变量
char token[WORDLEN]="";//用于拼接单词
//去除前导空格
while(buf[i]==' ')i++;
//开始识别单词
int cur_state=0;
while(DFA[cur_state][col(buf[i])]){//存在后继状态
cur_state=DFA[cur_state][col(buf[i])];//进入下一状态
if(buf[++i]=='\0')break;//指向下一字符,判缓冲区内字符是否处理完。
}
return t;//返回当前单词的二元式
}
//转换函数
int col(char c)
{
if(c>='a'&&c<='z')c='a';
if(c>='0'&&c<='9')c='0';
// const char COL_CHAR[]="a0=+*,;()# ";
for(int i=0;i<=(int)strlen(COL_CHAR);i++)
if(c==COL_CHAR[i])return i;
cout<<"Error char>"<<c<<endl;exit(0); //程序终止运行
}//预处理函数
void pro_process(char *buf)
{
ifstream cinf("source.txt",ios::in);
int i=0;char old_c='\0',cur_c;//计数器,前一个字符,当前字符。
bool in_comment=false;//状态标志,false表示当前字符未处于注释中。
while(cinf.read(&cur_c,sizeof(char))){//从文件读一个字符
switch(in_comment){
case false:
if(old_c=='/' && cur_c=='*'){//进入注释
i--;//去除已存入扫描缓冲区的字符'/'
in_comment=true;
}
else {
if(old_c=='\\' && cur_c=='\n') //去除续行符'\',包括后续换行符。
i--;//去除已存入扫描缓冲区的字符'\'
else {
if(cur_c>='A' && cur_c<='Z') cur_c+=32;
if(cur_c=='\t' || cur_c=='\n') cur_c=' ';//空格
buf[i++]=cur_c ;}}
break;
case true:
if(old_c=='*' && cur_c=='/')//离开注释
in_comment=false;
}//end of switch
old_c= cur_c;//保留前一个字符
}//end of while
buf[i]='#';}
4、结果的输入与输出
输入内容在source.txt中,如下:
egin/*S=2*3.14*R*R+2*3.14*R*H*/
Real R,h,s;
s=2*3\
14*r*(r+++h) kmoiul
End
运行结果如下:
{ NUL
c NUL
i r
, NUL
i h
, NUL
i s
; NUL
i s
= NUL
x 2
* NUL
x 314
* NUL
i r
* NUL
( NUL
i r
$ NUL
+ NUL
i h
) NUL
i kmoiul
} NUL
# NUL
实验三
1、程序设计思路
在自上而下预测分析控制程序的基础上,根据文法规则进行语法分析,如字串是句子,写出文法的最左推导。根据表达式文法的预测分析表,对输入的符号串进行分析。输入的符号串需是单词二元式。若产生式匹配,则输出产生式。
2、实现过程
X 存放当前栈顶符号的工作单元,当X是终结符时,读入下一个符号;当X是非终结符时,判断其是否为#,若不是,则判断其M[X,a]是否是产生式(匹配),匹配则逆序出栈,然后按最左推导输出。具体代码如下:
for(i=strlen(p[M[lin(X)][col(t.code)]])-1;i>=0;i)
{stack[++top]=*(p[M[lin(X)][col(t.code)]]+i);
cout<<X<<"->"<<p[M[lin(X)][col(t.code)]]<<endl;}
3、源程序关键代码
#include <fstream.h>
#include <iostream.h>
#include <stdlib.h>
#include <string.h>
struct code_val{
char code;char val[20];
};
const char *p[ ]={ //指向产生式右部符号串
"TD","+TD","","FS","*FS","","(E)","i","x","y"
};
//0. E→TD D代表E'
//1. D→+TD
//2. D→ε
//3. T→FS S代表T'
//4. S→*FS
//5. S→ε
//6. F→(E)
//7. F→i
//8. F→x
//9. F→y
const char T[ ]="+*()ixy#"; //分析表的列符
const char NT[ ]="EDTSF"; //分析表的行符,行符为EE'TT'F。
const int M[ ][8]={
/*在预测分析表M中存放指针数组p的下标x,设M[i][j]=x,通过p[M[i][j]]=p[x]获取右部符号串。*/
{-1,-1,0,-1,0,0,0,-1},//p[0]指向第0个产生式右部符号串"TD",-1表示出错。
{1,-1,-1,2,-1,-1,-1,2},
{-1,-1,3,-1,3,3,3,-1},
{5,4,-1,5,-1,-1,-1,5},
{-1,-1,6,-1,7,8,9,-1}
};
//函数原型
int lin(char ); //非终结符转换为行号
int col(char ); //终结转换为列号
bool isNT(char); //isNT判断是否是非终结符
bool isT(char); //isT判断是否是终结符。
void main(void)
{
int i,j=0;
ifstream cinf("lex_r.txt",ios::in); //从文件lex_r.txt输入数据
ofstream cout("par_r.txt",ios::out); //结果输出至文件par_r.txt(cout重定义)
struct code_val t; //定义结构变量,存放单词二元式。
cinf>>t.code>>t.val; //读一个单词的二元式
char stack[20]={'#','E'};int top=1; //栈赋初值
char X=' '; //用于显示,并非必要。
cout<<"step"<<'\t'<<"stack"<<'\t'<<"X"<<'\t'<<"t.code"<<endl; //用于显示,并非必要。
cout<<j<<')'; //用于显示,并非必要。
while(1){
cout<<'\t'; //用于显示,并非必要。
for(i=0;i<=top;i++) cout<<stack[i]; //用于显示,并非必要。
cout<<'\t'<<' '<<'\t'<<t.code<<endl;//用于显示,并非必要。
X=stack[top--]; //出栈
cout<<++j<<')'<<'\t'; //用于显示,并非必要。
for(i=0;i<=top;i++) cout<<stack[i]; //用于显示,并非必要。
cout<<'\t'<<X<<'\t'<<t.code<<endl; //用于显示,并非必要。
if(X=='#'){
if(X==t.code){cout<<"\tAcc"<<endl;break; //跳出循环}
else{cout<<"Err in #>"<<X<<'\t'<<t.code<<endl;exit(0);}
}//end of if(X=='#')
if(isT(X)){ //是否是终结符
if (X== t.code)
cinf>>t.code>>t.val; //读下一单词二元式
else{cout<<"Err in T>"<<X<<'\t'<<t.code<<endl;exit(0);}
continue;}//end of if(isT(X))
if(isNT(X)){ //是否是非终结符
if(M[lin(X)][col(t.code)]==-1){
cout<<"Err in NT>"<<X<<'\t'<<t.code<<endl;exit(0);
}
else{for(i=strlen(p[M[lin(X)][col(t.code)]])-1;i>=0;i--)
stack[++top]=*(p[M[lin(X)][col(t.code)]]+i);
cout<<X<<"->"<<p[M[lin(X)][col(t.code)]]<<endl;}
continue;}//end of if(isNT(X))
cout<<"Err in main( )>"<<X<<endl;exit(0);}//end of while
}//end of main
int lin(char c) //将EDTSF分别转换为01234
{ for(int i=0;i<(int)strlen(NT);i++)
if(c==NT[i])return i;
cout<<"Err in lin( ) >"<<c<<endl;exit(0);}
int col(char c) //将+* ()ixy#分别转换为01234567
{or(int i=0;i<(int)strlen(T);i++)if(c==T[i])return i;
cout<<"Err in col( )>"<<c<<endl;exit(0);}
bool isNT(char c) //是否是非终结符
{for(int i=0;i<(int)strlen(NT);i++) if(c==NT[i])return true;return false;}
bool isT(char c) //是否是终结符(不包括'#')
{for(int i=0;i<(int)strlen(T)-1;i++)if(c==T[i])return true;return false;}
4、结果的输入与输出
文件lex_r.txt输入数据,如下:
i a + nul i b # nul
结果输出至文件par_r.txt,如下:
step stack X t.code
0) #E i
1) # E i
E->TD
#DT i
2) #D T i
T->FS
#DSF i
3) #DS F i
F->i
#DSi i
4) #DS i i
#DS +
5) #D S +
S->
#D +
6) # D +
D->+TD
#DT+ +
7) #DT + +
#DT i
8) #D T i
T->FS
#DSF i
9) #DS F i
F->i
#DSi i
10) #DS i i
#DS #
11) #D S #
S->
#D #
12) # D #
D->
# #
13) # #
Acc
实验四
1、程序设计思路
在LR语法分析器的控制程序的基础上,添加语义栈,在对字符串进行分析的同时,也翻译字符串。
2、实现过程
当action <0时,进行归约,action为-n,则,即归约编号为n的产生式。
若action=-1,则归约产生式E→E+T。语义栈的栈顶 yu[top]应变为当前位置与其后第二个位置的和,如下:
case -1: yu[top]=yu[top]+yu[top+2];
同理,其余产生式的语义翻译也如下:
case -2:yu[top]=yu[top];
case -3:yu[top]=yu[top]*yu[top+2];
case -4:yu[top]=yu[top];
case -5:yu[top]=yu[top+1];
case -6:yu[top]=yu[top];
最后,当程序接受acc之后,输出翻译结果,即输入栈顶元素。
3、源程序关键代码
#include <fstream.h>
#include <iostream.h>
#include <stdlib.h>
#include <string.h>
struct code_val{char code;char val[20];};
const char *p[]={ "S→E","E→E+T","E→T","T→T*F","T→F","F→(E)","F→i" };
const char TNT[ ]="+*()i#ETF"; //LR分析表列的字符
const int M[][9]={ //LR分析表数字化,列字符+*()i#ETF用数字012345678标识。
{ 0, 0, 4, 0, 5,0, 1, 2, 3}, //0表示出错,s4用4表示。
{ 6, 0, 0, 0, 0,99}, //Acc用99表示
{-2, 7, 0,-2, 0,-2}, //r2用-2表示
{-4,-4, 0,-4, 0,-4},
{ 0, 0, 4, 0, 5, 0, 8, 2, 3},
{-6,-6, 0,-6, 0,-6},
{ 0, 0, 4, 0, 5, 0, 0, 9, 3},
{ 0, 0, 4, 0, 5, 0, 0, 0,10},
{ 6, 0, 0,11},
{-1, 7, 0,-1, 0,-1},
{-3,-3, 0,-3, 0,-3},
{-5,-5, 0,-5, 0,-5}
};
int col(char); //列定位函数原型
void main()
{int state[50]={0}; //状态栈初值
int yu[50]={0};
char symbol[50]={'#'}; //符号栈初值
int top=0; //栈顶指针初值
ofstream cout("par_r.txt"); //语法分析结果输出至文件par_r.txt
ifstream cin("lex_r.txt"); // lex_r.txt存放词法分析结果,语法分析器从该文件输入数据。
struct code_val t; //结构变量,存放单词二元式。
cin>>t.code>>t.val; //读一单词
int action;
int i,j=0; //输出时使用的计数器,并非必要。
cout<<"step"<<'\t'<<"状态栈"<<'\t'<<"符号栈"<<'\t'<<"输入符号"<<endl;// do{
cout<<j++<<')'<<'\t'; //输出step,并非必要。
for(i=0;i<=top;i++)cout<<state[i];cout<<'\t';//输出状态栈内容,并非必要。
for(i=0;i<=top;i++)cout<<symbol[i]; //输出符号栈内容,并非必要。
cout<<'\t'<<t.code<<endl; action=M[state[top]][col(t.code)];
if(action>0 && action!=99){ //移进
state[++top]=action;
symbol[top]=t.code;
yu[top]=atoi(t.val);
cin>>t.code>>t.val; //读一单词
}
else if(action < 0){ //归约
if(strcmp(p[-action]+3,"ε")) //ε产生式的右部符号串长度为0,无需退栈。
top=top-(strlen(p[-action])-3); //"→"为汉字,占二字节,故减3。
state[top+1]=M[state[top]][col(p[-action][0])]; //产生式左部符号
symbol[++top]=p[-action][0];
switch(action)
{
case -1: yu[top]=yu[top]+yu[top+2];break;
case -2:yu[top]=yu[top];break;
case -3:yu[top]=yu[top]*yu[top+2];break;
case -4:yu[top]=yu[top];break;
case -5:yu[top]=yu[top+1];break;
case -6:yu[top]=yu[top];break;
}
}
else if(action==99){ //接受
cout<<'\t'<<"Acc"<<endl;
cout<<'\t'<<yu[top]<<endl;
break;}
else{ //出错
cout<<"Err in main()>"<<action<<endl;break;}}
while(1);}
int col(char c) //将字符+* ()i#ETF分别转换为数字012345678
{ for(int i=0;i<(int)strlen(TNT);i++)
if(c==TNT[i])return i;
cout<<"Err in col char>"<<c<<endl;
exit(0); }
4、结果的输入与输出
语法分析器从该文件lex_r.txt输入数据,如下:
i 3
* nul
i 3
+ nul
i 5
# nul
语法分析结果输出至文件par_r.txt,如下:
step 状态栈 符号栈 输入符号
0) 0 # i
1) 05 #i *
2) 03 #F *
3) 02 #T *
4) 027 #T* (
5) 0274 #T*( i
6) 02745 #T*(i +
7) 02743 #T*(F +
8) 02742 #T*(T +
9) 02748 #T*(E +
10) 027486 #T*(E+ i
11) 0274865 #T*(E+i )
12) 0274863 #T*(E+F )
13) 0274869 #T*(E+T )
14) 02748 #T*(E )
15) 0274811 #T*(E) #
16) 02710 #T*F #
17) 02 #T #
18) 01 #E #
Acc
24
实验名称:粉体真密度的测定粉体真密度是粉体质量与其真体积之比值,其真体积不包括存在于粉体颗粒内部的封闭空洞。所以,测定粉体的真密度…
研究生实验报告范本实验课程实验名称实验地点学生姓名学号指导教师范本实验时间年月日一实验目的熟悉电阻型气体传感器结构及工作原理进行基…
实验报告课程名称物证技术学实验项目名称捺印手印样本指纹显现提取班级与班级代码074213070853实验室名称或课室法学实验教学中…
滁州市政府组织退耕还林(黑体,小二,1.5倍行距,段前段后0.5行)——5060451007范雪花(学号,TimesNewRoma…
科学实验报告单1科学实验报告单2科学实验报告单3科学实验报告单4九完小科学实验报告单10九完小科学实验报告单11九完小科学实验报告…
统计学实验报告一姓名专业学号日期地点实验项目一描述性统计区间估计在EXCEL里的实现一实验目的1掌握利用EXCEL菜单进行数据的预…
重庆交通大学学生实验报告实验课程名称预测与决策开课实验室管理学院实验室学院年级数学专业班学生姓名龙凯学号开课时间20xx至20xx…
实验一系列缺口试样静拉伸实验及断口形貌观察1实验目的11了解材料在硬性应力状态和应力集中情况下的脆性趋向12了解试样缺口几何形状对…
神华亿利能源有限责任公司电厂试验报告编号GYSY20xx0072设备类型预防性试验试验设备试验日期主管审核单位签章神华亿利能源有限…
蛋白质与酶工程包埋法制备固定化微生物预实验报告实验目的1考察PYD是否与麦芽汁培养基一样可发酵酵母2考察干酵母活化与酵母培养过夜活…