Разработка сканера
Министерство образования РФ
Тульский государственный университет
Кафедра АТМ
Курсовая работа
по курсу
«Теория вычислительных процессов»
Тула – 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[]=".Недопустимое
выражение:",
__
[]="───────────────────────";
fstream
inFile,outFile;
cout<<"\t┌─────────────────────┐\n";
cout<<"\t│
1.Ввод с клавиатуры.│\n";
cout<<"\t│
2.Ввод с файла. │\n";
cout<<"\t└─────────────────────┘\n";
do
{
cout<<"\t
Ваш выбор:";
n=Prov_itn();
if(n<1
|| n>2)
cout<<"\t
Неверно указан номер пункта меню.\n";
else
break;
}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);
}
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;
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: //Считываемый символ оператор
{
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
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.