Как классы реализованы в компиляторах - PullRequest
7 голосов
/ 28 октября 2010

Я хотел бы реализовать тип класса для своего собственного маленького языка, но то, что я сначала подумал, не будет слишком сложным, поставило меня в тупик. У меня есть синтаксический анализатор, и это сторона кода, с которой у меня возникают проблемы. Может ли кто-нибудь пролить свет на лучший / правильный путь? В частности, я хотел бы сделать это в LLVM, поэтому, хотя мне нужно знать общие черты этого кода, любой конкретный код LLVM, с которым я должен работать, был бы фантастическим.

Спасибо T.


N.B. Мой опыт работы с LLVM в основном основан на обучающих материалах по Kaleidoscope, а также немного поэкспериментировал с ним, но я далек от полного понимания API LLVM.

Ответы [ 3 ]

6 голосов
/ 31 октября 2010

Очень, очень неполный обзор:

Класс - это структура (вы знаете C / C ++, не так ли?)

Методы в остальном обычные функции, за исключением того, что они получают дополнительный неявный аргумент: сам объект.Этот аргумент обычно называется «this» или «self» внутри функции.Символы области видимости могут (C ++, JavaScript) или не могут (PHP, Python) быть доступны по умолчанию в методах.

Наследование по сути склеивает структуры и, возможно, также объединяет таблицы символовтакже, как обычно, символы базового класса доступны по умолчанию из методов класса, который вы сейчас анализируете.Когда вы встречаете символ (поле или метод) внутри метода, вам нужно выполнить поиск по возрастанию, начиная с текущего класса, поднимаясь по иерархии.Или вы можете реализовать его так, чтобы вы искали его только в одной таблице символов, которая является результатом слияния.

Виртуальные методы вызываются косвенно.В некоторых языках все методы являются виртуальными по умолчанию.Реализация будет зависеть от того, является ли это полностью динамическим языком, и в этом случае вы всегда ищете имя функции в классе во время выполнения , и, таким образом, все ваши методы становятся виртуальными автоматически;или в случае статических языков компиляторы обычно строят так называемые таблицы виртуальных методов.Я не уверен, что вам это вообще нужно, поэтому я не буду вдаваться в подробности.

Конструкторы - это специальные методы, которые вызываются либо при создании нового объекта (обычно с'new') или иначе вызываются как часть цепочки вызовов конструктора из конструкторов-потомков.Здесь возможно множество различных реализаций, одна из которых заключается в том, что конструктор принимает неявный аргумент «this», который может иметь значение NULL, если объект еще не создан, и также возвращает его.

Destructiors - это обычные методы, которые обычно вызываются неявно, когда объект выходит из области видимости.Опять же, вам нужно учитывать возможность восходящей цепочки вызовов для деструкторов.

Интерфейсы сложны, если, опять же, ваш язык не является полностью динамичным.

4 голосов
/ 01 ноября 2010

Вы должны купить Стэна Липпмана, Внутри объектной модели C ++. Все, что вам нужно, там.

1 голос
/ 05 ноября 2010

Вероятно, есть несколько стратегий для реализации этого, вот одна из них:

A vtable (Виртуальная таблица) - это постоянная во время компиляции структура с указателями на функции.(Все значения известны во время компиляции.)

(Вы можете назвать указатель на виртуальную таблицу «интерфейсом», если хотите.)

OOP-класс на языке безлюбая способность наследования - это структура, которая содержит константный указатель на свою vtable в качестве первой переменной-члена.Этот указатель используется для точной идентификации типа объекта, а также с множественным наследованием аспекта / представления (как что было приведено?) Для этого объекта.

Если вы хотите иметь множественное наследование, тогда вам нужночтобы иметь возможность (static_) приводить указатель к производному классу к его родительскому классу, исправляя байтовый адрес на лету.Это может быть реализовано с помощью одной виртуальной функции или (лучше) со значением смещения со знаком, хранящимся в виртуальной таблице.

Приведение (dynamic_) от указателя к родительскому классу к указателю на производный класс либо подразумеваетпоиск в, вероятно, большой структуре данных (массив, хеш-таблица, что угодно) или реализуется через одну виртуальную функцию.

Каждый вызов функции из vtable требует приведения объекта-указателя к типу, которыйподходит для функции.Это может быть сделано либо вызывающей стороной, считывающей смещение со знаком (соотнесенное с функцией) из виртуальной таблицы, либо вызываемой стороной, которая затем является только прокси исходной функции.

В некоторых языках (особеннофункциональные языки) вы можете определить ссылки на (нетипизированные) объекты, которые создают список интерфейсов / классов типов, действительных для этого объекта.Такая ссылка содержит один указатель на базовый объект и список указателей на соответствующие таблицы.

...