TugBoat --
новый транслятор с Клиппера на СЧто такое TugBoat ?
TugBoat - дополнительный интеллектуальный компилятор с языка Клиппер на язык C.
А теперь об этом поподробнее и пореалистичнее…
Дополнительный компилятор
С самого начала для меня задача заключалась в ускорении выполнения существующих Клиппер-программ. Повторюсь, “существующих”. То есть если разработчик использовал библиотеку
QWERTY_for_Clipper очень левого разработчика со всеми исходными текстами — он может ускорить свое приложение, в том числе и ускорить функции их этой библиотеки. Если же он использует библиотеку ASDFG_for_Clipper очень правого разработчика и исходников этой библиотеки нету в пределах досягаемости — ну что ж, можно ускорить работу только своего кода, а чужой код приходится использовать как есть.Как это работает ? Ну, я просто генерю С-код, а на С написано 85 % Клиппера. Естественно, это может работать вместе, если все сделано правильно. Список моих недоработок смотри в “
Bugs”. Подробнее же механизм работы читайте дальше.Увеличение скорости
Вначале была идея. “Если интерпретатор Клиппера написан большей частью на
C и выполняет в основном декодирование байт-кода в вызовы соответствующих C функций — почему бы не попробовать странслировать исходники на Клиппере в C – программу, с непосредственными вызовами этих функций ?”Первый вариант
TugBoat примерно это и делал. Порождался С-код, состоящий сплошь из вызовов других функций. Скорость увеличилась, но ненамного - на десятки процентов. Львиную доли времени съедал динамический контроль типов.Следующим шагом было обнаружение и выделение статического типа переменных. Особенно типа “целый” , “длинный целый”, “логический”, “дата”, операции над которыми могут выполняться без привлечения Клиппер-машины. Тут и появилась “интеллектуальность” в компиляторе (см. ниже)
Но все равно получающийся С-код выглядел непристойно. Причина — дурная практика
N-уровневой адресации в клипперовских массивах. Но писал кто-то, а отвечать мне! В Клипперовской программеf[1][2][3] += a[4][5][6]
выглядит почти приемлемо. В С-программе это выглядит просто ужасно. И пришлось добавлять классический глобальный оптимизатор — с вынесением общих подвыражений и чисткой циклов вверх. Как правило, после прохода оптимизации сишный код становится на 30% короче (и на сколько-то быстрее)
. Теперь выходной код выглядит получше:
Код без оптимизатора |
Код с оптимизатором |
CLC_putaa0any (f, (1), (2)); _putln (CLC_puta1long (3)); CLC_putaa0any (a, (4), (5)); _putln (CLC_puta1long (6)); _tos--; LONGCAST(_tos) += LONGCAST (_tos-1); CLC_putaa0any (f, (1), (2)); CLC_popa2 ((3)); |
{ ITEM _loc1 = CLC_putaa0 (a, (1), (2), -1); CLC_putaa0any (f, (4), (5)); CLC_popa0long (_loc1, (3), (CLC_puta0long (_loc1, (3)) + CLC_puta1long (6))); } _pull (1);
|
Поподробнее о механизме работы смотри в “Теории” и “Истории”
“Интеллектуальность” или обнаружение семантических ошибок
Задача вычисления статических типов для языка с динамической типизацией хоть и сложна, но относится к категории “уже пройденных”. Похожие методы использовались при трансляции ЛИСПа в машинный код (помните японский проект ЭВМ пятого поколения ? Вот тогда).
Я это сделал. Например
Вы увидите что-то вроде:Warning FILE.prg 123: Local variable I type SHORTINT in function …
Тут и появилась “интеллектуальность” в компиляторе — просто внутри него происходит ошибка вычисления статического типа в том месте, где в программе произошла бы ошибка динамической типизации (например 1 +
“1”, или 2 > nil — все это выражения с ошибками типизации). Например:>> local i := 0
>> i := str (i) + i
>>----------- сообщение ------------
>>Error a.PRG 4: Type clash, SHORTINT to STRING
Подробно расписывать здесь как вычисляются статические типы я не могу (это три прохода компилятора, то есть словами это будет очень долго и потому скучно). Бог даст, подвернется коммерчески приемлемый вариант перевода
TugBoat на “Open Source”, тогда и посмотрите. Ну а если такого варианта не будет — ну что ж, придется более-менее подробно расписывать. Но позже. То есть не знаю когда.Новые возможности
Можно описывать типы параметров функции, например:
external function qwerty(__integer,__integer|__real,__array)__nil
Синтаксис описания EXTERNAL функций
:external имя_функции function (arg1, arg2,...) returned
где "arg" или "returned" есть
[тип] | [тип] |...
То есть можно написать, например:
external function val (__string) __INTEGER | __REAL
Синтаксис описания STATIC функций
:__static имя_функции function (arg1, arg2,...) returned
где "arg" or "returned" то же самое
Предупреждение: все описания функций должны быть в начале файла
Можно описывать явно типы переменных, например
function qwerty (a,b,c)
local __shortint i
if a == int(b)
for i = 1 to len ( с )
c[i] := str ( i )
next
endif
return nil
Синтаксис переменных с типами:
STATIC [type] имя := выражение, имя := выражение, ...
LOCAL [type] имя := выражение, имя := выражение, ...
где [type] есть один из:
__shortint
то есть "short int" в "C"__integer
то есть "long int" в "C"__logical
то есть "int" в "C"__real
то есть "ITEM" в "C"__string
то есть "ITEM" в "C"__array
то есть "ITEM" в "C"__nil
то есть "ITEM" в "C"__date
то есть "long" в "C"
Теория
Конечно, Вы это знаете, но тем не менее повторю начальные данные
эти процедуры (вызываемые интерпретатором) написаны на
может быть, если вызывать эти процедуры непосредственно из
C-программы, скорость увеличится ?и отсюда начинается история
TugBoat…В Клиппер-машине все локальные переменные и временные результаты храняться в моделируемом стеке в виде структур данных по 14 байтов, причем по первому байту определяется, что это - целое число, строка или массив и т.д. . То есть прибавить единицу к переменной в Клиппере — значит:
Buglist
Строки в квадратных скобках недоступны
If “abcd” == [abcd]
Переменные с именами, совпадающими с ключевыми словами недоступны
If := 1
Protected mode
из под Блинкера крайне нестабильноВыражение вида
If a > 2.or. a < -2
Дает синтаксическую ошибку
– перед .or. должен быть пробел
Best regards,
http://www.geocities.com/cl2cru/
Ai mailto:ai@bogorod.tula.net (Bulatov Vladislav)