Д.Н.Кузнецов, А.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 НАЖМИТЕ ЛЮБУЮ КНОПКУ