Турбо-компиляция. Что дальше?

                   Д.Н.Кузнецов, А.E.Недоря


     Термин  "турбо-компилятор",  или просто "турбина", прочно
вошел в лексикон программистов. Своим происхождением он обязан
первой  широко доступной системе подобного класса TURBO PASCAL
фирмы    Borland.    Турбо-компилятор    представляет    собой
интегрированную    систему,   поддерживающую   основной   цикл
разработки      программного      обеспечения      (ПО)      -
редактирование-компиляция-запуск. Он  включает в себя редактор
текста  программ,  быстрый компилятор, способный компилировать
программы   по   схеме   "память   ->  память",  и  подсистему
отладочного  запуска  скомпилированных  программ.  Объединение
трех  этих  функций  в рамках одной системы позволяет получить
новые возможности:
     1)  Переход  от  редактирования  к  компиляции сводится к
нажатию   нескольких  клавиш  в  редакторе.  После  завершения
компиляции система переходит опять в состояние редактирования.
Нет  необходимости  запускать редактор и компилятор средствами
ОС,  не  надо  выходить из редактора для запуска компилятора и
снова  входить  в  редактор  для  продолжения  редактирования.
Запуск  скомпилированной программы также происходит без выхода
из редактора.
     2)  По  ошибке  при компиляции редактор позиционируется в
место   ошибки,   исключая  необходимость  запоминать  ошибки,
выданные компилятором, и искать их позиции в тексте.
     3) Турбо-компилятор может существенно сократить обращение
к  внешним  устройствам,  и соответственно, увеличить скорость
компиляции. Нет необходимости читать файл исходного текста (он
в   памяти   редактора),  нет  необходимости  записывать  файл
листинга.  Более  того,  турбо-компилятор может не писать файл
кода   и   файлы   с  информацией  для  отладчика  при  каждой
компиляции,   а  записывать  их  по  требованию  пользователя.
Особенно важна эта особенность турбо-компилятора для модульных
языков.  Так,  Модула-2  компилятор существенную часть времени
своей     работы    занимается    чтением    симфайлов    [1].
Турбо-компилятор может прочесть симфайлы и преобразовать их во
внутреннее представление при первой компиляции, а в дальнейшем
использовать их уже во внутреннем представлении.
     Турбо-компилятор  может предоставлять также разнообразные
дополнительные  возможности:  символьную  отладку  с выходом в
исходный текст при ошибках исполнения, поддержку использования
и создание библиотек и т.д..
     Естественно, турбо-компилятор требует значительно больших
ресурсов  (например, оперативной памяти), чем при традиционном
подходе,  но  этот недостаток окупается увеличением скорости и
удобства  работы. Очевидна необходимость турбо-компилятора для
автоматизированного     рабочего    места    профессионального
программиста,   что   соответствует   подходу,  принятому  для
семейства    процессоров   КРОНОС   [2].   Перед   разработкой
турбо-компилятора с языка Модула-2 мы рассматривали два пути:
     - разработка с нуля;
     - интеграция  уже  существующих  компонент   ОС Excelsior
(редактор ex, компилятор m2 и оболочка системы shell).
     Был   выбран  второй  путь,  как  менее  трудоемкий.  Для
реализации турбо-компилятора были разработаны следующие модули
(подробнее см. Приложение 2):
     - библиотека для запуска Модула-2 компилятора (mcPublic);
     - встроенный   в    редактор    shell   с  возможностями,
аналогичными оболочке системы (exShell, exExec);
     - модуль, обеспечивающий запуск компилятора в редакторе и
обработку ошибок компиляции (exComp);
     - головной модуль турбо-компилятора (e2).
     Взаимосвязь   редактирующих   и  компилирующих  компонент
системы приведена в Приложении 1.
     В  текущей (первой) версии турбо-компилятор не использует
возможностей оптимизации обращений к внешним устройствам. Так,
файл  кода  всегда  пишется  на  диск, а симфайлы читаются при
каждой  компиляции  заново.  В настоящее время идет реализация
авторами нового компилятора с расширенной Модулы-2 (mx), и при
реализации его турбо-версии эти возможности будут реализованы.
     Кроме  традиционных  для  турбо-компилятора возможностей,
которые  описаны выше, наш компилятор поддерживает возможность
создания  и  исполнения  так называемых фильтров. Фильтр - это
утилита,  запускаемая  в  редакторе  и имеющая доступ к образу
редактируемого  файла  в  памяти.  Она  может по номеру строки
текста  получить  строку, изменить содержимое строки, вставить
или  удалить  группы  строк  и  т.д..  Фильтром является любая
утилита, использующая библиотеку ScreenMgr (см. Приложение 3).
В  Приложении  3  приведены  примеры фильтров: фильтр, который
преобразует в помеченном диапазоне строк все маленькие буквы в
большие,  и  фильтр  подсчета  частоты  использования  слов  в
тексте.
     Наличие    фильтров   позволяет   динамически   добавлять
дополнительные  возможности  в  редактор,  причем добавлять их
могут  не  только  разработчики,  но и пользователи редактора.
Простота  написания  фильтров определяется простым интерфейсом
модуля  ScreenMgr.  В состав фильтров могут входить форматеры,
перекодировщики,  компиляторы,  утилиты  печати для конкретных
печатающих устройств и т.д..
     Модуль   ScreenMgr   можно   рассматривать  как  прообраз
стандарта  исполняющей  системы,  то  есть  некоторой среды, в
которой  работают все утилиты, причем это может быть редактор,
обычная   оболочка  системы  или  система  управления  окнами.
Разработка такого стандарта приведет к независимости утилит от
программно-аппаратной обстановки, в которой они работают.
     Концепция   "бурной"  (turbo)  работы  по  разработке  ПО
является    новой,    элегантной   альтернативой   громоздким,
устаревшим    решениям    пошаговой,   диалоговой,   частичной
компиляции.   При   достижении  скоростей  компиляции  порядка
нескольких  тысяч  строк в минуту (Turbo Pascal-IV 20 тыс./мин
на   IBM  PC  AT  [I80286,  10Mhz],  Modula-2  6  тыс./мин  на
КРОНОС-2.6  [3Mhz])  цикл редактирование-компиляция-запуск для
типичного   модуля   размером  300-700  строк  укладывается  в
считанные  секунды.  Объединение концепции "TURBO" с модульным
принципом разработки ПО (как это сделано в Excelsior-II, Turbo
Pascal-IV) дает программисту принципиально новые возможности в
разработке программ. Качественно меняется сам стиль разработки
и   использования   программного   обеспечения.   Традиционные
текстовые   редакторы  и  последовательные  компиляторы  (типа
внешняя  память  ->  внешняя  память)  даже  в  самых развитых
"диалоговых  системах" являются, по сути, всего лишь частичной
автоматизацей процесса
     "программа_на_бланке" ->
         "колода_перфокарт"    ->
             "трансляция"          ->
                 "загрузочный_модуль"   ->
                      "редактирование связей" ->
                           "исполнение программы"   ...
Турбо-системы  стали  первым  реальным  шагом на пути создания
"миров",  в  которых должен обитать создатель ПО. Естественно,
именно  в  понятиях  и терминах таких миров должно происходить
дооснащение  программиста необходимыми средствами, такими, как
базы  знаний  о  программах,  системы  синтеза программ и др..
Предложенный механизм "фильтров" - еще один шаг по этому пути.


                          ЛИТЕРАТУРА

1. Кузнецов   Д.Н.,   Недоря   А.Е.   Симфайлы  как  интерфейс
   операционной    системы    //Информатика.   Технологические
   аспекты. - Новосибирск, 1987 с.68-75.
2. Кузнецов  Д.Н.  и  др.  КРОНОС  -  автоматизированное место
   профессионального   программиста   //Методы   трансляции  и
   конструирования программ. - Новосибирск (в печати).

   
ПРИЛОЖЕНИЕ 1


     Связь компонент редактора и компилятора:

        ex              e2          m2       mc
         \             /  \         |        /
          \           /    \        |       /
           \         /     exComp   |      /
            \       /         \     |     /
             \     /           \    |    /
         exMain, exShell          mcPublic
           |       |                |
           |     exExec             |
           V                        V
        редактор                 Modula-2
        текстов                 компилятор



exMain    -- Библиотека редактирования.
exShell   -- Шелл (оболочка) редактора.
exExec    -- Запуск задач в редакторе.
mcPublic  -- Библиотека запуска компилятора.

ex        -- Головной модуль текстового редактора
             (без возможности компиляции).
m2        -- Головной модуль компилятора.
mс        -- Головной модуль компилятора с возможностью
             масовой компиляции
             (mc *.m - компиляция всех модулей рабочей директории).
e2        -- Турбо-компилятор.


     Объем  дополнительно  разработанного  ПО  для  реализации
турбо-компилятора:

           +----------------+---------------+
           | Имя модуля     |  Число строк  |
           |                |  в реализации |
           +----------------+---------------+
           | mcPublic       |       42      |
           | exComp         |      164      |
           | exShell        |      186      |
           | exExec         |      218      |
           +----------------+---------------+
           | Итого:         |      610      |
           +----------------+---------------+



ПРИЛОЖЕНИЕ 2

DEFINITION MODULE mcPublic; (* Ned 20-Oct-87. (c) KRONOS *)

FROM SYSTEM     IMPORT  WORD;

TYPE
  GETLINE = PROCEDURE (VAR ARRAY OF CHAR);
  PRINT   = PROCEDURE (ARRAY OF CHAR, SEQ WORD);
  ERROR   = PROCEDURE (INTEGER,INTEGER, ARRAY OF CHAR, SEQ WORD);
  PRAGMA  = ['a'..'z'];

TYPE
  INFO = RECORD
           name  : ARRAY [0..79] OF CHAR; -- имя модуля
           lines : INTEGER;               -- число строк
           errors: INTEGER;               -- число ошибок
           time  : INTEGER;               -- время процессора
           iotime: INTEGER;               -- время ввода/вывода
           codes : INTEGER;               -- размер кода
         END;

PROCEDURE enterCompiler(cpu: INTEGER);
(* Инициализация компилятора. Компилятор будет порождать
   код для процессора с номером -cpu-.
*)

PROCEDURE compile(print,info: PRINT;
                  error: ERROR;
                  getline: GETLINE;
                  maxer: INTEGER;
                  VAR res: INFO);
(* Запуск компилятора. Компилятор использует процедуры
   print,info - для сообщений компилятора;
   error      - для сообщений об ошибках;
   getline    - для чтения очередной строки исходного текста.
   maxer      - максимальное число ошибок.
   res        - информация о результатах компиляция.
*)

PROCEDURE pragma(p: PRAGMA; onoff: BOOLEAN);
(* Определение опции компилятора. *)

PROCEDURE exitCompiler;
(* Завершение компиляции. *)

END mcPublic.


DEFINITION MODULE exShell; (* Leo 30-Apr-88. (c) KRONOS *)

PROCEDURE Interpret(cmd: ARRAY OF CHAR; refresh: BOOLEAN);
(* Исполняет команду cmd.
   refresh - надо ли перерисовывать экран после исполнения
   команды.
*)

END exShell.


DEFINITION MODULE exExec; (* Andy & Ned 17-Apr-88. (c) KRONOS *)

PROCEDURE call(line: ARRAY OF CHAR; refresh: BOOLEAN);
(* Исполнение задачи.
   line    - строка с именем задачи и параметрами.
   refresh - надо ли перерисовывать экран после исполнения
   команды.
*)

END exExec.


ПРИЛОЖЕНИЕ 3

                       ПРИМЕРЫ ФИЛЬТРОВ


DEFINITION MODULE ScreenMgr; (* Ned 03-May-88. (c) KRONOS *)

FROM SYSTEM     IMPORT  WORD;

PROCEDURE curl(): INTEGER;
(* Возвращает номер текущуй строки. *)

PROCEDURE jump(line: INTEGER);
(* Прыжок на строку с номером line *)

PROCEDURE get(VAR s: ARRAY OF CHAR; VAR sz: INTEGER);
(* Взять текущую строку. *)

PROCEDURE size(): INTEGER;
(* Размер текущей строки. *)

PROCEDURE put(VAL s: ARRAY OF CHAR; sz: INTEGER);
(* Записать текущую строку. *)

PROCEDURE delete(n: INTEGER);
(* Удалить n строк начиная с текущей. *)

PROCEDURE insert(n: INTEGER);
(* Вставить n строк перед текущей. *)

PROCEDURE refresh;
(* Перерисовать экран. *)

PROCEDURE message(wait: BOOLEAN; VAL form: ARRAY OF CHAR; SEQ args: WORD);
(* Вывести сообщение. *)

TYPE FRAME = RECORD  undef: BOOLEAN;
               l0,c0,l1,c1: INTEGER;
             END;

PROCEDURE frame(VAR f: FRAME);
(* Определить границы области.
   Диапазон строк l0..l1, диапазон столбцов c0..c1.
*)

END ScreenMgr.


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

MODULE cap; (* Ned 02-Jun-88. (c) KRONOS *)

FROM ScreenMgr  IMPORT  FRAME, jump, frame, get, put, refresh
                      , message;
FROM Misc       IMPORT  Capital;

PROCEDURE capital(VAR s: ARRAY OF CHAR; size: INTEGER);
  VAR i: INTEGER;
BEGIN
  FOR i:=0 TO size-1 DO s[i]:=Capital(s[i]) END;
END capital;

VAR  f: FRAME;
  line: ARRAY [0..255] OF CHAR;
  no  : INTEGER;
  size: INTEGER;

BEGIN
  frame(f);                  -- получаю границы области
  IF f.undef THEN            -- если область не определена
    message(TRUE,"НЕ УСТАНОВЛЕНН МАРКЕР НАЧАЛА И/ИЛИ КОНЦА");
    HALT
  END;
  no:=f.l0;
  WHILE no<=f.l1 DO          -- для всех выделенных строк
    jump(no);                -- выбрал строку с номером no
    get(line,size);          -- взял строку
    capital(line,size);      -- преобразование строки
    put(line,size);          -- запись строки
    INC(no);
  END;
  refresh;                   -- перерисовка экрана
END cap.


     2. Фильтр подсчета частоты использования слов

MODULE words; (* Ned 02-Jun-88. (c) KRONOS *)

FROM ScreenMgr  IMPORT  jump, get, refresh, message, last;
FROM Strings    IMPORT  Str2, GetWord, Len;
FROM StdIO      IMPORT  ShowAndWait, print, Home, Clear;

CONST N=1024;

TYPE Word=ARRAY [0..31] OF CHAR;

VAR
  line: ARRAY [0..255] OF CHAR;
  no  : INTEGER;
  size: INTEGER;

VAR words: INTEGER;
     word: ARRAY [0..N-1] OF Word;
    count: ARRAY [0..N-1] OF INTEGER;

PROCEDURE scan;
  VAR i: INTEGER;  w: Word;
BEGIN Str2(line);
  GetWord(line,w);
  WHILE Len(w)#0 DO
    i:=0;
    WHILE (i<words) & (word[i]#w) DO INC(i) END;
    IF i>=words THEN
      IF words<HIGH(word) THEN
        word[words]:=w; count[words]:=1;
        INC(words);
      END;
    ELSE
      INC(count[i]);
    END;
    GetWord(line,w);
  END;
END scan;

PROCEDURE sort;
  VAR i,j: INTEGER;  w: Word;  done: BOOLEAN;
BEGIN
  REPEAT done:=TRUE;
    FOR i:=0 TO words-2 DO
      IF count[i]>count[i+1] THEN done:=FALSE;
        w:=word [i]; word [i]:=word [i+1]; word [i+1]:=w;
        j:=count[i]; count[i]:=count[i+1]; count[i+1]:=j;
      END;
    END;
  UNTIL done;
END sort;


BEGIN Home;
  words:=0;
  FOR no:=0 TO last() DO
    jump(no); get(line,size); scan;
  END;
  sort; Home; Clear;
  FOR no:=0 TO words-1 DO
    print("%-32.32s %3d\n",word[no],count[no]);
    IF no MOD 24 = 23 THEN
      ShowAndWait("НАЖМИТЕ ЛЮБУЮ КНОПКУ ДЛЯ ПРОДОЛЖЕНИЯ");
      Home; Clear;
    END;
  END;
  ShowAndWait("НАЖМИТЕ ЛЮБУЮ КНОПКУ");
END words.

ФАКСИМИЛЕ ПОСЛЕДНИХ ЭКРАНОВ ПОСЛЕ РАБОТЫ words
НАД ТЕКСТОМ ЭТОЙ СТАТЬИ

как                                3
реализации                         3
возможности                        3
это                                3
фильтров                           3
турбо-компилятор                   4
Турбо-компилятор                   4
не                                 4
компилятора                        4
файл                               4
В                                  4
на                                 4
строк                              4
редактор                           5
компилятор                         5
их                                 5
турбо-компилятора                  5
->                                 5
по                                 6
к                                  6
компиляции                         6
может                              6
с                                  6
при                                7
НАЖМИТЕ ЛЮБУЮ КНОПКУ ДЛЯ ПРОДОЛЖЕНИЯ
системы                            8
для                               10
-                                 12
и                                 24
в                                 28
НАЖМИТЕ ЛЮБУЮ КНОПКУ