- •2.1. Входная грамматика в структурированной форме
- •2.2. Су-схема и транслирующая грамматика
- •2.3. Функции переходов преобразователя
- •3.1. Грамматика лексических единиц и структура лексем
- •3.2. Диаграмма состояний лексического анализатора
- •3.3. Структуры данных и символы действия
- •4.1. Неформальное описание семантики
- •4.2. Атрибутная грамматика
- •4.3. Описание символов действия
- •4.4. Пример вывода в атрибутной грамматике.
- •5.1. Построение функций переходов атрибутного преобразователя.
- •5.2. Построение инструкций атрибутного преобразователя.
4.1. Неформальное описание семантики
После работы лексического анализатора на вход атрибутного преобразователя будут подаваться лексемы. На этапе описания переменных, мы должны сформировать таблицу значений, выделить под каждую описанную переменную память в этой таблице и записать в таблице переменных ссылку на ячейку в таблице значений.
Таблица переменных будет совпадать с таблицей идентификаторов, но в структуру каждого элемента таблицы идентификаторов добавим поле с указателем на элемент таблицы значений.
Когда на вход подается цепочка лексем, мы находим идентификатор переменной из описания, который имеет атрибут, указывающий на таблицу идентификаторов (ТИ), смотрим была ли описана эта переменная ранее. Если была, то выход с кодом ошибки. Если нет, то создаем элемент таблицы переменных и записываем в структуру переменной ее тип; выделяем память, соответствующую ее типу, в таблице значений и записываем ссылку в структуру переменной. Также необходимо занести информацию о том, что это – переменная (установить количество элементов = 1).
Если мы описываем массив, то мы в структуру переменной в ТП заносим информацию о массиве (количество элементов). После этого выделяем память в ТЗ, состоящей из N элементов (N – количество элементов в массиве). И далее записываем указатель в ТП на начало этого поля памяти (первый элемент массива).
Операции могут выполняться с двумя типами данных Boolean и Char. Операции не могут выполняться, если в них используются операнды различного типа. Чтобы это учесть, введем в структуру ячейки памяти поле TypeZ (TChar, TBool), которое и будет указывать нам тип переменной, значение которой хранится в данной ячейке. Также в выполнении операции не могут участвовать переменные и элементы массива, которые не имеют значения (не инициализированы).
При работе с массивами необходимо проверять индексы элементов массивов при обращении к ним на допустимые значения.
4.2. Атрибутная грамматика
<I>↓a1 ↑b1 ::=<Vars> ↓a2 ↑b2 <Code> ↓a3 ↑b3
a2=a1; a3=b2; b1=b3;
<MasBool>↓a4 ↑b4 ↑x1 ::=’<arr>’ <Id>↑x2 ’,’ <Chislo>↑y1 {WrRM}↓x3 ↓y2 {FMB}↓a5 ↑b5 ↓x4 ’</arr>’
a5=a4; b4=b5; (x1, x3, x4)=x2; y2=y1;
< MasChar>↓a6 ↑b6 ↑x5 ::=’<arr>’ <Id>↑x6 ’,’ <Chislo>↑y3 {WrRM}↓x7 ↓y4 {FMC}↓a7 ↑b7 ↓x8 ’</arr>’
a7=a6; b6=b7; (x5, x7, x8)=x6; y4=y3;
<ElMas>↑t1 ::=’<earr>’<Id>↑x9 ’,’ <Chislo>↑y5 {FUkTZEM}↓x10 ↓y6 ↑t2 ’</earr>’
t1=t2; x10=x9; y6=y5;
<Vars>↓a8 ↑b8 ::=’<boolean>’<NamesBool>↓a9 ↑b9 ’</boolean>’<R3>↓a10 ↑b10
b8=b10; a9=a8; a10=b9;
<Vars>↓a11 ↑b11 ::=’<char>’<NamesChar>↓a12 ↑b12 ’</char>’<R3>↓a13 ↑b13
b11=b13; a12=a11; a13=b12;
<R3>↓a14 ↑b14 ::=<Vars>↓a15 ↑b15
a15=a14; b14=b15;
<R3>↓a16 ↑b16 ::=$
b16= a16;
<NamesBool>↓a17 ↑b17 ::=<Id>↑x11 {NewB}↓a18 ↑b18 ↓x12 <R4>↓a19 ↑b19
b17=b19; a18=a17; a19=b18; x12=x11;
<NamesBool>↓a20 ↑b20 ::=<MasBool>↓a21 ↑b21 ↑x13 <R4>↓a22 ↑b22
b20=b22; a21=a20; a22=b21;
<R4>↓a23 ↑b23 ::=’,’<NamesBool>↓a24 ↑b24
a24=a23; b23=b24;
<R4>↓a25 ↑b25 ::=$
b25= a25;
<NamesChar>↓a26 ↑b26 ::=<Id>↑x14 {NewC}↓a27 ↑b27 ↓x15 <R5>↓a28 ↑b28
b26=b28; a27=a26; a28=b27; x15=x14;
<NamesChar>↓a29 ↑b29 ::=<MasChar>↓a30 ↑b30 ↑x16 <R5>↓a31 ↑b31
b29=b31; a30=a29; a31=b30;
<R5>↓a32 ↑b32 ::=’,’<NamesChar>↓a33 ↑b33
a33=a32; b32=b33;
<R5>↓a34 ↑b34 ::=$
b34= a34;
<Code>↓a35 ↑b35 ::=’<ass>’<Perem>↑t3 ’,’<Vyrazh>↓a36 ↑b36 ↑t4 {FAt=}↓t5 ↓t6 ↓t7 ’</ass>’<R6>↓a37 ↑b37
a36=a35; a37=b36; b35=b37; (t5, t7)=t3; t6=t4;
<Perem>↑t8 ::= <Id>↑x17 {FUkTZId}↓x18 ↑t9
x18=x17; t8=t9;
<Perem>↑t10 ::= <ElMas>↑t11
t10=t11;
<Vyrazh>↓a38 ↑b38 ↑t12 ::= <Const>↑z1
b38=a38; t12=z1;
<Vyrazh>↓a39 ↑b39 ↑t13 ::= <Simvol>↑c1
b39=a39; t13=c1;
<Vyrazh>↓a40 ↑b40 ↑t14 ::= <Perem>↑t15
b40=a40; t14=t15;
<Vyrazh>↓a41 ↑b41 ↑t16 ::= <Operation>↓a42 ↑b42 ↑t17
a42=a41; b41=b42; t16=t17;
<Operation>↓a43 ↑b43 ↑t18 ::= ‘<and>’<Operand>↓a44 ↑b44 ↑t19 ’,’<Operand>↓a45 ↑b45 ↑t20
{FAt&}↓t21 ↓t22 ↓t23 {NextZ}↓a46 ↑b46 ‘</and>’
a44=a43; a45=b44; b43=b46; (t18, t23, a46)=b45; t21=t19; t22=t20;
<Operation>↓a47 ↑b47 ↑t24 ::= ‘<or>’<Operand>↓a48 ↑b48 ↑t25 ’,’<Operand>↓a49 ↑b49 ↑t26
{FAtV}↓t27 ↓t28 ↓t29 {NextZ}↓a50 ↑b50 ‘</or>’
a48=a47; a49=b48; b47=b50; (t24, t29, a50)=b49; t27=t25; t28=t26;
<Operation>↓a51 ↑b51 ↑t30 ::=‘<not>’<Operand>↓a52 ↑b52 ↑t31{FAt!}↓t32 ↓t33 ↓t34{NextZ}↓a53 ↑b53 ‘</not>’
a52=a51; b51=b53; (t30, t34, a53)=b52; t32=t31; t33=NULL;
<Operand>↓a54 ↑b54 ↑t35 ::= <Operation>↓a55 ↑b55 ↑t36
a55=a54; b54=b55; t35=t36;
<Operand>↓a56 ↑b56 ↑t37 ::= <Perem>↑t38
b56=a56; t37=t38;
<Operand>↓a57 ↑b57 ↑t39 ::= <Const>↑z2
b57=a57; t39=z2;
<R6>↓a58 ↑b58 ::= <Code>↓a59 ↑b59
a59=a58; b58=b59;
<R6>↓a60 ↑b60 ::= $
b60=a60;
Для работы нам понадобятся следующие типы атрибутов:
1. Для идентификатора:
↑X– ссылка на идентификатор в таблице идентификаторов
2. Для числа:
↑Y– ссылка на число в таблице чисел
3. Для логической константы:
↑Z– номер ячейки в таблице логических констант
4. Для символьной константы:
↑С – номер ячейки в таблице символьных констант
Для ячеек таблицы значений
↓A– указатель на первую свободную ячейку до начала трансляции выражения
↑B– указатель на первую свободную ячейку после завершения трансляции выражения
T– указатель на ячейку, в которой хранится (в которую необходимо записать) значение выражения (константы, переменной, элемента массива, результата операции)