-
Notifications
You must be signed in to change notification settings - Fork 4
Лексический анализ
Перед тем, как начать перевод кода, написанного на языке ассемблера, в байт-код программа-транслятор проводит так называемый лексический анализ исходного кода.
В информатике лексический анализ («токенизация», от англ. 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"
В случаях, когда транслятор может однозначно отделить компоненты друг от друга, пробельные символы между ними можно не указывать:
live%42
loop:sti r1, %:live, %1
.name"Batman"
.comment"This city needs me"
Но есть случаи, когда без хотя бы одного пробела или tab'а не обойтись.
В аргументах операций могут присутствовать числа со знаком минус, но использование знака плюс вызовет ошибку. Его в составе числа быть не может.
А вот лидирующие нули могут присутствовать:
live %0000042
Для предоставленной программы asm
регистром является строка состоящая из символа r
и одной или двух цифр.
Поэтому все следующие примеры будут успешно транслированы в байт-код:
r2
r01
r99
Особенное внимание стоит обратить на последний из них.
Тот факт, что его трансляция не вызывает каких-либо ошибок, свидетельствует о том, что asm
ничего не знает о конфигурации виртуальной машины и значении константы REG_NUMBER
.
Такое поведение программы абсолютно логично. Ведь транслятор и виртуальная машина являются отдельными сущностями, которые не знают о конфигурации (или даже существовании) друг друга.
И в случае изменения значения константы REG_NUMBER
один и тот же байт-код может стать для виртуальной машины из невалидного валидным, и наоборот.
При значении
REG_NUMBER
равным16
операция с аргументом-регистромr42
будет некорректной. А при значении49
она же будет выполнена без проблем.
Но два особых случая работы программы asm
вызывают вопросы — r0
и r00
.
Эти два примера оригинальный транслятор также обработает без проблем. Хотя это противоречит логике задания, в котором сказано:
Registry: (
r1
<–>rx
withx
=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
файлами без исполняемого кода.