Структура данных
Данные, обрабатываемые языком Рефал, представляют собой последовательности атомов, структурированные несколькими согласованными между собою видами скобок. Например, в некотором конкретном синтаксисе такое выражение могло бы иметь вид {a+[b-(c+d)**2]/3}*(a+d). В поле памяти Рефал-машины задействованы два вида скобок: структурные и функциональные.
Выражения языка Рефал.
- Атомы являются выражениями.
- Любая последовательность выражений является выражением.
- Выражение E, заключенное в структурные скобки, является выражением. Атомы и выражения в структурных скобках носят общее имя термов.
- Если E — выражение, A — описанный в программе атом, AE, заключенное в функциональные скобки, является выражением (называемым функциональным выражением). A называется детерминативом этого выражения.
В конкретном синтаксисе Рефала функциональные скобки обозначаются < >, структурные -- ( ). Атомы делятся на:
- Символы (байты, простые символы).
- Составные символы (имена, определенные в программе) представлены идентификаторами, начинающимися с большой буквы.
- Целые числа без знака, меньшие 232, например, 123456789.
- Действительные числа, например, 123456789.E-5.
В поле памяти выделяется основная часть, а также стеки глобальных данных - закопанные данные. Перед каждым шагом исполнения в основной части поля памяти выделяется активная часть - поле зрения. Данные в поле зрения и закопанные данные имеют общую структуру1), которая является подструктурой структуры поля памяти. Поскольку и программа имеет практически ту же самую структуру2), в ходе развития языка появилась третья структура данных (метаданные), расширяющая поле памяти.
Дадим точные определения.
Объектное выражение — выражение, не содержащее функциональных скобок.
Минимальное функциональное выражение — выражение, имеющее вид <E>, где E — объектное выражение.
поле памяти Рефал-машины представляет собой набор выражений, одно из которых называется основной частью. В основной части в любой момент, за исключением момента выдачи окончательного результата и остановки программы, есть функциональные скобки.
Поле зрения (активная часть) поле памяти — первое из встречающихся в основной части поля памяти минимальных функциональных выражений.
Детерминатив — первый символ в функциональной скобке.
Детерминатив интерпретируется как имя функции, обрабатывающей содержимое функциональных скобок. Эта функция должна определяться статически, поэтому в ходе вычислений не могут образовываться выражения вида < <e.1> e.2>. В подавляющем большинстве случаев детерминатив должен быть именем, но некоторые обычные символы, например +, также могут использоваться в качестве детерминативов.
Пример 5.2.3. Рассмотрим пример памяти Рефал-машины в ходе вычислений.
Поле памяти:
'aaxzACDE' <Sort <Perm 'G'1.5E5> <Perm 115 'F'> <Perm 112 -2.0E-5>><Sort AllRight Sort Perm 'QRTS'>'XZ<(')
Поле зрения выделено в поле памяти жирным шрифтом. Заметим, что в поле памяти можно выделить данные, обработка которых уже завершена и которые не изменятся до конца исполнения программы (те, которые находятся вне программных скобок; в нашем случае 'aaxzACDE' и 'XZ<('). У символов, представляющих скобки, есть 'обычные' двойники, не обязательно имеющие парные и не влияющие на структурирование выражения. Первый атом Perm стоит в позиции функции, а последний из атомов Perm стоит в позиции данных, так что имена функций могут формироваться3) динамически. При записи программы пробелы, если они не находятся внутри символьных констант, игнорируются, за исключением тех, которые отделяют один символ от другого (эти пробелы просто опускаются после того, как на этапе лексического анализа сыграли роль разделителей). И, наконец, еще одна тонкость. 123 — это один атом, '123' — три атома, -123.0 — опять один атом, -123 — два атома: символ '-', после которого стоит число.
Кроме основной части поля памяти, в ходе исполнения может появиться несколько стеков закопанных выражений, например:
Stack1 '=' 15 Stack2 '=' Perm B A 21 Perm C2 C1 -45 Perm 'X' 20 60
В принципе, несколько стеков — избыточная конструкция.
Но, поскольку здесь стеки рассматриваются как общие области памяти, лучше в каждом модуле иметь свой стек. К сожалению, явной связи между стеками и модулями в Рефал-программах нет.
Допустим, есть строка < AB(CD)(E)F>. Она во всех известных нам Рефал-системах представляется двунаправленным списком, изображенным на рис. 5.1. Этот формат представления стал общераспространенным для Рефал-систем, начиная с реализации, описанной в [25]. Однако
Рис. 5.1. Реализация структуры данных Рефала
он не является обязательным4). Преобразование выражений в формат для обработки делается один раз, при вводе информации либо при трансляции программы.
Рассмотрим конкретный синтаксис выражений.
Идентификатор — любая последовательность цифр и букв, начинающаяся с большой буквы. Идентификатор является символьным литералом и представляет составной символ. Символы, заключенные в одинарные ' ' кавычки, являются символьными литералами, представляют сами себя. Дважды повторенная кавычка представляет кавычку. Двойные кавычки " " используются для ограничения имени составного символа, не обязательно являющегося идентификатором5). Если вне кавычек встречается символ, не являющийся скобкой, частью идентификатора или числа, это трактуется как ошибка.
Определение метавыражения Рефала получается из определения выражения добавлением еще одного базисного случая: переменная является метавыражением.Переменные не могут быть детерминативами.
Метавыражение называется образцом, если оно не содержит функциональных скобок.
В конкретном синтаксисе обозначение переменной включает тип и символ переменной, записываемые как тип.атом. В стандартном Рефале имеются переменные трех типов: символьные (s.First), термовые (t.Inner) и общие (e.Last).
Значением символьной переменной служит атом, термовой — терм (символ или выражение в скобках), общей — произвольное (может быть, пустое) объектное выражение.
Рефал развивался как язык символьных преобразований в самом широком смысле этого слова, и поэтому в него была заложена возможность обрабатывать собственные программы.Он предоставляет стандартные функции метакодирования, взаимно-однозначно и взаимнообратно преобразующие произвольное метавыражение в объектное и наоборот. Таким образом, появляется возможность создавать программы в ходе выполнения других программ и затем выполнять их "на лету". Такая возможность, просто гибельная для программ в большинстве систем и стилей программирования, в данном случае не приводит ни к каким отрицательным последствиям из-за уникального концептуального единства и продуманности языка6).