Skip to content

Лексический анализ

VBrazhnik edited this page Jan 3, 2019 · 1 revision

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

В информатике лексический анализ («токенизация», от англ. tokenizing) — процесс аналитического разбора входной последовательности символов на распознанные группы — лексемы, с целью получения на выходе идентифицированных последовательностей, называемых «токенами» (подобно группировке букв в словах).

Источник: Лексический анализ — Википедия

Этот процесс заключается в разборе кода чемпиона на отдельные составные части, каждая из которых будет причислена к одному из типов.

Например, следующая строка после проведенного лексического анализа превратиться в ...:

loop: sti r1, %:live, %1

...список токенов:

Номер Содержимое Тип
1 loop: LABEL
2 sti INSTRUCTION
3 r1 REGISTER
4 , SEPARATOR
5 %:live DIRECT_LABEL
6 , SEPARATOR
7 %1 DIRECT

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

Особенности работы

Именно благодаря этим сообщениям и «методу научного перебора» можно узнать следующее:

Порядок команд

Команды для установки имени и комментария можно менять местами:

.comment    "This city needs me"
.name       "Batman"

Строка

Токен типа STRING включает в себя всё от открывающей до закрывающей кавычки. И на этом пути его не остановят ни переносы строк, ни символы комментариев.

Поэтому приведенный ниже пример абсолютно корректен:

.name "one
#two
three"

Необязательные пробелы и tab'ы

В случаях, когда транслятор может однозначно отделить компоненты друг от друга, пробельные символы между ними можно не указывать:

live%42
loop:sti r1, %:live, %1
.name"Batman"
.comment"This city needs me"

Но есть случаи, когда без хотя бы одного пробела или tab'а не обойтись.

±0

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

А вот лидирующие нули могут присутствовать:

live %0000042

Регистры

Для предоставленной программы asm регистром является строка состоящая из символа r и одной или двух цифр.

Поэтому все следующие примеры будут успешно транслированы в байт-код:

r2
r01
r99

Особенное внимание стоит обратить на последний из них.

Тот факт, что его трансляция не вызывает каких-либо ошибок, свидетельствует о том, что asm ничего не знает о конфигурации виртуальной машины и значении константы REG_NUMBER.

Такое поведение программы абсолютно логично. Ведь транслятор и виртуальная машина являются отдельными сущностями, которые не знают о конфигурации (или даже существовании) друг друга.

И в случае изменения значения константы REG_NUMBER один и тот же байт-код может стать для виртуальной машины из невалидного валидным, и наоборот.

При значении REG_NUMBER равным 16 операция с аргументом-регистром r42 будет некорректной. А при значении 49 она же будет выполнена без проблем.

Два особых случая

Но два особых случая работы программы asm вызывают вопросы — r0 и r00.

Эти два примера оригинальный транслятор также обработает без проблем. Хотя это противоречит логике задания, в котором сказано:

Registry: (r1 <–> rx with x = REG_NUMBER)

И если незнание программой значения верхней границы (REG_NUMBER) логично и легко объяснимо. Ведь при изменении конфигурации виртуальной машины один и тот же участок байт-кода может стать из невалидного валидным. То результат трансляции r0 и r00 будет некорректным всегда.

Поэтому при реализации собственной asm эту проблему стоит исправить.

Размер исполняемого кода

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

С виртуальной машиной все немного иначе. Для нее установлено ограничение на максимальный объем исполняемого кода в байтах с помощью константы CHAMP_MAX_SIZE.

В выданном файле op.h эта константа инициализируется следующими строками:

# define MEM_SIZE           (4 * 1024)
// ...
# define CHAMP_MAX_SIZE     (MEM_SIZE / 6)

То есть в данном случае размер исполняемого кода чемпиона не должен превышать 682 байта.

С минимальной границей всё немного интересней.

Виртуальная машина без проблем примет в работу .cor-файл, в котором размер исполняемого кода будет равен нулю.

А вот произвести такой файл с помощью предоставленного транслятора не так просто.

Если кроме установки имени и комментария чемпиона больше ничего не записать в .s-файл, то конвертировать его в байт-код не удастся.

Но если дописать в конец всего одну метку, то можно получить в результате желанный файл без исполняемого кода:

.comment    "This city needs me"
.name       "Batman"

loop:
# Конец файла

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

Но в этом случае они не учли некоторые моменты и создать такой файл всё же можно.

Как с этим жить?

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

Так и убрать её полностью, что выглядит более логичным решением. Ведь оригинальная виртуальная машины без проблем работает с .cor файлами без исполняемого кода.