Ввод символов для Ada83 в системе VAX/VMS

#ada

Вопрос:

Еще один вопрос типа ретро-вычислений…

Я надеюсь, что кто-нибудь там вспомнит, как выполнять прямой ввод символов с терминала в виртуальных машинах с помощью Ada83 (v3.0A).

К сожалению, эта старая версия Ada не реализует GET_IMMEDIATE в пакете TEXT_IO.

В книге Джонса «Ада в действии» в разделе 3.7.1 есть дразнящий намек, но я не смог найти списки, на которые ссылается текст, или что-либо в справочном руководстве по языку DEC, что могло бы помочь напрямую. Я уверен, что сделал это в ФОРТРАНЕ и ПАСКАЛЕ давным-давно, но ни за что на свете не могу вспомнить, как это было!

Я знаю, что мог бы облегчить себе жизнь, обновив или даже переключившись на Linux и используя компилятор GNAT, но половина удовольствия заключается в том, чтобы выяснить, как все работает (или в данном случае работало раньше).

Спасибо

Комментарии:

1. Вы знаете, что существует специализированный ретрокомпьютерный обмен стеками ?

Ответ №1:

Для начала, пожалуйста, обратите внимание, что у меня нет никакого опыта работы с VAX/виртуальными машинами, и у меня нет доступа к системе VAX. Тем не менее, раздел 3.7.5 книги содержит довольно подробную информацию о работе (отсутствующего) кода. Используя это описание (и некоторую информацию из Справочного руководства по времени выполнения VAX Ada, раздел 8.6, или Справочного руководства по времени выполнения для систем OpenVMS, раздел 7.7, см. Здесь) Я попытался (более или менее) реконструировать некоторую часть пакета виртуальных машин (т. Е. Как это могло выглядеть). Результат показан ниже. Я понятия не имею, компилируется ли он вообще, но это кажется хорошей отправной точкой для продолжения расследования.

Обновление (4 июля-2021)

Из интереса я углубился немного дальше, и кажется, что QIO и QIOW на самом деле стоят системные службы с именем «Очередь ввода-вывода (ожидание)». Эти службы описаны в некоторых более поздних документах виртуальных машин:

  • Справочное руководство по системным службам OpenVMS (см. Здесь).
  • Справочное руководство пользователя ввода-вывода OpenVMS (см. Здесь).

В первом руководстве описываются параметры $QIO и $QIOW , в то время как во втором руководстве описываются функции драйвера терминала, которые, вероятно, потребуются здесь (см. главу 5 и приложение A. 5).

Основываясь на этих документах, кажется, что вам нужно использовать использование $QIO и $QIOW в сочетании с функциями IO_READVBLK и IO_WRITEVBLK . Я не уверен, что это на самом деле правильно, но это, по крайней мере, кажется правдоподобным. Я добавил это в приведенный ниже код.

disk2/dec/vmss.ada (попытка восстановления)

 package VMS is

   VMS_IO_ERROR : exception;

   task INPUT is

      entry Ready (RDY : out BOOLEAN);
      --  Returns true if a new character is available.

      entry Get (CH : out CHARACTER);
      --  Blocks until a new character is available.

   private

      entry KeyPush;
      --  The AST service routine.

      pragma AST_ENTRY (KeyPush);

   end INPUT;

   package OUTPUT is

      procedure Put (CH : CHARACTER);
      --  Writes a character to the terminal.

   end OUTPUT;

end VMS;
 

disk2/dec/vmsb.ada (попытка восстановления)

 package body VMS is

   task body INPUT is separate;

   package body OUTPUT is separate;

end VMS;
 

disk2/dec/vmsbi.ada (попытка восстановления)

 with SYSTEM; use SYSTEM;      --  To make "or" visible.
with STARLET;
with CONDITION_HANDLING;

separate (VMS)

task body INPUT is

   ASG_STATUS : CONDITION_HANDLING.COND_VALUE_TYPE;
   QIO_STATUS : CONDITION_HANDLING.COND_VALUE_TYPE;

   CHANNEL    : STARLET.CHANNEL_TYPE;
   TERM_DEV   : constant STARLET.DEVICE_NAME_TYPE := "SYS$COMMAND";
   --  ??? Not sure if "SYS$COMMAND" is a valid device definition.

   QIO_IOSB   : STARLET.IOSB_TYPE;
   pragma VOLATILE (QIO_IOSB);

   NEW_DATA   : BOOLEAN;
   KEYINPUT   : STRING (1 .. 1) := (1 => '?');

begin
   STARLET.ASSIGN (
      STATUS => ASG_STATUS,
      DEVNAM => TERM_DEV,
      CHAN   => CHANNEL);

   if not CONDITION_HANDLING.SUCCESS (ASG_STATUS) then
      CONDITION_HANDLING.STOP (ASG_STATUS);
      raise VMS_IO_ERROR;
   end if;

   NEW_DATA := FALSE;

   loop
      STARLET.QIO (
         STATUS => QIO_STATUS,
         CHAN   => CHANNEL,
         FUNC   => STARLET.IO_READVBLK or STARLET.IO_M_NOECHO or STARLET.IO_M_NOFILTR,
         IOSB   => QIO_IOSB,
         ASTADR => INPUT.KeyPush'AST_ENTRY,
         P1     => SYSTEM.TO_UNSIGNED_LONGWORD (KEYINPUT'ADDRESS),  --  Address of the buffer.
         P2     => 1);                                              --  Length of the buffer.

      if not CONDITION_HANDLING.SUCCESS (QIO_STATUS) then
         CONDITION_HANDLING.STOP (QIO_STATUS);
         raise VMS_IO_ERROR;
      end if;

      --  Buffer input.
      L1 : while not NEW_DATA loop
         select
            accept KeyPush do
               NEW_DATA := TRUE;
            end KeyPush;
         or
            accept Ready (RDY : out BOOLEAN) do
               RDY := FALSE;
            end Ready;
         or
            terminate;
         end select;
      end loop L1;

      --  Buffer output.
      L2 : while NEW_DATA loop
         select
            accept Get (CH : out CHARACTER) do
               CH := KEYINPUT (1);
               NEW_DATA := FALSE;
            end Get;
         or
            accept Ready (RDY : out BOOLEAN) do
               RDY := TRUE;
            end Ready;
         or
            terminate;
         end select;
      end loop L2;

   end loop;

end INPUT;
 

disk2/dec/vmsbo.ada (попытка восстановления)

 with SYSTEM;
with STARLET;
with CONDITION_HANDLING;

separate (VMS)

package body OUTPUT is

   CHANNEL  : STARLET.CHANNEL_TYPE;
   TERM_DEV : constant STARLET.DEVICE_NAME_TYPE := "SYS$OUTPUT";
   --  ??? Not sure if "SYS$OUTPUT" is a valid device definition.

   procedure Put (CH : CHARACTER) is
   
      QIO_STATUS : CONDITION_HANDLING.COND_VALUE_TYPE;
      
      QIO_IOSB   : STARLET.IOSB_TYPE;
      pragma VOLATILE (QIO_IOSB);

      BUFFER     : STRING (1 .. 1) := (1 => CH);
      
   begin
      STARLET.QIOW (
         STATUS => QIO_STATUS,
         CHAN   => CHANNEL,
         FUNC   => STARLET.IO_WRITEVBLK,
         IOSB   => QIO_IOSB,                                        --  Not sure if this is actually needed here.
         P1     => SYSTEM.TO_UNSIGNED_LONGWORD (BUFFER'ADDRESS),    --  Address of the buffer.
         P2     => 1);                                              --  Length of the buffer.
      
      if not CONDITION_HANDLING.SUCCESS (QIO_STATUS) then
         CONDITION_HANDLING.STOP (QIO_STATUS);
         raise VMS_IO_ERROR;
      end if;
      
   end Put;

begin
   declare
      ASG_STATUS : CONDITION_HANDLING.COND_VALUE_TYPE;
   begin
      STARLET.ASSIGN (
         STATUS => ASG_STATUS,
         DEVNAM => TERM_DEV,
         CHAN   => CHANNEL);

      if not CONDITION_HANDLING.SUCCESS (ASG_STATUS) then
         CONDITION_HANDLING.STOP (ASG_STATUS);
         raise VMS_IO_ERROR;
      end if;
      
   end;

end OUTPUT;
 

main.ada

 with VMS;
with TEXT_IO;

procedure MAIN is
   CH : CHARACTER := '?';
begin
   while CH /= 'q' loop
      VMS.INPUT.Get (CH);
      TEXT_IO.PUT (CH);     --  Might be convenient for debugging.
      VMS.OUTPUT.Put (CH);
   end loop;    

end MAIN;
 

Комментарии:

1. КОМАНДА SYS$- это не только допустимое логическое имя, но и то, которое используется терминалом, когда команда выполняется в сценарии (ввод SYS$считывался бы из файла сценария, а не из терминала), и QIO/QIOW-это функции, которые я помню, много лет назад использовал с FORTRAN. К сожалению, мой ВАКС в настоящее время «дуется» (снова), так что может пройти несколько дней, прежде чем я смогу продолжить расследование! Проголосованный ответ просто из-за количества исследований и деталей, которые вы включили (даже если код не работает как есть, ответ на правильном пути и очень полезен).