Язык программирования rexx: Язык REXX, к 40 летию появления / Хабр

Язык REXX, к 40 летию появления / Хабр

REXX — довольно древний, передовой для своего времени язык. Он появился, согласно википедии, в 1979 году, то есть ему недавно исполнилось 40 лет. Не самый конечно старинный язык, но возраст достойный.

Rexx это аббревиатура, означает она Restructured Extended Executor, что вероятно отсылает нас к его предкам EXEC/EXEC2. Я с ним познакомился в операционной системе VM/SP 3, где он пришел на замену именно этим скриптовым языкам. Потом он был популярен в OS/2, использовался во многих других ОС, было создано множество реализаций и производных диалектов.


Ему не слишком много внимания уделялось на Хабре, постараюсь восполнить пробелы в этой статье.

Предки, истоки, авторы


У первоначальной реализации языка был один автор, сотрудник IBM Mike Cowlishaw. Эта реализация была написана на ассемблере S/360.

Википедия считает, что на REXX повлияли PL/1, EXEC и EXEC2 и Алгол. В целом да, это язык несомненно по своему синтаксису — наследник Алгола (или Pascal, если угодно). То есть, циклы, блоки и т.п. конструкции окружаются не фигурными скобками, а ключевыми словами, do/end, например. Что же касается EXEC и EXEC2, то REXX был создан как их замена, а больше пожалуй ничего общего с ними и не имеет. Ну а по сравнению с PL/1 REXX сильно проще, да и назначение языка совершенно другое.

Как выглядит код на REXX:

/* Просуммировать числа от 1 до 10 */
sum = 0
do count = 1 to 10
    say count
    sum = sum + count
end
say "Сумма этих чисел равна " sum"."

Особенности


Что, на мой взгляд, было самым интересным или необычным в этом языке?

1. Синтаксис языка достаточно свободный, это совсем не Фортран, разумеется. На Алгол и паскаль похоже больше всего. На basic в общем тоже.

Есть операторы, типичные для структурного программирования.

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

Типизация динамическая. Переменная может интерпретироваться как строка или как число, в разные моменты выполнения, а также может быть не определена (это можно проверить, хоть и кривовато). Фактически, в языке один примитивный тип данных — строки, над которыми можно проводить арифметические операции, если строка представляет собой правильное число.

Вот маленький примерчик из википедии:

say hello /* => HELLO */
hello = 25
say hello /* => 25 */
hello = "say 5 + 3"
say hello /* => say 5 + 3 */
interpret hello /* => 8 */
drop hello
say hello /* => HELLO */


Отсюда видно, что неопределенная переменная в первой (и последней) строке вычисляется в свое имя прописными буквами. Это и есть способ проверки на неопределенность.

Оператор interpret — это аналог того, что сегодня обычно зовут eval.

Обработка ошибок пожалуй больше всего похожа на Basic:

signal on halt
do forever
... /* произвольный код */
end
halt: /* метка.  далее обработчик ошибок halt, например просто выход */
exit


Это обработка завершения программы (кнопкой с терминала). Кроме halt, есть и другие «сигналы», в том числе, например, syntax (синтаксическая ошибка в интерпретируемом коде). Не помню, чтобы я это практически применял, но вполне логично проверять на синтаксическую правильность например то, что подается на вход interpret.

2. В нем не было регулярных выражений, как скажем в Perl (до Perl впрочем еще оставалось почти 10 лет). Сама концепция регулярных выражений появилась раньше, и они уже несомненно были, скажем, утилита grep уже существовала. Вместо них был оператор parse, который является некоторым упрощенным аналогом регулярок, с подстановкой групп в переменные.

parse [origin] [template]


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

fio = 'Иван, Иванов'
parse var fio firstName ',' LastName
say firstName
say LastName


Это, конечно же, сильно проще регулярных выражений, хотя бы потому что, не было ни метасимволов типа \d, ни повторения в виде * или +, ни альтернатив, ничего такого.

3. У Rexx был API, который позволял его использовать как язык для скриптования не только ОС (CMS), но и любой другой программы, которая этот API поддерживала. Т.е. фактически, это был язык для написания DSL. Вероятно, один из первых. При этом среда исполнения могла реализовать и предоставить интерпретатору дополнительные функции или команды, доступные в итоге программе.

Выглядело это примерно так: при запуске текстового редактор XEDIT он искал где-то на доступных дисках файл под названием PROFILE XEDIT, который содержал скрипт на REXX. Этот скрипт мог назначать функциональные клавиши, и определять дополнительные команды, доступные из XEDIT. По смыслу сегодня это ближе всего к .bashrc, например. Или его аналогу для vim.

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

4. Не требовалось какого-то специального синтаксиса для передачи команд хост-среде (т.е. ОС, или скажем текстовому редактору). Вместо этого, все выражения, которые Rexx не распознал, передавались на выполнение. Таким образом, чтобы записать внутри скрипта команду ОС, достаточно было заключить ее в кавычки, например:

'list * * * (stack'


Команду можно было построить путем конкатенации строковых констант и переменных. В качестве символа операции конкатенации выступал просто пробел.

Чтобы команду передать в другое приложение, имелся оператор address. Например, при использовании в среде текстового редактора XEDIT, чтобы выполнить команду не XEDIT, а ОС (CMS), нужно было сделать так:

address cms
'list * * * (stack'


5. В CMS был реализован API для доступа к стеку команд ОС, которым в том числе и Rexx пользовался для обмена данными. Команда выше возвращала полученный список файлов в стек, откуда скрипт мог их забрать, читая по строчке как стандартный ввод. В чем-то это аналогично юниксным пайпам, но несколько отличается от них. Пайп это все-таки поток байтов, а стек в CMS — это набор строк. В общем-то, это типичное различие между идеологией Unix и ОС от IBM, где файлы в значительной степени были ориентированы на строки фиксированной или переменной (но при этом известной) длины.

6. Как часть API приложения могли иметь доступ к переменным Rexx скрипта, могли читать и изменять их. Это был еще один способ обмена данными.

7. Была реализована довольно эффективная арифметика произвольной точности. Произвольной — это значит например 100 знаков и более — на сколько памяти хватит.

8. Управление памятью — автоматическое. Хотя и имелся например, оператор drop для удаления значения переменной (ассоциативного массива или его элементов), но в любом случае, дел с указателями и размерами блоков вы не имели.

9. В качестве единственной, но при этом весьма универсальной структуры данных были ассоциативные массивы, очень похожие например на javascript. То есть, если вы пишете a.1, это элемент массива a с ключом 1. Если пишете a.b, то это элемент с ключом b.

Вот скажем процедура добавления слова в словарь:

add_word: procedure expose dictionary.
   parse arg w
   n = dictionary.0 + 1
   dictionary.n = w
   dictionary.0 = n
return


Переменная dictionary в этом фрагменте — это наш ассоциативный массив. Процедура не возвращает этот массив, а делает его доступным извне (при помощи expose). dictionary.0 хранит число элементов в словаре (это просто соглашение, и как видите, мы его выполняем сами), dictionary.n — n-е слово словаря.

10. Средств низкоуровневого доступа к памяти или к API OC язык не имел, хотя в принципе написать для него что-то подобное было вполне возможно. Могу назвать пару примеров расширений языка, одно было предназначено для работы с базой данных SQL/DS (DB2), а второе — для обмена сообщениями между виртуальными машинами в рамках VM/SP. То есть, все что вы сможете оформить как DSL, в принципе может быть реализовано.

Поддержка REXX в приложениях


Кроме самой CMS сразу же поддерживал REXX основной текстовый редактор XEDIT. Он позволял писать макросы на REXX, которые можно было повесить на функциональные клавиши, или вызывать как команды, как из командной строки, так и в качестве т.н. «префиксных» команд, которые вводились рядом со строкой(строками) текста, и позволяли ей(ими) манипулировать. Например, команда d позволяла удалить строку, рядом с которой была введена, были команды копирования или перемещения, и другие. А макрос на REXX мог к примеру преобразовать строку в прописные или в строчные буквы.

Второе приложение, поддерживавшее язык на моей памяти, называлось DMS (Display Management System for CMS (DMS/CMS)), и было это средство разработки интерактивных программ, состоящих из экранных форм (panels). Из REXX можно было выбрать одну из заранее нарисованных форм, заполнить ее поля значениями, и показать на экране. После нажатия пользователем функциональной клавиши программа получала управление обратно, и переменные REXX содержали значения измененных полей. Самым близким функциональным аналогом DMS я бы назвал HTML и его формы. И по сложности (простоте) разработки это было пожалуй еще чуть проще, хотя по выразительным возможностям HTML разумеется выигрывает (например, в DMS вообще не было изображений, что впрочем объяснимо текстовыми терминалами).

Еще одно приложение, которое стоило бы упомянуть, называлось ISPF. Но это уже было сильно шире DMS, и было похоже скорее на интегрированную среду разработки, как она выглядит сейчас, с поправкой на текстовые терминалы. И да, текстовый редактор тоже программировался на REXX.

Начиная с VM/SP 6 в CMS появились средства для создания на экране терминала виртуальных окон переменного размера, и показа в них текста. Соответствующий API появился и для REXX (а точнее, это и было в первую очередь расширение REXX).

Еще одним весьма интересным применением REXX был так называемый автооператор. Это было приложение, запускавшееся в виртуальной машине оператора ОС, которое получало все сообщения, обычно приходившие на терминал оператора, и позволяло их обрабатывать программными средствами. Обработчик команд — скрипт на REXX. Таким образом можно было например дать некоторые возможности оператора многим людям, для чего эти люди просто посылали сообщения виртуальной машине оператора, а обработчик (от имени привилегированного пользователя — оператора) выполнял для них какие-то команды. Ну например, монтировал в системе тома дисков или лент.

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

Влияние на разработку


Я бы сказал, что с появлением REXX в VM/SP 3 мы начали писать на нем значительную часть того, что ранее писалось например на PL/1. Это достаточно мощный, и в тоже время все еще простой язык, позволяющий нормально структурировать сравнительно большие приложения. В первую очередь наверное благодаря его возможностям интеграции, когда он применялся как DSL.

Возможности выполнять запросы к базе данных (SQL/DS), отображать экранные формы, читать и писать файлы покрывают значительную часть потребностей по разработке бизнес приложений.

Очевидно, язык многим понравился. Он был в OS/2, был на Амигах, под Windows, и много где еще. Позже были Object REXX с объектными расширениями, и NetREXX для JVM. Главное — этот язык все еще живой. И в общем-то, если бы пришлось выбирать, на чем сегодня писать скрипты, то рассматривая например Rexx, bash, совершенно птичий язык cmd.exe — я бы выбрал однозначно первый. Но вот в сравнении уже с языками более новыми, такими как Perl, Python, и многими-многими другими — уже все не так очевидно. Скажем, идея Rexx о передаче команд и переменных в среду исполнения была хороша — но идея, допустим COM, с его объектной ориентированностью — все же более функциональная.

Несмотря на прошедшие 40 лет, он все еще применяется в IBM z OS, да и книжка по языку, если верить википедии, вышла совсем недавно, примерно в 2012. Для разных ОС вполне можно загрузить живые реализации, и попробовать его самостоятельно.

REXX — Энциклопедия языков программирования

Дата создания:
1979
Парадигма:
  • матричная
  • объектно-ориентированная
  • процедурная
  • структурная
  • функциональная
Типизация:
  • динамическая
  • нестрогая
  • неявная
  • типизированная
Принятые расширения файлов:
.rex
Реализации и версии (свернуть все | развернуть все):
  • Regina

    • Regina 3. 3

Язык программирования

REXX — интерпретируемый язык программирования, изначально предназначенный для создания макросов и использования в качестве скриптового языка. Он был разработан в IBM для проприетарных операционных систем (z/VM, z/OS, z/VSE, OS/2, AIX).

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

В настоящее время доступны как минимум две открытые реализации, Open Object REXX и Regina, и минимум одна проприетарная, uni-REXX. Для некоторых реализаций существуют не только интерпретаторы, но и компиляторы.

Элементы синтаксиса:

Комментарии, которые могут быть вложенными/* … */
Регулярное выражение идентификатора переменной[A-Za-z?_][A-Za-z?_0-9]*
Присваивание значения переменнойvarname = value
Группировка выражений( … )
Блокdo … end
Равенство=
Неравенство<>, \=
Тождественное равенство==
Тождественное неравенство\==
Сравнение<, >, <=, >=
Определение функцииfuncname: procedure
Вызов функцииy = f(x)
Вызов функции без параметровy = f()
Последовательность;
Если — тоif CONDITION then STATEMENT
Если — то — иначеif CONDITION then STATEMENT; else STATEMENT
Бесконечный циклdo forever . .. end
Цикл с предусловиемdo while CONDITION … end
Цикл с постусловиемdo until CONDITION … end
Цикл for — next для диапазона целых чисел с инкрементом на 1do i = 1 to j … end
Цикл for — next для диапазона целых чисел с декрементом на 1do i = 1 to j by -1 … end


Логотип Rexx Language Association

Примеры:

Hello, World!:

Пример для версий

Regina 3.3

say 'Hello, World!'

Факториал:

Пример для версий

Regina 3.3

В примере используется рекурсивное определение факториала.

REXX позволяет установить произвольную точность вычислений. В данном случае 14 знаков необходимо для того, чтобы все факториалы выводились как целые числа. Без первой строки факториалы, начиная с 13!, выводятся как числа с плавающей точкой.

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

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

  numeric digits 14
  do n = 0 to 16
    say n"! = "factorial(n)
  end
exit
factorial: procedure
  parse arg n .
  if n = 0 then
    n = 1
  else
    n = n * factorial(n - 1)
  return n

Числа Фибоначчи:

Пример для версий

Regina 3.3

В этом примере используется рекурсивное определение чисел Фибоначчи.

  numbers = ''
  do n = 1 to 16
    numbers = numbers||fibonacci(n)", "
  end
  say numbers".. ."
exit
fibonacci: procedure
  parse arg n .
  if n < 3 then
    n = 1
  else
    n = fibonacci(n-1) + fibonacci(n-2)
  return n

Числа Фибоначчи:

Пример для версий

Regina 3.3

В этом примере используется итеративное вычисление чисел Фибоначчи. Массивы реализованы как “корневые переменные”: обращение к элементам массива идет по их индексам fib.1 (или fib.first).

  fib.0 = 0
  fib.1 = 1
  output = fib.1||', '
  do f = 2 to 16
    e = f - 1; d = f - 2
    fib.f = fib.e + fib.d
    output = output||fib.f', '
  end
  say output"..."
exit

The Rexx Language

The Rexx Language

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

×RexxLA ГлавнаяО RexxLAО RexxСообществоУчастникиСимпозиум

Свяжитесь с нами

Что такое Рекс?

Rexx — это процедурный язык программирования, который позволяет писать программы и алгоритмы в ясной и структурированной форме. Его легко использовать как экспертам, так и обычным пользователям. Rexx был разработан, чтобы облегчить манипулирование символическими объектами, с которыми люди обычно имеют дело, такими как слова и числа. Хотя Rexx может отдавать команды своей хост-среде и вызывать программы и функции, написанные на других языках, Rexx также спроектирован так, чтобы быть независимым от вспомогательного системного программного обеспечения, когда количество таких команд сведено к минимуму.

Общее программирование с использованием Rexx

Rexx предоставляет мощный характер и арифметические способности в простой структуре. Его можно использовать для написания простых программ с минимальными накладными расходами, но его также можно использовать для написания надежных больших программ. Его можно использовать для многих программ, для которых в противном случае использовался бы BASIC, и его структура может выглядеть несколько похожей на структуру структурированной программы BASIC. Обратите внимание, однако, что Rexx не BASIC!

Простая программа в Rexx выглядит так:

            /* Сосчитайте до десяти и сложите числа */
            сумма = 0
            сделать счет = от 1 до 10
               скажи считай
               сумма = сумма +плюс; считать
            конец
            сказать: «Сумма этих чисел равна сумме».
             
Программирование макросов с использованием Rexx

Многие приложения программируются с помощью макросов. К сожалению, в мире Unix почти каждое приложение имеет свой макроязык. Поскольку Rexx, по сути, является языком манипулирования символами, он может предоставить макроязык для всех этих приложений, предоставляя простой в использовании и согласованный интерфейс для всех приложений. Лучшими примерами таких систем являются CMS (операционная система IBM для мэйнфреймов, которая была родиной Rexx) и Amiga. Тем не менее, IBM OS/2 наверстывает упущенное, и теперь, когда Rexx свободно доступен в Unix, скоро начнут появляться приложения, использующие Rexx в качестве макроязыка. Два продукта уже существуют. Это Uni-XEDIT от Workstation Group и THE (редактор Hessling) от Марка Хесслинга.

Rexx рассматривает любую инструкцию, которую он не сразу распознает, как выражение, которое он оценивает и передает в хост-среду как команду.

Простой макрос XEDIT в Rexx выглядит так:

            /* этот макрос XEDIT центрирует строку, содержащую курсор. */
            width = 72 /* Ширина, в пределах которой центрируется линия */
            "extract /cursor/curline" /* расположение курсора и текущей строки # */
            if cursor.3=-1 /* если курсор не на строке... */
            затем "emsg Курсор не в строке данных" /* затем выдать сообщение об ошибке */
            иначе сделать
               restore=curline.2-cursor.1 /* насколько далеко курсор от текущего */
               ":"||cursor.3 /* сделать строку курсора текущей */
               "extract /curline" /* получить текущую строку */
               "заменить" center(strip(curline. 3),width) /* центрировать текущую строку */
               restore /* восстановить старую текущую строку */
            конец
             
Другие приложения Rexx

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

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

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

Новости

О нашей продукции

Связаться с нами

Логин участника

Документы

Рекс Симпозиум

Рекс Язык

История Рекса

Политика конфиденциальности

Ссылки

Скачать ooRexx

Скачать Регина

Скачать NetRexx

Скачать BSF4ooRexx

Основы Rexx — Учебник по Rexx


После завершения этой главы вы сможете:


REXX (Restructured EXtended eXecutor) — это мощный интерактивный язык программирования, который может выполнять системные команды, такие как TSO, ISPF и т. д. Он позволяет:

  • Запросить информацию с терминала и вывести вывод на терминал.

  • Выполнение команд TSO под управлением программы.

  • Разработка утилит на заказ.

  • Чтение и запись файлов.

REXX — это более современный, мощный интерпретируемый командный язык и процедурный язык, который позволяет писать программы и алгоритмы в ясной и структурированной форме. Его легко использовать как экспертам, так и обычным пользователям.

REXX может отдавать команды своей хост-среде и вызывать программы и функции, написанные на других языках.


Особенности REXX:

Особенности REXX:

  • Простота использования

  • Свободный формат

  • Удобные встроенные функции

  • Возможности отладки

  • Язык перевода

  • Расширенные возможности анализа


Общий формат операторов REXX:

Обязательным оператором в REXX является /*REXX*/ . Этот оператор должен быть включен в начало каждой программы REXX. REXX поддерживает операторы произвольного формата:

  • Может появиться где угодно между столбцами 1 и 72.

  • Может иметь любое количество встроенных заготовок.

  • Может заканчиваться символом конца строки или точкой с запятой (;).

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

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

  • Комментарии появляются между разделителями /* и */ и могут занимать одну или несколько строк.

Общая форма оператора REXX — [Метка:] термин [;], где термин — это либо комментарий, либо выражение.


Пример:

/*РЕКС*/
/* Простое заявление*/ Скажи «Привет»
/*Утверждение с использованием запятой для разделения двух строк*/ Произнесите «Используя запятую»,
«Растянуть две строки»
/*Утверждения, использующие точку с запятой в одной строке*/
Скажите «Точка с запятой»; Скажите «используется для написания нескольких операторов в одной строке».  

Создание REXX EXEC:

Прежде чем вы сможете написать REXX-программу с именем EXEC, вам необходимо создать набор данных, содержащий исполняемую программу. Набор данных может быть как последовательным, так и секционированным, но если вы планируете создать более одного исполняемого файла, проще создать библиотеку REXX как секционированный набор данных (PDS).

Рекомендуется выделять набор данных с вашим префиксом в качестве первого квалификатора, любым именем в качестве второго квалификатора и предпочтительно exec в качестве третьего квалификатора.

Например, RACFID.SOURCE.EXEC

Советы и рекомендации:

Всегда лучше вызывать программы REXX как REXX exec.


Инструкции в REXX EXEC:

Инструкции REXX подразделяются на следующие категории:

  • Ключевое слово

  • Назначение

  • Этикетка

  • Нуль

  • Команда

Ключевое слово:

Ключевое слово указывает языковому процессору выполнить некоторую операцию.