Re: Refal+ abstract syntax


Subject: Re: Refal+ abstract syntax
From: Andrey Slepuhin (pooh@msu.ru)
Date: Mon Dec 20 1999 - 14:28:13 MSK


Добрый день всем!

Arkady Klimov wrote:
>
> Андрей,
>
> ----- Original Message -----
> From: Andrey Slepuhin <pooh@msu.ru>
> To: Arkady Klimov <klark@bagirra.rinet.ru>
> Cc: <refal@botik.ru>
> Sent: Friday, December 17, 1999 6:55 PM
> Subject: Re: Refal+ abstract syntax
>
> > Arkady Klimov wrote:
> > >
> > > Андрей, спасибо, это уже почти то, что надо.
> > > "У целом" принимается.
> > >
> > > А теперь перейдем к постатейному обсуждению.
> > >
> > > Но сначала одно общефилософское замечание.
> >
> > [note snipped]
> >
> > С моей точки зрения главное в АС - это
> > 1) Общий синтаксис для всех рефалов.
> > 2) Самодостаточное описание модуля, не требующее никакой дополнительной
> > информации для его компиляции.
> >
> > Во всех своих утверждениях я исхожу именно из этого.
> Арк:
> А я спорю с пунктом 2). См. ниже.

Я не вижу, как можно выполнить 1) без 2).

> >
> > На самом деле я уже давно хотел (но боялся) предложить следующее:
> > все имена в момент использования (и разрешить это в исходном синтаксисе
> > -
> > вроде бы ограничений нет) представлять в виде
> >
> > <name> ::= <simple_name> | <module_name>.<simple_name>
> > <module_name> ::= <level_name> | <module_name>.<level_name>
> >
> > При этом алгоритм следующий: если парсер встретил объявление имени -
> > то имя полностью раскрывается со всеми префиксами модулей и помещается в
> > таблицу. Если же имя встретилось в момент использования, то оно ищется
> > в таблице, но не по полному совпадению, а по совпадению с "хвостом".
> > Если таких совпадений несколько - то ругаться, что имя слабо
> > специфицировано. Получается как в Java или C++... Тогда если в
> > абстрактном синтаксисе оставить только полностью специфицированные имена
> > (а оно так и должно быть), то в принципе можно обойтись и без USE
> > (а также и без linkage-спецификаторов - ведь для каждого имени будет
> > известен модуль, где оно определено).
> > А при компиляции в какой-то формат для динамической загрузки можно,
> > если что, создавать хэш-таблицу нужных модулей. Кроме того так мы не
> > потянем за собой никаких ненужных модулей если кто-то по ошибке
> > подключил их с помощью $use.
> Арк:
> С идеей разрешить составные имена, в том числе в исходном синтаксисе,
> согласен.
> Когда именно ругаться - надо уточнять. Искать "по хвостам" - тоже
> сомнительный
> принцип. Ява ищет от начал, другое дело, что некоторые модули могут быть
> открыты
> на использование их имен простым образом (предложением import, по-нашему -
> use).

Именно это я и имею в виду. И тогда сравнение происходит с "хвостами".
В целом я говорю о следующем: если у нас есть
$use A.B.C.D X.Y.D;
и в обоих модулях определена функция F, то мы ее в момент использования
функции писать A.B.C.D.F, C.D.F, X.Y.F - все будет в порядке. Если же мы
напишем просто F или D.F - нас должны обругать, что функция слабо
специфицирована.

> Идея, что в АС следует оставить только полные имена тоже правильная, если
> мы
> договорились о том, что разрешение имен парсером исходного текста уже
> сделано.

Ага.

> Однако мне сам этот подход не вполне нравится. Альтернатива состоит в том,
> что
> собственно парсер использует только один исходный файл, а разрешение
> имен приоизводится отдельно как следующая фаза. Я бы предложил попытаться
> провести в жизнь оба подхода, то есть сделать как бы два АС: первичный и
> вторичный.
> Отличаться они будут только аспектами, связанными с именами и модулями.
> Если в каком-то встретятся непреодолимые трудности - ну тогдо можно и
> отказаться.
>
> По поводу тезиса 2), что компилятор из АС должен мочь все сделать на основе
> информации об одном АС-модуле, у меня тоже есть сомнения, поскольку одному
> компилятору (как нынешний Рефал-6) достаточно и исходного модуля,
> Рефалу Плюс требуется кое-что от определений других модулей (форматы,
> например),

Вот-вот. Поэтому парсер и должен включать эту информацию в АС.

> а где гарантия, что новому компилятору не понадобится еще
> какая-нибудь информация (например, о вызываемости функциями друг друга).

Значит эта информация должна быть в будущем включена в АС. Изменять
АС в сторону расширения никто не запрещает.

> Я бы хотел, чтобы еще кто-то высказался по этому вопросу. (Сережа Абрамов,
> ау!).

Присоединяюсь к пожеланию. И вообще, такое ощущение, что кроме нас троих
дискуссия никому не интересна :-(((

> Коротко повторю:
> Есть выбор из следующих вариантов:
>
> A) Парсер использует как вход только один файл, выдает АС-модуль
> с неразрешенными именами.
>
> B) Парсер использует данный файл и все его окружение и выдает
> АС-модуль, в котором все имена разрешены и имеется вся информация
> об их определениях, достаточная для (любого?) компилятора.
>
> C) Реализуются оба варианта, то есть реализуется вариант A), который затем
> дополняется до B) написанием отдельной фазы (StaticElaboration), которая
> соберет всю информацию, достаточную для дальнейшей компиляции.

Проблема в том, что фаза StaticElaboration должна быть своя для каждого
рефала. Зачем тогда принципиально нужен АС в варианте а) ???

> А суть варианта C) в том, чтобы сейчас выработать и опубликовать оба
> стандартных
> представления АС, как до StaticElaboration, так и после него. Как вы
> понимете,
> я за 3).
>
> >
> > > > 4) Описания определений всех объектов изменены в соответствии с 3).
> > >
> > > Вспомним философское замечание в начале письма. Данное изменение
> > > предполагает, что поиск внешних определений произведен на стадии
> > > до формирования АС, то есть парсером. Я не уверен, что это правильно.
> > > Можно ли услышать аргументацию за это?
> > > Мне лично кажется, что парсеру следовало поручить только обработку
> > > отдельного файла,
> > > а разрешение внешних имен выполнить как этап обработки в рамках АС.
> >
> > Дело то в том, что модуль может и не существовать в виде АС,
> > а например будет только в откомпилированном виде + include file.
> > И что тогда делать? Парсер абстрактного синтаксиса не должен иметь
> > дело с синтаксисом include file'а конкретного рефала. Здесь есть некая
> > аналогия с .class-файлами в той же Java - там все имена уже полностью
> > специфицированы.
> Арк:
> Ну, class-файлы, это уже результат компиляции, а никак не AC.

Это просто в качестве примера.

> А в целом
> данный аргумент ("что модуль может и не существовать в виде AC" -
> то есть в виде исходного текста, да?) говорит больше в пользу моего
> подхода:
> парсер работает только одним исходным файлом, тем, для которого его
> попросили. Если компилятору понадобилась дополнительная информация - он
> ее возьмет либо в ранее скомпилированных им структурах, которые этот
> компилятор и понимает, либо запустит парсер для других исходных модулей.

Да не знает компилятор ничего про этот парсер. На то и АС, чтобы быть
общим для всех рефалов. Я могу вообще придумать свой собственный
рефал-- или, скажем, сделать парсер, который генерирует рефальский АС
из другого функционального языка 8-)). Откуда парсер будет браться,
для каких файлов его вызывать? Да и от исходных модулей - одни
include'ы.

> > > > 6) NOT и ITER сохранены как есть. С моей точки зрения их раскрытие
> > > > слишком далеко двигает нас в сторону виртуального кода и может
> > > > привести к менее удобному представлению при компиляции в
> > > > императивные языки.
> > > Это нормально. Но не отменяет возможности на ранней стадии компиляции
> > > устранить NOT и ITER путем их раскрытия в АС же. Я не вижу почему эти
> > > раскрытия специфичны для какого-то одного типа реализации. Полагаю,
> > > они универсальны.
> >
> > Я не против возможных расширений, но мне существенно не нравится
> > использование
> > LABEL в раскрытии ITER. Я бы еще согласился на
> >
> > t.Label ::= (LABEL s.LabelName e.Sentence)
> >
> > чтобы получились помеченные предложения, но не LABEL как
> > абстрактная метка.
> Арк:
> Какая, собственно, разница?

Такая, что, скажем, в Java нельзя просто сказать goto на метку,
а метка используется только в break и continue; для этого метка
привязана к соответствующему блоку. В моем варианте помеченное
предложение будет переходить в помеченный блок - компиляция будет
проще. А метка сама по себе - ну что с ней делать?

> А правильно ли я понимаю, что в твоем варианте
> после t.Label не должно быть продолжения предложения? (То есть t.Label
> тогда
> должен относиться к так называемым терминирующим операторам, таким как
> FAIL.)

Если вопрос о о том, можно ли в этом случае снять с LABEL скобки -
то ответ отрицательный.

> И тот же вопрос относительно Try и Iter (в последнем варианте).

Ответ тот же самый. Конечно можно написать, скажем,
TRY e.TrySentence CATCH e.CatchSentence ENDTRY но зачем??? А потом
руками считать уровни вложенности? Другой вопрос, что можно написать
(TRY e.TrySentence CATCH e.CatchSentence) или
TRY t.TrySentence t.CatchSentence - это вопрос вкуса. Мне больше
нравится
выделять сложные операторы скобками и не использовать лишних тегов,
но если есть принципиальные возражения - я не буду слишком сильно
настаивать.

> Замечу, что в своем (предыдущем) варианте я старался минимизировать
> количество таких операторов. Поэтому и у Error нет явного аргумента, его
> аргумент - все окончание предложения.

Ммм... Насколько я помню, в Рефале+ аргумент у ERROR - это объектное
выражение,
и если мы его только этим ограничим, то для ERROR надо бы ввести
отдельный
синтаксис. Если же мы допустим, что аргументом у ERROR может быть
значение
любого предложения, то тогда можно оставить все как есть (вопрос: что
будет,
если при вычислении аргумента ERROR возникнет новый ERROR? ;-) )

> >
> > Как я уже писал - я бы ограничил константы до терма и ввел define'ы,
> > которые раскрываются сразу - на самом деле этого хватает для всего.
> > Я думаю, на первых порах можно константы сразу раскрывать, а позже
> > эту часть синтаксиса довести до ума.
> Арк:
> Я хотел сказать, что, если уж имена-константы определяются в АС, то надо
> не забыть указать, как они там используются.

Угу. И поэтому хотелось бы услышать мнения на эту тему. Лично меня,
наверное, вполне бы устроило раскрытие констант парсером, а остальное
можно и сэмулировать (тем более имея t.Initializer).

> > > 1. Для объектов типов BOX, STRING, VECTOR и, возможно, TABLE - вести
> > > понятие начального значения:
> > >
> > > t.Object ::= (s.Linkage s.ObjectType s.ObjectName
> e.InitialValue)
> > >
> > > e.InitialValue ::= e.ResultExpression
> > >
> > > (ограничения - те же, что и для initializer'а.
> >
> > Я уже думал над этим. Только непонятно, кто будет проверять, что
> > начальное значение, скажем для VECTOR имеет корректный формат?
> Арк:
> В момент засылки, то есть при загрузке.

Ну, если ни у кого возражений нет - я e.InitialValue введу.
Вопрос: а не делает ли это t.Initializer слегка obsolete?

> > > 3. В последнем письме от 17.12 ты предлагаешь разделить декларацию и
> > > определения.
> > > Мне кажется, это тоже можно вводить как стадию обработки в рамках АС.
> Но
> > > может
> > > компилятору это и не требуется?
> >
> > Компилятору в момент использования функции надо знать ее форматы.
> > Если не разносить декларацию и определение, то потребуется два прохода.
> Арк:
> А разве результат парсера не является объектным выражением, целиком
> находящимся оперативной памяти? Тогда лишний проход не составляет
> проблемы. А некоторые компиляторы все равно будут делать лишние проходы.
> Например, компилятор в Яву может интересоваться графом вызовов для
> оптимизации.

Ну, если так... И если гарантировать, что _все_ компиляторы будут
сразу загружать АС в память целиком - тогда можно и первый вариант
(кстати, с эстетической точки зрения он мне нравится больше :-) ).

Всего доброго,
Андрей.



This archive was generated by hypermail 2b25 : Mon Oct 25 2004 - 21:24:58 MSD