Skip to content

dermagen/simpleton

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 

Repository files navigation

Описание языка программирования ПРОСТЕЦ

1. Формат входного текста программы

Входной текст программы состоит из блоков кода, которые могут быть предварены, разделены и завершены произвольными сопроводительными комментариями. Начало блока кода сигнализирует строка, начинающаяся с трех знаков тильды (~~~) за которой идет название языка заглавными буквами (ПРОСТЕЦ) и, факультативно, номером версии в виде целого числа или двух целых чисел разделенных точкой. Между тильдами и названием, а также между названием и номером версии могут вставляться знаки пробела. Окончание блока сигнализируется строкой тоже начинающейся с трех знаков тильды, но за которыми не следует ничего больше кроме возможных знаков пробела. Компилятор игнорирует все входные строки кроме строк внутри кодовых блоков; хотя разбиение самого кода на блоки при этом может быть произвольным, принято не прерывать блок посередине незавершенного выражения.

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

NB. Интерпретатор языка стартующий в интерактивном режиме предполагает что оператор будет вводить строки кода а не комментарии, поэтому ввод строки сигнализирующей начало блока кода не требуется.

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

2. Формат кода программы

Код программы состоит из отдельных строк оканчивающихся знаком новой строки. За пределами изображений строчных литералов входные строки кода могут оканчиваться терминальными построчными комментариями. Терминальный построчный комментарий считается логически эквивалентным одному пробелу; подобный комментарий начинается с восклицательного знака (!) и заканчивается знаком непосредственно предшествующим знаку новой строки на той же строке. Сам знак новой строки при этом не входит в комментарий и играет свою обычную роль.

3. Выражения

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

Формулы как правило описывают вычисление возвращающее одно значение, результат формулы. Одна формула может быть подвыражением другой формулы, пользующейся её результатом для вычисления своего результата.

NB. В дальнейшем мы будем пользоваться термином результат не предполагая явно что он состоит из одного значения, хоть в большинстве случаев это так. Там где количество значений в результате требует внимания, об этом будет сказано явно.

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

NB. Дихотомия формулы/команды играет в основном чисто грамматическую роль. Формулы могут свободно вкладываться друг в друга без специальных вспомогательных синтаксических элементов; команды сочетаются иным образом и напрямую частью формул быть не могут. Определения могут являться частью команд, но не являются командами сами по себе.

3.1. Формулы

Формулы строятся по образцу традиционных арифметических и логических выражений. Элементарные формулы состоят из единственного элемента, например числа или имени (имена и буквальные представления чисел, литер и строк приведены в Приложении 1). Более сложные формулы строятся из более простых при помощи знаков операций и вызовов функций; параметры функций должны быть окружены круглыми скобками, которые одновременно применяются для управления старшинством операций:


log(y) * (x + 1)

Старшинство операций определяет как группируются подвыражения, окруженные знаками операций с двух сторон. Например, операция умножения * «старше» операции сложения +, поэтому подвыражения выражения x + y * z группируются как (x + (y * z)), т.е. y между двумя знаками операций «достается» более старшему знаку, в данном случае умножению.

Знаки операций участвующие в формулах разбиваются по старшинству на 10 категорий. Категории получили свои названия по своим самым характерным операциям, но не следует придавать этим названием слишком большое значение — в каждую категорию могут входить самые разные знаки, не связанные ничем кроме грамматического старшинства. Каждая категория имеет единую для всех знаков группы ассоциированность, определяющую как группируются выражения в которых подвыражение находится между двумя знаками одной и той же категории. Лево-ассоциированные операции отдают такое подвыражение левому знаку (например выражение x - y - z группируется как ((x - y) - z), а право-ассоциированные — правому. Операции группы 1 одноместные т.е. принимают только один аргумент справа; остальные операции двухместные, т.е. принимают два аргумента, левый и правый.

Старшинство Название категории Операции Ассоциация
1 изменения знака - + (-) (+) ~ @ . (~) (одноместные)
2 умножения * / (*) (/) (\) (&) (&~) {&} {&~} влево
3 сложения + - (+) (-) (|) (^) {|} {^} влево
4 минимум/максимум <> >< (<<) (>>) влево
5 отношения < > <= >= {<} {>} {<=} {>=} {<-} влево
6 равенства == /= {=} {/=} [=] [/=] влево
7 логические конъюнкции & влево
8 логические дизъюнкции | влево
9 порождение новых # ## вправо
10 абстракции => вправо

Вызов функции имеет неявно-операторный синтаксис — в качестве неявного символа операции разделяющего вызываемое выражение (например имя функции) и его аргументы (список формул разделенных запятыми заключенный в круглые скобки) выступает не имеющий внешнего выражения символ операции суперпозиции. Этот неявный символ имеет приоритет выше всех перечисленных, так что выражение x * f (y) ожидаемо группируется как (x * (f (y))). Суперпозиция лево-ассоциирована, поэтому f(x)(y) группируется как (f(x))(y).

NB. Аргументы вызова функции должны всегда писаться в скобках, даже если аргумент один: вместо математической нотации sin x требуется писать sin(x), также как вместо неявного умножения ab требуется писать явное a * b.

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

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

В случае когда кортеж содержит один аргумент, иногда возникает потребность снять ограничения по количеству значений на аргумент и передать все значения возвращаемые аргументом «напрямую», как если бы скобок не было. Потребность в такой форме возникает, например, в ситуации когда необходимо передать результаты одного вызова функции на вход другой. Запись f(g()) будет работать только если g возвращает ровно одно значение. Для того чтобы передать все значения и по-прежнему иметь возможность пользоваться круглыми скобками, требуемыми грамматикой вызова функции, используется «открытая» форма кортежа, оканчивающаяся на троеточие, т.е. (ф ... ). Такая форма не накладывает никаких ограничений на количество значений возвращаемых ф, так что запись f(g()...) обеспечит необходимую передачу всех значений из g в f.

NB. Не следует путать неформальную нотацию повтора (···) с троеточием как частью синтаксиса кортежа (...).

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

NB. Круглые скобки могут окружать не только формулы, но и команды. В случае команд, скобки могут нести дополнительную смысловую нагрузку о которой написано в соответствующем разделе.

Формулы-операции разбиваются на смысловые группы по типу принимаемых и возвращаемых значений. Далее следует краткое описание основных групп.

3.1.1. Арифметические операции (смешанная арифметика)

Арифметические операции оперируют числами. Все операции этой группы принимают как целые так и вещественные числа в качестве аргументов; если все аргументы такой операции целые и результат тоже может быть представлен в виде целого числа (что зависит от реализации), то результат будет тоже целым, иначе результат — вещественное число.

NB. Все реализации должны поддерживать целые числа в диапазоне -536870912 .. 536870911 включительно. Вещественные числа как правило представлены в виде чисел плавающей арифметики двойной точности и операции с ними не являются абсолютно точными в математическом смысле.

Изменения знака (одноместные): - +

Умножение и деление: * /

Сложение и вычитание: + -

Минимум и максимум: >< <>

Сравнения: < > <= >=

Проверки на равенство/неравенство: == /=

3.1.2. Арифметические операции (целочисленная арифметика)

Целочисленные операции принимают только целые аргументы и всегда возвращают целые значения. Целочисленное деление (/) округляет в сторону нуля, целочисленный остаток (\) возвращает парное к нему значение, так что для всех x и y для которых обе операции определены, выполняется равенство х (/) y (+) х (\) y == y.

Изменения знака (одноместные): (-) (+)

Умножение, деление и остаток: (*) (/) (\)

Сложение и вычитание: (+) (-)

Побитная инверсия: (~)

Побитное «и», «или», исключающего «или», маска: (&) (|) (^) (&~)

Побитные сдвиги: (<<) (>>)

3.1.3. Операции над последовательностями

Взятие первого элемента непустой последовательности (одноместная): @

Взятие остатка непустой последовательности без первого элемента (одноместная) : .

Присоединение элемента в начало последовательности: #

Конкатенация двух последовательностей: ##

Проверки на равенство/неравенство: [=] [/=]

3.1.4. Операции над множествами

Пересечение и вычитание: {&} {&~}

Объединение, симметричная разность: {|} {^}

Проверка принадлежности: {<-}

Проверки на подмножество: {<} {<=}

Проверки на надмножество: {>} {>=}

Проверки на равенство/неравенство: {=} {/=}

3.1.5. Логические операции

Логические операции принимают и возвращают логические значения. Вычисление аргументов логического «и» и логического «или» производится слева направо и прекращается как только результат операции оказывается полностью определён.

Логическая инверсия («не», одноместная): ~

Логическая конъюнкция («и»): &

Логическая дизъюнкция («или»): |

3.1.6. Функциональная абстракция

Формулы вида и => ф и (и, ···) => ф описывают безымянные функции. Первый вариант эквивалентен записи (и) => ф и тоже описывает функцию с одним аргументом. Все имена аргументов и, ··· должны быть различными; при вызове функции с соответствующим числом аргументов эти имена получат результаты вычисления аргументов в качестве значений (по одному значению на аргумент) и могут использоваться при вычисления тела функции ф, на которое распространяется область их видимости.

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

3.2. Команды

Команды, как и формулы, строятся при помощи знаков операций и вложенных выражений. Однако, в отличие от формул, команды дополнительно могут использовать одновременно два разделительных знака, тем самым соединяя три выражения. Формат такой трёхместной операции X з Y ; Z или X з Y , Z где з это знак операции; два выражения справа всегда разделяются либо запятой либо точкой с запятой.

Несмотря на то, что команды выступают отдельно от формул, все команды устроены так чтобы из них была возможность собрать выражение возвращающее значение и тем самым пригодное в качестве подвыражения формулы. Для этой цели грамматика языка устроена так, что последним выражением в двух- или трёхместной команде может быть либо формула (и тогда результатом вычисления всей команды может стать результат этой формулы), либо другая команда, вычисляемая после и в контексте заданном остальными выражениями команды. Там самым команды собираются в цепочку, оканчивающуюся на формулу; такая цепочка, будучи заключена в круглые скобки ( ) или эквивалентные им ограничители, с точки зрения грамматики является формулой и может использоваться в тех же местах где ипользуются формулы описанные в предыдущем разделе.

Знаки операций команд по старшинству находятся на самой нижней, 11-й ступени иерархии. Все они право-ассоциированы, так что каждая команда включает в себя команду, являющуюся её последним выражением, а формула оканчивающая цепочку команд оказывается вложенной глубже всех.

Старшинство Название категории Операции Ассоциация
11 двухместные команды ; : <: >: вправо
11 трёхместные команды := ; -> ; вправо по последнему выражению

Поскольку команды играют важнейшую роль в формировании кода программы, необходимо разобрать основные из них подробнее.

3.2.1. Команда последовательного исполнения ( двухместная операция ; )

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

Типичным примером подобного рода формул являются выражения ввода-вывода, требующие контроля за последовательностью исполнения.

3.2.2. Команда исполнения в контексте определения ( двухместная операция ; )

Команда вида о ; в где о это определение локальных переменных, а в - произвольная команда или формула использует тот же знак операции что и команда последовательного исполнения, но отличается от неё грамматически так как определения отличаются от формул. В языке существует несколько видов определений, и все из них строятся вокруг знака операции =, где слева от знака стоит имя или более сложная конструкция, напоминающая вызов функции или кортеж с именами в качестве подвыражений, а справа — формула, задающая начальное значение или набор значений. Виды определений обсуждаются в разделе 3.3.; все варианты имеют одну общую характеристику: вычисление определения порождает значения для группы определяемых имён, получающих выражение в в качестве своей зоны видимости. Результатом вычисления всей команды является результат в, при вычислении которого могут использоваться значения имён из о.

Пример:


(х = log(y); x * 2)   ! возвращает удвоенный логарифм y

(l(x) = log(x); l(y) * 2)   ! тот же результат что и выше

3.2.3. Команда присваивания ( трёхместная операция := ; )

Команда вида и := ф ; в где и это имя ранее определенной переменной, ф — произвольная формула а в — произвольная команда или формула предназначена для присваивания переменной нового значения. Вычисление команды начинается с вычисления формулы ф, которая должна вернуть одно значение, которое далее записывается в качестве нового значения переменной и. Команда присвоения гарантирует что все побочные эффекты от исполнения ф и изменения значения переменной и будут завершены до начала вычисления в. Результатом всей команды являются результат в.

NB. Присваивание не является формулой поскольку не имеет собственного значения. Императивные языки, в которых присваивание играет центральную роль, стремятся упростить его использование и делают его выражением, но в данном случае такой необходимости нет.

3.2.4. Команда выбора ( трёхместная операция -> ; )

Команда вида ф1 -> ф2 ; в где ф1 и ф2 — произвольные формулы, а в - произвольная команда или формула позволяет принять решение о передаче управления в зависимости от логического результата. Вычисление команды начинается с вычисления формулы ф1 которое должно возвратить логический результат. Если возвращенное значение истинно, результатом команды будет результат вычисления формулы ф2, иначе будет произведено вычисление выражения в и возвращён его результат.

Грамматическая несимметричность двух ветвей команды выбора обусловлена частотой использования ветвей; одним из характерных способов определения результата является перебор вариантов:


(x < 0 -> -1; x > 0 -> 1; 0)   ! возвращает знак х в виде целого числа

3.2.5. Команда метки ( двухместная операция : )

Команда метки предназначена для обозначения места в цепочке команд, к которому можно вернуться для повторного исполнения, т.е. для организации цикла. Однако, в отличие от меток в большинстве других языков программирования, команда метки в языке ПРОСТЕЦ позволяет передавать новые значения переменных цикла не через изменение переменных, а напрямую, через параметры метки. В сущности, такая метка является ничем иным как локально определённой функцией, каждое обращение к которой не прерывает исполнение а является вызовом функции.

Команда метки имеет вид им(о, ···) : в, где им это имя метки, (о, ···) это возможно пустая последовательность определений имён параметров, а в — формула или команда. Каждое определение о имеет вид и = ф, выражение в находится в области видимости имени метки им и имён параметров и···.

Неформально, команда ведёт себя следующим образом: сначала вычисляются значения формул ф··· и вводятся локальные имена и···, получающие эти значения в качестве начальных. Вместе с этим, вводится локальное имя им, получающее в качестве значения функцию позволяющую вызвать новую итерацию с новыми значениями этих параметров. Далее происходит вычисление внутреннего выражения в, входящего в зону видимости всех новых имен. Если вычисление этого выражения не приводит к вызову имени метки им с новыми параметрами, то команда метки завершается и результат в становится её результатом. Если же в процессе исполнения такой вызов происходит, каждый подобный вызов приводит к повторному исполнению в с новыми значениями локальных имён и···, причём к исполнению возвращающему значение а не просто передающему управление подобно оператору goto.

Формально, смысл команды метки определяется её трансформацией в определение и вызов локальной рекурсивной функции. Команда вида

им(и = ф, ···) : в

полностью эквивалентна команде исполнения в контексте определения

им = (и, ···) => (в) ; им(ф, ···)

Пример:


 ! итеративное определение функции факториал
 fact(x) = (f(x=x, v=1): x > 1 -> f(x-1, x*v); v)

NB. Для того чтобы управляющие структуры отложенных вычислений не накапливались в памяти, вызов функции-метки должен находиться в позиции из которой производится возврат результата команды (её так называемой хвостовой позиции — см. ниже).

3.2.6. Команда запоминания цепочки возврата ( двухместная операция <: )

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

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

Для прямой манипуляции с цепочками возврата в языке существует две команды. Команда запоминания цепочки возврата имеет вид и <: в, где и это новое локальное имя, а в — любая формула или команда. В начале вычисления данной команды её неявная цепочка возврата делается явной и доступной внутри в под локальным именем и. Далее следует вычисление в, с той же неявной цепочкой возврата, которой в «обычной» ситуации и передаётся результат вычисления в. Однако ситуация может и не быть «обычной» — для этого существует парная команда нелокального возврата.

3.2.7. Команда нелокального возврата ( двухместная операция :> )

Команда вида ф :> фв где ф и фв — произвольные формулы предназначена для осуществления нелокального перехода к ранее запомненной цепочке возврата. Работает она следующим образом: сначала вычисляется формула фв, результатом которой должна быть цепочка возврата, ранее полученная при помощи вышеописанной команды запоминания <:. Далее, неявная цепочка возврата сопровождающая вычисление всей команды заменяется только что вычисленной и формула ф вычисляется уже с ней, отправляя ей свой результат (ноль или больше значений).

Неформально, эффект нелокального возврата выглядит так: результат ф не возвращается в обычное место как бы положенное по тексту программы, а «ныряет» и «выныривает» в качестве результата команды <: в которой данная цепочка возвратов фв была запомнена. То есть вычисления продолжаются в совершенно другом месте, так, будто никаких вызовов с момента запоминания цепочки не происходило вовсе (однако происходили все побочные эффекты: присвоение переменным, изменение объектов в памяти, ввод-вывод и т.д.).

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

NB. В реализации языка цепочки возврата могут быть представлены как процедуры и в такой реализации возвращаемый результат можно было бы передать в функцию цепочки возврата явно в качестве аргументов, т.е. (х, 1, y+z) :> f эквивалентно f(х, 1, y+z). Запись в виде операции :>, однако, не просто делает нелокальный переход более заметным в тексте программы; если возвращаемый результат производится вложенным вызовом, запись f(foo()) вызовет foo с удлинённой цепочкой возврата, чтобы уже потом её заменить по возвращении из foo(), в то время как запись foo() :> f сразу подставит нужную. Разница станет заметна если внутри foo() текущая цепочка запоминается, например для реализации сопрограмм — в одном случае цепочки будут удлинняться при каждом переключении, в другом нет.


 ! факториал с нелокальным выходом
 fact(x) = (res <: f(x=x, v=1): х < 1 -> v :> res; f(x-1, x*v))

3.3. Определения

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

3.3.1. Простое одиночное определение

Самым простым видом определения является определение вида и = ф где и это имя, а ф — формула, задающая начальное значение для и (определяющее выражение). Формула ф вычисляется в контексте где это имя доступно но не имеет определенного значения (и стало быть не может быть использовано во время вычисления ф); результат формулы по окончанию её вычисления становится значением имени (результат должен состоять из одного значения).


(х = log(y)*2; y+1)  ! возвращает  log(y)*2+1

3.3.2. Определение одиночной функции

Определение вида и (и1, ···) = ф служит для более наглядного определения функции, и может быть заменено на эквивалентное простое одиночное определение с операцией функциональной абстракции в качестве определяющего выражения:

и (и1, ···) = ф

полностью эквивалентно

и = (и1, ···) => ф

Пример:


(z(x, y) = log(x)+log(y); z(1.0, 3.0))      ! возвращает log(1.0)+log(3.0)

(z = (x, y) => log(x)+log(y); z(1.0, 3.0))  ! тот же результат

3.3.3. Совместное определение

Данное определение имеет вид последовательности вышеописанных одиночных определений разделённых точкой с запятой ;. Вычисление такого определения производится последовательно путём вычисления его составных частей (слева направо), но с объединённой зоной видимости определяемых имён: зоной видимости для всех имён является весь набор их определяющих выражений. Это, в частности, позволяет определять группу взаимно-рекурсивных функций. Пример:


(even(x) = x <  1 |  odd(x-1);    ! начало совместного определения  
  odd(x) = x >= 1 & even(x-1);    ! конец совместного определения
 even(5))                         ! проверка на чётность не проходит

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

NB. Для совместного определения требуется чтобы все определяемые имена были различны.

3.3.4. Одновременное определение

Определение вида (и, ···) = ф определяет группу имён одновременно. Левая часть такого определения — список имён разделенных запятой, заключенный в круглые скобки. Определяющим выражением для такой формы может служить любая формула, вычисление которой возвращает нужное количество значений; оно не входит в зону видимости определяемыех имён. Это дает возможность определять одно и то же имя снова и снова, давая ему значение, вычисленное с использованием «старого» имени, или менять значения местами, определяя новые имена при помощи старых (см. пример ниже).

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

3.3.5. Вложенное определение

Вложенное определение имеет вид последовательности из одиночных, совместных или одновременных определений, разделённых знаком точка с запятой ;. Совместные определения собираются заранее, так что на данном этапе выступают как одно целое. Вложенное определение вычисляется последовательно слева направо; каждое индивидуальное определение в последовательности вычисляется в области видимости всех имён определённых ранее и может обращаться к их значениям (т.е. все побочные эффекты к этому моменту завершены и имена получили свои значения). Имена определённые позднее могут совпадать с именами определёнными ранее по ходу последовательности; в окончательный набор видимых имён не войдут имена, «перекрытые» последующим определением.


(x = 1; (x) = x+1; (x) = x+1; x)          ! возвращает 3

(х = 1; y = 2; (x, y) = (y, x); 10*x+y)   ! возвращает 21 

4. Выражения верхнего уровня

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

4.1. Формулы верхнего уровня

Формулы верхнего уровня имеют вид ф ; где ф — произвольная формула. Результат вычисления ф в интерактивном режиме выводится на экран, в других режимах игнорируется.

4.2. Определения верхнего уровня

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

В интерактивном режиме определения верхнего уровня вычисляются по мере поступления и определённые имена становятся доступными для использования сразу по окончании вычисления соответствующего определения.

В остальных режимах исполнение программы начинается со специально помеченной процедуры называемой процедурой входа.

ПРИЛОЖЕНИЯ

Приложение 1. Грамматика языка

В этом приложении приводятся правила задающие полную грамматику языка. Правила пишутся в расширенной БНФ-нотации: в дополнение к знаку ::= разделяющему левую и правую часть правила и знаку | разделяющему альтернативы, используются следующие соглашения:

| ··· | — неформальное повторение, пропущенные правила

{ х } — элемент х является необязательным (может повторяться 0 или 1 раз)

х ··· — элемент х может повторяться 0 или больше раз

х , ··· — элемент х может повторяться 0 или больше раз; повторения разделяются запятой

Элементы грамматики записываются в угловых скобках. Некоторые из них, например <ЗНАК НОВОЙ СТРОКИ>, определены за пределами приведенной грамматики; названия таких элементов пишутся прописными буквами.

П 1.1. Лексические элементы

Правила для лексических элементов не подразумевают никаких дополнительных знаков между элементами грамматики, все элементы пишутся последовательно в соответствии с описанием. Все повторы элементов покрывают максимально длинную часть входного текста.

П 1.1.1. Комментарии и пробелы

<пробел> ::= <ПРОБЕЛ> | <ТАБУЛЯЦИЯ>

<комментарий> ::= ! <ЛЮБОЙ ЗНАК КРОМЕ НОВОЙ СТРОКИ> ···

<пробел или комментарий> ::= <пробел> | <комментарий>

<внутристрочный пробельный материал> ::= <пробел или комментарий> ···

<комментарий с новой строкой> ::= <комментарий> <ЗНАК НОВОЙ СТРОКИ>

<пробел или комментарий или новая строка> ::= <пробел> | <комментарий> | <ЗНАК НОВОЙ СТРОКИ>

<пробельный материал> ::= <пробел или комментарий или новая строка> ···

П 1.1.2. Константы

<цифра> ::= 0 | ··· | 9

<цифра 1-9> ::= 1 | ··· | 9

<двоичная цифра> ::= 0 | 1

<восьмеричная цифра> ::= 0 | ··· | 7

<шестнадцатеричная цифра> ::= 0 | ··· | 9 | A | ··· | F | a | ··· | f

<целое> ::= 0 | <цифра 1-9> <цифра> ···

<двоичное целое> ::= 2' <двоичная цифра> <двоичная цифра> ···

<восьмеричное целое> ::= 8' <восьмеричная цифра> <восьмеричная цифра> ···

<десятеричное целое> ::= 10' <цифра> <цифра> ···

<шестнадцатеричное целое> ::= 16' <шестнадцатеричная цифра> <шестнадцатеричная цифра> ···

<целое число> ::= <двоичное целое> | <восьмеричное целое> | <десятеричное целое> | <шестнадцатеричное целое> | <целое>

<знак> ::= + | -

<показатель степени> ::= e | E | *10^

<порядок> ::= <показатель степени> { <знак> } <целое>

<вещественное число> ::= <целое> . <цифра> <цифра> ··· { <порядок> } | <целое> <порядок>

<численная константа> ::= <вещественное число> | <целое число>

<логическая константа> ::= '0 | '1

<описание литеры> ::= <ЛЮБОЙ ЗНАК КРОМЕ ' " ‹ › « » ~ И УПРАВЛЯЮЩИХ> | <код знака>

<код знака> ::= <код '> | <код "> | <код ‹> | <код ›> | <код «> | <код »> | <код ~> | <код табуляции> | <код новой строки> | <код вставки 1> | <код вставки 2> | <код пропуска знака новой строки> | <универсальный код>

<код '> ::= ~'

<код "> ::= ~"

<код ‹> ::= ~‹

<код ›> ::= ~›

<код «> ::=

<код »> ::=

<код ~> ::= ~~

<код табуляции> ::= ~|

<код новой строки> ::= ~/

<код вставки 1> ::= ~@

<код вставки 2> ::= ~*

<код пропуска знака новой строки> ::= ~ <пробел> ··· <ЗНАК НОВОЙ СТРОКИ>

<универсальный код> ::= ~ <целое число> ;

<литерная константа> ::= ' <описание литеры> ' | <описание литеры>

<строковая константа> ::= " <описание литеры> ··· " | « <описание литеры> ··· »

<константа> := <численная константа> | <логическая константа> | <литерная константа> | <строковая константа>

П 1.1.3. Имена и символы операций

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

N.B. Полный набор букв, поддерживаемых конкретной реализацией языка, называется азбукой реализации. Конкретная азбука может накладывать дополнительные ограничения на допустимые имена.

<строчная буква> ::= a | ··· | z | <ДРУГАЯ СТРОЧНАЯ БУКВА>

<строчная буква, цифра или подчерк> ::= <строчная буква> | <цифра> | _

<слово> ::= <строчная буква> <строчная буква, цифра или подчерк> ···

<слово или число> ::= <слово> | <число>

<пробел, дальше слово или число> ::= <ПРОБЕЛ> <слово или число>

<имя> ::= <слово> <пробел, дальше слово или число> ···

<прописная буква> ::= A | ··· | Z | <ДРУГАЯ ПРОПИСНАЯ БУКВА>

<буквенный символ операции> ::= <прописная буква> <прописная буква> ···

<символ операции> ::= <буквенный символ операции> | - | + | ··· | :>

П 1.2. Грамматические элементы

Правила для грамматических элементов подразумевают возможность разделения любых двух элементов пробельным материалом (т.е. элементом <пробельный материал>). Все повторы элементов покрывают максимально длинную часть входного текста. В случаях когда две альтернативы могут породить один и ту же последовательность, считается что последовательность порождается альтернативой стоящей ближе к началу правила.

<выражение> ::= <команда> | <формула>

П 1.2.1. Элементарные формулы

<эф> ::= <константа> | <имя> | ( <выражение> ) | <кортеж> | <вызов>

<кортеж> ::= ( <формула> , ··· ) | ( <формула> ... )

<вызов> ::= <эф> <кортеж>

П 1.2.2. Формулы группы изменения знака (одноместные операции)

<зф> ::= <зоп> <зф> | <эф>

<зоп> ::= - | + | (-) | (+) | ~ | @ | . | (~)

П 1.2.3. Формулы группы умножения

<уф> ::= <уф> <уоп> <зф> | <зф>

<уоп> ::= * | / | (*) | (/) | (\) | (&) | (&~) | {&} | {&~}

П 1.2.4. Формулы группы сложения

<сф> ::= <сф> <соп> <уф> | <уф>

<соп> ::= + | - | (+) | (-) | (|) | (^) | {|} | {^}

П 1.2.5. Формулы группы минимум-максимум

<мф> ::= <мф> <моп> <сф> | <сф>

<моп> ::= <> | >< | (<<) | (>>)

П 1.2.6. Формулы группы отношения

<оф> ::= <оф> <ооп> <мф> | <мф>

<ооп> ::= < | > | <= | >= | {<} | {>} | {<=} | {>=} | {<-}

П 1.2.7. Формулы группы равенства

<рф> ::= <рф> <роп> <оф> | <оф>

<роп> ::= == | /= | {=} | {/=} | [=] | [/=]

П 1.2.8. Формулы группы логической конъюнкции

<кф> ::= <кф> <коп> <рф> | <рф>

<коп> ::= &

П 1.2.9. Формулы группы логической дизъюнкции

<дф> ::= <дф> <доп> <кф> | <кф>

<доп> ::= |

П 1.2.10. Формулы группы порождения новых последовательностей

<нф> ::= <дф> <ноп> <нф> | <дф>

<ноп> ::= # | ##

П 1.2.11. Формулы группы абстракции

<аф> ::= <нф> <аоп> <аф> | <нф>

<аоп> ::= =>

NB. Более детальный грамматический разбор должен ограничить вид возможных левых частей операции => так:

<имя> | ( <имя> , ··· )

заодно проверив что среди имён в скобках нет дубликатов

На этом грамматическая башня формул завершается

<формула> ::= <аф>

П 1.2.12. Команды

Все команды имеют один и тот же приоритет. Для удобства можно описать грамматику команд в упрощённом виде, не вдаваясь в подробности структуры подвыражений. Дополнительные ограничения на отдельные операции будут даны в примечаниях.

<команда> ::= <двухместная команда> | <трёхместная команда>

<двухместная команда> ::= <формула или определение> <дмоп> <выражение>

<формула или определение> ::= <формула> | <определение>

<дмоп> ::= ; | : | <: | :>

NB. Более детальный грамматический разбор должен ограничить вид возможных левых частей операции : так:

<имя> ( <определение> , ··· )

где определение ограничено простым вариантом

<имя> = <формула>

заодно проверив что среди определяемых имён нет дубликатов

NB. Левой частью операции <: должно быть <имя>

NB. Обе части операции :> должны иметь вид <формула>

<трёхместная команда> ::= <формула> <тмоп> <формула> ; <выражение>

<тмоп> ::= := | ->

NB. Левой частью операции := ; должно быть <имя>

NB. Средней частью операции -> ; может быть двухместная команда с оператором :>.

П 1.2.13. Определения

<определение> ::= <вложенное определение>

<вложенное определение> ::= <невложенное определение> ; <вложенное определение> | <невложенное определение>

<невложенное определение> ::= <совместное определение> | <одновременное определение>

<совместное определение> ::= <одиночное определение> ; <совместное определение> | <одиночное определение>

<одиночное определение> ::= <простое определение> | <определение функции>

<простое определение> ::= <имя> = <формула>

<определение функции> ::= <имя> ( <имя> , ··· ) = <формула>

<одновременное определение> ::= ( <имя> , ··· ) = <формула>

П 1.2.14. Выражения верхнего уровня

<выражение верхнего уровня> ::= <формула верхнего уровня> | <команда верхнего уровня> | <определение верхнего уровня>

<формула верхнего уровня> ::= <формула> ;

<команда верхнего уровня> ::= <имя> := <формула> ;

<определение верхнего уровня> ::= <одиночное определение> ;

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

П 1.2.15. Программы

<программа> ::= <выражение верхнего уровня> ···

Приложение 2. Средства расширения грамматики

Базовая грамматика, описанная в Приложении 1, не предоставляет достаточно средств для создания наглядного и удобочитаемого кода. Такие средства могут быть созданы путём расширения грамматики, т.е. дописывания новых грамматических правил к уже существующим и описания их поведения посредством преобразования их в базовые или добавленные ранее выражения языка.

П 2.1. Лексические элементы

Как и в основной части, правила для лексических элементов не подразумевают никаких дополнительных знаков между элементами грамматики.

<метаимя> ::= < <имя элемента> { <ПРОБЕЛ> <целое> } >

<имя элемента> ::= зоп | ··· | аоп | ··· | формула | команда | блок | итд

<сл> ::= <буквенный символ операции>

П 2.2. Грамматические элементы

Правила в этой части позволяют разделять элементы при помощи элемента <пробельный материал> из основной грамматики.

<образец> ::= <сл> | <метаимя> | <образец> <образец>

<заготовка> ::= <заготовка выражения> | <заготовка определения>

<заготовка выражения> ::= ( <выражение> )

<заготовка определения> ::= ( <определение> ... )

NB. Для того чтобы <заготовка> в правиле могло содержать метаимена, основная грамматика предварительно расширена добавлением к каждому существующему правилу варианта с метаименами, соответствующими определяемому элементу, например:

<выражение> ::= ··· | <выражение> | <выражение 0> | <выражение 1> | ···

тем самым заготовка может быть грамматически корректной и содержать метаимена из образца

<правило расширения> ::= <метаимя> ::+ <образец> ==> <заготовка>

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

Общими требованиями к правилам являются следующие:

  1. Метаимя начинающее правило должно не содержать численного элемента и должно соответствовать одному из правил грамматики

  2. Все метаимена в образце должны быть различны и тоже соответствовать правилам грамматики

  3. Образец не может содержать два метаимени подряд

  4. Заготовка должна использовать каждое метоимя образца ровно один раз, за исключением метоимён произведенный от основы имя

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

П 2.3. Определение новых операций

Допускается определение новых буквенных символов операций. Правила должны иметь следующий вид (не больше одного правила на один символ, кроме правил описанных в разделе 2.3.12.):

П 2.3.1. Определение новых именованных констант

<эф> ::+ <сл> ==> <заготовка выражения>

Пример:


 <эф> ::+ TRUE ==> '1

П 2.3.2. Определение новых видов формул группы изменения знака

<зф> ::+ <сл> <зф> ==> <заготовка выражения>

Заготовка такого правила должна содержать однократное упоминание <зф>. Пример:


 <зф> ::+ ABS <зф> ==> ( x = <зф>; x < 0 -> -x; x )

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

П 2.3.3. Определение новых видов формул группы умножения

<уф> ::+ <уф> <сл> <зф> ==> <заготовка выражения>

Заготовка такого правила должна содержать по одному упоминанию <уф> и <зф>. Пример:


 <уф> ::+ <уф> MOD <зф> ==> ( <уф> (\) <зф> )

Прочие формулы расширяются таким же образом, так что будут описаны в сокращенном виде.

П 2.3.4. Определение новых видов формул группы сложения

<сф> ::+ <сф> <сл> <уф> ==> <заготовка выражения>

П 2.3.5. Определение новых видов формул группы группы минимум-максимум

<мф> ::+ <мф> <сл> <сф> ==> <заготовка выражения>

П 2.3.6. Определение новых видов формул группы отношения

<оф> ::+ <оф> <сл> <мф> ==> <заготовка выражения>

П 2.3.7. Определение новых видов формул группы равенства

<рф> ::+ <рф> <сл> <оф> ==> <заготовка выражения>

П 2.3.8. Определение новых видов формул группы логической конъюнкции

<кф> ::+ <кф> <сл> <рф> ==> <заготовка выражения>

Приведём в качестве примера аналог операции & определённый при помощи команды -> ;


 <кф> ::+ <кф> AND <рф> ==> ( x = <кф>; x -> <рф>; x )

П 2.3.9. Определение новых видов формул группы логической дизъюнкции

<дф> ::+ <дф> <сл> <кф> ==> <заготовка выражения>

Приведём в качестве примера аналог операции | определённый при помощи команды -> ;


 <дф> ::+ <дф> OR <кф> ==> ( x = <дф>; x -> x; <кф> )

Последующие операции ассоциированы вправо.

П 2.3.10. Определение новых видов формул группы порождения новых последовательностей

<нф> ::+ <дф> <сл> <нф> ==> <заготовка выражения>

П 2.3.11. Определение новых видов формул группы абстракции

<аф> ::+ <нф> <сл> <аф> ==> <заготовка выражения>

П 2.3.12. Определение новых именованных формул с блочной структурой

Под блочной стуктурой понимается вид грамматических элементов, ограниченных служебными словами с обеих сторон. Такие элементы могут быть определены следующим образом:

<блок> ::+ <сл> <образец> <сл> ==> <заготовка выражения>

или

<блок> ::+ <сл> <образец> <итд> ==> <заготовка выражения>

или

<итд> ::+ <сл> <образец> <итд> ==> <заготовка выражения>

или

<итд> ::+ <сл> ==> <заготовка выражения>

или

<итп> ::+ <сл> <образец> <итп> ==> <заготовка определения>

или

<итп> ::+ <сл> ==> <заготовка определения>

где <итд> — любое метаимя с основой на итд ( <имя элемента> итд ) и численным индикатором, а <итп> — любое метаимя с основой на итп ( <имя элемента> итп ) и численным индикатором; если правило содержит метаимя с основой итд или итп, должно быть хотя бы одно правило с именно этим метаименем в левой части.

Этот вид правил предназначен для определения новых видов формул, ограниченных с двух сторон спецсимволами; именем определяемой операции является открывающий символ. Образец между символами или символом и метаименем с основой итд / итп может содержать нумерованные или не нумерованные метаимена соответствующие категориям <имя>, <формула>, <команда>, <итд> и <итп>. Mетаимена категорий <формула>, <команда>, <итд> и <итп> должны быть упомянуты в заготовке ровно один раз.

Примеры:


<блок>  ::+  BEGIN <команда> END 
        ==> (<команда>) 

<блок>  ::+  IF <формула> THEN <команда> <итд 1> 
        ==>  (<формула> -> (<команда>);
              <итд 1>) 

<итд 1> ::+  ELIF <формула> THEN <команда> <итд 1> 
        ==>  (<формула> -> (<команда>);
              <итд 1>) 

<итд 1> ::+  ELSE <команда> ENDI
        ==>  (<команда>)

<итд 1> ::+  ENDI 
        ==>  ()

<блок>  ::+  CASE <формула> <итд 2> 
        ==>  (_it = <формула>; <итд 2>)

<итд 2> ::+  WHEN <формула> DO <команда> <итд 2> 
        ==>  (_it == <формула> -> (<команда>);
              <итд 2>)

<итд 2> ::+  ELSE <команда> ENDC
        ==>  (<команда>)

<итд 2> ::+  ENDC 
        ==>  ()

<блок>  ::+  WHILE <формула> DO <команда> ENDW
        ==>  (loop ():
              <формула> -> ((<команда>) ; loop());
              ()) 

<блок>  ::+  FOR <имя> <итп 3> <команда> ENDF 
        ==>  (_start = 0; _end = INFTY;  
              _step = 1; _result() = ();
              <итп 3>;
              loop(<имя> = _start):
              <имя> >= _end -> _result();
              (<команда>);
              loop(<имя> + _step))

<итп 3> ::+  FROM <формула> <итп 3>
        ==>  (_start = <формула>; <итп 3> ...)

<итп 3> ::+  UPTO <формула> <итп 3> 
        ==>  (_end = <формула>; <итп 3> ...)

<итп 3> ::+  STEP <формула> <итп 3>
        ==>  (_step = <формула>; <итп 3> ...)

<итп 3> ::+  RESULT <формула> <итп 3>
        ==>  (_result() = <формула>; <итп 3> ...)

<итп 3> ::+  DO 
        ==>  (...)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published