File (522774)
Текст из файла
ОписаниеПредисловиеСпособом решения данной задачи выберем «обощенные конечные автоматы». Чтобы упростить таблицу переходов, введем две дополнительные функцииget – получение символа из файла после препроцессорной обработки (вырезании комментариев, неименованных строковых констант, директив препроцессору,лишние «пустые строки») и sget – получение информации о следующем участке кода (оператор, символоткрытия или закрытия блока). Теперь основная, с точки зрения запроса пользователя, функция overviewдолжна аккуратно проанализировать результаты работы sget и составить отчет.Теперь более подробно. Начнем с начала, а вклассе начало – конструктор.File::File()File (char *fname) {text=new ifstream(fname, ios::in);name=fname;if ((*text)==NULL)cout<<"Bad file name\n";lastcr=1;}#include <iostream.h>#include <fstream.h>class File {private:ifstream* text;char *name;bool lastcr;bool eval(char fchar, char* exl);void rewind();public:File (char *fname);bool eof();char get();char sget();void print();void printtrace();void overview();};Конструктор открывает сессию работы сфайлом, сохраняет его имя и ругается, еслифайл, почему-то, не открылся.char File::get()Эта функция реализует препроцессор.
Его задачи:1. Определять конец файла (код возврата – 0)2. Вырезать неименованные строковые константы3. Вырезать препроцессорные директивы4. Вырезать однострочные комментарии5. Вырезать многострочные комментарииОпределение конца файла, скорее является дополнительной задачей, но это позволяетизбежать последующие проверки. В этом случае код возврата равен 0 – символ EOF. Проверка на достижение конца файла проводится для каждойif (eof()) return(0);задачи препроцессора.while(buff!=nbuff) {(*text).read(&nbuff,1);if (eof())return(0);}Вырезание неименованных строковых констант происходит по следующей схеме: программа увидела символ «кавычка», затем игнорирует все следующие символы, вплотьдо такой же кавычки.Вырезание директив препроцессору.
Такого рода выwhile(nbuff!=10) {ражение начинается с символа '#' и заканчивается симво(*text).read(&nbuff,1);лом CR (Carriage Return, возврат каретки). Вот здесь сущеif (eof())ствует определенная проблема – в разных ОС по разномуreturn(0);}могут обозначать перенос строки. В ОС Linux, для которойпервоначально писались модули, символ CR равен 10. В Windows же, CR равен 13 + 10. Нотак как оба значения заканчивается на 10, примем его за символ переноса строки. Таким образом улучшится переносимость приложения. Так вот, при поступлении из потока '#', программа ждет либо конец строки, либо конец файла (что не исключено, но в ANSI C++ желательноЗадание #1 - Описание - char File::get() /страница 1 из 8/оставлять пустую строку в конце файла).Удаление однострочных комментариев схоже салгоритмом для препроцессорных директив.
Отличие – в «ожидании» двойного символа '/'. Длямногострочных комментариев добавляется проверка условия попадания подряд символов '*' и '/'.Смысл алгоритма прост: если встретился '*', то следующим должен быть '/'. Вложенные комментарии(nested comments) не поддерживаются, как и в ANSI C++.while(nbuff!='/') {while(nbuff!='*') {(*text).read(&nbuff,1);if (eof()) return(0); }(*text).read(&nbuff,1);if (eof()) return(0); }Теперь рассмотрим следующую вспомогательную функцию, основанную на get.char File::sget()Данная функция возвращает четыре вида значения, которые характеризуют участок кода:1. { – символ открытия блока2.
} – символ закрытия блока3. ; – символ оператора (строки текста)4. 0 – символ EOFЕсли функции попадаются эти символы, она их сразу возвращает. Иначе, начинает сканировать текст до нахождения подходящего.Но не все так просто. Нам надо считать количество строк в разных частях программы, для статистики важна унифицированность.
Например, код:i++;j++;иcase '{':case '}':case ';':return(buff);i++; j++;Первый код можно назвать «двустрочный», зато второй – «однострочный». А действиеодинаковое. Так вот, для стандарта условимся, что в подобных случаях рассматривать по двестроки в каждом случае. Это легко сделать, не обращая внимание на символы возврата каретки.
Теперь еще одна ситуация:if (...) i++;Здесь две сторки кода, но уже придуманными способами этоотследить нельзя. Поэтому программа просматривает код еще наналичие ключевых слов. Для удобства введена вспомогательнаяфункция eval. Это реализация классической схемы конечных автоматов. Недостаток такого подхода в том, что функция осуществляет чтение из файла, поэтому нельзя проверять сразунесколько вариантов, вследствии чего программа сначала определяет только одну из всех возможных комбинаций для проверки.switch (buff) {case 'i':kw=eval(buff,"if");break;...}if (kw)return(';');Если проверка подтверждает наличие ключевого слова – оно интерпритируется как«строка кода».void File::overview()Эта функция выполняет основную часть задания.Программа получает значение sget.
Если это '{' или ';', то увеличиваются соответствующие счетчики, при закрытии блока проводится проверка на максимальную вложенность и проч.Определение наибольшего или наименьшего значения происходит по стандартному алгоритму выбора такого элемента из конечного множества.Если попадается символ 0, на стандартный поток выводится статистика файла: максимальное, минимальное число операторов (строк) в блоке, число символов '{' и '}'. При несовпадении последних значений, выдается предупреждение.Задание #1 - Описание - void File::overview() /страница 2 из 8/ЛистингиFile: unit1.cpp#include "file.cpp"int main(){File a("file.cpp"); //Create class for filea.overview(); //Print overview of lifea.overview(); //One more time}cout<<"\nFile source with MEpreprocessor: \n";a.print(); //Print source text with MEP directivescout<<"\nFile trace: \n";a.printtrace(); //Print trace of sget functionreturn 0;//---------------------------------------------------------------------------File: file.cpp//Module of file analizator#include <iostream.h>#include <fstream.h>class File {private:ifstream* text; //Source filechar *name; //Source file name;bool lastcr; //Is last char 'CR'?bool eval(char fchar, char* exl) { //Is EXL variable contains in next read from filechar buff=fchar;int i=0;while (exl[i]>0) {if (buff==exl[i]) {i++;(*text).read(&buff,1);if ((*text).eof())return(0); //Isn't;}elsereturn(0); //Isn't}if (buff==' '||buff==0||buff=='('||buff=='{') //After keyword to be space or '('and '{'return(1); //Is itelsereturn(0); //Isn't}void rewind() { //Rewind text file to startdelete text;text=new ifstream(name, ios::in);}public:Задание #1 - Листинги - File: file.cpp /страница 3 из 8/File (char *fname) { //Default class constructor, arg - filename}text=new ifstream(fname, ios::in); //Open source filename=fname;if ((*text)==NULL)cout<<"Bad file name\n"; //If error occuredlastcr=1;bool eof() { //At EOFreturn((*text).eof());}char get() { //Get char from file with MEPreprocessorchar buff;char nbuff;while(1) {if (eof())return(0); //At EOF to return '0' signal(*text).read(&buff,1);switch (buff) {case '\"': //Cutting string or char constantscase '\'':nbuff=0;while(buff!=nbuff) {(*text).read(&nbuff,1);if (eof())return(0);}break;case '#': //Cutting preprocessor dirictivesnbuff=0;while(nbuff!=10) { //CHR(10)="CR" - carrier return(*text).read(&nbuff,1);if (eof())return(0);}break;case '/': //Start cutting comments(*text).read(&buff,1);switch(buff) {case ('/'): //Cutting one-line commentsnbuff=0;while(nbuff!=10) {(*text).read(&nbuff,1);if (eof())return(0);}break;case ('*'): //Cutting multi-lines commentsnbuff=0;while(nbuff!='/') {while(nbuff!='*') {(*text).read(&nbuff,1);if (eof())return(0);}(*text).read(&nbuff,1);if (eof())return(0);}break;default:return(buff);}break;Задание #1 - Листинги - File: file.cpp /страница 4 из 8/case 10: //Don't get empty linesif (lastcr==0) {lastcr=1;return(10);}break;case 0: //At EOFcout<<"<EOF>\n";return(0);break;}}default: //Default mode: switch lastcr to FALSEif (lastcr==1)lastcr=0;return(buff);}char sget() { //Special getchar buff=get();while(1) {if (eof())return(0);switch(buff) {case '{': // Open block signcase '}': // Close block signcase ';': // Operator signreturn(buff); //Return '}', '{' and ';'default:bool kw=0; //Is word - keywordswitch (buff) {case 'i':kw=eval(buff,"if"); //Ifbreak;case 'e':kw=eval(buff,"else"); //Elsebreak;case 'w':kw=eval(buff,"while"); //Whilebreak;case 's':kw=eval(buff,"switch"); //Switchbreak;case 'c':buff=get();switch (buff) {case 'a':kw=eval(buff,"ase"); //Casebreak;case 'l':kw=eval(buff,"lass"); //Classbreak;}break;}if (kw)}}}return(';'); //Keyword assign as operatorbuff=get(); //Else start one more timebreak;void print() { //Print file source with MEPrewind();char buff=get();while (buff>0) {cout<<buff;Задание #1 - Листинги - File: file.cpp /страница 5 из 8/}}buff=get();void printtrace () { //Print trace of file using function sget()rewind();char buff=sget();while (buff>0) {cout<<buff;buff=sget();}}void overview () { //Print overview stats of filerewind();int open=0, close=0; //Count of open, close block signint level=0; //Deep levelint min=0; int max=0; //Min & max values of number of operatorsint maxlevel=0, minmin=-1, maxmax=0; //Max deep level, max of max and min of minoperators cntchar buff; //Bufferwhile(1) {buff=sget();switch (buff) {case '{': //Open blockopen++;level++;min=0;break;case '}': //Close blockclose++;if (level>maxlevel)maxlevel=level;level--;if (level==0)if (max>maxmax) {maxmax=max;max=0;}if (minmin==-1)minmin=min;if (min<minmin)minmin=min;break;case ';': //Operator or keywordmin++;max++;break;case 0: //At EOF: print resultscout<<"File "<<name<<" overview:\n"<<"Max operators in block: "<<maxmax<<"\nMin operators in block: "<<minmin<<"\nMax deep: "<<maxlevel<<"\nOpen block: "<<open<<"\nClose block: "<<close<<"\n";if (close>open)cout<<"Warning: file contains more '}'s than '{'s\n";elseif (close<open)cout<<"Warning: file contains more '{'s than '}'s\n";}};}}cout<<"\n";return;Задание #1 - Листинги - File: file.cpp /страница 6 из 8/ТестыTest: example.cppFile example.cpp overview:Max operators in block: 11Min operators in block: 0Max deep: 4Open block: 6Close block: 7Warning: file contains more '}'s than '{'sFile example.cpp overview:Max operators in block: 11Min operators in block: 0Max deep: 4Open block: 6Close block: 7Warning: file contains more '}'s than '{'sFile source with MEpreprocessor:int main (int argc, char* crgv[]) {char* buff;if (1==1) {if (2==2) {if (3==3) {if (4==4)cin>>buff;}}}buff=;buff=; buff=;buff=; buff=;}}void erase () {delete;}void noop () {}File trace:{;;{;{;{;;}}};;;;;}}{}{}Test: file.cpp(only overview and trace)File file.cpp overview:Max operators in block: 160Min operators in block: 1Max deep: 7Open block: 29Close block: 29File trace:;{;;{;;;{;{;;;;;};};;;}{;;}{;;;;}{;}{;;;{;;;;{;;;;{;;;};;;;{;;;{;;;};;;;{;{;;;};;;};;};;;{;;};;;;;;;;}}}{;;{;;;{;;;;;;{;;;;;;;;;;;;;;;{;;;;;;};};;;;}}}{;;;{;;}}{;;;{;;}}{;;;;;;;;{;;{;;;;;;;;;;;{;;};;;;;;;;;;;;;;;;;}}}};Задание #1 - Тесты - Test: file.cpp /страница 7 из 8/Source: example.cpp//This is a example file#define#include "eeeee{}"/* This comments will be deletedAnd this too#define???*/ //Comments - no problem ;-)int main (int argc, char* crgv[]) {char* buff;if (1==1) {if (2==2) {if (3==3) {if (4==4)//So cool!cin>>buff;}}}buff="open {, close } ;;;;; {{{ }}} //";buff='{'; buff='}';buff=""; /*!!!!*/ buff="void example (int a) {{{{{{{{{{{{{}}}}}}}}}}}}}}}}}}}}}}";}}void erase () {//erasedelete; //Yahoooo!!!!!!!!!!!!11/* Erase too}*/void noop () {}Задание #1 - Тесты - Source: example.cpp /страница 8 из 8/.
Характеристики
Тип файла PDF
PDF-формат наиболее широко используется для просмотра любого типа файлов на любом устройстве. В него можно сохранить документ, таблицы, презентацию, текст, чертежи, вычисления, графики и всё остальное, что можно показать на экране любого устройства. Именно его лучше всего использовать для печати.
Например, если Вам нужно распечатать чертёж из автокада, Вы сохраните чертёж на флешку, но будет ли автокад в пункте печати? А если будет, то нужная версия с нужными библиотеками? Именно для этого и нужен формат PDF - в нём точно будет показано верно вне зависимости от того, в какой программе создали PDF-файл и есть ли нужная программа для его просмотра.