Таблица символов — это важная структура данных, созданная и поддерживаемая компиляторами для хранения информации о появлении различных объектов, таких как имена переменных, имена функций, объекты, классы, интерфейсы и т. Д. Таблица символов используется как для анализа, так и для синтеза. части компилятора.
Таблица символов может служить следующим целям в зависимости от используемого языка:
-
Хранить имена всех сущностей в структурированной форме в одном месте.
-
Чтобы проверить, была ли объявлена переменная.
-
Чтобы реализовать проверку типов, путем проверки присваиваний и выражений в исходном коде семантически правильно.
-
Чтобы определить область имени (разрешение области).
Хранить имена всех сущностей в структурированной форме в одном месте.
Чтобы проверить, была ли объявлена переменная.
Чтобы реализовать проверку типов, путем проверки присваиваний и выражений в исходном коде семантически правильно.
Чтобы определить область имени (разрешение области).
Таблица символов — это просто таблица, которая может быть линейной или хеш-таблицей. Он поддерживает запись для каждого имени в следующем формате:
<symbol name, type, attribute>
Например, если таблица символов должна хранить информацию о следующем объявлении переменной:
static int interest;
тогда он должен хранить запись, такую как:
<interest, int, static>
Предложение атрибута содержит записи, связанные с именем.
Реализация
Если компилятор должен обрабатывать небольшой объем данных, тогда таблица символов может быть реализована в виде неупорядоченного списка, который легко кодировать, но он подходит только для небольших таблиц. Таблица символов может быть реализована одним из следующих способов:
- Линейный (отсортированный или несортированный) список
- Двоичное дерево поиска
- Хеш-таблица
Среди всех таблиц символов в основном реализованы в виде хеш-таблиц, где сам символ исходного кода рассматривается как ключ для хэш-функции, а возвращаемое значение является информацией о символе.
операции
Таблица символов, как линейная, так и хэш, должна обеспечивать следующие операции.
вставить ()
Эта операция чаще используется на этапе анализа, т. Е. В первой половине компилятора, где идентифицируются токены и имена хранятся в таблице. Эта операция используется для добавления в таблицу символов информации об уникальных именах, встречающихся в исходном коде. Формат или структура, в которой хранятся имена, зависит от используемого компилятора.
Атрибутом символа в исходном коде является информация, связанная с этим символом. Эта информация содержит значение, состояние, область и тип символа. Функция insert () принимает символ и его атрибуты в качестве аргументов и сохраняет информацию в таблице символов.
Например:
int a;
должен быть обработан компилятором как:
insert(a, int);
уважать()
Операция lookup () используется для поиска имени в таблице символов для определения:
- если символ существует в таблице.
- если он объявлен до его использования.
- если имя используется в области.
- если символ инициализирован.
- если символ объявлен несколько раз.
Формат функции lookup () зависит от языка программирования. Базовый формат должен соответствовать следующему:
lookup(symbol)
Этот метод возвращает 0 (ноль), если символ не существует в таблице символов. Если символ существует в таблице символов, он возвращает свои атрибуты, хранящиеся в таблице.
Управление областью
Компилятор поддерживает два типа таблиц символов: глобальную таблицу символов, к которой могут обращаться все процедуры, и таблицы символов области , которые создаются для каждой области в программе.
Чтобы определить область имени, таблицы символов расположены в иерархической структуре, как показано в примере ниже:
. . . int value=10; void pro_one() { int one_1; int one_2; { \ int one_3; |_ inner scope 1 int one_4; | } / int one_5; { \ int one_6; |_ inner scope 2 int one_7; | } / } void pro_two() { int two_1; int two_2; { \ int two_3; |_ inner scope 3 int two_4; | } / int two_5; } . . .
Вышеуказанная программа может быть представлена в иерархической структуре таблиц символов:
Глобальная таблица символов содержит имена для одной глобальной переменной (значение int) и двух имен процедур, которые должны быть доступны для всех дочерних узлов, показанных выше. Имена, упомянутые в таблице символов pro_one (и всех ее дочерних таблицах), недоступны для символов pro_two и его дочерних таблиц.
Эта иерархия структуры данных таблицы символов хранится в семантическом анализаторе, и всякий раз, когда нужно искать имя в таблице символов, он ищется с использованием следующего алгоритма:
сначала будет выполнен поиск символа в текущей области видимости, то есть в текущей таблице символов.
если имя найдено, то поиск завершен, иначе оно будет искать в таблице родительских символов до тех пор, пока
либо имя найдено, либо имя таблицы было найдено в глобальной таблице символов.