实验目的
编译原理在JAVA可测试性中的应用。通过对源程序进行分析,在特定位置增加特定的打印语句,方便对程序执行过程的跟踪定位。比如:函数出入口增加打印语句。
实验要求
1、 读取一个JAVA文件,进行语法解析,在函数出入口增加打印语句,并将改写后的程序更新到JAVA文件中去。
输入: 从控制台读入一个JAVA程序文件
输出:更新后的JAVA程序文件, 增加了打印语句
2. 输入输出文件示例:(仅为示意)
输入文件:
public class helloworld {
public static int Add(int a, int b){
int ret;
ret =a+b;
return ret;
}
public static void main(String[] args) {
System.out.println("result="+Add(1,2));
}
}
输出文件:
public class helloworld {
public static int Add(int a, int b){
System.out.println("EnterFunction helloworld::Add(a="+a+",b="+b+")!");
int ret;
ret =a+b;
System.out.println("Exit Function helloworld::Add(a="+a+",b="+b+")!");
return ret;
}
public static void main(String[] args) {
System.out.println("Enter Functionhelloworld::main(args="+args.toString()+")!");
System.out.println("result="+Add(1,2));
System.out.println("Exit Functionhelloworld::main(args="+args.toString()+")!");
}
}
程序分析设计说明
1)函数入口打印语句可以在变量定义之前
2)对于非void型函数、有返回值的需要在return之前输出函数打印语句。
3)输入输出参数暂只考虑简单类型和String类型,不考虑自定义对象等其它类型。
4)如果有输入参数,捕获输入参数值,并打印出来。
5) 如果Object参数,打印时采用toString()转换。
6) 更新后的文件能正常编译运行成功,且新增加的打印语句不影响原有程序逻辑。
代码:
#include <bits/stdc++.h>
using namespace std;
enum symbol
{
classsym=0,
publicsym=1,
protectedsym=2,
privatesym=3,
staticsym=4,
returnsym=5,
voidsym=6,
intsym=7,
charsym=8,
booleansym=9,
Stringsym=10,
Integersym=11,
lbrace=12,//{
rbrace=13,//}
lparen=14,//(
rparen=15,//)
semicolon=16,
lzhushi=17,/* /* */
rzhushi=18,//*/
zhushi=19,//
comma=20,//,
lsquare=21,//[
rsquare=22,//]
Plus=23,//+
Minus=24,//-
times=25,//*
slash=26,//
eql=27,//=
neq=28,/* != */
lss=29,// <
leq=30,//<=
gtr=31,//>
geq=32,//>=
quote=33,/*\*/
period=34,
number=35,
ident=36,
nil=37,
note=38,
};
struct aFunction{
string returnType;
string funcname;
vector<string> paraList;
string printfFuncInfo;
};
string programsrc;
string filename;
string strfilename;
string programdest;
string strclassname;
aFunction aFunc;
/*
变量说明:
line 从终端读入的字符串; 当前所指位置在计数器 p
token 为存放的单词自身字符串;当前所指位置在计数器 m
number 整型常数
sym 每个单词符号种类
*/
char buffer[500];
char line[500],token[12],ch;
enum symbol sym;
int p,m, num;
char *word[12]= {"Integer","String", "boolean","char","class","int","private","protected","public","return","static","void"};
int Err;
void getsym();
void block();
void save();
int error(int x);
void FuncName();
void ParaName();
void FuncBody();
int main()
{
ifstream in("in.txt");
p=0;
if (! in.is_open())
{ cout << "Error opening file"; exit (1); }
while (!in.eof() )
{
in.getline (buffer,100);
/*cout<<"i:::";
cout<<buffer<<endl;*/
for(int i=0;i<100;i++){
if(buffer[i]!='\0')line[p++]=buffer[i];
else break;
}
line[p++]='\n';
}
cout<<line<<endl;
line[p++]='\0';
//逐个单词扫描;
Err = 0;
p=0;
block();
if ((Err==0)){
printf("syntax parses success!\n");
save();
cout<<programdest;
}
else
printf("syntax parses failed!\n");
return 0;
}
void save()
{
time_t t = time(0);
char tmp[64];
strftime( tmp, sizeof(tmp), "%S",localtime(&t) );
strfilename=tmp;
strfilename+=".txt";
char buf[30];
strcpy(buf, strfilename.c_str());
strncpy(buf,strfilename.c_str(),strfilename.length());
freopen(buf,"w",stdout);
}
void getsym()
{
for(m=0; m<12;m++) token[m++]=NULL;
ch=line[p++];
m=0;
/*TODO 单词识别*/
while((ch==' '||ch=='\n'||ch==' ')) {
if(ch==' ') programdest+=" ";
else if(ch=='\n') programdest+="\n";
else if(ch==' ') programdest+=" ";
ch=line[p++];
}
//字母打头的字符串;标识符
if((ch<='z'&&ch>='a')||(ch<='Z'&&ch>='A'))
{
do
{
token[m++]=ch;
ch=line[p++];
}while((ch<='z'&&ch>='a')||(ch<='Z'&&ch>='A')||(ch<='9'&&ch>='0'));
sym=ident;
token[m++]='\0';
ch=line[p--];
for(int n=0;n<12;n++)
{
if(strcmp(token,word[n])==0)
{
if(n==0) sym=Integersym;
else if(n==1) sym=Stringsym;
else if(n==2) sym=booleansym;
else if(n==3) sym=charsym;
else if(n==4) sym=classsym;
else if(n==5) sym=intsym;
else if(n==6) sym=privatesym;
else if(n==7) sym=protectedsym;
else if(n==8) sym=publicsym;
else if(n==9) sym=returnsym;
else if(n==10) sym=staticsym;
else if(n==11) sym=voidsym;
break;
}
}
/*TODO识别标识符IDENT和保留字*/
}
else if((ch<='9'&&ch>='0'))
{
num=0;
do{
num=num*10+ch-'0';
ch=line[p++];
}while((ch<='9'&&ch>='0'));
ch=line[p--];
sym=number;
/*TODO识别数字NUMBER*/
}
else {
switch(ch)
{
case '=': //赋值符号
sym=eql;
token[m++]=ch;
break;
case '<': //<=和<符号
token[m++]=ch;
ch=line[p++];
if(ch=='=')
{
token[m++]=ch;
sym=leq;
}
else{
sym=lss;
p--;
}
break;
case '>': //>=和>符号
token[m++]=ch;
ch=line[p++];
if(ch=='=')
{
sym=geq;
token[m++]=ch;
}
else{
sym=gtr;
p--;
}
break;
case '+':
sym=Plus;
token[m++]=ch;
break;
case '-':
sym=Minus;
token[m++]=ch;
break;
case '*':
sym=times;
token[m++]=ch;
break;
case '/':
ch=line[p++];
if(ch=='*'){
//cout<<"in\n";
char fr;//前面的一个符号
fr='*';
ch=line[p++];
while(1){
fr=ch;
ch=line[p++];
if(fr=='*'&&ch=='/') break;
}
sym=note;
token[m++]=ch;
}
else
{
sym=slash;
token[m++]=ch;
p--;
}
break;
case '(':
sym=lparen;
token[m++]=ch;
break;
case ')':
sym=rparen;
token[m++]=ch;
break;
case ';':
sym=semicolon;
token[m++]=ch;
break;
case ',':
sym=comma;
token[m++]=ch;
break;
case '{':
sym=lbrace;
token[m++]=ch;
break;
case '}':
sym=rbrace;
token[m++]=ch;
break;
case '[':
sym=lsquare;
token[m++]=ch;
break;
case ']':
sym=rsquare;
token[m++]=ch;
break;
case '.':
sym=period;
token[m++]=ch;
break;
case ' ':
token[m++]=ch;
break;
case '"':
sym=quote;
token[m++]=ch;
break;
default:
sym=nil;
break;
}
}
token[m++]='\0';
if(sym!=nil){
programdest+=&token[0],&token[strlen(token)];
}
//如果想看分析的每一个sym,请打开这个注释
//printSym(sym);
//处理语句分析中的注释
if(sym==note) getsym();
}
/*TODO 程序块处理*/
void block()
{
getsym();
while(sym!=publicsym&&sym!=protectedsym&&sym!=privatesym&&sym!=classsym) getsym();
if(sym==publicsym || sym==protectedsym || sym==privatesym) getsym();
if(sym==classsym){
getsym();
strclassname=&token[0],&token[strlen(token)];
//cout<<"class:::::: "<<strclassname <<endl;
//class主体
getsym();
if(sym!=lbrace){
error(1);
}
getsym();
while(sym!=rbrace){
FuncName();
}
//class结束
}
}
/*TODO函数名处理*/
void FuncName()
{
while(sym!=publicsym&&sym!=protectedsym&&sym!=privatesym&&sym!=staticsym&&sym!=voidsym&&sym!=Stringsym&&sym!=intsym&&sym!=booleansym&&sym!=charsym) getsym();
if(sym == publicsym || sym == protectedsym || sym == privatesym) getsym();
if(sym == staticsym) getsym();
//函数返回类型
if(sym == voidsym || sym == Stringsym || sym == intsym || sym == booleansym || sym == charsym){
aFunc.returnType=&token[0],&token[strlen(token)];
//函数名
getsym();
aFunc.funcname=&token[0],&token[strlen(token)];
//函数参数
getsym();
if(sym != lparen){
error(3);
}
getsym();
ParaName();
aFunc.printfFuncInfo = "Function "+strclassname + "::" + aFunc.funcname+"(";
int i;
for(i=0;i<aFunc.paraList.size()-1;i++){
aFunc.printfFuncInfo += aFunc.paraList[i]+"=\"+"+aFunc.paraList[i]+"+\",";
}
if(aFunc.paraList.size()>0){
aFunc.printfFuncInfo += aFunc.paraList[i]+"=\"+";
}
aFunc.printfFuncInfo+=")!\");";
programdest+="\n System.out.println(\"Enter ";
programdest+=aFunc.printfFuncInfo;
//函数体
if(sym!=lbrace){
error(5);
}
FuncBody();
if(sym!=rbrace){
error(6);
}
getsym();
}
}
/*TODO函数参数处理*/
void ParaName(){
aFunc.paraList.clear();
while(sym != rparen){
getsym();
if(sym == lsquare){
getsym();
while(sym != rsquare) getsym();
getsym();
}
//&token[0],&token[strlen(token)]
aFunc.paraList.push_back(token);
getsym();
if(sym==comma){
getsym();
}
}
getsym();
}
/*TODO函数体处理*/
void FuncBody(){
if(aFunc.returnType.compare("void")!=0){
while(sym != returnsym) getsym();
programdest = programdest.substr(0,programdest.length()-6);
programdest += "\n";
programdest += " System.out.println(\"Exit "+aFunc.printfFuncInfo;
programdest += "\n return ";
}
while(sym != rbrace) getsym();
if(aFunc.returnType.compare("void")==0){
programdest = programdest.substr(0,programdest.length()-1);
programdest += "\n";
programdest += " System.out.println(\"Exit "+aFunc.printfFuncInfo+"\r\n";
}
}
/*TODO出错处理*/
int error(int x){
switch(x){
case 1:
cout<<"Error "<<x<<" : class 定义缺少左括号{";
break;
case 2:
cout<<"Error "<<x<<" : class 定义缺少右括号}";
break;
case 3:
cout<<"Error "<<x<<" : function 定义缺少左括号(";
break;
case 4:
cout<<"Error "<<x<<" : function 定义缺少右括号)";
break;
case 5:
cout<<"Error "<<x<<" : function 定义缺少左括号[";
break;
case 6:
cout<<"Error "<<x<<" : function 定义缺少右括号]";
break;
default:
break;
}
cout<<" [pos= "<<p<<";Token = "<<token<<";\n";
//printSym(sym);
Err++;
return Err;
}