Разработка сканера
Разработка сканера
24 Министерство образования РФ Тульский государственный университет Кафедра АТМ Курсовая работа по курсу «Теория вычислительных процессов» Тула - 2003 Содержание: Введение……………………………………………………………………3 1.Постановка задачи….……………………………………………………4 1.1. Задание…………………………………………..……………………..4 2.1. Глобальные переменные и необходимые подпрограммы…….….…4 3.1. Диаграмма состояний………………………………..………………..5 2.Текст программы………………………………………………………...7 3. Инструкция пользователю……………………………………………..14 4. Тестовый пример……………………………………………………….14 Вывод………………………………………………………………............14 Список использованных источников……………………………………15 Введение: На сегодняшний момент существует огромное количество разнообраз -ных языков программирования. Все они имеют свою историю, свою область применения, и перечислять даже наиболее известные из них не имеет смысла. Но все эти языки построены на основе одних и тех же принципов, основы которых определяет теория формальных языков и грамматик. 1. Постановка задачи: 1.1. Задание: В данной контрольно-курсовой работе необходимо выполнить лексический анализ текста программы на некотором условном языке программирования. Таким образом требуется разработать сканер, который считывает литеры первоначальной, исходной программы и строит слова, или иначе символы, исходной программы (идентификаторы, служебные слова, одно- или двулитерные разделители). Символами в языке, для которого необходимо разработать сканер являются: 1.Служебные слова: Цикл …; Пока … Делать; Продолжить; Вещественный; Двойной. 2.Операторы: +, -, *, /, (, ), =, <>, <, >. 3.Идентификаторы: ( рус.буква | _ ), ( рус.буква | _ | цифра )*. 4.Логические операции: И, ИЛИ, НЕ. 5.Комментарий: {*…*}, {{ -до конца строки. 1.2. Глобальные переменные и необходимые подпрограммы: Для работы сканера требуются следующие переменные и подпрограммы: 1. char c, где c - глобальная переменная, значением которой всегда будет сканируемая литера исходной программы. 2. int Class, где Class содержит целое число, которое характеризует класс литеры, находящейся в с. Будем считать, что если Class = 1 то это цифра, Class = 2 - буква, Class = 3 - литера `{`, Class = 4 - оператор, Class = 5 - недопустимое выражение. 3. char s[20] - массив который будет содержать цепочку литер, составляющих символ. 4. void Getchar(char, int&) - функция, задача которой состоит в том, чтобы выбрать следующую литеру исходной программы и поместить ее в с, а класс литера в Class. 5. int LookUp(char* ) - функция которая осуществляет поиск символа, набранного в s, по таблице служебных слов и логических операций. Если символ является служебным словом, то LookUp возвратит 1, если символ это логическая операция то LookUp вернет 2, в противном случае функция вернет 3. 1.3. Диаграмма состояний: Метка D используется вместо любой из меток 0, 1, 2, … , 9, т. е. D представляет класс цифр. Это делается для упрощения диаграммы. Аналогично метка L представляет класс буквы А, Б, … , Я, а, б, … , я, а DELIM представляет класс разделителей (операторов). Литера { обрабатывается особым образом. Некоторые дуги не помечены. Эти дуги будут выбраны, если сканируемая литера не совпадает ни с одной из литер, которыми помечены другие дуги. Добавим семантику в диаграмму состояний. Введем команду Gc, сокращенно обозначив таки образом функцию void Getchar(char, int&). Под первой дугой, ведущей к состоянию S, записана команда init, которая указывает на необходимость выполнения подготовительных действий и начальных установок, а именно проверка содержимого с, и если там пробел, то повторно вызывается void Getchar(char, int&) до тех пор, пока в с не окажется литера, отличная от пробела если команда init определит конец файла то программа будет завершена. Команда ADD означает, что литера с добавляется к строке s. В состоянии Print int печатается определенное программой целое число, в Print sl - служебное слово, в Print log - логическая операция, в Print id - идентификатор, в Print com - комментарий, в Print еrror - недопустимое выражение. Из любого состояния Print дуги ведут в состояние S до тех пор, пока init не определит конец файла. Рисунок 1. Диаграмма состояний с семантическими процедурами. 2. Текст программы: #include <fstream.h> #include <stdlib.h> #include <process.h> #include <stdio.h> #include <conio.h> #include <ctype.h> #include <string.h> int Prov_itn(); //Проверка на ввод целого положительного числа int LookUp (char*); //Поиск символа по таблице служебных слов void Getchar(char,int&);//Определяет класс литеры void main() { char s[20],f_in[10]="in.txt",f_out[10],c,k,a; int Class,Quit=0,Q=0,x,i,n,j=0; char _ []="-----------------------", _cel[]=".Целое :", _op []=".Оператор :", _kom[]=".Комментарий :", _id []=".Идентификатор :", _sl []=".Служебное слово :", _log[]=".Логическая операция :", _err[]=".Недопустимое выражение:", __ []="-----------------------"; clrscr(); fstream inFile,outFile; cout<<"\t----------------------¬\n"; cout<<"\t¦ 1.Ввод с клавиатуры.¦\n"; cout<<"\t¦ 2.Ввод с файла. ¦\n"; cout<<"\tL----------------------\n"; do cout<<"\t Ваш выбор:"; n=Prov_itn(); if(n<1 while(1); if(n==1) { inFile.open(f_in,ios::trunc |ios::in | ios::out); cout<<"\nВводите текст (в конце текста введите !):\n"; for(;(a=getchar())!='!';) inFile<<a; inFile.close(); inFile.open(f_in,ios::in | ios::out); cout<<"\nВведите имя файла вывода: "; cin >>f_out; outFile.open(f_out,ios::trunc |ios::in | ios::out); if(!outFile) { cout<<"Ошибка окрытия файла: "<<f_out; } } if(n==2) { cout<<"Введите имя файла ввода: "; cin >>f_in; inFile.open(f_in,ios::in | ios::out ); if(!inFile) { cout<<"\nОшибка открытия файла: "<<f_in; } if(inFile.peek()!=EOF) { cout<<"Содержимое файла:\n\n"; while(inFile.peek()!=EOF) { inFile.get(c); cout<<c; } } else { cout<<"Файл пуст!"; getch(); exit(0); } inFile.close(); inFile.open(f_in,ios::in | ios::out ); cout<<"\n\nВведите имя файла вывода: "; cin >>f_out; outFile.open(f_out,ios::trunc |ios::in | ios::out); if(!outFile) { cout<<"\nОшибка окрытия файла: "<<f_out; } } //Проверка содержимого файла if(inFile.peek()!=EOF) { Quit=1; inFile.get(c); Getchar(c,Class); outFile<<_<<"\n"; } else Quit=0; while(Quit==1) { j++; while(c==' '||c=='\n') { if(inFile.peek()==EOF) { Quit=0; break; } inFile.get(c); Getchar(c,Class); } switch(Class) { case 1: //Считываемый символ цифра { i=0; do { s[i]=c; i++; if(inFile.peek()==EOF) { Quit=0; break; } inFile.get(c); Getchar(c,Class); }while(Class==1); s[i]='\0'; outFile<<j<<_cel<<s<<"\n"; } break; case 2: //Считываемый символ буква { i=0; do { s[i]=c; i++; if(inFile.peek()==EOF) { Quit=0; break; } inFile.get(c); Getchar(c,Class); }while(Class<=2); s[i]='\0'; x=LookUp(s); if(x==1) outFile<<j<<_sl<<s<<"\n"; if(x==2) outFile<<j<<_log<<s<<"\n"; if(x==3) outFile<<j<<_id<<s<<"\n"; } break; case 3: //Считываемый символ начало комментария { { i=0; s[i]=c; i++; if(inFile.peek()==EOF) { Quit=0; outFile<<j<<_err<<s<<"\n"; break; } inFile.get(c); Q=0; if(c=='*') { s[i]=c; i++; do { if(inFile.peek()==EOF) { Quit=0; break; } inFile.get(c); if(c=='*') { if(inFile.peek()==EOF) { Quit=0; break; } inFile.get(k); if(k!='}') continue; s[i]=c; i++; s[i]=c=k; i++; Q=1; if(inFile.peek()==EOF) { Quit=0; break; } inFile.get(c); } }while(Q!=1); s[i]='\0'; Getchar(c,Class); outFile<<j<<_kom<<s<<"\n"; } else { if(c=='{') { s[i]=c; i++; do { if(inFile.peek()==EOF) { Quit=0; break; } inFile.get(c); }while(c!='\n'); inFile.get(c); s[i]='\0'; Getchar(c,Class); outFile<<j<<_kom<<s<<"\n"; } else { Getchar(c,Class); outFile<<j<<_err<<s<<"\n"; } } }break; case 4: //Считываемый символ оператор { i=0; s[i]=c; if(s[i]=='<' && inFile.peek()!=EOF) { inFile.get(c); Getchar(c,Class); if(c=='>') { i++; s[i]=c; if(inFile.peek()!=EOF) { inFile.get(c); Getchar(c,Class); } else Quit=0; }} else { if(inFile.peek()!=EOF) { inFile.get(c); Getchar(c,Class); } else Quit=0; } i++; s[i]='\0'; outFile<<j<<_op<<s<<"\n"; }break; case 5: { i=0; do { s[i]=c; i++; if(inFile.peek()!=EOF) { inFile.get(c); Getchar(c,Class); } else { Quit=0;break; } }while(Class==5); s[i]='\0'; outFile<<j<<_err<<s<<"\n"; }break; } if(Quit==0) outFile<<__<<"\n"; } cout<<"Содержимое файла:\n\n"; outFile.close(); outFile.open(f_out,ios::in | ios::out ); { while(outFile.peek()!=EOF) { outFile.get(c); cout<<c; } } inFile.close(); outFile.close(); getch(); } //Определяет класс литеры void Getchar(char cc,int& Class1) { int i; char ca[]={'+','-','*','/','(',')','=','<>','<','>'}; char cb[]={'А','Б','В','Г','Д','Е','Ж','З','И','Й','К', 'Л','М','Н','О','П','Р','С','Т','У','Ф','Х', 'Ц','Ч', 'Ш','Щ','Ъ','Ы','Ь','Э','Ю','Я','а', 'б','в','г','д','е','ж','з','и','й','к','л', 'м','н','о','п','р','с','т','у','ф','х','ц', 'ч','ш','щ','ъ','ы','ь','э','ю','я','_'}; char cd[]={'1','2','3','4','5','6','7','8','9','0'}; for(i=0;i<10;i++) if(cc==cd[i]) { Class1=1; return; } if(cc=='{') { Class1=3; return; } for(i=0;i<10;i++) if(cc==ca[i]) { Class1=4; return; } for(i=0;i<65;i++) if(cc==cb[i]) { Class1=2; return; } if(cc==' ' || cc=='\n') Class1=10; else Class1=5; } //Поиск символа по таблице служебных слов int LookUp(char* s) { int i; char *log[]={"И","ИЛИ","НЕ"}; char *sl []={"Цикл","Пока","Делать","Продолжить","Вещественный","Двойной"}; for(i=0;i<6;i++) { if(strcmp(s,sl[i])==0) return 1; } for(i=0;i<3;i++) { if(strcmp(s,log[i])==0) return 2; } return 3; } //Проверка на ввод целого положительного числа int Prov_itn() { char k1[5],k2[5]; int nn; cin>>k1; nn=atoi(k1); itoa(nn,k2,10); if (strlen(k1)!=strlen(k2)) return 0; return nn; } 3. Инструкция пользователю: В данной программе пользователю предоставляется выбор из двух альтернатив: ввести текст вручную либо считать из файла. После выбора ввода программа в тексте определит служебные слова, идентификаторы, операторы, логические операции, комментарии, если таковые имеются. 4. Тестовый пример: +---------------------+ ¦ 1.Ввод с клавиатуры.¦ ¦ 2.Ввод с файла. ¦ +---------------------+ Ваш выбор:2 Введите имя файла ввода: in.txt Содержимое файла: Пока {*(ldfjvkdfvfjkb*} Вещественный<> += Введите имя файла вывода: put.txt Содержимое файла: ----------------------- 1.Служебное слово :Пока 2.Комментарий :{**} 3.Служебное слово :Вещественный 4.Оператор :<> 5.Оператор :+ 6.Оператор := ----------------------- Вывод: В настоящей работе была показана работа сканера, при которой выполняется полный лексический анализ исходной программы. Список использованных источников: 1. Грис Д. Конструирование компиляторов для цифровых вычислительных машин. М.: Мир, 1975; 2. Хантер Р. Проектирование и конструирование компиляторов. М.: Финансы и статистика, 1984. 3. Касьянов В.Н., Поттосин И.В. Методы построения трансляторов. Новосибирск: Наука, 1986.
|