Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Современные проблемы информатики и ВТ

..pdf
Скачиваний:
2
Добавлен:
05.02.2023
Размер:
309.15 Кб
Скачать

Министерство образования и науки РФ

Федеральное государственное бюджетное образовательное учреждение высшего профессионального образования

«Томский государственный университет систем управления и радиоэлектроники» (ТУСУР)

Методические указания по выполнению практических и самостоятельных работ по дисциплине «Современные проблемы информатики и ВТ»

Для специальностей:

230100 - «Информатика и вычислительная техника»

Факультет: экономический Профилирующая кафедра: экономической математики, информатики и статистики

Обеспечивающая кафедра: экономической математики, информатики и статистики

Разработчик:

доц. каф. ЭМИС Стась А.Н.

2012 г.

1

Содержание

 

Лексический анализ..................................................................................................................

3

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

7

Простейшие приемы оптимизации грамматики......................................................................

8

Анализ текста программы по КС-грамматике.........................................................................

9

Построение LL-анализатора по грамматике..........................................................................

10

Проверка выражений..............................................................................................................

14

Интерпретация ОПЗ................................................................................................................

17

ОПЗ и машинно-независимая оптимизация...........................................................................

20

Генерация команд...................................................................................................................

21

Тетрадное и триадное представления и их получение..........................................................

21

2

Лексический анализ

 

 

 

 

 

 

 

 

Основная

задача

лексического

анализа - разбить входной текст,

состоящий

из

последовательности одиночных

символов,

на

последовательность слов,

или

лексем,

т.е. выделить эти слова

из

непрерывной

 

последовательности

символов. Лексический

анализатор

иногда называют сканером.

Все

символы входной последовательности

с

этой точки зрения разделяются на символы,

принадлежащие

каким-либо

лексемам, и

символы, разделяющие лексемы (разделители). Обычно все

лексемы делятся на классы.

 

 

 

 

 

 

 

Примерами лексем

являются

числа

(целые,

восьмеричные,

 

шестнадцатиричные, действительные и т.д.), идентификаторы, комментарии, операнды. Отдельно выделяются ключевые слова и символы пунктуации (иногда их называют символы-ограничители). Как правило, ключевые слова - это некоторое конечное подмножество идентификаторов. Другие типы идентификаторов – имена переменных. В некоторых языках (например, ПЛ/1) смысл лексемы может зависеть от ее контекста и невозможно провести лексический анализ в отрыве от синтаксического.

С точки зрения дальнейших фаз анализа лексический анализатор

выдает информацию

двух

сортов: о

последовательности лексем и о

конкретных

значениях отдельных лексем

(идентификаторов,

констант и

т.д.). Как

приавило

строятся таблицы

объектов – идентификаторов,

констант, ключевых слов и т.д . Комментарии выбрасываются.

 

Работа

лексического

анализатора

описывается

с помощью

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

Опишем лексику простейшего языка программирования.

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

; разделителиоператоров Присваивание :=

Операции бинарные: +, -, *, / (div), \ (mod),<,>,<=,>=,!=,= (рез – 0,1) A[i] – доступ к элементу массива – индексация (начальный индекс – 0). Комментарии: |*…….*| Команды:

INPUT <перем> - ввод

OUTPUT <выр> - вывод

IF <выр> THEN <оператор 1> [ELSE <оператор 2>] WHILE <выр> DO <оператор>;

{составной оператор} (в паскале BEGIN…END)

FUNC<назв>(<параметр>) – начало функции

3

RET возвр. Знач. – возврат из функции

<назв. Функ.>(<парам>) – вызов функции внутри выражения. HALT – прекращение выполнения программы.

Пример 1. Вычисление суммы от 1 до N

IINPUT n; s:=0; i:=1;

WHILE i<n DO { s:=s+i;

i:=i+1

}; OUTPUT s HALT;

Пример 2. Вычисление факториала.

INPUT N;

OUTPUT fact(n);

HALT;

FUNC fact(k);

IF k=1 THEN RET 1 ELSE RET(k*fact(k-1));

Описание лексики с помощью конечного автомата

 

a..z,

0..9

;

п

+,-

(

)

[

]

:

=

>,<

!

|

*

{

}

 

A..Z

 

 

 

,/,\,

 

 

 

 

 

 

 

 

 

 

 

 

S

A

B

S

S

S

S

S

S

S

C

S

D

E

F

S

S

S

A

A

A

S

I

S

S

S

S

S

C

S

D

E

F

S

S

S

 

 

 

 

 

 

(ф-

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ция)

 

 

 

 

 

 

 

 

 

 

 

B

Ош

B

S

S

S

Ош

S

Ош

S

Ош

S

D

E

F

S

Ош

S

С

Ош

Ош

Ош

Ош

Ош

Ош

Ош

Ош

Ош

Ош

S

Ош

Ош

F

Ош

Ош

Ош

 

 

 

 

 

 

 

 

 

 

 

(:=)

 

 

 

 

 

 

D

A (<,>)

B

Ош

S

Ош

Ош

Ош

Ош

Ош

Ош

S

Ош

Ош

F

Ош

Ош

Ош

 

 

(<,>)

 

(<,

 

 

 

 

 

 

(<=,

 

 

 

 

 

 

 

 

 

 

>)

 

 

 

 

 

 

>=)

 

 

 

 

 

 

E

Ош

Ош

Ош

Ош

Ош

Ош

Ош

Ош

Ош

Ош

S

Ош

Ош

F

Ош

Ош

Ош

 

 

 

 

 

 

 

 

 

 

 

(!=)

 

 

 

 

 

 

F

Ош

Ош

Ош

Ош

Ош

Ош

Ош

Ош

Ош

Ош

Ош

Ош

Ош

Ош

G

Ош

Ош

G

G

G

G

G

G

G

G

G

G

G

G

G

G

G

H

G

G

H

G

G

G

G

G

G

G

G

G

G

G

G

G

Кон

G

G

G

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ком

 

 

 

I

A

B

S

I

S

S

S

S

S

C

S

D

E

F

S

S

S

 

(нов)

(нов)

 

 

 

(ф-

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ция)

 

 

 

 

 

 

 

 

 

 

 

S- выделение лексемы

4

A – выделение идентификатора или ключевого слова.

B – выделение числовой константы

C – Возможно присваивание

D – простые или составные операции сравнения <,>,<=,>=

E – возможно операция “!=”.

F- возможно комментарий

G – комментарий

H – возможен конец комментария

I – возможен вызов функции

Таблица ключевых слов: K1 - INPUT

K2 - OUTPUT

K3 - IF

K4 – THEN

K5 - ELSE

K6 - WHILE

K7 - DO

K8 - FUNC

K9 - RET

K10 - HALT.

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

Лексический анализатор, как правило, вызывается как подпрограмма.

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

В некоторых языках (например, ПЛ/1 или Фортран) ключевые слова Обратим внимание на некоторые моменты работы с нашим языком. По окончании выделения идентификатора, проверяем имя в таблице ключевых слов. Если идентификатор заканчивается “(“ – имя функции между возможны пробелы, поэтому при подозрении на данный случай необходима задержка выделения идентификатора (нетерминал I)). Ключевые слова заменяем их кодами. Переменные и константы вносим в таблицы и заменяем ссылками на элементы таблицы. Сложные операнды (больше 1-го символа заменяем на одиночные символы).

5

Обратим внимание, что по окончании комментария мы должны обеспечить возврат в точку, предшествующую началу комментария. При нахождении ув состоянии «возможен комментарий» прекращается генерация символов 1-го внутреннего представления.

Примеры 1-х внутренних представлений.

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

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

Например, := - @, <= - ~, >= $, != - ^

Пример 1. Вычисление суммы от 1 до N

INPUT n;

K1I1;

s:=0;

I2@C1;

i:=1;

I3@C2;

WHILE i<=n DO {

K6I3~I1K7{

s:=s+i;

I2@I2+I3;

i:=i+1

I3@I3+C3

};

};

OUTPUT s

K2I2;

HALT;

K10;

 

$C1=0$C2=1$C3=1

Пример 2. Вычисление факториала.

 

 

INPUT n;

K1I1;

OUTPUT fact(n);

K2F1(I1);

HALT;

K10;

FUNC fact(k);

K8F1(I2);

IF k=1 THEN RET 1 ELSE

K3I2=C1K4K9C2K5

RET k*fact(k-1);

K9I2*F1(I2-C3);

 

$C1=1$C2=1$C3=1

6

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

Задачи синтаксического анализа.

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

Синтаксис языков программирования, чаще всего описывается контекстносвободной грамматикой, хотя бывают и исключения (shell – автоматный синтаксис, ALGOL-60 – КЗ-синтаксис). Очевидно, что задача является расширением задачи анализа КС-языка.

Описание синтаксиса языка

Опишем синтаксис нашего языка:

<программа>:-{<оператор>;}*[оператор] <оператор>:-<составной оператор>|<простой оператор> <составной оператор>:-{<программа>} <простой оператор>:-<присваивание>| <ввод>| <вывод>| <условный

оператор>| <цикл c предусловием> |<заголовок функции>| <возврат из функции>| <останов> <присваивание>:-<переменная>:=<выражение>

<ввод>:-INPUT <переменная>

<вывод>:-OUTPUT <выражение>

<условный оператор>:-IF <выражение> THEN <оператор> [ELSE <оператор>]

<цикл с предусловием>:-WHILE <выражение> DO <оператор> <заголовок функции>:-FUNC <имя функции> (<имя переменной>) <возврат из функции>:-RET <выражение>

<останов>:-HALT <выражение>:-<операнд>| (<выражение>) | <выражение><операция><выражение>

<операнд>:-<переменная>| <константа>| <вызов функции> <операция>:- +| -| *| /| \| <| >| <=|>=| =| != <переменная>:- <имя переменной>| <имя переменной>[<выражение>] <вызов функции>:- <имя функции>(<выражение>)

7

Замеч. Лишние пробелы, комментарии, переводы строки и т.д. удалены на этапе лексического анализа.

Описание синтаксиса в виде КС-грамматике.

От описания в форме Б-Н легок перйти к описанию в виде КС-грамматики, с учетом представления на первом внутреннем языке:

В нашем случае имеем:

S-> A;S| A| л

A-> B| C

B-> {S}

С –> D | E | F |G | H| I| J| K

D-> L@M

E-> k1L

F-> k2M

G->k3Mk4A|k3Mk4Ak5A

H-> k6Mk7A

I-> k8N(O)

J-> k9M

K-> k10

L-> O| O[M]

M-> P | (M)| MRM

N-> fT

O-> iT

P-> L| U| V

R -> +| -| *| /| \| <| >| ~| $| =| ^

T-> 0T| 1T |…..| 9T| 0| 1|…| 9

U-> cT

V-> N(M)

S – программа (последовательность операторов)

A – оператор

B – составной оператор

C – простой оператор

D – присваивание E – ввод

F – вывод

G – условный оператор

H – цикл с предусловием

I – заголовок функции

J – возврат из функции K – останов

L – переменная

M – выражение

N – имя функции

O – имя переменной P – операнд

R – операция

T – номер (константы, переменной, ключевого слова или функции)

U – константа

V – вызов функции

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

Простейшие приемы оптимизации грамматики

Простейшим способом оптимизации является уменьшение числа нетерминалов за счет упразднения тривиальных правил типа A -> B с

8

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

Проведем преобразования для нашей грамматики:

S-> A;S| A| л

S -> A;S| A| л

A -> B| C

A -> {S}| L@M| k1L| k2M| k3Mk4A|

B -> {S}

k3Mk4Ak5A| k6Mk7A| k8N(O)| k9M| k10

С –> D | E | F |G | H| I| J| K

L -> O| O[M]

D -> L@M

M -> L | U | V| (M)| MRM

E -> k1L

N -> fT

F -> k2M

O -> iT

G ->k3Mk4A|k3Mk4Ak5A

R -> +| -| *| /| \| <| >| ~| $ =| ^

H -> k6Mk7A

T -> oT| 1T|….| 9T| 0| 1|…| 9

I -> k8N(O)

U -> cT

J -> k9M

V -> N (M)

K -> k10

 

S -> A;S| A| л

L -> O| O[M]

A -> {S}| L@M| k1L| k2M| k3Mk4A|

M -> P | (M)| MRM

k3Mk4Ak5A| k6Mk7A| k8N(iT)| k9M| k10

N -> fT

L -> iT| iT[M]

O -> iT

M -> iT | iT[M]| cT| N(M)| (M)| MRM

P -> L| U| V

N -> fT

R -> +| -| *| /| \| <| >| ~| $| =| ^

R -> +| -| *| /| \| <| >| ~| $ =| ^

T -> 0T| 1T |…..| 9T| 0| 1|…| 9

T -> oT| 1T|….| 9T| 0| 1|…| 9

U -> cT

 

V -> N(M)

 

 

 

Таким образом, мы получаем формальную грамматику, в соответствие с которой будем анализировать синтаксис. Для простоты сначала рассмотрим относительно простую задачу анализа текста программы на наличие синтаксических ошибок, которая как легко видеть сводится к обычному КС-анализу. Общие подходы к решению этой задачи были рассмотрены в рамках дисциплины ТА. Этот подход предполагает моделирование построение ие и моделирование МА. Здесь, мы подробнее рассмотрим применяемые на практике частные методике, как мы увидим частные случаи применения МА, позволяющие достичь линейно трудоемкости анализа с помощью детерминированного алгоритма (алгоритм МА недетерминированный).

Анализ текста программы по КС-грамматике

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

Левый и правый проходы определяются прямым или обратным просмотром цепочки. На практике чаще применяют левые проходы.

9

Левое порождение генерируется, если в каждый момент раскрывается самый левый нетерминал, правое порождение соответственно моделируется, если в каждый момент раскрывается самый правый нетерминал.

На примерах легко увидеть что нисходящий анализ генерирует левое порождение, а восходящий – правое.

В соответствие с типами проходов и порождений различают типы алгоритмов: LL, LR, RL, RR.

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

Построение LL-анализатора по грамматике.

Идея детерминированного LL-анализатора: цепочка просматривается слева направо (от начала программы к концу), моделируется левое порождение, т.е. применяется нисходящий анализ. Детерминированность алгоритма пытаемся обеспечить на основании текущего символа входной цепочки, и возможно нескольких символов за текущим. Обратим внимание, что неоднозначными могут быть только операции замены нетерминала в стеке.

Рассмотрим подробнее идею на примере:

S -> S+S| S*S| (S)|a a+(a*a)+(a*a)+a

Глядя на эту грамматику, очень трудно предположить, как сделать первый переход в зависимости от символа входной цепочки (к-й очевидно может быть только символом “a”). Главной причиной неудобства является левая рекурсия, т.е. возможность вывода нетерминала из самого себя без сдвига по входной цепочке за конечное число применения Л-переходов.

Примеры левой рекурсии: S->S+S

S->S*S (за 1 переход)

S → Aa

A → Bb | f B → Cc C → Dd | e

D → Az

Здесь леворекурсивный цикл, вовлекающий A, B, C, D.

Чтобы заменить этот цикл прямой

левой рекурсией, упорядочим

нетерминалы следующим образом: S, A, B, C, D.

 

Рассмотрим все порождающие правила вида

 

10