Текст программы компилятора
Полный текст всех модулей компилятора, созданного при реализации примера выполнения курсовой работы, приведен в Приложении 3. Те из этих модулей, которые не зависят от входного языка, были использованы ранее при выполнении лабораторных работ № 1–4. Кроме того, модули можно найти в архиве, располагающемся на веб-сайте издательства, в подкаталогах CURSOV и COMMON.
Все функциональные модули и их назначение в работе были рассмотрены выше.
Организация интерфейса с пользователем
По заданию компилятор должен получать входные данные из командной строки (обработка командной строки описана далее). Дополнительно для созданного компилятора реализован графический интерфейс с пользователем, аналогичный интерфейсу, использованному в лабораторных работах № 2–4. Окно графического интерфейса открывается в том случае, когда командная строка не указана.
Модуль, обеспечивающий интерфейс с пользователем (FormLab4), реализует графическое окно TCursovForm на основе класса TForm библиотеки VCL. Он обеспечивает интерфейс средствами Graphical User Interface (GUI) в ОС типа Windows на основе стандартных органов управления из системных библиотек данной ОС. Этот модуль обеспечивает также обработку входной командной строки компилятора и включает в себя две составляющие:
• файл программного кода (файл FormLab4.pas);
• файл описания ресурсов пользовательского интерфейса (файл FormLab4.dfm).
Более подробно принципы организации пользовательского интерфейса на основе GUI и работа систем программирования с ресурсами интерфейса описаны в [3, 5–7]. Полный текст программного кода модуля интерфейса с пользователем приведен в листинге П3.14 в приложении 3. Описание ресурсов пользовательского интерфейса, связанное с этим модулем, можно найти в архиве, располагающемся на веб-сайте издательства, в файле FormLab4.dfm в подкаталоге CURSOV.
Модуль FormLab4 построен на основе такого же модуля, который использовался для реализации интерфейса с пользователем в лабораторной работе № 4. Он содержит все данные, управляющие и интерфейсные элементы, которые были использованы в лабораторных работах № 2–4. Такой подход оправдан, поскольку этапы компиляции при выполнении курсовой работы совпадают с этапами выполнения соответствующих лабораторных работ.
Кроме органов управления, использованных в лабораторных работах № 2–4, интерфейсная форма, описанная в модуле FormLab4, содержит органы управления для генератора ассемблерного кода, которые созданы для курсовой работы:
• в многостраничной вкладке (PageControl1) появилась новая закладка (SheetAsm) под названием «Команды»;
• на закладке SheetAsm расположены интерфейсные элементы: ListAsm – список для вывода и просмотра порожденных ассемблерных команд;
• на первой закладке SheetFile («Исходный файл») появился дополнительный орган управления – флажок с двумя состояниями («пусто» или «отмечено»): CheckAsm – при включении этого флажка выполняется оптимизация результирующего кода, а при отключении – не выполняется.
Внешний вид новой закладки интерфейсной формы TCursovForm приведен на рис. 5.4.

Рис. 5.4. Внешний вид пятой закладки интерфейсной формы для курсовой работы.
Обработка входного файла в курсовой работе происходит в той же последовательности и в том же порядке, как это было описано при выполнении лабораторной работы № 4. Последним этапом, который отсутствовал в лабораторной работе, является этап порождения результирующего кода. На этом этапе выполняется следующая последовательность действий:
• вызывается функция MakeRegisters (модуль TrdAsm – листинг П3.13, приложение 3), которая распределяет регистры процессора по списку триад, результатом выполнения функции является количество необходимых временных переменных для списка триад (если регистров процессора не хватило), это значение запоминается;
• очищается содержимое списка ассемблерных команд ListAsm;
• в список ассемблерных команд записываются строки заголовка программы в соответствии с заданием;
• запоминается перечень всех идентификаторов программы (с помощью функции IdentList из модуля FncTree – листинг П3.2, приложение 3);
• если перечень идентификаторов не пустой, то:
– в список строк записывается ключевое слово маг;
– в список строк записываются все идентификаторы через запятую с указанием требуемого типа данных (integer);
• в список ассемблерных команд записываются строки заголовка функции CompileTest в соответствии с заданием;
• если количество необходимых временных переменных больше нуля, то:
– в список строк в тело функции помещается ключевое слово маг;
– за ключевым словом в списке строк записываются все имена временных переменных – таким образом временные переменные для хранения значений триад становятся локальными переменными функции Compi 1 eTest и размещаются в стеке;
• в список заносится заголовок ассемблерного кода (ключевые слова begin и asm и команда pushad для сохранения значений регистров процессора в стеке);
• вызывается функция MakeAsmCode (листинг П3.13, приложение 3), которая заполняет список текстом ассемблерных команд;
• в список заносится конец ассемблерного кода (команда popad для восстановления значений регистров процессора из стека и два ключевых слова end);
• в список помещаются строки тела главной программы в соответствии с заданием.
В отличие от лабораторных работ вся обработка данных в курсовой работе вынесена в отдельную функцию CompRun. Это сделано для того, чтобы для выполнения компиляции одна и та же функция вызывалась вне зависимости от того, как запущен компилятор – с командной строкой или без нее.
Обработка командной строки
Как требуется по заданию, созданный компилятор должен уметь работать с командной строкой. Для созданного в данном примере компилятора командная строка должна иметь вид:
<компилятор> <входной_файл> [<ключи>]
где:
<компилятор> – имя исполняемого файла компилятора;
<входнойфайл> – имя входного файла и путь к нему (если путь не указан, то компилятор ищет файл в текущем каталоге), первый обязательный параметр командной строки;
<ключи> – необязательные параметры (ключи) запуска компилятора (второй и последующие параметры).
Если входной файл не указан (нет ни одного параметра в командной строке), то открывается окно графического интерфейса с пользователем, которое было описано выше. Иначе, если входной файл указан, компилятор читает исходную программу из этого файла, обрабатывает ее, и если программа не содержит ошибок – помещает результаты в выходной файл, а сообщения об ошибках – в специальный файл ошибок. После этого компилятор сразу же завершает свою работу (никакое окно на экране в этом случае не отображается). Имя выходного файла и имя файла для сообщений об ошибках компилятор определяет, исходя из указанных параметров (ключей запуска).
Если указанный в строке запуска входной файл не найден, то компилятор выдает сообщение об ошибке чтения файла и после этого открывает окно графического интерфейса с пользователем (как если бы имя файла не было указано).
Проверка наличия параметров в командной строке запуска компилятора выполняется сразу при старте компилятора (функция FormCreate, модуль FormLab4, листинг П3.14 в приложении 3). Для этого используется системная функция Param-Count из библиотеки языка Object Pascal, которая возвращает количество параметров в командной строке (0 – параметры отсутствуют). Для анализа параметров командной строки используется системная функция ParamStr из библиотеки языка Object Pascal, которая возвращает строковое значение параметра по его порядковому номеру в командной строке. При этом нулевым параметром считается имя исполняемого файла.
Второй и последующий параметры в командной строке считаются ключами – необязательными параметрами запуска компилятора. Ключей в командной строке может быть любое количество (в том числе может не быть ни одного ключа, в этом случае командная строка содержит только один параметр – имя входного файла). Ключи могут следовать в командной строке в любом порядке. Ключи определяют режим работы компилятора и некоторые условия компиляции. Каждый ключ является отдельным параметром. Ключи отделяются друг от друга пробелами (если ключ должен содержать пробелы внутри себя, его следует взять в двойные кавычки – "…", – как это принято для параметров командных строк в ОС).
Каждый ключ должен начинаться с символа «-» (минус), за которым следует символ ключа (строчная или прописная буква латинского алфавита), а за ним – параметр ключа, если требуется.
Символы ключей имеют следующее значение (строчные и прописные буквы имеют одинаковое значение, поэтому здесь рассматриваются только прописные буквы):
• А – флаг оптимизации команд ассемблера, определяет, выполняется или нет оптимизация результирующего кода; за символом должно идти указание значения флага:
1 оптимизация выполняется (флаг включен);
0 – оптимизация не выполняется (флаг выключен), любой другой символ, следующий за символом А, воспринимается как 0;
• С – флаг свертки объектного кода, определяет, выполняется или нет оптимизация списка триад методом свертки объектного кода; за символом должно идти указание значения флага:
1 оптимизация выполняется (флаг включен);
0 – оптимизация не выполняется (флаг выключен), любой другой символ, следующий за символом С, воспринимается как 0;
• S – флаг исключения лишних операций, определяет, выполняется или нет оптимизация списка триад методом исключения лишних операций; за символом должно идти указание значения флага:
1 оптимизация выполняется (флаг включен);
0 – оптимизация не выполняется (флаг выключен), любой другой символ, следующий за символом S, воспринимается как 0;
• 0 – имя результирующего файла, непосредственно за символом должно идти имя файла и путь к нему (если путь не указан, считается, что файл будет находиться в текущем каталоге, откуда запущен компилятор);
• Е – имя файла с ошибками, непосредственно за символом должно идти имя файла и путь к нему (если путь не указан, считается, что файл будет находиться в текущем каталоге, откуда запущен компилятор).
Если какой-то из ключей не указан, то компилятор принимает значение ключа по умолчанию. Для флагов установлены следующие значения по умолчанию:
• флаг оптимизации команд ассемблера – включен;
• флаг свертки объектного кода – включен;
• флаг исключения лишних операций – включен.
Имя файла результирующей программы по умолчанию считается совпадающим с именем входного файла, но с расширением. asm. Имя файла с ошибками компиляции по умолчанию также считается совпадающим с именем входного файла, но с расширением. err. Путь к этим файлам по умолчанию устанавливается таким же, как и к входному файлу (первый параметр командной строки).
Анализ параметров командной строки запуска компилятора реализован в функции ProcessParams (модуль FormLab4, листинг П3.14 в приложении 3).
Например, командная строка:
cursov.exe myfile.txt
запустит на выполнение компилятор (cursov. ехе) для обработки файла myfi 1 е. txt. При успешной компиляции результирующая программа будет записана в файл myfi 1 е. asm, а ошибки, если они будут обнаружены, – в файл myfile.err. При этом компилятор будет выполнять все виды оптимизации (оптимизацию методом свертки объектного кода, оптимизацию методом исключения лишних операций и оптимизацию результирующего ассемблерного кода), поскольку ни один ключ не указан и все флаги будут установлены по умолчанию.
Командная строка:
cursov.exe infile.txt – Ooutfile.asm – Eerrfile.txt – A0 – S0
запустит на выполнение компилятор (cursov.exe) для обработки файла infile.txt. При успешной компиляции результирующая программа будет записана в файл outfile.asm, а ошибки, если они будут обнаружены, – в файл errfile.txt. При этом компилятор будет выполнять только оптимизацию методом свертки объектного кода, поскольку два ключа (-АО и – SO) отключают два других метода оптимизации.
Информацию в файл ошибок компилятор всегда дописывает в конец файла, и только если такого файла нет, он создается заново. Дата и командная строка запуска компилятора всегда записываются в файл ошибок. Поэтому в том случае, когда компиляция выполнена успешно, в файл ошибок помещаются только две строки – командная строка и время запуска компилятора. В остальных случаях там будет присутствовать и информация об ошибке (построенный компилятор умеет обнаруживать только одну ошибку – ту, которая первой встретится ему в исходном тексте входной программы).
Файл с результирующей программой всегда создается заново. Если такой файл уже существовал в момент запуска компилятора, то он будет уничтожен.
Пример входной программы и результирующей программы
Для иллюстрации работы созданного компилятора взяты два примера входной программы:
1. Программа, вычисляющая факториал числа.
2. Программа, на примере которой можно иллюстрировать работу оптимизирующих алгоритмов.
Оба примера приведены в приложении 4.
Первый пример вычисляет факториал входной величины, причем если величина отрицательная или превышает 31, то программа возвращает 0. Умножение реализовано через цикл операций сложения. Входной файл приведен в листинге П4.1, а полученный результирующий файл – в листинге П4.2, приложение 4.
Второй пример содержит почти бессмысленную программу, которая всегда возвращает значение, равное 0, но на примере этой программы можно хорошо проиллюстрировать работу оптимизирующих алгоритмов. Входной файл приведен в листинге П4.3, в листинге П4.4 приведен результирующий файл, полученный без применения оптимизации, а в листинге П4.5 – файл, полученный с применением оптимизации. Желающие могут сравнить ассемблерный код этих двух файлов и проверить эффективность используемых алгоритмов оптимизации.[12]
Больше книг — больше знаний!
Заберите 30% скидку новым пользователям на все книги Литрес с нашим промокодом
ПОЛУЧИТЬ СКИДКУ