Содержание

Содержание.. 2

1. Постановка задачи. 3

2. Список ключевых слов и текст программы для анализа. 3

3. Интерфейс программы.. 4

4. Алгоритм и результаты работы программы.. 5

5. Листинг программы.. 9

Список литературы... 13

1. Постановка задачи

Задача состоит в создании программы на С++ в среде Builder Borland 6.0.

Программа обрабатывает текст программы на С++, которая хранится в виде файла кода на диске и выполняет следующие действия:

1) подсчитывание ключевых слов Си и их количества, которые используются в коде;

2) составление перечня имен простых переменных, которые используются в левой части оператора присвоения;

3) составление перечня меток программы в алфавитном порядке.

2. Список ключевых слов и текст программы для анализа

Перед созданием программы была проведена подготовительная работа по созданию списка ключевых слов Си. Это было сделано с помощью справочной системы Borland C++ Builder.

Список ключевых слов хранится в файле keywords.txt.

Список организован как одна строка текста, отдельные ключевые слова разделены знаком табуляции.

Программа может быть расширена для поиска и других ключевых слов – например, не языка Си, а спецификации С++ в С++ Builder. Для этого нужно только обновить файл ключевых слов, т.е. поменять содержание файла keywords.txt с помощью справочной системы С++. Кроме того, этот файл может иметь другое название, лишь бы он был в текстовом формате, т.е. с расширением txt.

Текст программы для анализа содержится в текстовом файле alg1.txt. Файл для анализа может иметь и другое название, необходимо лишь, чтобы он был текстовым.

3. Интерфейс программы

Программа имеет одну главную форму, которая приведена на рисунке 1.

Главное меня предлагает три пункта:

-         открытие файла ключевых слов – для этого необходимо в окне программы выбрать команду ФАЙЛ, затем в браузере выбрать файл keywords.txt; тем самым произойдет подключение списка ключевых слов;

-         открытие файла с текстом кода – для этого необходимо в окне программы выбрать команду ФАЙЛ, затем в браузере выбрать файл alg1.txt; тем самым произойдет подключение файла для анализа;

-         собственно работа программы;

-         выход из программы.

Кнопка запуска анализа кода становится активной только тогда, когда оба файла успешно открыты.

При нажатии на эту кнопку происходит анализ кода в соответствии с поставленными задачами и файлом ключевых слов.

Полученные результаты выводятся в текстовом поле Memo.

Закрыть программу можно с системной кнопки выхода в правом верхнем углу окна и с помощью пункта меню.

При закрытии главной формы программы открытые файлы автоматически закрываются.

4. Алгоритм и результаты работы программы

Программа работает с использованием строковых переменных и контейнеров типа вектор, которые позволяют хранить последовательности.

Программа выполняет работу анализа в следующей последовательности:

1.     составление списка ключевых слов как вектора в оперативной памяти;

2.     в тексте программы ищутся и удаляются комментарии различных видов и ненужные строковые константы, заключенные в кавычки;

3.     подсчет количества различных видов ключевых слов;

4.     подсчет имен переменных;

5.     подсчет меток;

6.     вывод полученных данных.

Так, в контрольном примере содержится следующий код программы:

#include "stlexam.h"

#pragma hdrstop

#include <vector>

#include <list>

#include <algorithm>

#include <ctype.h>

#include <string>

#include <string.h>

#include <iostream>

goto Jane;

#ifndef _RWSTD_NO_NAMESPACE

using namespace std;

#endif

class iotaGen

{

  public:

    iotaGen (int iv) : current(iv) { }

    int operator () () { return current++; }

  private:

    int current;

};

//

// Illustrate the use of the fill and fill_n functions.

//

void fill_example ()

{

    cout << "Illustrate fill function" << endl;

    //

    // Example 1, fill an array with initial values

    //

    char buffer[100], *bufferp = buffer;

    fill (bufferp,(bufferp + 100),'\0');

    fill_n (bufferp, 10, 'x');

    cout << buffer << endl;

    //

    // Example 2, use fill to initialize a list.

    //

    list<string,allocator<string> > aList;

    fill_n (inserter(aList, aList.begin()), 10, "empty");

    copy(aList.begin(), aList.end(), ostream_iterator<string,char,char_traits<char> >(cout, " "));

    cout << endl;

    //

    // Example 3, use fill to overwrite values in a list.

    //

    fill (aList.begin(), aList.end(), "full");

    copy(aList.begin(), aList.end(), ostream_iterator<string,char,char_traits<char> >(cout, " "));

    cout << endl;

    //

    // Example 4, fill in a portion of a list.

    //

    vector<int,allocator<int> > iVec(10);

    generate (iVec.begin(), iVec.end(), iotaGen(1));

    vector<int,allocator<int> >::iterator seven = find(iVec.begin(), iVec.end(), 7);

#ifndef _RWSTD_FILL_NAME_CLASH

    fill(iVec.begin(), seven, 0);

#else

    std_fill(iVec.begin(), seven, 0);

#endif

    copy(iVec.begin(), iVec.end(), ostream_iterator<int,char,char_traits<char> >(cout));

    cout << endl;

}

//

// Illustrate the use of the copy function.

//

void copy_example ()

{

    cout << "Illustrate copy function " << endl;

    //

    // Example 1, a simple copy.

    //

    char * source  = "reprise";

    char * surpass = "surpass";

    char buffer[120], *bufferp = buffer;

    copy(source, source + strlen(source) + 1, bufferp);

    //

    // Example 2, self copies.

    //

    *copy(bufferp + 2, bufferp+ strlen(buffer), bufferp) = '\0';

    int buflen = strlen(buffer) + 1;

    copy_backward(bufferp, bufferp + buflen, bufferp + buflen + 3);

    copy(surpass, surpass + 3, bufferp);

    //

    // Example 3, copy to output.

    //

    copy(bufferp, bufferp + strlen(buffer), ostream_iterator<char,char,char_traits<char> >(cout));

    cout << endl;

    //

    // Example 4, use copy to convert type.

    //

    list<char,allocator<char> > char_list;

    copy(bufferp, bufferp + strlen(buffer),

         inserter(char_list,char_list.end()));

    char * big = "big ";

    copy(big, big + 4, inserter(char_list, char_list.begin()));

    char buffer2[200], *buffer2p = buffer2;

    *copy(char_list.begin(), char_list.end(), buffer2p) = '\0';

    cout << buffer2 << endl;

}

#include <sstream>

string generateLabel ()

{

    //

    // Generate a label string of the form L_ddd.

    //

    static int lastLabel = 0;

    ostringstream ost;

    ost << "L_" << lastLabel++ << '\0';

    return ost.str();

}

//

// Illustrate the use of the generate and genrate_n functions.

//

void generate_example ()

{

    cout << "Illustrate generate algorithm" << endl;

    //

    // Example 1, generate a list of label numbers.

    //

    list<string,allocator<string> > labelList;

    generate_n (inserter(labelList, labelList.begin()), 4, generateLabel); 

    copy(labelList.begin(),labelList.end(),ostream_iterator<string,char,char_traits<char> >(cout," "));

    cout << endl;

    //

    // Example 2, generate an arithmetic progression.

    //

    vector<int,allocator<int> > iVec(10);

    generate (iVec.begin(), iVec.end(), iotaGen(2));

    generate_n (iVec.begin(), 5, iotaGen(7));

    copy (iVec.begin(), iVec.end(), ostream_iterator<int,char,char_traits<char> >(cout, " "));

    cout << endl;

}

//

// Illustrate the use of the algorithm swap_ranges.

//

void swap_example ()

{

    cout << "Illustrate swap_ranges algorithm" << endl;

    //

    // First make two parallel sequences.

    //

    int data[] = {12, 27, 14, 64}, *datap = data;

    vector<int,allocator<int> > aVec(4);

    generate (aVec.begin(), aVec.end(), iotaGen(1));

    //

    // Illustrate swap and swap_itr.

    //

    swap(data[0], data[2]);

    copy (data, data+4, ostream_iterator<int,char,char_traits<char> >(cout, " "));

    cout << endl;

    vector<int,allocator<int> >::iterator last = aVec.end(); last--;

    iter_swap(aVec.begin(), last);

    copy (aVec.begin(), aVec.end(), ostream_iterator<int,char,char_traits<char> >(cout, " "));

    cout << endl;

    //

    // Now swap the entire sequence.

    //

    swap_ranges (aVec.begin(), aVec.end(), datap);

    copy (data, data+4, ostream_iterator<int,char,char_traits<char> >(cout, " ")), cout << endl;

    copy (aVec.begin(), aVec.end(), ostream_iterator<int,char,char_traits<char> >(cout, " "));

    cout << endl;

}

int main ()

{

    cout << "STL generic algorithms -- initialization algorithms" << endl;

    fill_example();

    copy_example();

    generate_example();

    swap_example();

    cout << "End of initialization tests" << endl;

    return 0;

}

В результате работы программы получается следующий результат:

Ниже приведен листинг программы.

5. Листинг программы

#include <vcl.h>

#pragma hdrstop

#include "MainUnit.h"

#include "functions.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TFrmMain *FrmMain;

AnsiString codefilename="";

AnsiString keywordsfilename="";

//---------------------------------------------------------------------------

__fastcall TFrmMain::TFrmMain(TComponent* Owner)

        : TForm(Owner)

{

}

//---------------------------------------------------------------------------

void __fastcall TFrmMain::N2Click(TObject *Sender)

{

if(odKeywords->Execute()) keywordsfilename=odKeywords->FileName;

keyfile.open(keywordsfilename.c_str(),0x0);

if (codefile.is_open()) btnGo->Enabled=true;

}

//---------------------------------------------------------------------------

void __fastcall TFrmMain::N3Click(TObject *Sender)

{

if(odCode->Execute()) codefilename=odCode->FileName;

codefile.open(codefilename.c_str(),0x0);

if (keyfile.is_open()) btnGo->Enabled=true;

}

//---------------------------------------------------------------------------

void __fastcall TFrmMain::FormClose(TObject *Sender, TCloseAction &Action)

{

codefile.close();

keyfile.close();

}

//---------------------------------------------------------------------------

void __fastcall TFrmMain::btnGoClick(TObject *Sender)

{

//Составление массива ключевых слов

CreateKeysMas();

/*for (int i=0;i<keys.size();i++)

        {

        mResults->Lines->Add(keys.at(i));

        }*/

//Создание массива количеств встречаемости ключевых слов в коде

char c;

AnsiString code="";

while (codefile.get(c)) code+=c;

//Исключение комментариев

while(code.Pos("/*"))

        {

        int firstpos=code.Pos("/*");

        int lastpos=code.Pos("*/");

        if (firstpos<=lastpos) code.Delete(firstpos,lastpos);

        }

while(code.Pos("//"))

        {

        int firstpos=code.Pos("//");

        int lastpos=code.SubString(code.Pos("//"),code.Length()).Pos("\n")+code.Pos("//");

        if (firstpos<=lastpos) code.Delete(firstpos,lastpos-firstpos);

        }

while(code.Pos("\""))

        {

        int firstpos=code.Pos("\"");

        int lastpos=code.SubString(code.Pos("\""),code.Length()).Pos("\"")+code.Pos("\"");

        if (firstpos<=lastpos) code.Delete(firstpos,lastpos-firstpos);

        }

//Подсчет ключевых слов

AnsiString code1=code;

for (int i=0;i<keys.size();i++)

        {

        while (code1.Pos(keys.at(i)))

                {

                keyscount.at(i)++;

                code1.Delete(code1.Pos(keys.at(i)),keys.at(i).Length());

                }

        }

vector<AnsiString> perems;

code1=code;

//Подсчет имен переменных

while (code1.Pos("="))

        {

        if (code1[code1.Pos("=")+1]!='=')

        {

        int lastpos=code1.Pos("=")-1;

        int firstpos=0;

        int temppos=lastpos;

        while (code1[temppos]==' ')

                {

                code1.Delete(temppos,1);

                }

        while (firstpos==0)

                {

                temppos--;

                int tmp=0;

                if (code1[temppos]=='\n' || code1[temppos]==';' || code1[temppos]==' ' || code1[temppos]=='{') firstpos=temppos+1;

                }

        perems.push_back(code1.SubString(firstpos,lastpos-firstpos));

        code1.Delete(firstpos,lastpos+1);

        }

        else code1.Delete(0,code1.Pos("=="));

        }

//Подсчет меток

code1=code;

vector<AnsiString> metki;

 while (code1.Pos("goto"))

                {

                int firstpos=code1.Pos("goto");

                AnsiString tmp=code1.SubString(code1.Pos("goto"),code1.Length());

                int lastpos=tmp.Pos(";")+firstpos;

                metki.push_back(code1.SubString(firstpos+5,lastpos-firstpos-6));

                code1.Delete(firstpos,lastpos);

                }

mResults->Lines->Add("Использование ключевых слов:");

for (int i=0;i<keys.size();i++)

        {

        if (keyscount.at(i)!=0)

        {

        AnsiString tmp=keys.at(i)+" - "+AnsiString(keyscount.at(i));

        mResults->Lines->Add(tmp);

        }

        }

mResults->Lines->Add("Использованные имена переменных при присвоении:");

for (int i=0;i<perems.size();i++)

  {

  mResults->Lines->Add(perems.at(i));

  }

mResults->Lines->Add("Использованнные метки:");

  for (int i=0;i<metki.size();i++)

  {

  mResults->Lines->Add(metki.at(i));

  }

}

//---------------------------------------------------------------------------

void __fastcall TFrmMain::N5Click(TObject *Sender)

{

FrmMain->Close();

}

//---------------------------------------------------------------------------

ДОПОЛНИТЕЛЬНЫЕ ФУКЦИИ

#include <fstream>

#include <vector>

using namespace std;

ifstream codefile;

ifstream keyfile;

vector<AnsiString> keys;

vector<int> keyscount;

void CreateKeysMas()

{

char c=' ';

AnsiString oneword="";

while (keyfile.get(c))

{

if (c!='\t') oneword+=c;

else

        {

        keys.push_back(oneword);

        oneword="";

        }

}

keyscount.resize(keys.size());

}

Список литературы

1.     Романов Е.Л. Практикум по программированию на C++, Спб: Питер, 2003 г, 123 с.

2.     Справочная система C++ Builder 6.0

3.     Страуструп Б. Язык программирования С++. Специальное издание, М: Издательство БИНОМ, 1104 стр. 2005 г.

4.     Форум cplusplus.ru.