Пояснительная записка к курсовой работе по дисциплине "Системное программное обеспечение"

Вид материалаПояснительная записка

Содержание


1.Техническое задание 1.1.Название разработки Название разработки данной курсовой работы – транслятор. 1.2.Назначение разработки
1.3.Функциональные характеристики
1.4.Требования к среде эксплуатации
1.5.Требования к среде разработки
2.2.Исходные данные к курсовой работе
2.3.Этапы трансляции
3.Грамматика языка 3.1.Формализация правил для лексических и синтаксических конструкций языка
3.2.Преобразование грамматики для нисходящего разбора
3.3.Тестирование грамматики
4.Разработка алгоритма работы транслятора 4.1.Схема модулей работы транслятора
4.2.Лексический анализатор
4.3.Синтаксический анализатор
4.4.Генерация объектного кода
5.Программная реализация транслятора 5.1.Перечень и описание используемых модулей
5.1.2.Синтаксический анализатор
5.1.3.Генерация объектного кода
6.Тестирование транслятора Вариант полного тестирования всего транслятора приведен в приложении 2. 6.1.Тестирование лексического
6.2. Тестирование синтаксического и семантического анализатора.
7.Инструкция программиста
8.Инструкция пользователей
...
Полное содержание
Подобный материал:

Пояснительная записка к курсовой работе

по дисциплине “Системное программное обеспечение”

на тему: “Проектирование транслятора”


Содержание

1. Техническое задание 4

1.1. Название разработки 4

1.2. Назначение разработки 4

1.3. Функциональные характеристики 4

1.4. Требования к среде эксплуатации 4

1.5. Требования к среде разработки 4

2. Анализ задачи проектирования 5

2.1. Цель и задачи выполнения курсовой работы 5

2.2. Исходные данные к курсовой работе 5

2.3. Этапы трансляции 5

3. Грамматика языка 7

3.1. Формализация правил для лексических и синтаксических конструкций языка 7

3.2. Преобразование грамматики для нисходящего разбора 7

3.3. Тестирование грамматики 8

4. Разработка алгоритма работы транслятора 9

4.1. Схема модулей работы транслятора 9

4.2. Лексический анализатор 9

4.3. Синтаксический анализатор 13

4.4. Генерация объектного кода 15

5. Программная реализация транслятора 17

5.1. Перечень и описание используемых модулей 17

5.1.1. Лексический анализатор 17

5.1.2. Синтаксический анализатор 17

5.1.3. Генерация объектного кода 18

6. Тестирование транслятора 20

6.1. Тестирование лексического анализатора 20

6.2. Тестирование синтаксического и семантического анализатора. 20

7. Инструкция программиста 22

8. Инструкция пользователей 23

9. Заключение 24

Список использованной литературы 25

Приложение 1 26

Файл scanner.cpp 26

функция удаления пробелов 26

удаление строчных коментариев 26

удаление блочных коментариев 26

Файл scanner_pascal_v2 28

функция выдачи значимой литеры 28

функция поиска лексемы в таблице 28

функция добавления лексемы в таблицу 28

функция анализа констант 29

функция анализа разделителей 29

функция анализа символических имен 30

Файл sintex_analize.cpp 31

стек для формирования инфиксной записи при генерации кода 31

класс ввода-вывода 32

функции генерации объектного кода и польской записи 33

рекурсивные функции синтаксического анализа 35

Приложение 2 42

Тестирование сканера. 42

Тестирование синтаксического и семантического анализатора 43



1.Техническое задание

1.1.Название разработки


Название разработки данной курсовой работы – транслятор.

1.2.Назначение разработки


Назначением разработки является трансляция исходного текста программы, написанного на языке программирования Pascal.

1.3.Функциональные характеристики


В соответствии с вариантом задания необходимо разработать программу транслятора со следующими характеристиками:
  • язык программирования, для которого проектируется транслятор - Pascal;
  • подмножество языка - арифметические выражения целого типа, операторы присваивания, цикла с предусловием, бесформатного ввода-вывода;
  • тип промежуточного кода программы – польская запись;
  • тип транслятора - компилятор;
  • метод разбора – нисходящий с возвратами;
  • язык программирования, на котором производиться реализация транслятора – Pascal;

1.4.Требования к среде эксплуатации


Требование к среде следующие: персональный IBM PC/AT/ATX – совместимый компьютер с процессором не ниже Pentium 133 и имеющий не менее 64 МБ оперативной памяти, опе­рационная система MS Windows 98/2000/XP. Среда эксплуатации должна обладать .NET framework v2.0

1.5.Требования к среде разработки


Средой разработки данной курсовой работы является интегрированная среда разработки приложений MS Visual Studio .NET 2005.

2.Анализ задачи проектирования

2.1.Цель и задачи выполнения курсовой работы


Целью выполнения курсового проекта является проектирование транслятора программы, написанной на языке программирования Pascal.

2.2.Исходные данные к курсовой работе


В соответствии с вариантом задания необходимо разработать программу транслятора со следующими характеристиками:
  • язык программирования, для которого проектируется транслятор - Pascal;
  • подмножество языка - арифметические выражения целого типа, операторы присваивания, цикла с предусловием, бесформатного ввода-вывода;
  • тип промежуточного кода программы – польская запись;
  • тип транслятора - компилятор;
  • метод разбора – нисходящий с возвратами;
  • язык программирования, на котором производиться реализация транслятора - Pascal.

2.3.Этапы трансляции


Общую задачу трансляции обычно разделяют на несколько этапов:
  1. Лексический анализ;
  2. Синтаксический и семантический анализ;
  3. генератор объектного кода.

Одним из основных требований, предъявляемых к трансляторам, является их способность обрабатывать любые входные цепочки символов, в том числе и ошибочные. В последнем случае транслятор должен выводить информацию об ошибке.

Этапы работы транслятора схематически можно представить следующим образом (Рис. 1).



Рис. 1 Схема работы транслятора

3.Грамматика языка

3.1.Формализация правил для лексических и синтаксических конструкций языка



Грамматика заданного подмножества языка Pascal в расширенной форме Бекуса-Наура будет иметь вид:


1)<программа>::= program ;[<обьявление>]<тело>

2)<обьявление>::=var:{,}:integer;

3)<тело>::=begin:<оператор>{<оператор>}end.

4)<оператор>::=<объявление>|<цикл>|<присваивание>|<ввод>|<вывод>

5)<присваивание>::=:=<выражение>;

6)<ввод>::=read();

7)<вывод>::=write();

8)<цикл>::=while:<лог-выражение>:do<тело>;

9)<выражение>::=<мульт.опер>{(+|-)<мульт.опер>}

11)<мульт.опер>::=<операнд>{(*|/)<операнд>}

12)<операнд>::=<оп>|(<выражение>)

13)<оп>::=|

14)<лог-выражение>::=<выражение><лог-операция><выражение>

15)<лог-операция>::=<|>|<=|>=|=

16)::=<буква>{<буква>|<цифра>}

17)::=<цифра>{<цифра>}

18)<буква>::=A…z

19)<цифра>::=0…9

3.2.Преобразование грамматики для нисходящего разбора


Основная задача отладки грамматики – определение наличия в ней левосторонней рекурсии. Это необходимо, так как алгоритм нисходящего синтаксического разбора с возвратами будет работать неправильно при наличии в грамматике левосторонней рекурсии. Предложенный алгоритм сам по себе рекурсивен, поэтому, если на вход будет подана такая грамматика, программа зациклится и вызовет переполнение стека.

Так как грамматика представлена в расширенной форме Бекуса-Наура, то наличие в ней левосторонней рекурсии исключается.

3.3.Тестирование грамматики


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

4.Разработка алгоритма работы транслятора

4.1.Схема модулей работы транслятора


На первом этапе работы транслятора производиться лексический анализ исходной программы (сканер). Входными данными для сканера являются: исходный текст программы, грамматика основных символов и таблица ключевых слов. Сканер обрабатывает входные данные и составляет таблицу символических имен.

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

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

В данной реализации генерация объектного кода проходит параллельно с генерацией внутреннего представления программы..

Схема модулей представлена на Рис. 2



Рис. 2. Схема модулей

4.2.Лексический анализатор


Как уже отмечалось, первым этапом работы транслятора является лексический анализатор. Основная задача лексического анализатора - разбить входной текст, состоящий из последовательности одиночных символов, на последовательность слов, или лексем, то есть выделить эти слова из непрерывной последовательности символов. Иными словами сканер должен обнаружить и выделить из исходного текста основные символы языка, к которым можно отнести идентификаторы, служебные слова, целые числа, одно и двулитерные разделители, такие, как *, +, := и т.п.

Разбор лексемы производится в 3 этапа. Сначала запускаеться подпрограмма, которая удаляет из исходного файла комментарии и незначимые символы. На втором этапе из входного файла выбирается первый символ и определяется его тип. Символы подразделяются на 3 типа:

Const – цифра (0-9);

Char – буква (a-z, A-Z, _ );

Delim – разделитель –символы ( ) * + - ; { }

В зависимости от определенного типа обработка входной строки передается в один из обработчиков, которые читают далее входной поток, пока встречают символы, которые подходят к их лексемам. Как только встретится символ не подходящий к лексеме, которая может быть на выходе данного обработчика, делается вывод о завершении текущей лексемы, управление передается в общий обработчик, при этом следующий символ уже выбран и его класс определен.

В таблице 1 приведено внутреннее представление символов.

Таблица 1. Внутреннее представление символов

Символ

Тип

Код

+

DEL

1

-

DEL

2

*

DEL

3

/

DEL

4

(

DEL

5

)

DEL

6

=

DEL

7

:

DEL

8

;

DEL

9

,

DEL

10

<

DEL

11

>

DEL

12

<=

DEL

13

>=

DEL

14

:=

DEL

15

.

DEL

16

var

NAME

21

begin

NAME

22

integer

NAME

23

end

NAME

24

for

NAME

25

do

NAME

26

while

NAME

27

program

NAME

28

then

NAME

29

read

NAME

30

write

NAME

31

to

NAME

32


Константы и идентификаторы имеют тип соответственно CONST и ID, а их код присваивается динамически во время формирования таблицы констант и идентификаторов, код всех констант отрицательный, что облегчает работу в дальнейшем.

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

На основе разработанной грамматики и таблицы внутреннего представления символов, строится диаграмма состояний сканера, которая приведена на Рис. 3 . На основании данной диаграммы строится программная реализация сканера.



Рис. 3. Диаграмма состояний сканера


gc – читает очередной символ из входного потока и определяет его тип.

Intab – проверяет наличие лексемы в соответствующей таблице

pushtab – записывает неизвестную лексем в таблицу и присваивает ей код

delimpr – вывод кода разделителя в выходной поток.

constpr – вывод кодаконстанты в выходной поток.

charpr – вывод кода идентификатора или служебного слова в выходной поток.


Конечный автомат является циклическим, поэтому, после выдачи типа лексемы, он переходит в начальное состояние. На графе (см. рис. 3) это не отражено. Автомат прекращает работу, когда начальная функция gc прочитает конец файла.

Каждая лексема после анализа заносится в таблицу лексем. Таблица представляет собой массив элементов, каждый из которых является структурой, в которой ранится исчерпывающая информация по каждой лексеме

4.3.Синтаксический анализатор


Синтаксический анализ выполняется методом нисходящего разбора с возвратами. Учитывая, что сам по себе данный метод является рекурсивным, выгоднее использовать рекурсивную функцию. Суть метода состоит в следующем. Рекурсивная функция вызывается для начального символа грамматики, тот в свою очередь вызывает эту функцию для первого символа своей первой альтернативы. Если функция возвращается с признаком успешного разбора символа, она вызывается для второго символа первой альтернативы, в противном случае, для первого символа второй альтернативы. Если в данной альтернативе функция для всех символов вернула признак успеха, он возвращается «родителю» - в вышестоящую функцию. Такой принцип действует для всех символов. Конечным символом является терминал. Если терминал во входной грамматике соответствует терминалу во входной цепочке, функция возвращает успех, в противном случае – неудачу. Для нетерминальных символов возвращение того или иного признака означает, для успеха – возврат всех вызванных данным терминалом функций с признаками успеха, для неудачи – возврат хотя бы одной функции, вызванной данным терминалом, с признаком неудачи.

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

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

Первый недостаток – программа должна использовать только правильную грамматику без левосторонней рекурсии, иначе рекурсивная функция начнет вызывать себя бесконечное число раз, что приведет к «зависанию» программы, переполнению стека и снятию программы операционной системой.

Вторая проблема заключается в том, что возврат функции на каком-то шаге не означает неправильности входной цепочки (так как разбор допускает возвраты, и у каждого нетерминала может быть несколько альтернатив). С другой стороны возвращаемое функцией значение – единственный признак успеха или неудачи разбора. Говорить о том, что входная цепочка неверна можно только в случае возврата признака неуспеха для начального символа грамматики. Отсюда налицо проблема локализации синтаксических ошибок. Произвести ее невозможно.

В процессе синтаксического анализа входной цепочки синтаксический анализатор путем вызова семантических подпрограмм (в случае успеха в определенной части разбираемой цепочки) формирует внутренне представление программы.

В качестве внутреннего представления программы используется польская запись, которая просто и точно указывает порядок выполнения операций. В этой записи операторы следуют непосредственно за операндами. Например, А*В записывается как АВ* и т.д.

Блок-схема алгоритма работы распознавателя приведена на рис.5.



Рис.5. Алгоритм работы синтаксического распознавателя.

4.4.Генерация объектного кода


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

В качестве объектного кода используется язык C. Для хранения промежуточных результатов операций были использованы временные переменные.

Генерация объектного кода осуществлялась путем вызова подпрограмм генерации участков кода во время синтаксического анализа. Это возможно из-за особенностей метода нисходящего разбора с возвратами. Данный метод в рекурсивной реализации позволяет в каждой функции анализа грамматики в случае успеха вызывать программы формирования объектного кода в случае успеха. Таким образов при «раскручивании» рекурсивной цепочки можно сформировать автокод «на лету».



Рис.6. Алгоритм работы генератора объектного кода.

5.Программная реализация транслятора

5.1.Перечень и описание используемых модулей

5.1.1.Лексический анализатор


Данный модуль описывается в файле scaner_pas_v2.cpp /scaner_pas_v2.cpp

В лексическом анализаторе используются следующие функции:
  • char gc(ifstream& f) – функция берет из потока непробельный символ
  • int intab(string tabname, string st) – функция проверяет наличие строки в некоторой таблице и возврашает ее номер
  • int pushtab(string tabname, string st) – помешает символ в конец таблицы и возврашает ее номер
  • int pers(char r) – возврашает тип символа
  • void conspr(ifstream& f,ofstream& ff, ofstream& pr, char s) – разбор и накопление константы и вывод ее в выходной поток
  • void delimpr(ifstream& f,ofstream& ff, ofstream& pr,char s) – разбор разделителей
  • void switcher(ifstream& f, ofstream& ff, ofstream& pr) – переключает поток в соответствии с типом символа
  • int _tmain(int argc, _TCHAR* argv[]) – главная функция

Код данных модулей приведен в приложении 1.

5.1.2.Синтаксический анализатор


Данный модуль описан в файлах sintax_analize/sintax_analize.cpp


В синтаксическом анализаторе используются следующие функции:
  • bool program(temp& f); - Описание программы
  • bool declar(temp& f); - обьявления
  • bool mdeclar(temp& f); - множество обьявлений
  • bool body(temp& f); - тело
  • bool listid(temp& f); - индентификатор
  • bool mlistid(temp& f); - множество индентификаторов
  • bool operators(temp& f); - операторы
  • bool oper(temp& f); - оператор
  • bool cickl(temp& f); - цикл
  • bool dec(temp& f); - инициализация
  • bool inp(temp& f); - ввод
  • bool outp(temp& f); - вывод
  • bool expr(temp& f); - выражение
  • bool sum(temp& f); - мультипликативная операция
  • bool mul(temp& f); - операнд
  • bool wbody(temp& f); - тело для цикла
  • bool logexp(temp& f); - логическое выражение цикла
  • class temp – интерфейс ввода-вывода


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

Код данных модулей приведен в приложении 1.

5.1.3.Генерация объектного кода


Данный модуль описан в файле sintax_analize/sintax_analize.cpp

В данном модуле используются следующие функции:
  • void getl(temp& f) – установка метки (для ПЗ)
  • void onlexp(temp& f) – запись метки в лог. выражениях
  • void programA(temp& f, int nid) – генерация «шапки»
  • void declarA(temp& f, int nid) – генерация обьявления
  • void topbody(temp&f) – генерация верха тела программы
  • void infix(temp& f, string op) – перевод ПЗ в инфиксную
  • void decA(temp& f, int id) - инициализация
  • void stan(temp& f, int type) – инициализация в лог выражении
  • void input(temp& f) – ввод
  • void output(temp& f) – вывод
  • void expr_(temp& f, int t) – выражения
  • void genlog(temp& f, int type) – генерация лог выражений
  • void cikltop(temp& f) – генерация «шапки цикла»

Данные функции вызываються в ходе синтаксического анализа и формируют определенный участок автокода программы.

Код данного модуля приведен в приложении 1.

6.Тестирование транслятора


Вариант полного тестирования всего транслятора приведен в приложении 2.

6.1.Тестирование лексического анализатора


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

Как уже отмечалось выше, после успешной работы сканера генерируются таблицы символических и лексических имен, которые подаются на вход к синтаксическому анализатору. Поэтому важно, чтобы первый этап работы транслятора работал безошибочно.

Суть тестирования заключается в следующем: на вход к лексическому анализатору подаются данные, для которых известна информация на выходе, и, если на выходе оказывается ожидаемый результат, то сканер работает правильно.

В ходе тестирования было проверено несколько вариантов исходных текстовых файлов, каждый из которых сканер обработал корректно. На основании этого было сделано предположение о корректности работы сканера при любых других входных данных.

Варианты входных файлов и результаты тестирования приведены в приложении 2.

6.2. Тестирование синтаксического и семантического анализатора.


Задачей распознавателя явлеяться генерация внутреннего представления цепочки, поступающей с выхода сканера.

В ходе успешного вполнения распозанаватель должен получить внутреннее представление программы, полностью эквивалентное входной цепочке сканера. Так же необходима корректная генерация программы на объектном языке.

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

В ходе тестирования были проверенны как корректные, так и некорректные синтаксически цепочки. Каждую из них распознаватель корректно обработал и сформировал внутреннее представление программы, эквивалентное данной.

Варианты входных файлов и результаты тестирования приведены в приложении 2.


7.Инструкция программиста


Разработанное приложение (компилятор языка Pascal) представляет собой консольное многомодульное приложение, состоящее из следующих модулей:
  • Scanner.exe – модуль удаления незначимых символов программы
  • Scanner_pascal_v2.exe – лексический анализатор
  • Sintex_analize.exe – синтаксический и семантический анализатор
  • Start.bat – сценарий выполнения модулей

Внешние файлы, используемые приложением:
  • Dfg.txt – таблица констант
  • Id.txt – таблица идентификаторов
  • Nam.txt – таблица служебных слов
  • Del – таблица разделителей
  • SVODKA.txt – отчет работы сканера
  • Programma.txt – результат работы сканера
  • Pz.txt – польская запись
  • Obj.txt - автокод

8.Инструкция пользователей


Транслятор позволяет транслировать исходный тексты программ, написанных на языке высокого уровня Pascal с сильно ограниченными функциональными возможностями, а именно:
  • арифметические выражения целого типа;
  • операторы присваивания;
  • операторы бесформатного ввода-вывода.
  • цикл с предусловием

Чтобы запустить собранный файл нужно два раза щелкнуть мышкой по соответствующей пиктограмме или набрать в командной строке следующую команду: $programDir\start.bat.

9.Заключение


В результате выполнения данной курсовой работы был создан функционирующий интерпретатор подмножества языка PASCAL. Были отработаны этапы проектирования трансляторов, такие как лексический разбор текста, синтаксический анализ по методу нисходящего разбора с возвратами, формирование промежуточной формы – польской записи. Была изучена и проработана соответствующая техническая литература.

Список использованной литературы

  1. Грис Д. Конструирование компиляторов для цифровых вычислительных машин. - М.: Мир 1975. –544 с.
  2. Савин Н.И. Системное программное обеспечение ЭВМ, вычислительных комплексов, систем и сетей. Методические указания по выполнению курсовой работы. – Тула, ТулГУ (каф. ЭВМ), 2000.
  3. Оформление текстовых и графических документов по вычислительной технике: методические указания / Составитель Т.И. Матикашвили. – Тула, ТулГУ (каф. ЭВМ), 1997.
  4. Серебряков В.А. Основы конструирования компиляторов. – М.:Эдиториал, 2001. – 224 с.
  5. Степанов М.Ф. Машинный перевод и общение на естественном языке. – Саратов, 2000. – 98 с.
  6. ГОСТ 19.106-78 ЕСПД. Требования к программным документам, выполненным печатным способом
  7. Матикашвили Т.И. компьютерное оформление отчетных документов. – Тула, 2000.



Приложение 1

Файл scanner.cpp



#include "stdafx.h"

#include

#include

#include

using namespace std;


void serch(ifstream& fi, ofstream& f);

void serch(ifstream& fi, ofstream& f){

char g=' ';

for(;!fi.eof();g=' '){

fi>>g;

функция удаления пробелов



switch(g){

case ' ':

break;

default:

f<

удаление строчных коментариев


void catcom(ifstream& f1, ofstream& f2);

void catcom(ifstream& f1, ofstream& f2){

char s=' ';char buf=' ';char line[100];

for(;!f1.eof();s=' ', buf=' '){

f1>>s;

switch(s){

case '/':

f1>>buf;

if(buf!='/'){f2<
else{f1.getline(line,100);break;}

default:

f2<

удаление блочных коментариев


void catcom1(ifstream& f1, ofstream& f2);

void catcom1(ifstream& f1, ofstream& f2){

char s=' ';char buf=' ';

for(;!f1.eof();s=' ',buf=' '){

f1>>s;

switch(s){

case '/':

f1>>buf;

if(buf!='*'){f2<
else{

for(int t=0;t!=1;){

f1>>buf;

if(buf=='*')

{

f1>>s;

if(s=='/'){t=1;}

else{f1.seekg(-1,SEEK_CUR);}

}

}}

break;

default:

f2<

void cat(ofstream &f, int set);

void cat(ofstream &f, int set){

f.seekp(-set,SEEK_END);

for(int i=0;i!=set;i++){

f<<'1';}}


int _tmain(int argc, _TCHAR* argv[])

{

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

ofstream bf("id.txt");

ofstream bf1("dfg.txt");

bf<
bf1<
bf.close();

bf1.close();

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


ifstream f1 ("1.pas");

ofstream f2 ("2.pas");

catcom(f1,f2);

f1.close();

f2.close();

ifstream f11 ("2.pas");

ofstream f22 ("11.pas");

catcom1(f11,f22);

f11.close();

f22.close();

ifstream f111 ("11.pas");

ofstream f222 ("1.txt");

serch(f111,f222);

f111.close();

f222.close();

_getch();


return 0;

}

Файл scanner_pascal_v2


#include "stdafx.h"

#include "stdafx.h"

#include

#include

#include

#include

using namespace std;

функция выдачи значимой литеры


char gc(ifstream& f){

char s='1';

f>>s;

if(s!=' '){return s;}

else{return gc(f);}}

функция поиска лексемы в таблице


int intab(string tabname, string st){

ifstream fi(tabname.c_str());

string buf;

string term;

term="|" ;


for(int i=1;;i++){

fi>>buf;

if(buf==term){return 0;}

if(buf==st){return i;}

else{continue;}

}

fi.close();

}

функция добавления лексемы в таблицу


int pushtab(string tabname, string st){

ifstream fi(tabname.c_str());

string buf;

string term;

term="|" ;


for(int i=1;;i++){

fi>>buf;

if(buf==term||buf==""){

fi.close();

fstream f(tabname.c_str(), ios_base::in|ios_base::out);

f.seekp(-3,SEEK_END);

f<
f.close();


return i+1;}

else{continue;}

}

}


//функция определения типа символа потока

int pers(char r){//выдает тип символа

if(r=='0'||r=='1'||r=='2'||r=='3'||r=='4'||r=='5'||r=='6'||r=='7'||r=='8'||r=='9'){return 1;}

if(r=='+'||r=='-'||r=='*'||r=='/'||r=='('||r==')'||r=='='||r==':'||r==';'||r==','||r=='<'||r=='>'||r=='.'){return 2;}

return 3;}

функция анализа констант


void conspr(ifstream& f,ofstream& ff, ofstream& pr, char s){

string buf;

buf=buf+s;

char h=' ';

int n=0;

for(;!f.eof();){

h=gc(f);

if(pers(h)!=1){f.seekg(-1, SEEK_CUR);break;}

else{

buf=buf+h;}

}


n=intab("dfg.txt",buf);

if(n!=0){

ff<<"<"<<-n<<"><"<"<
else{

n=pushtab("dfg.txt",buf);

ff<<"<"<<-n<<"><"<"<
}

функция анализа разделителей


void delimpr(ifstream& f,ofstream& ff, ofstream& pr,char s){

string buf,buf2;//создаем буферы

buf=buf+s; //заполняем поступившим разделителем

buf2=buf2+s;

char h=' ';//место под символ

h=gc(f); //берем символ из потока

if(pers(h)==2){

buf=buf+h;} //составляем 2-ой разделитель если можно

else{f.seekg(-1,SEEK_CUR);} //есди нет возврашаем позицию

int tt=intab("del.tab", buf);//опредедяем нахождение в таблице 1го и 2го разделителя

int t=intab("del.tab", buf2);

if(tt!=0){

//пишем в поток имеюшийся

ff<<"<"<<"<"<
else{f.seekg(-1,SEEK_CUR);

if(t!=0){

ff<<"<"<<"<"<
else{

cout<<"syntex error -> Encorrect delemitor ->"<

}

функция анализа символических имен


int charpr(ifstream& f,ofstream& ff, ofstream& pr,char s){

string buf;

string buf2;

buf2=s;

buf=buf+s;

char h=' ';

int n=0;


for(;!f.eof();){

h=gc(f);

if(pers(h)==2){f.seekg(-1, SEEK_CUR);break;}

else{

buf=buf+h;

n=intab("nam.txt",buf);

if(n!=0){ff<<"<"<<"<"<
n=intab("id.txt",buf);

if(n!=0){ff<<"<"<<"<"<
}}

n=intab("nam.txt",buf2);

if(n!=0){ff<<"<"<<"<"<
n=intab("id.txt",buf2);

if(n!=0){ff<<"<"<<"<"<
n=pushtab("id.txt",buf);

ff<<"<"<<"<"<
}

//Функция разбора символа потока

void switcher(ifstream& f, ofstream& ff, ofstream& pr){//переключает в соответствуюшуюю ветку по типу символа

char s;

int ss=0;

s=gc(f);

ss=pers(s);

switch(ss){

case 1:conspr(f,ff,pr,s);break;

case 2:delimpr(f,ff,pr,s) ;break;

case 3:charpr(f,ff,pr,s);break;

default: throw 1;}}


//главная функция

int _tmain(int argc, _TCHAR* argv[])

{

ifstream fi("1.txt");

ofstream fo("SVODKA.txt");

ofstream foo("programma.txt");

for(;!fi.eof();){switcher(fi,fo,foo);}

foo<<0;

_getch();

fi.close();

fo.close();

foo.close();

return 0;}

Файл sintex_analize.cpp



#include "stdafx.h"

#include

#include

#include

#include

using namespace std;


string intab(string tn, int n);


string convert(string pr, int num){

string ret;

ofstream f("buf");

f<

f.close();

ifstream f_("buf");

f_>>ret;

f_.close();

return ret;

}

стек для формирования инфиксной записи при генерации кода


class stackk{

string *m;

int i;

int vv;

public:

stackk(int v){

vv=v;

m=new string [vv];

i=0;}

void invert(){

string *t;

string *m_=new string [vv];

for(int j=i, k=0; j!=0;j--,k++){m_[k+1]=m[j];}

t=m;

m=m_;

delete []t;

}

int pop(string var){

if((i+1)==vv){return 0;}

i++;

m[i]=var;}

string get(){

return m[i];}

string push(){

if(i==0){return "error";}

string y;

y=m[i];

i--;

return y;

}

void print(){

for(int j=i;j!=0;j--){

cout<
}

bool is_umpty(){

if(i==0){return true;}

else{return false;}}

};


класс ввода-вывода


class temp{

ofstream* pz;

ofstream* obj;

int* mas;

int l,t;

public:

temp(string pn, string pz_ ,string obj_ ){

ifstream f(pn.c_str());

pz= new ofstream(pz_.c_str());

obj= new ofstream(obj_.c_str());

//pz=pz_;

//obj=obj_;


int tt=0;

int b=0;

for(;;tt++){

f>>b;

if(b==0){break;}

}

l=0;

t=tt;

mas=new int[tt];

//f.seekg(0,SEEK_SET);

ifstream ff(pn.c_str());


for(int k=0;k!=tt;k++){

ff>>mas[k];}

l=0;

t=tt;

}

~temp(){pz->close();obj->close();delete []mas;}

void print(){

for(int i=0;i!=t;i++){

cout<
}

int seekg(int p){

if((l+p)<0||(l+p)>=t){return l;}

l=l+p;

return l;

}

int gt(){

if(l>=t){return 0;}

l++;

cout<
return mas[l-1];}

ofstream& pz__(){return *pz;}

ofstream& ob__(){return *obj;}


};

//Global


stackk big(2000);

int c_=0;

int label=1;

//end

функции генерации объектного кода и польской записи


//функция выдачи метки польской записи

void getl(temp& f){

f.pz__()<
label++;

}

//запись метки в логическом выражении

void onlexp(temp& f){

f.pz__()<<"&"<

}

//функция генерации новой шапки программы

void programA(temp& f, int nid){

f.ob__()<<"#include "<"<
f.ob__()<<"/*"<<"Proggram name:"<
}

//генерация обьявлений

void declarA(temp& f, int nid){

f.pz__()<<"id"<
f.ob__()<<"int id"<
;}

void topbody(temp&f){f.ob__()<<"void main(void){"<
void lbody(temp&f){f.ob__()<<"return 0;}"<

//перевод польской записи в инфиксную

void infix(temp& f, string op){

string fir;

string tempname;

string sec;

sec=big.push();

fir=big.push();

tempname=convert("temp", c_);c_++;

f.ob__()<<"int "<
big.pop(tempname);


}

//генерация присваивания

void decA(temp& f, int id){

f.ob__()<<"id"<
f.pz__()<<"id"<
}


void stan(temp& f, int type){

string pusher=big.push();

f.pz__()<<"lv"<
f.ob__()<<"logvar"<
}

//генерация ввода

void input(temp& f){

f.seekg(-1);

int id=f.gt();

f.pz__()<<"id"<
f.ob__()<<"scanf("<<'"'<<"%d"<<'"'<<","<<"id"<
}

//генерация вывода

void output(temp& f){

f.seekg(-1);

int id=f.gt();

f.pz__()<<"id"<
f.ob__()<<"printf("<<'"'<<"%d"<<'"'<<","<<"id"<
}

//генерация выражений

void expr_(temp& f, int t){

string buf;


switch(t){

case 1:

f.pz__()<<"+ ";

infix(f,"+");

break;

case 2:

f.pz__()<<"- ";

infix(f,"-");

break;

case 3:

f.pz__()<<"* ";

infix(f,"*");

break;

case 4:

f.pz__()<<"/ ";

infix(f,"/");

break;}


if(t>35){f.pz__()<<"id"<
if(t<0){f.pz__()<
}


void genlog(temp& f, int type){

string oper;


switch(type){

case 7:oper="==";break;

case 11:oper="<";break;

case 12:oper=">";break;

case 13:oper="<=";break;

case 14:oper=">=";break;}

getl(f);

f.ob__()<<"booltemp=(logvar1"<
f.pz__()<<"lv1 lv2 "<<"&"<

}

//генерация цикла

void cikltop(temp& f){f.ob__()<<"while(booltemp){"<
void cikllef(temp& f){f.ob__()<<"}"<

рекурсивные функции синтаксического анализа


bool program(temp& f);

bool declar(temp& f);

bool mdeclar(temp& f);

bool body(temp& f);

bool listid(temp& f);

bool mlistid(temp& f);

bool operators(temp& f);

bool oper(temp& f);

bool cickl(temp& f);

bool dec(temp& f);

bool decf(temp& f);

bool inp(temp& f);

bool outp(temp& f);

bool expr(temp& f);

bool sum(temp& f);

bool mul(temp& f);

bool wbody(temp& f);

bool logexp(temp& f);


string intab(string tn, int n){

ifstream f(tn.c_str());

string buf;

for(int i=0;i!=n-1;i++){

f>>buf;}

f.close();

return buf;}


bool program(temp& f)

{


int ter=0;

ter=f.gt();

if(ter!=28){return false;}

ter=f.gt();

if(ter<=35){return false;}

//Семантика-------------------

programA(f,ter);

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


ter=f.gt();

if(ter!=9){return false;}

if(declar(f)){

if(!body(f)){return false;}

return true;

}

if(!body(f)){return false;}


return true;

}

bool declar(temp& f)

{

int ter=0;

ter=f.gt();

if(ter!=21){f.seekg(-1);return false;}

ter=f.gt();

if(ter!=8){f.seekg(-2);return false;}

if(!listid(f)){return false;}

mlistid(f);

ter=f.gt();

if(ter!=8){f.seekg(-3);return false;}

ter=f.gt();

if(ter!=23){f.seekg(-4);return false;}

ter=f.gt();

if(ter!=9){f.seekg(-5);return false;}

mdeclar(f);

return true;


}

bool mdeclar(temp& f){

if(declar(f)){mdeclar(f);}

return true;}


bool body(temp& f){

int ter=0;

//Semantik

topbody(f);

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

ter=f.gt();

if(ter!=22){f.seekg(-1);return false;}

ter=f.gt();

if(ter!=8){f.seekg(-2);return false;}

if(!operators(f)){return false;}

operators(f);

ter=f.gt();

if(ter!=24){f.seekg(-3);return false;}

ter=f.gt();

if(ter!=16){f.seekg(-4);return false;}

//semantik

lbody(f);

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

return true;}


bool listid(temp& f){

int ter=0;

ter=f.gt();

if(ter<=35){f.seekg(-1);return false;}

//mlistid(f);

return true;}

bool mlistid(temp& f){

int ter=0;

//Семантика------------

f.seekg(-1);

ter=f.gt();

declarA(f, ter-37);

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

ter=f.gt();

if(ter!=10){f.seekg(-1);return false;}

if(!listid(f)){return false;}

mlistid(f);

return true;}


bool operators(temp& f){

if(oper(f)){operators(f);}

return true;}


bool oper(temp& f){

int ter=0;

if(declar(f)){return true;}

if(cickl(f)){return true;}

if(dec(f)){return true;}

if(inp(f)){return true;}

if(outp(f)){return true;}

return false;}


bool dec(temp& f){

int ter=0;

int id=0;

int d=0;

ter=f.gt();

if(ter<=35){f.seekg(-1);return false;}


id=ter;

ter=f.gt();

if(ter!=15){f.seekg(-2);return false;}

if(expr(f)){

d=f.gt();

if(d!=9){f.seekg(-3);return false;}

//semantic

decA(f, id);

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

return true;}

}


bool decf(temp& f){

int ter=0;

int d=0;

ter=f.gt();

if(ter<=35){f.seekg(-1);return false;}

ter=f.gt();

if(ter!=15){f.seekg(-2);return false;}

ter=f.gt();

if(expr(f)){ return true;}

if(ter<0){ return true;}

if(ter>35){ return true;}


return false;}


bool inp(temp& f){

int ter=0;

ter=f.gt();

if(ter!=30){f.seekg(-1);return false;}

ter=f.gt();

if(ter!=5){f.seekg(-2); return false;}

if(!listid(f)){f.seekg(-3); return false;}

input(f);

ter=f.gt();

if(ter!=6){f.seekg(-4); return false;}

ter=f.gt();

if(ter!=9){f.seekg(-5);return false;}

return true;}


bool outp(temp& f){

int ter=0;

ter=f.gt();

if(ter!=31){f.seekg(-1);return false;}

ter=f.gt();

if(ter!=5){f.seekg(-2); return false;}

if(!listid(f)){f.seekg(-3); return false;}

output(f);

ter=f.gt();

if(ter!=6){f.seekg(-4); return false;}

ter=f.gt();

if(ter!=9){f.seekg(-5);return false;}

return true;}


//Arifmetical expression

bool expr(temp& f){

int ter=0;

if(!sum(f)){return false;}

ter=f.gt();

if(ter==2||ter==1){

if(expr(f)){

expr_(f,ter);

return true;}

else{f.seekg(-1);return false;}

}

f.seekg(-1);

return true;}


bool sum(temp& f){

int ter=0;

if(!mul(f)){return false;}

ter=f.gt();

if(ter==3||ter==4){

if(sum(f)){expr_(f,ter);return true;}

else{f.seekg(-1);return false;}

}

f.seekg(-1);

return true;}


bool mul(temp& f){

int ter=0;

ter=f.gt();

if(ter>35||ter<0){expr_(f,ter);return true;}

if(ter!=5){f.seekg(-1); return false;}

if(!expr(f)){return false;}

ter=f.gt();

if(ter!=6){f.seekg(-2); return false;}


return true;

}

//END arifmetical expration

bool cickl(temp& f){

int ter=0;

ter=f.gt();

if(ter!=27){f.seekg(-1); return false;}

ter=f.gt();

if(ter!=8){f.seekg(-2); return false;}

if(!logexp(f)){return false;}

ter=f.gt();

if(ter!=8){f.seekg(-3); return false;}

ter=f.gt();

if(ter!=26){f.seekg(-4); return false;}

cikltop(f);

if(!wbody(f)){return false;}

cikllef(f);

return true;}


bool logexp(temp& f){

int ter=0;

//stan(f, 1);

if(!expr(f)){return false;}

stan(f, 1);

ter=f.gt();

if(ter!=11&&ter!=12&&ter!=13&&ter!=14&&ter!=7){f.seekg(-1);return false;}

//stan(f, 2);

if(!expr(f)){return false;}

stan(f, 2);

genlog(f, ter);

return true;}


bool wbody(temp& f){

int ter=0;

ter=f.gt();

if(ter!=22){f.seekg(-1);return false;}

ter=f.gt();

if(ter!=8){f.seekg(-2);return false;}

getl(f);

if(!operators(f)){return false;}

operators(f);

ter=f.gt();

if(ter!=24){f.seekg(-3);return false;}

ter=f.gt();

if(ter!=9){f.seekg(-4);return false;}

onlexp(f);

getl(f);

return true;}


int _tmain(int argc, _TCHAR* argv[])

{

temp p("pr", "pz.txt" , "obj.txt");

p.pz__()<<"#0"<
if(program(p)){cout<<"Generation complite"<
else{cout<<"Sintex error"<
p.pz__()<<"@"<

_getch();

return 0;

}

Приложение 2


Тестирование транслятора.

Тестирование сканера.


Исходный файл


program test;

begin:

var: a, b, с :integer;

a:=b;

read(a);

a:=a+b*(c-a/b);

while: a<10 :do

begin:

write(a);

a:=a+1;

end;

end.


Файл отчета сканера


<28>


<37>

<9><;>

<22>

<8><:>

<21>

<8><:>

<38>

<10><,>

<39>

<10><,>

<40><с>

<8><:>

<23>

<9><;>

<37>


<15><:=>

<38>

<9><;>

<30>

<5><(>

<37>


<6><)>

<9><;>

<37>


<15><:=>

<37>


<1><+>

<38>

<3><*>

<5><(>

<41>

<2><->

<37>


<4>

<38>

<6><)>

<9><;>

<27>

<8><:>

<37>


<11><<>

<-2><10>

<8><:>

<26>

<22>

<8><:>

<31>

<5><(>

<37>


<6><)>

<9><;>

<37>


<15><:=>

<37>


<1><+>

<-3><1>

<9><;>

<24>

<9><;>

<24>

<16><.>


Результат работы сканера


28 37 9 22 8 21 8 38 10 39 10 40 8 23 9 37 15 38 9 30 5 37 6 9 37 15 37 1 38 3 5 41 2 37 4 38 6 9 27 8 37 11 -2 8 26 22 8 31 5 37 6 9 37 15 37 1 -3 9 24 9 24 16 0

Тестирование синтаксического и семантического анализатора



Входной поток анализатора


28 37 9 22 8 21 8 38 10 39 10 40 8 23 9 37 15 38 9 30 5 37 6 9 37 15 37 1 38 3 5 41 2 37 4 38 6 9 27 8 37 11 -2 8 26 22 8 31 5 37 6 9 37 15 37 1 -3 9 24 9 24 16 0


Польская запись (# - метка, & - метка как параметр, @ - конец записи)

0#

id1 dec

id2 dec

id3 dec

id2 id1 init

id1 input

id1 id2 id5 id1 id2 / - * + id1 init

id1 lv1 initinv

10 lv2 initinv


1#

lv1 lv2 &2 &3 <


2#

id1 out

id1 1 + id1 init

&1 jmp


3#

@


Объектный код на языке С.


#include

#include

/*Proggram name: test*/

void main(void){

int temp=0;

bool booltemp=false;

int id1;

int id2;

int id3;

id1=id2;

scanf("%d",id1);

int temp0=id1/id2;

int temp1=id5-temp0;

int temp2=id2*temp1;

int temp3=id1+temp2;

id1=temp3;

int logvar1=id1;

int logvar2=10;

booltemp=(logvar1
while(booltemp){

printf("%d",id1);

int temp4=id1+1;

id1=temp4;

}

return 0;}