Язык REXX, к 40 летию появления

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

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

    image

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

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


    У первоначальной реализации языка был один автор, сотрудник 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. Для разных ОС вполне можно загрузить живые реализации, и попробовать его самостоятельно.

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 32

      +4
      А я первый свой вебсервер на REXX сделал.
      То есть там была некая оболочка на Си под ОС/2, которая умела слушать тисипи, и запускать нечно на REXX. Фактически там в одном флаконе были роутинг, отдача статитки и нечто напоминающии CGI.
      Работало всё это хозяйство по http/0.9 — это когда нет заголовка со всякими хедерами типа Host: и т.п. :)

      Прикиньте, было время, когда под разные хосты обязательно требовался отдельный ипшник :))
      Не прошло и 30-ти лет…
        0
        было время, когда под разные хосты обязательно требовался отдельный ипшник

        Более того — до сих пор некоторые smtp-серверы футболят запросы от тех, для кого обратный резолв не совпадает с прямым.
        Видимо некоторые студенты до сих пор настраивают sendmail по книгам 30-летней давности.

          0
          Студенты сендмайл настраивают?
          Ух ты! Где таких видели?
            0
            Да полно таких ещё, лол, серьёзно. :)
              0
              Да ладно! От sendmail.cf у опытного человека волосы дыбом встанут, а студенты вообще умрут как только попытаются понять что там к чему.
                0
                Шутка про протокол сислога и МакКузика. :3
                  0
                  Ну он-же макросами создаётся. На М4 или как оно там называется.
              0
              Ну зачем так категорично? Может постмастеру этого хоста неинтересна ваша почта, если она шлётся с хоста, где прямой и обратный резолв не совпадают. Это их полное право. У меня мейлсервера не принимают почту с Африки и Латинской Америки. Вот вообще не принимают. Нет, я не расист, просто мне так удобно.
                0

                Ну, если хостмастер думает, что google, yandex или masterhost всё бросит и будет перепиливать обратный резолв своих серверов на меня…
                Может и удобно, не спорю.

                  0
                  А вы точно хотите послать почту этому хостмастеру? И точно уверены, что он хочет эту почту принять? Вы ничего не знаете о причинах, которые побуждают человека принимать то или иное решение. И, кстати, у гугловских серверов прямой и обратный резолв на почтовых серверах таки совпадает, и по IPv4 и по IPv6. Ну и что, что сервер называется mail-lj1-x232.google.com, его не нужно переименовывать под каждого клиента гугла…
            0
            Ух, где-то в папочке (с завязками) до сих пор хранятся исходники каких-то скриптов, типа распечатки (на принтере ЕС-1055М) кода/документации на 4-х сторонах фальцованной широкой бумаги.

            А вот комплект для переплетных работ (нож и и пресс/зажим) давно утрачен. На работе более современный вариант — пластиковые «пружины», обложки и сам брошюровщик в кладовке лежат, но практически не используются.
              +3
              Вещь! В своё время под осью что им только не делал! Фэхи тоссил, из мп3 теги выковыривал и наоборот впихивал с заменой кодировки на православную. BBS-list-ы составлял. В файлопомойке по времени или размеру уборку делал. С архивами на арвиде тоже с помощью бобика ковырялся. Порнуху с больших помоек, типа galleries.adult-empire.com тоже с помощью бобика выкачивал. =)
              Сейчас под линухом, но бобик установлен. Сменил .cmd на .rex. =)
                0
                По поводу ббс и модема на 1200 без мнп можно пустить стариковскую слезу.
                Но зачем сейчас Рекс хоть в каком виде, кроме музейного?
                  +1
                  Ну, смотря где и для чего.

                  NetRexx 3.08 GA released — 2019/08/06 — так, для примера.
                    +1
                    Ну да, я понимаю что ибм будет поддерживать свои продукты до последнего и ещё где-то в мире есть программисты на Коболе с астрономическими зарплатами. Но в нормальном мире зачем это все?
                    (Пишу я глядя на свой сертификат IBM DB/2 Programmer)
                      +1
                      IBM тут (уже) никаким боком. NetRexx это с 2011 не их продукт — его отдали сообществу (хотя первоначальный автор вроде бы все тот же Майк). И как видите, его развивают прямо сейчас. Я не знаю, зачем его применяют, но в принципе, в экосистеме JVM — почему нет? Хуже оригинального REXX NetRexx не стал, стал лучше — при этом доступен импорт всего того, что написано в экосистеме Java, а этого добра просто навалом за много лет.
                        0
                        Слово «развивается» тут видимо не совсем уместно. Скорее не сдох пока благодаря одному уважаемому человеку, который всю жизнь плотно сидит на IBM, и который сейчас коммитит в НетРекс в свободное от работы время.

                        При всем уважении, но в репе за пару лет добавлено порядка 4 тыс строк.
                        Ну умер, да умер…
                          0
                          Ну, в общем таких языков, которые как бы живы и как-бы умерли — их не один. На мой сторонний взгляд даже Perl на сейчас не сильно лучше — 6 версию когда планировали? А когда через 100 лет появилась под другим названием — много ли народу на нее перешли?

                          Ну а так да, наверное zSeries это единственное место, где он реально на сегодня живой — и узкие ниши типа уже тут названных.
                +1
                Эх, молодость, молодость ). Чуть больше 30 лет назад ещё на ЕС-ке в СВМ написал на рексе базу данных неприводимых представлений федоровских групп для расчёта состава тензорных представлений оных. На ЕС-ке это был возможно наиболее удобный язык для работы со строками.
                  +1

                  Успел на нём в 90х написать BBS

                    +1
                    И я поностальгирую: я в своё время написал на ORexx многопоточный прокси-гейт, который позволял отсылать трафик программ, которые не поддерживали SOCKS, через туннель, открывая порт локально на 127.0.0.1 и перенаправляя трафик в SOCKS. Плюс там были функции анализа проходящего трафика, что-то похожее на зачатки Fiddler.
                      +2
                      Эх молодость, молодость… У меня на этом Rexx был мегаскрипт «закрытия дня» в банке — печать кучи документов на матричных принтерах и создание архивов. Этот скрипт пережил меня в банке лет на 8 и окончательно канул в Лету с заменой основного софта (ОДБ).
                        0
                        В пенсике, в своё время, косякоисправитель написал
                          0
                          Zoc — самый наверное продвинутый (и дорогой) эмулятор терминала под Mac скриптуется на REXX.
                            0
                            Да. Ещё он есть, как минимум, под винду и OS/2
                            0
                            С языком REXX я познакомился в 1989 году в процессе работы в среде СВМ (Система Виртуальных Машин) на мейнфрейме ЕС <какой-то там номер> (фактически это была OS-360 или 370, конечно).

                            REXX был языком достаточно удобным и понятным, хотя и не всегда. Например, прочитать строку со стандартного входа, что на языке C выглядело бы так:

                            s = fgets(in);

                            на языке REXX выглядело вот так:

                            parse pull s
                            'execio 1 diskr in'

                            Но в целом для своего времени язык был очень хорошим (сейчас, конечно, он морально устарел и начисто проигрывает таким языкам, как Python). В СВМ еще был текстовый редактор XEDIT, в котором можно было писать макросы на языке REXX.

                            Кстати, существовал клон редактора XEDIT, который работал на персональных компьютерах в среде MS DOS. Он назывался KEDIT, и макросы для него можно было писать на диалекте языка REXX, который назывался KEXX. Я с ним начал работать году в 1990-м.
                              0
                              s = fgets(in);

                              на языке REXX выглядело вот так:

                              parse pull s
                              'execio 1 diskr in'


                              ну вы тут слегка преувеличили. execio — это прочитать файл, в общем случае с диска и по имени. Для C вам придется файл открыть, прочитать, закрыть, так что в целом будет так на так. Хотя да, эта часть (I/O) не самая лаконичная в rexx, прямо скажем.
                                0
                                Я уже деталей через 30 лет не помню. Этот кусочек кода я взял из одного из своих скриптов тех лет. Возможно, можно было бы и проще сделать.
                                  0
                                  Ну я тоже подзабыл, но чтение из входного потока все-таки было просто parse pull, и все.
                                    0
                                    В OS/2, Regina Rexx и OpenObject Rexx это именно так, просто parse pull
                                      0
                                      Да в общем-то EXECIO это утилита для чтения/записи файлов, что как бы намекает на именованный файл, а не просто входной поток (он же — стек). Ну и в приведенном фрагменте сначала parse pull, а потом EXECIO, так что скорее всего EXECIO относился к какому-то следующему фрагменту кода, а сюда попал по ошибке.

                                      То есть, обычная логика такая:

                                      /* сначала читаем файл, и складываем в стек строки */
                                      'EXECIO DISKR имя тип буковка'
                                      /* а потом их из стека читаем */
                                      parse pull
                                      0
                                      Спасибо за отличный пост про замечательный и до сих пор современный Rexx! Со времен vm/sp он сильно изменился, за счет внешних средств. Давно появился PIPE, развился EXECIO, GLOBALV, а также, ISPF. REXX внедрили в zOS(MVS)/TSO. Появился компилятор Rexx, и возможность статического анализа нового и «старого» кода. Вообщем, язык жив, планируется (в частности — мною) для дальнейшего использования вместе с HLASM (сильно продвинутый вариант ASMH/ASM2) в новых проектах на современных «VM/SP» и «MVS» вместе с Linux. Кстати, любителей, IBM-кой «инфраструктуры» приглашаю в новый проект.

                              Only users with full accounts can post comments. Log in, please.