Учебный компилятор (для лекций по курсу "Разработка компиляторов")

Рассматривается небольшой учебный компилятор, иллюстрирующий современную технологию разработки компиляторов. Образцом для подражания является компилятор GCC.

Входной язык

Входным языком является ограниченное подмножество языка Си. Ограничения перечислены ниже.

Отметим, что логические выражения реализованы полностью, как положено по стандарту (например, второй аргумент конъюнкции "&&" не вычисляется, если первый равен false).

Устройство компилятора

Поскольку целью является иллюстрация современных средств и методов разработки, то компилятор максимально использует стандартные средства. При этом используются только свободно распространяемые GNU-программы. Компилятор реализован в системе Linux и, конечно, может быть скомпилирован в любом Unix'е с установленным пакетом GNU, а также в Windows с пакетом Cygwin (Cygwin -- это GNU под Windows).

Компилятор считывает исходный текст Си-программы из файла и преобразует ее в программу на языке Ассемблера, которая записывается в выходной файл. Используется Аccемблер "as", входящий в пакет GNU, целевым процессором является Intel 80386. Машинно-зависимая чась компилятора, т.е. описание системы комманд процесора, локализована в одном файле (в одной таблице) и составляет его небольшую часть. Компилятор может быть легко адаптирован для любого другого процессора или Ассемблера.

Компилятор называется "TinyCC" (по аналогии со SmallC). В нем использовались некоторые идеи мини-компилятора "Small-C" (Ron Cain) и учебного компилятора "TinyC", разработанного Д.В.Варсанофьевым и А.Г.Дымченко для поддержки аналогичного спецкурса в Московсом университе. Вместе с тем данный компилятор достаточно сильно отличается от "TinyC" (написан заново без использования кода TinyC, полностью реализует логические выражения, использует RTL в качестве машинно независитого внутреннего представления программы, что позволяет выполнять машинно независимую оптимизацию, и т.д.)

Исходный код компилятора:

Для сборки компилятора выполните "make" без аргументов. Затем "tinycc --help".

Архив содержит 3 тестовых файла "tstgcd.c", "tstsum.c" и "tstchar.c", написанных с соблюдением ограничений на входной язык, накладываемых компилятором "tinycc". Чтобы скомпилировать и запустить, например, программу "tstgcd.c", выполните (в Unix'е или под Cygwin) следующую последовательность комманд:

./tinycc tstgcd.c gcc tstgcd.s ./a.out В первой команде вызывается компилятор "tinycc", которому передается входной файл "tstgcd.c". Результатом является файл "tstgcd.s", содержащий скомпилированную программу на языке Ассемблера. Во второй строке вызывается "gcc", который в данном случае выполняет роль компилятора с Ассемблера и построителя задачи (можно было также выполнить две команды as tstgcd.s gcc tstgcd.o которые делают то же самое). В третьей строке выполняется созданная программа "a.out".

Компиляция под Windows

Под Windows следует установить пакет Cygwin (это вообще-то полезно сделать безотносительно к "TinyCC") -- иначе откуда вы возьмете LEX и YACC (bison и flex)? Есть очень небольшие отличия в ассемблерах "as" для Linux'а и для Windows в пакете Cygwin. А именно, глобальные имена в Windos начинаются с символа подчеркивания "_", в Linux'е он не нужен. Также почему-то Cygwin-Ассемблер "as" не понимает директив ".type" и ".size" -- впрочем, как оказалось, они не обязательны, и ассемблерный текст отлично компилируется и без них. Все отличия между Linux и Windows-версиями TinyCC содержатся в файле "i80386.c", в котором применяется условная компиляция. При работе под Windows в пакете Cygwin компилятор gcc определяет переменную препроцессора "__CYGWIN__", которая используется в директивах условной компиляции, когда следует различать случаи Linux и Windows. Таких мест очень немного, и все они сосредоточены в файле "i80386.c". В этом файле, а также в файле "i80386.h" содержится вся машинно-зависимая часть компилятора, остальной код не зависит ни от процессора, ни от используемого Ассемблера.

Материалы к лекциям