· DescriptorCreator - содержит статические методы для создания дескрипторов типов, полей и методов из строк, содержащих запись типов и сигнатур, используемую в языке. Экземпляры класса также не создаются;
· ClassHeaderParser, FieldDeclarationParser, MethodHeaderParser - используются при анализе заголовка класса, описаний полей и заголовков методов. Объекты этих классов сохраняют в себе информацию, извлеченную из анализируемого в конструкторе класса предложения;
· code_compiler.CodeCompiler - осуществляет анализ кода метода и генерацию байт-кода (включая третий и четвертый этапы компиляции). Данный процесс будет рассмотрен подробнее ниже;
· code_compiler.CommandCompiler - анализирует команды в исходном коде метода и создает объекты классов-потомков Command;
· code_compiler.Label - представляет метку в коде метода;
· code_compiler.LabelTable - таблица меток метода. Содержит имена меток, номера соответствующих им строк и смещения команд.
· SourceAnalyser - занимает центральное место в процессе анализа исходного текста. Конструктор данного класса принимает в качестве параметра объект класса Source. При вызове метода analyse() происходит анализ исходного кода и генерируется промежуточное представление программы в виде описанной выше структуры. В процессе анализа используются классы StringParser, ClassHeaderParser, FieldDeclarationParser, MethodHeaderParser, CodeCompiler и др. Данный метод возвращает объект класса ClassFile.
Класс MainClass содержит единственный метод main, являющийся точкой входа в программу. Здесь вначале создается объект класса Source, который передается для обработки объекту класса SourceAnalyser, затем у возвращенного методом SourceAnalyser.analyse() объекта класса ClassFile вызывается метод writeToFile, который и генерирует файл класса, являющийся результатом работы компилятора. Все перечисленные операции заключены в блок try/catch, перехватывающий любые исключения, в случае возникновения которых на консоль выводится соответствующее сообщение и процесс компиляции завершается. Диаграмма, в упрощенном виде показывающая этот процесс, изображена на рис. 3.
Рис. 3.
Обработка исходного файла.
Рассмотрим подробнее процесс компиляции кода метода. После обработки заголовка метода с помощью класса MethodHeaderParser, в случае, если метод не является абстрактным, в методе SourceAnalyser .analyse() считываются предложения maxstack и maxlocals. Затем считываются и заносятся в массивы предложения, содержащие команды и описания защищенных блоков. Эти массивы, а также ссылка на объект ConstantPool, представляющий область констант класса, передаются в качестве параметров конструктору класса CodeCompiler. У созданного объекта CodeCompiler вызывается метод compile(), возвращающий объект класса CodeAttribute, описывающий атрибут Code, содержащий байт-код метода. При этом происходят следующие процессы. В конструкторе класса CodeCompiler из строк, содержащих команды, выделяются имена меток, которые сохраняются в объекте класса LabelTable. Затем обрабатывается список строк, описывающих защищенные блоки. В методе CodeCompiler.compile() выполняются следующие операции. Сначала с помощью объекта класса CommandCompiler для каждой команды создается объект соответствующего класса. При этом одновременно для команд, при которых имеется метка, в объекте LabelTable сохраняется информация о смещении метки относительно начала метода. Как в описаниях защищенных блоков, так и в объектах, соответствующих командам перехода, на момент окончания этого шага вместо смещений перехода, содержатся порядковые номера команд, при которых расположены соответствующие метки. Замена их на действительные смещения производится на последнем шаге с помощью методов LabelTable.changePC() и Command.changeOffset().
Технология Java ориентирована на использование одного языка программирования. Система типов данных и другие особенности языка Java тесно связаны с функционированием JVM и форматом файла класса. Однако, существует открытая спецификация, позволяющие создавать как собственные реализации JVM, так и альтернативные средства разработки. С ее использованием мною разработан язык JASM, представляющий собой язык ассемблера для платформы Java, который позволяет создавать файлы классов, использующие значительную часть возможностей JVM, и реализован его компилятор.
1. Грис, Д. Конструирование компиляторов для цифровых вычислительных машин. М., «Мир», 1975.
2. Эккель, Б. Философия JAVA. СПб. 3-е изд.: Питер, 2003.
3. Tim Lindholm, Frank Yellin. The Java Virtual Machine Specification Second Edition. Sun Microsystems Inc. 1999.