Раскрутка компилятора. От TinyContext к Context 1.0

Через небольшое время после написания Tiny Context 1.0 была написана расширенная версия, включавшая локальные переменные, параметры функций и строковые констаны. Последнюю можно было передать как фактическое значение параметра функции при ее вызове и это единственное, что с ней можно было делать. Предполагалось, что параметр должен быть ссылкой на массив символов, но проверка этого не делалась (как и большинство других проверок).

Сначала это было сделано с использованием минимальной версии языка, потом компилятор был переписан с использованием расширенной версии. Первый шаг раскрутки был сделан и на этом все закончилось.

По идее можно это продолжить и реализовать все возможности Context'а, хотя бы его минимальной версии. Но это сложно и долго, может быть проще реализовать небольшое расширение, способное скомпилировать ранее написанный компилятор. Если бы все делалось последовательно, такой возможности съэкономить не было бы, но в целом это было бы выгоднее и правильнее.

Вопрос, хватит ли памяти? TynyContext использует некое подобие крошечной модели памяти, обычный Context - подобие компактной модели.

Для начала компилятор Context 1.03 (он сразу создает код, а не текст на ассемблере) был изменен так, чтобы все его объекты помещались в один сегмент памяти. Компилятор стал двухпроходным, проходы одинаковы, код после первого прохода некорректен, но определяется минимально возможный адрес начала данных. На втором проходе создается корректный код.

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

За счет шестнадцатиразрядных ссылок в TinyContext код еще уменьшится, но за счет худшей кодогенерации он на какую-то величину увеличится. В итоге оказалось, что уменьшение за счет коротких ссылок перевесило, но это стало известно только после завершения работы.

Позже выяснилось, что минимальная версия Context 1.02 и ассемблер тоже могут быть скомпилированы с помощью Tiny Context, но это было позже и на принятые решения не повлияло. Это более простой путь, так что без Context 1.03 вполне можно обойтись.

Сам же Context 1.02 может прямо или косвенно (с использованием промежуточных версий) компилировать все последующие версии.

Сделать нужно было две вещи:

По идее выбор между первым и вторым несложен - если что-то используется многократно, это что-то нужно реализовать, если нет - заменить. Если реализация чего-то сложна, то тоже заменить. В результате было сделано следующее:

В TinyContext добавлены

В TinyContext не было оператора select, но был if с множеством вариантов выбора. Оператор select реализован копированием кода для if и его небольшой модификацией (copy/paste).

В TinyContext ссылка на простую переменную и ссылка на массив разделены, совместимая ссылочная переменная является ссылкой и на простую переменную и на массив. Совместимые ссылки необходимы, но можно было ограничиться только параметрами и результатами функций, а глобальные и локальные ссылки не реализовывать.

Из исходного кода Context исключены

В TinyContext условие - это сравнение, никаких и/или/не в нем нет. Cложное условие всегда может быть заменено вызовом функции, возвращающей результат вычисления условия в виде числа (0 - истина, 1 - ложь, в выборе чисел есть произвол, но это несущественно).

Вставки кода (asm/inline) скорректированы поскольку в TinyContext ссылки занимают два байта, а не четыре. Команды ассемблера заменены соответствующими им кодами - TinyContext встроенного ассемблера не содержит и внешний ему недоступен.

Сколько при этом допущено ошибок - неизвестно, в качестве тестов использованись только сами модифицированные компиляторы.

В итоге получилось следующее:

Компилятор Число строк текста Размер кода (байт)
TinyContext 1.02 741/967 5,870
TinyContext 1.38 1,837/2,498 17,472
Context 1.03 3,017/3,772 36,314
Context 0.85(1.03m)1) 3,097/4,003 30,635
Asm8086 1.14 1,251/1,509 18,289
Asm8086 1.15(1.14m)1) 1,350/1,693 15,454
Context 1.02 2,452/2,999 30,029
Context 0.86(1.02m)1) 2,613/3,304 36,438
Context 1.062) 2,321/3,016 24,652
Turbo Pascal 1.00A3) н/д 33,280/24,529
Turbo Pascal 3.00A4) н/д 39,731/28,390

1) Модифицированные версии. Крошечная модель памяти, ссылки - 2 байта

2) Версия без операторов. Маленький компилятор не получился

3) Сравнение с Turbo Pascal очень условно поскольку в его 33,280 байт помимо компилятора входит еще текстовый редактор и библиотека времени выполнения. По-видимому, первые 8,751 байт файла TURBO.COM и составляют эту библиотеку. Во всяком случае они почти без изменений копируются в создаваемый COM-файл, этим и объясняется большой размер пустой программы. На компилятор и редактор текста остается всего 24,529 байт

4)Turbo Pascal 3.0 устроен сходным образом, но размеры немного больше. Был еще очень похожиий на Turbo Pascal редактор текста TE.COM (Turbo Editor). Он выпущен в том же 1985 году, что и Turbo Pascal 3.0, объем его кода 23,169 байт. Если считать, внутри Turbo Pascal 3.0 есть этот же редактор, на компилятор остается совсем мало - вычитание одного из другого дает всего 5,221 байт и это не выглядит правдоподобным. Возможно, в редакторе есть какая-то часть стандартной библиотеки и вычитать надо не весь его размер

В свое время малый размер Turbo Pascal казался мне чем-то удивительным...

Архив с исходными текстами здесь.

Top.Mail.Ru

Сайт создан в системе uCoz