Опубликован: 23.07.2006 | Доступ: свободный | Студентов: 2218 / 892 | Оценка: 4.28 / 4.17 | Длительность: 21:37:00
Специальности: Системный архитектор
Лекция 9:

Семантический анализ. Внутреннее представление

Конструирование типов

Типы языков программирования конструируются из примитивных типов, таких как boolean , char , integer , real и void , с помощью конструкторов типов. К примитивным типам естественно отнести и тип, который не используется при программировании, но весьма полезен для сигнализации о возникшей ошибке в типах; это тип - invalid . Для построения более сложных типов из примитивных обычно используются следующие конструкторы:

  1. Массивы. Если T - тип, то array (I, T) - тип, обозначающий тип массива с элементами типа T и индексным множеством I . Например, описание языка Pascal:
    var A: array [1..10] of integer;

    связывает выражение над типами array (1..10, T) с A .

  2. Произведение. Если T1 и T2 - типы, то их декартово произведение T1 * T2 также является типом.
  3. Структуры. Конструктор struct применяется к кортежу пар ( имя поля, тип поля ). Например, фрагмент программы на языке Pascal:
    type row = record
    address: integer;
    lexeme: array [1..15] of char
    end;
        var table: array [1..13] of row;

    Тип row строится из примитивных типов следующим образом:

    struct ((address*integer)  (lexeme*array (1..15, char))).
  4. Указатели. Если T - тип, то и pointer (T) - тип, определяющий " указатель на объект типа T ". Например, описание языка Pascal:
    var p: ^row;

    определяет переменную p , имеющую тип pointer (row) .

  5. Функции. Если T1, T2 - типы, то proc (T1, T2) - тип, определяющий процедуру, типы формальных параметров которой есть T1, а тип результата - T2. Например, функция mod , вычисляющая остаток, имеет тип proc (int *int, int) , а функция, определенная как
    function f (a, b: char) : ^integer;
    имеет тип proc (char char, pointer (integer)) .

Представление типов

Удобным путем представления выражений над типами являются графы. Мы можем конструировать деревья или DAG'и (ориентированные ациклические графы), листьями которых будут примитивные типы. Например:


Использование dag'ов более предпочтительно, поскольку в этом случае происходит иногда весьма значительная экономия памяти (вместо самих типов в этом случае хранится ссылка на них).

Мы можем использовать и линейное представление деревьев или dag'ов, например,

proc, 2, m1, m2, m2,
где m1 - указатель в таблицу на тип pointer, integer,
а m2 - указатель в таблицу на тип char.

Рассмотрим еще один способ кодирования типов, который был использован в компиляторе C, разработанном Ричи (D.M.Ritchie). Ограничимся тремя конструкторами типов: указателями, функциями и массивами: pointer (t) обозначает указатель на тип t , freturns (t) обозначает функцию от некоторых аргументов, которая возвращает значение типа t и, наконец, array (t) обозначает массив некоторой неопределенной длины элементов типа t . Приведем примеры типов:

char
freturns (char)
pointer (freturns (char))
array (pointer (freturns (char))).

Каждый из этих типов может быть представлен последовательностью битов. Поскольку у нас есть только три конструктора типа, мы можем использовать для кодирования два бита:

pointer               01
array                  10
freturns              11

Примитивные типы кодируются четырьмя битами:

boolean              0000
char                    0001
integer                0010
real                     0011

Используя такой способ кодирования, приведенные выше типы мы можем закодировать следующим образом:

char                                                      000000 0001
freturns (char)                                     000011 0001
pointer (freturns (char))                     000111 0001
array (pointer (freturns (char)))        100111 0001

Теперь вернемся к обсуждению структуры таблицы идентификаторов. Одно из полей ( toMode ) мы собирались использовать для определения типа идентификатора. Определив представление типов, которые могут появиться в программе, мы можем теперь зафиксировать, что поле toMode в - это либо указатель на дерево или dag , либо ссылка в таблицу типов ModeTab , хранящую линейное представление типов.