KnigaRead.com/

Евгений Зуев - Редкая профессия

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Евгений Зуев, "Редкая профессия" бесплатно, без регистрации.
Перейти на страницу:

Этот раздел хочется завершить несколько неожиданным выводом. Наличие в компиляторе двух базовых структур — семантических таблиц и дерева программы — сейчас расценивается нами как один из самых серьезных недостатков компилятора. Эти структуры реализованы на различных принципах, работа с ними организована по-разному, однако они существуют вместе, пронизаны взаимными ссылками (можно сказать, переплетены, как корни растущих рядом деревьев) и в некоторых случаях просто дублируют друг друга. Сходная информация о структуре программы присутствует и в таблицах, и в дереве, что долго приводило к путанице, и сейчас выглядит довольно нелепо. Например, в дереве имеются узлы, соответствующие объявлениям; это естественно, так как образы объявлений могут попадать в результирующий код. Что же касается таблиц, то они как раз и составлены на основе информации, извлеченной из объявлений. Поэтому в узлах-объявлениях содержится ссылка на соответствующее слово в таблицах. Семантическое слово, в свою очередь, имеет обратную ссылку на узел "своего" объявления, которая в ряде случаев оказалась необходимой. Инициализатор переменной из объявления представляется поддеревом, на которое имеются ссылки как из узла-объявления, так и из семантического слова. И так далее… Все это работает и даже вполне эффективно, но, конечно, с точки зрения программного дизайна весьма далеко от совершенства.

Описанное построение компилятора свидетельствует о нашем честном следовании классическим образцам, а также… о нашей боязни отойти от этих образцов. Даже подступая к языку, который заведомо отличался от "правильно" построенных, элегантных и простых языков, хорошо подходящих для книжного описания базовых концепций и методов компиляции, мы преувеличили степень универсальности решений, предлагаемых в подобных книгах.

Теперь мы это хорошо понимаем. В следующей версии компилятора все будет сделано по-другому.

Лебедь, рак и щука, или Гадкий утенок

Мой коллега и товарищ, Саша Кротов, вдвоем пару с которым мы, собственно, и сделали практически всю работу, имеет прекрасное образование (по моим наблюдениям, выпускники мехмата зачастую имеют более высокую программистскую квалификацию, чем окончившие ВМК — да простят меня мои однокашники!). Несмотря на естественное для его возраста отсутствие опыта крупных разработок, он поразительно быстро "въехал" в проект и вообще в проблемную область и очень скоро стал совершенно равноправным его участником. К этому времени он вполне осознал, насколько интереснее программировать компиляторы, чем наполнять базы данных, рисовать на экране вертящиеся фигуры или писать байты в порт и ожидать их оттуда.

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

Так что шеф, глядя на нашу троицу с неподдельной гордостью, вполне мог считать, что вместе мы горы свернем. Однако далеко не все было гладко…

В компиляторе есть проектные ошибки (хотя к настоящему моменту большинство из них мы извели, поначалу их было немало). "Снаружи" эти ошибки практически никак не проявляются и не дают покоя только нам, знающим наизусть все его внутренности. Некоторые из них были просто неизбежны, так как, закладывая то или иное решение несколько лет назад, мы никак не могли представить, к чему приведет непредсказуемая эволюция языка. Другие ошибки объяснялись недостаточным опытом — практически впервые мы пытались делать то, что называется коммерческим программным продуктом и исходили только из академических представлений о том, какова должна быть архитектура компилятора.

Но самая неприятная категория проектных ошибок — это те, которые возникли из-за недостаточно тщательного анализа на начальных этапах проекта и, что хуже, из-за того, что по некоторым принципиальным вопросам имелись различные мнения. Принимать решение всегда сложно еще и потому, что чье-то мнение, как правило, приходится отвергать. Тяжело и тому, кто отвергает, и неприятно тому, чье мнение не учитывается. Зачастую бывает так, что трудно предпочесть какой-либо конкретный вариант из нескольких альтернатив просто потому, что все они достаточно обоснованы и могут быть использованы; в таких случаях необходимо чье-то волевое решение, которое все участники должны безоговорочно принять. У нас в свое время просто не хватило духу проговорить все до конца и определиться полностью по всем принципиальным вопросам. В результате некоторые существенные решения принимались "по умолчанию" тем или иным участником проекта без согласования с другими. Винить в этом, естественно, следует прежде всего старшего участника — автора этой статьи (как самого опытного, а не самого умного!).

Так, компилятор сначала выполняет полный семантический анализ всего исходного текста, и только потом генерирует для всей программы результирующий код. Почему такая организация компилятора была выбрана третьим участником, до сих пор непонятно. Какое-то объяснение было тогда дано, но оно тут же выпало из нашей памяти, и вспомнить сейчас невозможно, а попытаться самим объяснить — не получается. Такое решение (удивительно, но принятое без всякого обсуждения) приводит к тому, что компилятор сохраняет полное дерево программы (и, следовательно, вынужден сохранять и семантические таблицы, так как они друг с другом сильно связаны) вплоть до завершения обработки всего исходного текста. Более логичным и экономичным был бы подход, согласно которому для каждой функции выполняется вся обработка, вплоть до генерации кода, после чего в структурах компилятора сохраняется только информация из ее заголовка, необходимая для компиляции вызовов. Исключение достаточно сделать для встраиваемых (inline) функций, да и то не всегда.

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

Получилось так, что семантические таблицы были спроектированы, имея в виду второй, более естественный подход, а структура дерева — согласно первому подходу. Разработчику семантических таблиц (мне, попросту говоря), будучи поставленному перед фактом уже в процессе реализации, ничего не оставалось, как срочно перекроить их структуру. Крайне неприятно, но эта ситуация сохранилась и по сей день. Надо ли уточнять, что эти структуры были в свое время придуманы двумя участниками, которые в свое время не смогли (не захотели) вместе обсудить свои решения и возможные проблемы…

Справедливости ради следует сказать, что такое проектное решение неожиданно оказалось весьма уместным и даже естественно необходимым в «следующей жизни» нашего компилятора. Однако, в том, первоначальном, проекте оно сильно осложнило разработку компилятора, и, конечно, было недопустимым.

Комментарий 2001 года

Подобных, более мелких, но крайне неприятных рассогласований и неувязок было много, и, самое ужасное, с течением времени их число нарастало. Возникало тяжелое ощущение того, что компилятор — это большая темная комната, а у тебя только маломощный фонарик, который в состоянии осветить небольшой аппарат — твои модули. От аппарата тянутся в темноту провода и вереницы зубчатых колес. Что делается в дальних углах, неизвестно. Иногда вокруг раздаются какие-то звуки, из темноты выступают части каких-то движущихся механизмов, назначение которых остается неведомым, даже если осветить их. Время от времени из темноты раздается голос, настоятельно требующий: "нажми на кнопку с надписью ABC", "переведи рычаг XYZ в правое положение". Что делается в комнате и как все работает вместе, понять совершенно невозможно.

Пришло время говорить о неприятном — через некоторое время от нас ушел третий участник. Он весь был ориентирован на получение результата, а не на процесс его достижения. Само по себе это исключительно ценное качество, его наличие (подкрепленное высокой квалификацией) гарантирует успешное завершение работы в заданные сроки. Однако в данном случае оно обернулось своей худшей стороной — откровенно небрежным кодированием ("компилятор соптимизирует" — классический ответ на все замечания), принятием важных решений "на ходу", без всякого обсуждения и плохо скрываемым недовольством коллегами, которые непонятно почему копаются там, где надо скорее программировать. Главное — скорее! За один день сделать работоспособный синтаксис, за месяц — добиться трансляции программы "Hello world!". Сложность системы не играет никакой роли, все программы устроены одинаково. Модули должны взаимодействовать согласно своим интерфейсам, обсуждать и комментировать которые нет смысла, они и так сами за себя говорят — на то они и интерфейсы.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*