Иллюстрированный самоучитель по задачам и примерам Assembler

Препроцессор команд ХММ-расширения

Центральное место в макроопределении ХММ1 d_st_f3 занимают команда целочисленного устройства (в данном случае – CMPXCHG) и директива ORG. Первое действие данной макрокоманды – выяснить тип операнда приемника (dst) в макрокоманде MOVSS, так как он может быть и регистром, и ячейкой памяти. Это необходимо для правильного определения кода операции, которая будет управлять направлением потока данных. После того как определен приемник данных, с помощью условного перехода осуществляется переход на ветвь программы, где будет выполняться собственно формирование соответствующего ХММ-команде MOVSS кода операции.

Формирование кода операции ХММ-команды MOVSS производится с помощью директивы org, которая предназначена для изменения значения счетчика адреса. В строках 6 или 11 директива org устанавливает значение счетчика адреса равным адресу метки х. Адрес метки х является адресом первого байта машинного кода команды CMPXCHG. Директива db в следующих строках размещает по этому адресу байтовые значения 0F3H,0Fh, ор&_ld или 0F3H,0Fh, op&st, в зависимости от того, какое действие производится – загрузка (_ld) или сохранение (_st). Значение opc_Movss, с помощью которого формируются значения op&_st и ор&_ld, определены в начале файла iaxmm.inc:

opcjtovssjd – 010Н
opc_Movss_st – 011H

Для дотошных читателей заметим еще один характерный момент. Для его полного понимания необходимо хорошо представлять себе формат машинной команды и назначение его полей. Достаточно полная информация об этом приведена в литературе. Обратите внимание на порядок следования операндов в заголовке макрокоманды, который построен по обычной для команд ассемблера схеме: коп назначение, источник.

В команде CMPXCHG порядок обратный. Этого требует синтаксис команды. Это хорошо поясняет назначение бита d во втором байте кода операции, который характеризует направление передачи данных в микропроцессор (то есть в регистр) или в память (из микропроцессора (регистра)). Вы можете провести эксперимент. Проанализируйте машинные коды команды MOV:

  • Команды с непосредственным операндом: MPPS RXMM1. RXMM2/ml28, 18 CMPSS RXMM1, RXMM2/m32 .i8
  • Однооперандные команды: FXRSTOR m512 FXSAVE m512 LDMXCSR m32 STMXCSR m32

Из перечисленных выше групп команд можно вывести следующую обобщенную структуру команды:

метка: код_операции операнд1. операнд2, операнд3; текст комментария

Данная структура почти совпадает со структурой обычных команд ассемблера. В соответствии с общими принципами трансляции препроцессор будет работать с исходной программой в несколько этапов.

  1. Лексический анализ (сканирование) исходного текста.
  2. Синтаксический анализ.
  3. Генерация кода.

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

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

В главе 2 описаны основные шаги разработки компилятора. Для интерпретатора разница невелика, в чем мы убедимся ниже.

Для распознавания лексем входной программы разработаем сканер, следуя для этого следующему алгоритму.

  1. Выделить классы лексем.
  2. Определить классы литер.
  3. Определить условия выхода из сканера для каждого класса лексем.
  4. Каждому классу лексем поставить в соответствие грамматику класса 3.
  5. Для каждой грамматики, построенной на шаге 4, построить конечный автомат, который будет распознавать лексему данного класса.
  6. Выполнить объединение ("склеивание") конечных автоматов для всех классов лексем.
  7. Составить матрицу переходов для "склеенного" конечного автомата.
  8. "Навесить" семантику на дуги "склеенного" конечного автомата.
  9. Выбрать коды лексической свертки для терминалов грамматики и формат таблицы идентификаторов.
  10. Разработать программу сканера.
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.