RSL: курс молодого бойца

Заставь дурака богу молиться — он и лоб расшибет.
Пословица

От автора

Меня зовут Дмитpий Кoтepoв. Честно говоря, я пишу статью во внезапном приливе альтруизма и сострадания ко всему живому на факультете ВМиК (если таковое еще осталось). Мне, в общем-то, все равно, будете ли вы следовать указаниям, приведенным в этой статье, или нет. Работаете вы в Far или в Windows Commander — да хоть в командной строке. Меня даже не волнует, прочитаете вы статью до конца, или запустите браузером в окно. Однако, если все же решитесь, прежде, чем импровизировать, пожалуйста, попробуйте все то, что тут описывается, слово в слово. В ЦК все-таки не дураки сидят. А у нас тут не ЦК.

Я также буду предполагать, что вы большую часть своего времени (свободного или как — это уж ваше персональное дело, каждый сходит с ума по-своему) проводите в Windows. Закостенелым пользователям Linux данная статья не адресована (пишите свою, если только сможете нормально настроить кодировку в Gnome).

Постановка проблемы

О чем это я?.. Раз вы все еще тут, вероятно, вам повезло учиться на программистском потоке факультета ВМиК. Для тех, кто до сегодняшнего дня (а сегодня хэллоуин, 31 октября 2002 года) не ходил ни на один семинар по RSL (или вообще в первый раз слышит это магическое и до боли отвратительное сочетание букв), поясняю: RSL — это вот такая штука:

scheme
  some = class
    type
      Vertex = Text,
      Edge = Vertex >< Vertex >< Duration >< Nat,
      RoadGraph = Vertex-set >< Edge-set,

    value
      empty: Database = ( ({}, {}), {} ),

      addVertex: Database >< Vertex -~-> Database
      addVertex (db, newVert) is let ((V, E), sch)=db in
          ((V union {newVert}, E), sch)
      end
      pre let ((V, E), sch) = db in
        all x: Vertex :- x isin V /\ x ~= newVert
      end
      /* и т.д. до бесконечности */
  end


Иначе не определишь.

Если вашей реакцией является вопрос: «А как это запустить?», то вот вам минус-балл на экзамене — это никак не запускается, оно просто существует. (По вопросу существования всего сущего просьба обращаться к Dee Mon-у, а то я вас совсем тут запутаю своими теориями.)

Следующий вопрос — где все это должно существовать. Пристегните ремни, если хотите пережить ответ. Готовы?.. Ну так вот. На шестом этаже, не доходя буквально самую чуточку (если смотреть сверху) до резиденции проф. Смелянского, есть такой компьютерный класс. Правда, лично я бы назвал его калькуляторным... нет, пылесным... или, лучше, керосиново-примусным классом, ибо то, что там стоит, компьютером называли только с большой натяжкой, да и то — во времена Архимеда (и только сам Архимед). Ну, в общем, там стоят Sun-ы (есть такое название в лаконичном русском языке — Sun-ы — для сущностей, которые я только что попытался описать). И именно на этих Sun-ах и должен существовать указанный текст «программы» (это называется «схемой», или «спецификацией»). Причем он должен там распознаваться специальным редактором-анализатором, который называется raise.

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

По счастью, указанный редактор позволяет не только набирать код RSL внутри себя, но и подгружать внешний текстовой файл — например, тот, который приведен выше. Однако коварные разработчики и тут подложили нам, ничего не подозревающим программистам, свинью: в случае, если файл содержит синтаксическую ошибку (или если сплошная ошибка, этот ваш файл, содержит чуть-чуть правильного кода), raise не говорит, на какой же именно строке он «заткнулся». Таким образом, отладка «спецификаций» на Sun-ах становится делом, посильным лишь титанам (и Максу Клинову, и мазохистам, а может, и тем, и другим).

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

Что делать?

Я предлагаю строить эшелон обороны на двух фронтах. Писать и отлаживать спецификации удобно Windows (а где ж еще, в примусе керосин закончился), а запускать — с помощью специального скрипта на Sun-ах. Если на Sun-ах не заработало — что же, уши стен шестого этажа надолго запомнят возглас вашего недовольства. Когда имеется чувство, что ошибок много, стоит пойти на седьмой этаж в машзал и там все спокойно исправить. Если же ошибок мало, можете воспользоваться редактором под Unix — vi или xedit (один другого «краше»).

Отлаживаем — в Windows

Прежде всего скачайте вот эту программу — rsl2cpp.zip. В архиве один-единственный EXE-шник, который умеет проверять (и довольно неплохо — об этом ниже) синтаксис в исходных файлах. Самое главное, что программа показывает, в какой строке произошла ошибка! Вы должны запускать ее так:

rsl2cpp.exe -s ВашФайл.rsl

В каком редакторе набирать код?.. В общем-то, в любом. Однако учтите, что при использовании Far (который я тоже уважаю, но не настолько же...) вы будете вынуждены постоянно переключаться между окнами для проверки синтаксиса в только что дописанном фрагменте (подчас по 20 раз в минуту). Если вы накачиваете большой и безымянный пальцы (лежащие на Alt+Tab), а также бицепс правой руки (Enter), то на здоровье. Я же предлагаю воспользоваться гораздо более удобным редактором — EditPlus 2 (без комментариев). Вы можете легко настроить его на выполнение проверки синтаксиса по сочетанию Ctrl+1, и все не выходя из редактора:

Настройки для подключения rsl2cpp.exe к EditPlus

После этого — редактируйте текст на здоровье, нажимая периодически Ctrl+1 для проверки, все ли вы делаете правильно. Рекомендую, кстати, вносить изменения мелкими порциями, каждый раз проверяя, не закралась ли ошибка.

Воюем — тоже в Windows

Ничто не совершенно в этом мире, и ничто не мир в этом совершенстве. В любой программе имеются ошибки, и rsl2cpp.exe отнюдь не является исключением. Единственное, чnо можно сказать наверняка — для корректной спецификации rsl2cpp.exe выдает OK практически всегда. Если же имеются неточности, то программа может повести себя двояко:

  1. Выдать, что произошла синтаксическая ошибка, и указать номер строки, где ее следует искать. Это — нормальное поведение.
  2. Вылететь со следующим сообщением:

    Error: char* RSLAnalyzer::getCTOPName(SyntaxNode* op)#default

    К счастью, такое сообщение «оно» выдает только в одном случае (определено экспериментально):

    scheme
      some = class
        type
          T = Text >< Text
        value
          f: T -> Bool
          f((a,b)) is true /* *** */
      end

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

          f(x) is let (a,b)=x in true end

    Понятно?.. Ну не любит он скалярные произведения — в скобках путается.

    Нужно сказать, что в случае наличия в коде указанной ошибки там могут присутствовать также и ошибки другого типа (например, синтаксические). Вот программа, содержащая синтаксическую ошибку (10a — это не число), но, тем не менее, не ругающаяся на нее:

    scheme
      some = class
        type
          T = Text >< Text
        value
          f: T -> Bool
          f((a,b)) is true,
          N: Int = 10a /* тут ошибка! */
      end

  3. Отформатировать винчестер. (Ни разу не было замечено.)

Однако это еще не все. У rsl2cpp.exe есть еще одна небольшая несовместимость с raise (на этот раз в обратную сторону). Она касается следующего кода:

f: Text -> Bool
f(v) is
  exists i:Nat :- i>0

Эта спецификация, прекрасно «работающая» в rsl2cpp.exe, дает ошибку в raise: вероятно, в последнем неправильно реализованы приоритет exists, и требуются скобки:

f: Text -> Bool
f(v) is (
  exists i:Nat :- i>0
)

Естественно, последний вариант работает также и в rsl2cpp.exe.

Переносим все на Unix

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

  1. Файл на дискете должен иметь имя не длиннее 8 символов, совпадающее с именем схемы (внутри файла), плюс расширение rsl: например, some.rsl.
  2. Файл не должен содержать символов \r, которые вставляют в него практически все Windows-редакторы.
  3. Файл не должен содержать комментарии /* ... */, ибо глупый raise такие не понимает.

Как видите, довольно много условий. Далее я приведу скрипт, который «чистит» исходники таким вот образом, а пока предположим, что все условия выполнены. Итак, что необходимо сделать, чтобы взять указанный файл с дискеты и запустить его в raise:

  1. Войти в систему с указанным администратором логином и паролем (у нас был логин rsl2813, а пароль 3a6op, может, и у вас будет такой же). Естественно, это нужно делать на машине, имеющей дисковод.
  2. Набрать команду openwin.
  3. Подождать несколько минут (часов?) и позакрывать все лишние окна (у керосинок склероз, памяти мало).
  4. Запустить в командной строке xterm и дальше работать только с этим окном терминала. Дело в том, что он поддерживает Tab, стрелки и т.д., тогда как «стандартный» терминал все это не умеет. Вероятно, мечта Sun — клавиатура с одной кнопкой — ВЫКЛ, о стрелках там и не слыхивали. (Впрочем, нет: там должна еще быть кнопка на букву «Эс»; кто знает, догадается, о чем речь.)
  5. Набрать eject -d. При этом в качестве побочного эффекта откроется окно, похожее на Проводник, и там будет ваша дискета.
  6. Перетащить файлы с дискеты на панель файлового менеджера. В общем, догадаетесь.
  7. Чтобы он пожевал-пожевал, да и выплюнул вашу дискетку, наберите eject.
  8. Далее введите команду: raise some.rsl, где some.rsl — это имя только что скопированного файла. Подождите минутку-другую.
  9. Убедитесь, что он заглотил ваш код. В этом можно удостовериться, посмотрев на верхнюю часть окна: там должно быть написано что-то вроде 0 errors, ..., placeholder 0. Если где-то не нули, значит, вам не повезло, читайте данную статью еще раз.

Как поступают настоящие хакеры

Но это еще не конец. Вы когда нибудь видели хакера? И я тоже не видел. И не потому, что «настоящий хакер невидим, как человек-невидимка, и неслышим, как немой человек-невидимка», а потому что...

Сейчас речь пойдет о скрипте, который запускается в Unix и:

Скрипт будет называться run (можно скачать тут) и лежать в вашей домашней директории. Открытие любых RSL-файлов станет предельно простым: ./run имя_файла.rsl.

#!/usr/local/bin/perl -w
# Read source file at all.
$ARGV[0] or die "Usage: $0 <file-name>\n";
open(local *F, $ARGV[0]) or die "Could not open $ARGV[0]!\n";
binmode(F); local $/; $_ = <F>;

# Class name - temporary.
my $cls = "cls".time();
my $dir = "./tmp"; mkdir($dir,0770);

# Clean source.
s{\r}{}sg;
s{/\*.*?\*/}{}sg;
s{\S+ (\s* = \s* class)}{$cls$1}sxi;

# Write the file.
my $fname = "$dir/$cls.rsl";
open(local *F, ">$fname") or die "Could not write $fname!\n";
binmode(F); print F $_;
close(F); # always close before system()!

# Run RAISE.
system("raise $fname &") or die "$!\n";

Не забудьте поставить атрибут на выполнение для файла:

chmod +x run

Памятка бойцу невидимого фронта

Дмитpий Кoтepoв



(C) 2001-2003 CMC-MSU.RU