- •Теория вычислительных процессов и структур
 - •1. Предварительные математические сведения
 - •1.2. Операции над множествами Объединение множеств
 - •Пересечение множеств
 - •Разность множеств
 - •1.3. Множества цепочек
 - •1.4. Языки
 - •1.5. Алгоритмы
 - •1.6. Некоторые понятия теории графов
 - •2. Введение в компиляцию
 - •2.1. Задание языков программирования
 - •2.2. Синтаксис и семантика
 - •2.3. Процесс компиляции
 - •2.4. Лексический анализ
 - •2.5. Работа с таблицами
 - •2.6. Синтаксический анализ
 - •2.7. Генератор кода
 - •Алгоритм.
 - •2.8. Оптимизация кода
 - •2.9. Исправление ошибок
 - •2.10. Резюме
 - •3. Теория языков
 - •3.1. Способы определения языков
 - •3.2. Грамматики
 - •Пример.
 - •3.3. Грамматики с ограничениями на правила
 - •3.4. Распознаватели
 - •3.5. Регулярные множества, их распознавание
 - •3.6. Регулярные множества и конечные автоматы
 - •3.7. Графическое представление конечных автоматов
 - •3.8. Конечные автоматы и регулярные множества
 - •3.9. Минимизация конечных автоматов
 - •3.10. Контекстно-свободные языки
 - •3.10.1. Деревья выводов
 - •3.10.2. Преобразование кс–грамматик
 - •3.10.3. Грамматика без циклов
 - •3.10.4. Нормальная форма Хомского
 - •3.10.5. Нормальная формула Грейбах
 - •3.11. Автоматы с магазинной памятью
 - •3.11.1. Основные определения
 - •3.11.2. Эквивалентность мп-автоматов и кс-грамматик
 - •4.1. Эквивалентность мп-автоматов и кс-грамматик
 - •4.2. Ll(1)-грамматики
 - •4.3. Ll(1)-таблица разбора
 - •5. Синтаксический анализ снизу вверх
 - •5.1. Разбор снизу вверх
 - •5.2. Lr(1) - таблица разбора
 - •5.3. Построение lr – таблицы разбора
 - •5.4. Сравнение ll – и lr – методов разбора
 - •6. Включение действий в синтаксис
 - •6.1. Получение четверок
 - •6.2. Работа с таблицей символов
 - •7. Проектирование компиляторов
 - •7.1. Число проходов
 - •7.2. Таблицы символов
 - •Identifier, type.
 - •Int procedure rehash(int n)
 - •Int procedure rehash(int n)
 - •7.3. Таблица видов
 - •8. Распределение памяти
 - •8.1. Стек времени прогона
 - •Integer a, b, X, y
 - •Int table[1:10, -5:5].
 - •8.2. Методы вызова параметров
 - •8.3. Обстановка выполнения процедур
 - •8.4. «Куча»
 - •8.5. Счетчик ссылок
 - •8.6. Сборка мусора
 - •9. Генерация кода
 - •(Тип – адреса, номер - блока, смещение).
 - •9.2. Структура данных для генерации кода
 - •9.3. Генерация кода для типичных конструкций
 - •9.3.1. Присвоение
 - •9.3.2. Условные зависимости
 - •If b then c else d
 - •9.3.3. Описание идентификаторов
 - •9.3.4. Циклы
 - •9.3.5. Вход и выход из блока
 - •9.3.6. Прикладные реализации
 - •9.4. Проблемы, связанные с типами
 - •9.5. Время компиляции и время прогона
 - •10. Исправление и диагностика ошибок
 - •10.1. Типы ошибок
 - •10.2. Лексические ошибки
 - •10.3. Ошибки в употреблении скобок
 - •Begin end
 - •Case esac
 - •10.4. Синтаксические ошибки
 - •10.5. Методы исправления синтаксических ошибок
 - •End begin
 - •10.6. Предупреждения
 - •10.7. Сообщения о синтаксических ошибках
 - •10.8. Контекстно-зависимые ошибки
 - •Identifier xyz not declared
 - •Identifier blank alredy declared in block
 - •10.9. Ошибки, связанные с употреблением типов
 - •Int I; char c;
 - •10.10. Ошибки, допускаемые во время прогона
 - •10.11. Ошибки, связанные с нарушением ограничений
 
6.2. Работа с таблицей символов
Поскольку синтаксические анализаторы обычно используют контекстно – свободную грамматику, необходимо найти метод определения контекстно – зависимых частей языка. Например, во многих языках идентификаторы не могут применяться, если они ранее не описаны, и имеются ограничения в отношении способов употребления в программе значений различного типа. Кроме того, в языках программирования имеются ограничения на употребление различных знаков. Для запоминания описанных идентификаторов и их типов большинство компиляторов использует таблицу символов. В принятой формализации описания
int a
является определяющейреализациейа, а использованиеав другом контексте
a=4 или a+ b или read(a)
говорит, что имеется прикладная реализацииа.
Во многих языках программирования один и тот же идентификатор может использоваться для представления в различных частях программы различных объектов (например, в «голове» int, ав подпрограммеchar). В этом случае в таблице символов - это два разных объекта.
Таблица символов имеет ту же блочную структуру, что и сама программа, чтобы различать виды употребления одного и того же идентификатора. При построении таблицы символов учитываются основные свойства большинства языков:
определяющая реализация идентификатора появляется раньше любой прикладной реализации;
все описания в блоке помещаются раньше всех операторов и предложений;
при наличии прикладной реализации идентификатора, соответствующая определяющая реализация находится в наименьшем включающем блоке, в котором содержится описание этого идентификатора;
в одном и том же блоке идентификатор не может описываться более одного раза.
Пусть синтаксис описания идентификаторов задается правилами:

а блок определяется как
,
где

В этом случае структуру таблицы символов можно представить в виде
| 
			 
  | 
			 Levno  | 
			 
  | 
			 
  | 
			 
  | 
			 levno  | 
			 
  | 
			 
  | 
			 
  | 
			 levno  | 
			 
  | 
			 
  | 
| 
			 
  | 
			 
  | 
			 Type  | 
			 
  | 
			 
  | 
			 
  | 
			 type  | 
			 
  | 
			 
  | 
			 
  | 
			 type  | 
			 
  | 
| 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
| 
			 
  | 
			 
  | 
			 Type  | 
			 
  | 
			 
  | 
			 
  | 
			 type  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
| 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
| 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 type  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
			 
  | 
Таким образом, в любой точке разбора в цепи находятся те блоки, в которые делается текущее вхождение, а уже описанные идентификаторы помещаются в список идентификаторов для того блока, где они описаны.
Для описания таблиц задаются структуры строго фиксированной конфигурации. Обычно в этих структурах идентификаторы и типы представляются целыми числами. Имеется указатель на элемент таблицы символов, соответствующих наименьшему включающему блоку.
В языке, обладающем описанными выше четырьмя свойствами, в качестве структуры данных для таблицы символов удобно использовать стек, каждым элементом которого служит элемент этой таблицы символов.
При встрече с описанием соответствующий элемент таблицы символов помещается в верхнюю часть стека, а при выходе из блока все элементы таблицы символов, соответствующие описаниям в этом блоке, удаляются из стека. Указатель стека понижается до положения, которое он имел до вхождения в блок. В результате в любой момент разбора элементы таблицы символов, соответствующие всем текущим идентификаторам, находятся в стеке, а связанные с ними прикладные и определяющие реализации идентификаторов требуют поиска в стеке в направлении сверху вниз.
Рассмотренный метод иллюстрируется следующим примером
| 
			 Вид программы  | 
			 
  | 
			 
  | 
| 
			 begin int a, b . begin int c, d . end begin int e, f . end end  | 
			 
  | 
			 
  | 
| 
			 
  | 
			 
  | |
| 
			 f  | 
			 int  | |
| 
			 e  | 
			 int  | |
| 
			 b  | 
			 int  | |
| 
			 a  | 
			 int  | 
Таким образом, включение действий в грамматику позволяет получить простой и элегантный компилятор. При этом действия выполняются на соответствующем уровне в грамматике.
Контрольные вопросы
Технология включения действий в грамматику.
Получение четверок, грамматика для четверок.
Разбор арифметического выражения с одновременной генерацией кода.
Метод определения контекстно – зависимых частей языка.
Синтаксис описания идентификаторов и блоков.
Структура таблицы символов.
Программная реализация таблицы символов.

