ture містить абстрактний метод byte getByte (int n), який повинен повертати байт із заданим номером у команді. Ще один метод changeOffset має порожню реалізацію, але перевизначається в класах-нащадках, відповідних командам переходу. Він використовується для заміни номерів міток зміщеннями на третьому етапі компіляції. Безпосередніми спадкоємцями класу Command є класи, відповідні типовим форматам команд (Абстрактні) і команд, що мають унікальні формати. Більшість команд представляються класами, успадковує класи типових форматів. Імена класів команд мають вигляд C_xxx, де xxx - мнемонічне ім'я команди. Порожній команді none відповідає клас NoCommand. p> Клас ConstantPool містить як загальний список для всіх типів констант, що зберігає об'єкти класу CpInfo (базовий тип для класів, що представляють різні види констант), так і списки для констант окремих типів, що містять індекси елементів у першому списку. Ці списки описуються класами, вкладеними в клас ConstantPool. Така структура використовується для того, щоб при додаванні константи можна було швидко перевірити, чи не чи присутній вже ідентичний елемент у ConstantPool (ця перевірка проводиться не для всіх типів констант). Для кожного типу констант в класі ConstantPool існує свій метод додавання, який повертає індекс доданого (або знайденого існуючого) елемента в загальному списку. Серед спадкоємців CpInfo є спеціальний клас CpNone, який відповідає порожній структурі, що вставляється після констант типу Long і Double т. к. наступний за ними індекс вважається невживаних.
За процес компіляції відповідає пакет compiler, який містить такі класи:
В· Source - виконує функцію виділення пропозицій в початковому тексті. Конструктор цього класу приймає в Як параметр ім'я файлу, вміст якого розбивається на пропозиції та заноситься в коллекцию типу ArrayList . Метод String nextStatement () при кожнім виклику повертає чергову пропозицію;
В· StringParser - виконує функцію розділення рядків на лексеми. Кожен об'єкт цього класу відповідає одній оброблюваної рядку.
В· TokenRecognizer - має статичні методи, дозволяють визначити, чи є деяка рядок ключовим словом або коректним ідентифікатором. Об'єкти цього класу ніколи не створюються;
В· DescriptorCreator - містить статичні методи для створення дескрипторів типів, полів і методів з рядків, що містять запис типів і сигнатур, використовувану в мові. Екземпляри класу теж не створюються;
В· ClassHeaderParser, FieldDeclarationParser, MethodHeaderParser - використовуються при аналізі заголовка класу, описів полів і заголовків методів. Об'єкти цих класів зберігають у собі інформацію, витягнуту з аналізованого в конструкторі класу пропозиції;
В· code_compiler.CodeCompiler - здійснює аналіз коду методу і генерацію байт-коду (Включаючи третій і четвертий етапи компіляції). Даний процес буде розглянуто докладніше нижче;
В· code_compiler.CommandCompiler - аналізує команди у вихідному коді методу і створює об'єкти класів-нащадків Command;
В· code_compiler.Label - представляє мітку в коді методу;
В· code_compiler.LabelTable - таблиця міток методу. Містить імена міток, номери відповідних їм рядків і зміщення команд. p> В· SourceAnalyser - займає центральне місце в процесі аналізу вихідного тексту. Конструктор даного класу приймає в Як параметр об'єкт класу Source. При виклику методу analyse () відбувається аналіз вихідного коду і генерується проміжне представлення програми у вигляді описаної вище структури. У процесі аналізу використовуються класи StringParser, ClassHeaderParser, FieldDeclarationParser, MethodHeaderParser, CodeCompiler та ін Даний метод повертає об'єкт класу ClassFile.
Клас MainClass містить єдиний метод main, який є точкою входу в програму. Тут спочатку створюється об'єкт класу Source, який передається для обробки об'єкту класу SourceAnalyser, потім у повернутого методом SourceAnalyser.analyse () об'єкта класу ClassFile викликається метод writeToFile, який і генерує файл класу, що є результатом роботи компілятора. Всі перераховані операції укладені в блок try/catch, що перехоплює будь-які винятки, у разі виникнення яких на консоль виводиться відповідне повідомлення і процес компіляції завершується. Діаграма, у спрощеному вигляді показує цей процес, зображена на рис. 3. br/>В
Рис. 3.
Обробка вихідного файлу.
В
Розглянемо докладніше процес компіляції коду методу. Після обробки заголовка методу з допомогою класу MethodHeaderParser, у разі, якщо метод не є абстрактним, в методі SourceAnalyser. analyse () зчитуються пропозиції maxstack і maxlocals. Потім зчитуються і заносяться в масиви пропозиції, містять команди та описи захищених блоків. Ці масиви, а також посилання на об'єкт ConstantPool, що представляє область констант класу, передаються в якості параметрів конструктору класу CodeCompiler. У створено...