- •1. Постановка задачи
- •Задание 10
- •2. Описание входного языка
- •2.1. Синтаксис входного языка
- •2.2. Семантика входного языка
- •2.2.1.Встроенные типы данных входного языка
- •2.2.2.Операции входного языка и их приоритет
- •2.2.3.Конструкции входного языка
- •3. Описание этапа лексического анализа.
- •3.1. Определение типов лексем.
- •3.2. Определение синтаксиса лексем
- •3. Описание этапа синтаксического анализа.
- •3.1 Построение кс-грамматики входного языка.
- •3.2 Определение класса кс-грамматики входного языка.
- •3.3 Постоение таблиц переменных, меток, констант и векторов
- •3.4 Описание промежуточного языка.
- •3.5 Неформальное описание перевода
- •Построение транслирующей грамматики
- •Построение атрибутной транслирующей грамматики
- •Построение атрибутного дмп-процессора
- •Тестирование атрибутного дмп-процессора
3. Описание этапа лексического анализа.
На входе лексического анализатора находится последовательность ASCII символов, представляющая программу на входном языке. Задача ЛА состоит в разделении этой последовательности на слова языка (лексемы).
чтение исходной программы и выделение из нее лексем;
построение таблиц идентификаторов и констант;
преобразование входной программы (поток символов) в поток токенов, в котором каждый токен представляет лексему.
Если в исходной программе при записи лексем были допущены ошибки, лексический анализатор для каждой ошибки должен локализовать место ошибки, выполнить действия по нейтрализации ее последствий и выдать пользователю сообщение об ошибке.
3.1. Определение типов лексем.
Лексический анализатор исключает из текста исходной программы:
- незначащие (повторные) пробелы;
- символы табуляции и перевода строки;
- комментарии (между символами #).
Лексический анализатор не учитывает регистр символа.
Выделяются лексемы следующих типов:
идентификаторы (последовательность букв, не начинающаяся с цифры)
константы (числовые – целые, вещественные)
ключевые слова (void, main, if, else, for, printf, scanf, const, int, float, bool, goto, typedef)
знаки операций (+ - ++ -- ~~ * / && || ! = += -= *= /= < > >= <= == !=)
разделители ( , . ?: ; ( ) [ ] { } )
3.2. Определение синтаксиса лексем
Синтаксис лексем описывается с помощью автоматных грамматик.
Определим типы токенов, записываемых в выходной поток.
Токен |
Лексемы |
Языковая конструкция |
ID |
gfd kj8 jg45gcv … |
Последовательность букв и цифр, не начинающаяся с цифры. |
Lab | ||
CB |
0 1 |
Логические константы |
CI |
123 3426 5 … |
Целочисленные константы |
CF |
12.456 3.08 0.453 … |
Вещественные константы |
Str |
“jhgjhvg” |
Строковые константы |
IF |
if |
Ключевое слово IF |
ELSE |
else |
Ключевое слово ELSE |
MAIN |
main |
Ключевое слово MAIN |
VOID |
void |
Ключевое слово VOID |
FOR |
for |
Ключевое слово FOR |
GOTO |
goto |
Ключевое слово GOTO |
PRINTF |
printf |
Ключевое слово PRINTF |
SCANF |
scanf |
Ключевое слово SCANF |
TYPEDEF |
typedef |
Ключевое слово TYPEDEF |
CONST |
const |
Ключевое слово CONST |
Type |
int, float, bool |
Базовые типы данных |
Vector |
vector |
Ключевое слово Vector |
GOp |
+= -= *= /= = |
Отношение присваивания |
AddOp |
+ - |
Аддитивная операция |
MOp |
* / |
Мультипликативная операция |
RelOp |
< > <= >= == != |
Операция отношения |
UnOp |
++ -- ~~ |
Унарная операция |
LogOp |
&& || ! |
Логическая операция |
( |
( |
Разделитель ( |
) |
) |
Разделитель ) |
{ |
{ |
Разделитель { |
} |
} |
Разделитель } |
[ |
[ |
Разделитель [ |
] |
] |
Разделитель ] |
, |
, |
Разделитель , |
. |
. |
Разделитель . |
; |
; |
Разделитель ; |
Sep |
: ? |
Разделители для условного присваивания |
Разработаем структуры данных (таблицы) для хранения лексем различных типов.
1 |
Идентификатор (ID), метка (Lab)
Индекс Значение 0
…
n
|
|
| ||||||||||||||||||||||||||||||||||||||||||||||
2 |
Целочисленная
константа (CI)
Индекс Значение 0
…
m
|
3 |
Вещественная константа (CF)
Индекс Значение 0
…
k
| ||||||||||||||||||||||||||||||||||||||||||||||
4 |
Ключевое слово (KeyW)
|
5 |
Разделитель (Separator)
| ||||||||||||||||||||||||||||||||||||||||||||||
6 |
Логическая операция (BOp)
|
7 |
Описатель (Type)
| ||||||||||||||||||||||||||||||||||||||||||||||
8 |
Унарная операция (UnOp)
|
9 |
Операция типа + (AOp)
| ||||||||||||||||||||||||||||||||||||||||||||||
10 |
Операция типа * (MOp)
|
11 |
Строковая константа (Str)
Индекс Значение 0
…
t
| ||||||||||||||||||||||||||||||||||||||||||||||
12 |
Отношение (Rel)
|
13 |
Оператор присваивания (GOp)
|
Определим классы литер входного языка (литеры из одного класса одинаковым образом используются для образования лексем):
-
класс
терм. символ
литеры
латинская буква
a
a b c … z A B C …Z
цифра
n
0 1 2 3 4 5 6 7 8 9
операция типа +
+
+ -
операция типа *
*
* /
отицание
!
!
отношение
>
> <
операция типа и
&
| &
разделитель
,
( ) [ ] { } , . : ; ?
длина
~
~
кавычка1
“
“
кавычка2
”
”
знак комментария
#
#
Определим внешние спецификации процедур, описывающих семантику перевода исходного текста программы в строку токенов. Токен будем представлять в виде двух чисел – номера таблицы и индекса в ней.
FormToken – формирует лексему (по приведенному ниже автомату), обращается к другим функциям для работы с таблицами, формирования и вывода токена во входной поток.
ReadL - читает очередную литеру из входного потока, определяет и возвращает ее класс (см. пп. 3).
F_ID (lex) – обрабатывает прочитанную лексему-идентификатор: ищет ее в таблице ключевых слов (KeyW, № 4), если находит – формирует токен, соответствующий ключевому слову – (4 x), где x – номер ключевого слова в таблице . Иначе ищет лексему в таблице типов (Type, №7), если находит, формирует токен (7 x) c соответствующим номером x. Иначе ищет лексему в таблице идентификаторов (ID, № 0), если находит, формирует соответствующий токен (0 x), если нет, то добавляет запись в таблицу идентификаторов и формирует токен (0 n+1), где k – номер последнего идентификатора в таблице до добавления записи.
F_C (i, lex) - обрабатывает прочитанную лексему-число. Если i=0, то ищет в таблице целых чисел (CI, № 1), если i=1 – в таблице вещественных (CF, № 2). Если находит, формирует соответствующий токен (1 x) для целого числа, где x – его номер или (2 y) для вещественного (y – его номер), если нет, то добавляет запись в таблицу и формирует токен (1 n+1) или (2 m+1).
F_Str (lex) - обрабатывает прочитанную лексему-строку. Ищет в таблице строковых констант (Str, № 14). Если находит, формирует соответствующий токен (14 x), если нет, то добавляет запись в таблицу и формирует токен (14 n+1).
F_O (k, lex) – обрабатывает полученную лексему. Ищет лексему в таблице № k, формирует и выводит в выходной поток токен (k x) с найденным индексом x и заданным номером таблицы k.
Построим диаграммы конечных автоматов для каждой лексемы. Начальное состояние – S. Некоторые переходы нагружены процедурами, описанными выше. Некоторые из автоматов объединены.
идент-ры, кл. слова |
цел. и вещ. константы |
+ - ++ -- += -= |
1* - F_ID; |
1* - F_C (0); 2* - F_C (1) |
1* - F_O (9); 2* - F_O (8) 3* - F_O (13). |
! != |
> < >= <= == |
* / *= /= = |
1* - F_O (6); 2* - F_O (12) |
1* - F_O (12) |
1* - F_O (10); 2* - F_O (13) |
~~ |
&& || |
разделители |
1* - F_O (3) |
1* - F_O (8) |
1* - F_O (5) |
строковые константы |
комментарии |
|
| ||
1* - F_Str |
|
|
Построим общую диаграмму лексического анализатора (конечный автомат).
Тестирование лексического анализатора.
Возьмем в качестве контрольного примера следующую программу на входном языке:
int a=3.2;
vector b[3];
void main()
{
b=[7 a 0.8];
if (b[2]==a)
printf (“a=”,a);
}
В результате работы лексического анализатора получим таблицы:
0 |
Идентификатор (ID)
Индекс Значение 0 a 1 b |
1 |
Цел. константа
(CI)
Индекс Значение 0 3 1 7 2 2 |
2 |
Вещ.константа (CF)
Индекс Значение 0 3.2 1 0.8 | ||||||||||||||||||||
11 |
Строковая константа (Str)
Индекс Значение 0 a= |
|
|
|
|
И поток токенов на выходе:
(7 0) |
int |
(5 6) |
) |
(1 2) |
2 | |
(0 0) |
a |
(5 7) |
{ |
(5 4) |
] | |
(11 4) |
= |
(0 1) |
b |
(12 4) |
== | |
(2 0) |
3.2 |
(11 4) |
= |
(0 0) |
a | |
(5 2) |
; |
(5 3) |
[ |
(5 6) |
) | |
(4 10) |
vector |
(1 1) |
7 |
(4 8) |
printf | |
(0 1) |
b |
(0 0) |
a |
(5 5) |
( | |
(5 3) |
[ |
(2 1) |
0.8 |
(11 0) |
“a=” | |
(1 0) |
3 |
(5 4) |
] |
(5 0) |
, | |
(5 4) |
] |
(5 2) |
; |
(0 0) |
a | |
(5 2) |
; |
(4 2) |
if |
(5 6) |
) | |
(4 0) |
void |
(5 5) |
( |
(5 2) |
; | |
(4 1) |
main |
(0 1) |
b |
(5 8) |
} | |
(5 5) |
( |
(5 3) |
[ |
|
|