1. 程式人生 > >C++實踐參考——處理C++原始碼的程式

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)視窗選擇檔案。