C++實踐參考——處理C++原始碼的程式
【專案 - 處理C++原始碼的程式】
在CodeBlocks等IDE中都提供了程式碼格式整理的功能。完成這種功能的程式,操作的資料是用C++寫的原始碼檔案。C++原始檔是一種文字檔案,可以通過程式進行操作。
整合開發環境(IDE)對對程式進行編譯,操作的“資料”是源程式。編譯中,要對源程式進行詞法檢查和語法檢查,後續還要進行目的碼生成、程式碼優化等工作。相關的技術將在《編譯原理》課中學習。這些技術可以用在很多領域,當然也能夠讓我們對於程式語言有更深的瞭解。
本專案將以C++源程式為操作物件,完成對源程式的一系列處理。各功能可以分別編制一個程式實現(建議用這種簡單的方案),也可以將其整合在一起(向著自己做出IDE努力)。
(1)讀入一個C++程式,判斷其中是否只有一個main()函式,輸出“暫時沒有發現問題”,或者“沒有main()函式”,或者“不能定義多個main()函式”;
提示1:簡單處理,可以只比較判斷”main()”,考慮實際上的各種可能,main後面的括號中有任意多個空格及void的都應該算在內。建議按最簡單的情形處理。
提示2:建議設計一個函式,將讀到的程式碼與字串”main()”進行比較。函式用於判斷s1是否“包含”在讀入的一行s2中,呼叫時,形參s1處的實參用”main()”即可,這樣寫提升了“抽象”級別,更容易實現,對應更高的程式碼質量。
【參考解答】
#include <fstream> #include<iostream> #include<string> #include<cstdlib> using namespace std; int appear(char*s1,char*s2); int main( ) { char line[256]; char main_fun[8]="main()"; int main_num=0;//初時,尚未發現 //將檔案中的資料讀入到字元陣列中 ifstream sourceFile("source.cpp",ios::in); //以輸入的方式開啟檔案 if(!sourceFile) //測試是否成功開啟 { cerr<<"source code read error!"<<endl; exit(1); } while(!sourceFile.eof()) { sourceFile.getline(line,255,'\n'); main_num+=appear(line,main_fun); if (main_num>1) //多於1個,沒有必要再去讀取 break; } sourceFile.close(); //識別結論 if(main_num==0) cout<<"error: no main()."; else if (main_num==1) cout<<"right: a main() be exist."; else cout<<"error: more than one main()."; cout<<endl; return 0; } //返回s2在s1中出現了幾次 int appear(char*s1,char*s2) { int n=0,flag; char *p,*q; for(; *s1!='\0'; s1++) { if (*s2==*s1) /*判斷字串中是否有和要判斷的字串首字元相同的字元*/ { flag=1; p=s1 ; /*s1 p 為第一個相同字元的地址*/ q=s2; for(; *q!='\0';) /*如果有則判斷接下去的幾個字元是否相同*/ { if (*q++!=*p++) { flag=0; break; } } if (flag==1) n++; } } return(n); }
(2)讀入一個C++程式,使程式中的所有左花括號“{”和右花括號“}”都單獨佔一行,新程式儲存到另一個.cpp檔案中,並在螢幕上顯示處理過的程式,顯示時加上行號。
[參考解答]
#include <fstream> #include<iostream> //#include<string> #include<cstdlib> using namespace std; void outprogram(char *filename); int main( ) { char ch1,ch2; //將檔案中的資料讀入到字元陣列中 ifstream sourceFile("source.cpp",ios::in); //以輸入的方式開啟檔案 if(!sourceFile) //測試是否成功開啟 { cerr<<"source code read error!"<<endl; exit(1); } ofstream outFile("newsource.cpp",ios::out); //以輸出的方式開啟檔案 if(!outFile) //測試是否成功開啟 { cerr<<"new source code write error!"<<endl; exit(1); } ch1='\0'; while(!sourceFile.eof()) { sourceFile.get(ch2); //讀到了花括號,且前一個符號不是換行,應該加入一個換行 if((ch2=='{'||ch2=='}')&&(ch1!='\n')) outFile.put('\n'); else //當前讀到的不是換行,但前一個是花括號,此時也該加 if((ch1=='{'||ch1=='}')&&(ch2!='\n')) outFile.put('\n'); outFile.put(ch2); //輸出當前讀入的符號 ch1=ch2; } outFile.close(); sourceFile.close(); cout<<"經過處理後的源程式是:"<<endl; outprogram("newsource.cpp"); return 0; } void outprogram(char *filename) { char line[256]; int n = 1; ifstream inFile(filename, ios::in); //以輸入的方式開啟檔案 if(!inFile) //測試是否成功開啟 { cerr<<"file open error!"<<endl; exit(1); } while (!inFile.eof()) { inFile.getline(line,255,'\n'); cout<<n<<'\t'<<line<<endl; n++; } inFile.close(); return; }
(3)讀入一個C++程式,輸入m、n兩個數字,從第m行起的n行程式碼將作為註釋使用(即在這些行前面加上”//”),新程式儲存到另一個.cpp檔案中,並在螢幕上顯示處理過的程式,顯示時加上行號。
[參考解答]
#include <fstream>
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
void outprogram(const char *filename);
int main( )
{
char line[256];
int m,n;
//將檔案中的資料讀入到字元陣列中
ifstream sourceFile("source.cpp",ios::in); //以輸入的方式開啟檔案
if(!sourceFile) //測試是否成功開啟
{
cerr<<"source code read error!"<<endl;
exit(1);
}
ofstream outFile("newsource.cpp",ios::out); //以輸出的方式開啟檔案
if(!outFile) //測試是否成功開啟
{
cerr<<"new source code write error!"<<endl;
exit(1);
}
cout<<"您要將第m行開始的n行程式碼作為註釋,請輸入m和n:";
cin>>m>>n;
int n1=0;
while(!sourceFile.eof())
{
sourceFile.getline(line,255,'\n');
n1++;
if(n1>=m&&n1<m+n)
outFile.put('/').put('/');
outFile.write(line,strlen(line));
outFile.write("\n",1);
}
outFile.close();
sourceFile.close();
cout<<"經過處理後的源程式是:"<<endl;
outprogram("newsource.cpp");
return 0;
}
void outprogram(const char *filename)
{
char line[256];
int n = 1;
ifstream inFile(filename, ios::in); //以輸入的方式開啟檔案
if(!inFile) //測試是否成功開啟
{
cerr<<"file open error!"<<endl;
exit(1);
}
while (!inFile.eof())
{
inFile.getline(line,255,'\n');
cout<<n<<'\t'<<line<<endl;
n++;
}
inFile.close();
return;
}
(以下參考略)文書處理領域能做的工作也就此向大家敞開大門,下面一些功能作為選做內容,請有餘力的同學參考,想。
(4)(選做)讀入一個C++程式,將程式中的所有註釋(包括//形式和/*...*/形式的)刪除,新程式儲存到另一個.cpp檔案中,並在螢幕上顯示處理過的程式,顯示時加上行號。
(5)(選做)讀入一個C++程式,使程式中:(1)所有左花括號“{”和右花括號“}”都單獨佔一行;(2)每個語句單獨佔一行;(3)各行採用統一的縮格排放(每遇一個“{”,其下一行的程式,在第一個有意義的符號前的空格數增加4(也可以是增加一個’\t’),每遇一個“}”,其下一行的程式,在第一個有意義的符號前的空格數減少4(也可以是一個’\t’))。
(6)(選做)基於(5),用wxWidgets設計介面,在對話方塊中選擇要處理的原始檔名,並指定目標檔名後進行處理。如在左圖中點選按鈕“…”後,會利用“開啟檔案對話方塊”(wxFileDialog)視窗選擇檔案。