Re: Refal+ abstract syntax


Subject: Re: Refal+ abstract syntax
From: Arkady Klimov (klark@bagirra.rinet.ru)
Date: Sat Dec 18 1999 - 14:29:05 MSK


Андрей,

----- 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). См. ниже.

>
> > А теперь перейдем к обсуждению по пунктам.
> >
> > Сначала по изменениям.
> >
> > ----- Original Message -----
> > From: Andrey Slepuhin <pooh@msu.ru>
> > To: Arkady Klimov <klark@bagirra.rinet.ru>
> > Cc: Sergei M. Abramov <abram@botik.ru>; <refal@botik.ru>
> > Sent: Thursday, December 16, 1999 6:11 AM
> > Subject: Re: Refal+ abstract syntax
> >
> > > Добрый день всем!
> > >
> > > Извиняюсь за некоторую паузу в дискуссии.
> > > Я еще раз внимательно посмотрел на проект абстрактного синтаксиса
> > > и сделал свой вариант. Он лежит на
> > >
> > > http://forest.nmd.msu.ru/~pooh/refal_abstract_syntax.html
> > >
> > > На самом деле принципиальных различий практически нет, так что
> > > я думаю, что утверждение окончательного варианта не за горами.
> > > Что я изменил (по порядку):
> > >
> > > 1) t.ProgramFile заменено на t.Module (чисто косметическая замена
:-))
> > > 2) t.Source удалено - вместо этого нужно использовать прагмы
> > > (тем более, что абстрактный синтаксис не обязательно может
> > > иметь какой-то исходный текст)
> > ОК
> > > 3) t.Import удалено - на уровне абстрактного синтаксиса нельзя ничего
> > > вытащить из других модулей, т.к. их представление в АС может и не
> > > существовать. Вместо этого каждый объект имеет свой описатель
> > > IMPORT/EXPORT/LOCAL. Если нужно сохранить информацию о том,
> > > из каких модулей импортировались объекты - можно использовать
прагмы.
> > Это, конечно же, нужно, поэтому непонятно,
> > почему для этого надо прибегать к прагмам.
> > Причем это нужно будет сохранять не только в АС, но и в загрузочном
модуле.
> > Нам наконец пора иметь возможность (не обязательно в любой реализации,
> > но хотя бы в некоторых) обеспечить цивилизованную динамическую
загрузку.
> > Цивилизованной я называю такую, когда при загрузке модуля автоматически
> > могут быть подзагружены все используемые в нем модули, если они еще
> > не загружены. При этом также не нужно будет перечислять имена всех
> > модулей для начальной загрузки. (Сейчас в рефале-6 загрузка не является
> > цивилизованной)
> > Поэтому предлагаю.
> > а) Оставить список (USE e.ModuleNames).
> > б) В имени функции (REF s.name) разрешить использовать полные имена для
> > внешних функций: (REF s.ModuleName s.Name). Имена таких функций s.Name
> > могут безболезненно пересекаться с другими локальными или внешними
> > фунциями. Можно ввести стадию разрешения, которая будет пополнять все
> > ссылки (REF s.Name) до полных.
> > в) В s.ModuleName можно использовать точку, которая при превращении в
имя
> > файла переходит в слеш.
> > г) Считать ошибкой, если есть простая ссылка с именем, которое не
> > определено
> > ни локально, ни в одном из USEd модулей.
> > д) Декларации внешних функций пополнить именем модуля, где обнаружено
> > определение функции. Эти декларации вставляются на стадии разрешения,
> > а изначально могут отсутствовать (см.ниже).
>
> На самом деле я уже давно хотел (но боялся) предложить следующее:
> все имена в момент использования (и разрешить это в исходном синтаксисе
> -
> вроде бы ограничений нет) представлять в виде
>
> <name> ::= <simple_name> | <module_name>.<simple_name>
> <module_name> ::= <level_name> | <module_name>.<level_name>
>
> При этом алгоритм следующий: если парсер встретил объявление имени -
> то имя полностью раскрывается со всеми префиксами модулей и помещается в
> таблицу. Если же имя встретилось в момент использования, то оно ищется
> в таблице, но не по полному совпадению, а по совпадению с "хвостом".
> Если таких совпадений несколько - то ругаться, что имя слабо
> специфицировано. Получается как в Java или C++... Тогда если в
> абстрактном синтаксисе оставить только полностью специфицированные имена
> (а оно так и должно быть), то в принципе можно обойтись и без USE
> (а также и без linkage-спецификаторов - ведь для каждого имени будет
> известен модуль, где оно определено).
> А при компиляции в какой-то формат для динамической загрузки можно,
> если что, создавать хэш-таблицу нужных модулей. Кроме того так мы не
> потянем за собой никаких ненужных модулей если кто-то по ошибке
> подключил их с помощью $use.
Арк:
С идеей разрешить составные имена, в том числе в исходном синтаксисе,
согласен.
Когда именно ругаться - надо уточнять. Искать "по хвостам" - тоже
сомнительный
принцип. Ява ищет от начал, другое дело, что некоторые модули могут быть
открыты
на использование их имен простым образом (предложением import, по-нашему -
use).

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

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

Я бы хотел, чтобы еще кто-то высказался по этому вопросу. (Сережа Абрамов,
ау!).
Коротко повторю:
Есть выбор из следующих вариантов:

A) Парсер использует как вход только один файл, выдает АС-модуль
с неразрешенными именами.

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

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

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

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

> > > 5) Добавлен оператор FLUSH - см. мое письмо от 26 ноября в 16:14.
---опущено
> > > 6) NOT и ITER сохранены как есть. С моей точки зрения их раскрытие
> > > слишком далеко двигает нас в сторону виртуального кода и может
> > > привести к менее удобному представлению при компиляции в
> > > императивные языки.
> > Это нормально. Но не отменяет возможности на ранней стадии компиляции
> > устранить NOT и ITER путем их раскрытия в АС же. Я не вижу почему эти
> > раскрытия специфичны для какого-то одного типа реализации. Полагаю,
> > они универсальны.
>
> Я не против возможных расширений, но мне существенно не нравится
> использование
> LABEL в раскрытии ITER. Я бы еще согласился на
>
> t.Label ::= (LABEL s.LabelName e.Sentence)
>
> чтобы получились помеченные предложения, но не LABEL как
> абстрактная метка.
Арк:
Какая, собственно, разница? А правильно ли я понимаю, что в твоем варианте
после t.Label не должно быть продолжения предложения? (То есть t.Label
тогда
должен относиться к так называемым терминирующим операторам, таким как
FAIL.) И тот же вопрос относительно Try и Iter (в последнем варианте).
Замечу, что в своем (предыдущем) варианте я старался минимизировать
количество таких операторов. Поэтому и у Error нет явного аргумента, его
аргумент - все окончание предложения.
>
>
> > > 7) Немного изменены прагмы - но это не существенно.
> > > 8) В конце приведен вариант синтаксиса, в котором есть нераскрытые
> > > константы.
> > Это хорошо. Неясно теперь, как используются константы в теле программы.
> > Например, можно как (REF name), имея в виду, что такая конструкция
всегда
> > подразумевает ее замену на значение константы по имени name. В случае
> > фукнций
> > и объектов следует считать, что строятся автоматически определения
> > констант,
> > значениями которых являются настоящие символы-ссылки.
> > Однако, обращаю внимание, что значением константы в общем случае будет
> > не обязательно символ, и даже не обязательно терм. Но всегда -
объектное
> > (в смысле - ground) выражение, которое может быть всюду, включая
жесткий
> > образец.
>
> Как я уже писал - я бы ограничил константы до терма и ввел define'ы,
> которые раскрываются сразу - на самом деле этого хватает для всего.
> Я думаю, на первых порах можно константы сразу раскрывать, а позже
> эту часть синтаксиса довести до ума.
Арк:
Я хотел сказать, что, если уж имена-константы определяются в АС, то надо
не забыть указать, как они там используются.
>
> > Да, это расширение из Рефала-6. Он означает, что выражение должно быть
> > вычислено в момент загрузки. Вычисляется ради побочного эффекта,
> > значение игнорируется. Есть одна тонкость: момент вычисления
определяется
> > положением среди других элементов. При этом нет гарантии, что
нижеследующие
> > определения функций уже загружены и могут выполняться. Также уже должны
> > быть загружены целиком другие модули, которые используются из данного.
> > А это, в частности, означает, что в графе использований модулями друг
друга
> > не должно быть циклов.
> > Вообще, я думаю, это полезная конструкция, посколку позволяют делать
> > модули,
> > которые содержат в себе свою инициализацию (содержимого ящиков,
например),
> > и не требуют от пользователя вызывать инициализацию явно.
> > Кроме того, такие модули могут представлять самодостаточные программы,
не
> > требующие указывать их входные точки (GO, Main, и т.п.).
>
> Это все понятно и хорошо, правда проблем - не оберешься (см. мое
> следующее
> письмо).
>
> > А теперь несколько новых замечаний-дополнений.
> >
> > 1. Для объектов типов BOX, STRING, VECTOR и, возможно, TABLE - вести
> > понятие начального значения:
> >
> > t.Object ::= (s.Linkage s.ObjectType s.ObjectName
e.InitialValue)
> >
> > e.InitialValue ::= e.ResultExpression
> >
> > (ограничения - те же, что и для initializer'а.
>
> Я уже думал над этим. Только непонятно, кто будет проверять, что
> начальное значение, скажем для VECTOR имеет корректный формат?
Арк:
В момент засылки, то есть при загрузке.
> И еще - начальное значение возможно только для s.IntLinkage.
Арк:
Конечно.
>
> > 2. PragmaTrace. Отсутствует traceAll. Преднамеренно?
>
> Да. TraceAll - это Trace с пустым списком.
Арк:
Можно и так.
>
> > 3. В последнем письме от 17.12 ты предлагаешь разделить декларацию и
> > определения.
> > Мне кажется, это тоже можно вводить как стадию обработки в рамках АС.
Но
> > может
> > компилятору это и не требуется?
>
> Компилятору в момент использования функции надо знать ее форматы.
> Если не разносить декларацию и определение, то потребуется два прохода.
Арк:
А разве результат парсера не является объектным выражением, целиком
находящимся оперативной памяти? Тогда лишний проход не составляет
проблемы. А некоторые компиляторы все равно будут делать лишние проходы.
Например, компилятор в Яву может интересоваться графом вызовов для
оптимизации.
>
> > Надеюсь, не слишком утомил?
>
> Конечно, нет :-))
>
> Всего доброго,
> Андрей.



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