СОДЕРЖАНИЕ ВВЕДЕНИЕ 5 1 Подготовка учебно-методического пособия 7 ЗАКЛЮЧЕНИЕ 8 СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ 9 ПРИЛОЖЕНИЕ А Учебно-методическое пособие по машинно- ориентированным языкам программирования. Изм. Лист № докум. Разраб. Сухов И.В. Руководит Криворучко А.В. Проверил Чистяков А.Е. Утверд. Долгов В.В. Подпись Дата 11 09.04.04.270000.000 ПЗ Разработка учебнометодического пособия по машинно-зависимым языкам программирования Пояснительная записка Лит. Лист Листов 4 56 ДГТУ кафедра ПОВТиАС ВВЕДЕНИЕ Машинно-зависимые языки ориентированы на конкретную ЭВМ, имеют непосредственный доступ к аппаратным средствам ЭВМ и чаще всего используются для составления программ, входящих в состав операционной системы. Машинно-зависимые языки, в свою очередь, делят на машинные и машинно-ориентированные. Различают машинно-независимые и машинно-зависимые языки высокого уровня. Вторые пригодны при применении определенных серий МПК. Для программирования устройств, построенных с использованием комплекта серии КР580, разработан язык высокого уровня PL M-80, относящийся к классу машинно-зависимых языков высокого уровня. Класс машинно-зависимых языков представлен ассемблером. Язык ассемблера делает доступными все программно-управляемые компоненты ПЭВМ. Поэтому он применяется для написания программ, явно использующих специфику конкретной аппаратуры. Ассемблер - это наиболее трудоемкий язык программирования, и из-за его низкого уровня не удается построить средства отладки, которые существенно снизили бы эту трудоемкость. К машинно-зависимым языкам относят машинный и машинноориентированный языки. Машинный язык в качестве символов использует коды представления информации в ЭВМ. В группу машинно-зависимых языков программирования входят машинные и машинно-ориентированные языки. Язык ассемблера является машинно-зависимым языком. Это значит, что он отражает особенности архитектуры конкретного типа микрокомпьютеров. Программа, написанная на языке ассемблера для одного типа микрокомпьютеров, как правило, непригодна для другого, если оба типа не совместимы по своей архитектуре. По этой причине глубокое понимание языка ассемблера требует предварительного детального знакомства с архитектурой соответствующего микрокомпьютера. Универсального языка ассемблера, Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 5 подобного БЕЙСИКу, не существует. Рассматриваемый здесь язык совпадает с подробно изложенным в языком ассемблера, используемым в миникомпьютерах СМ-3 и СМ-4, совместимых по архитектуре с ДВК. В структуре языка Ассемблера используются машинные команды, мнемокоды и макрокоманды. Машинно-зависимые языки, в частности язык Ассемблера, используются в основном в качестве языков системного программирования. Они позволяют получать высококачественные по быстродействию и используемой памяти программы. Однако использование их требует досконального знания вычислительной машины. При решении задач системного программирования (разработка системного математического обеспечения ЭВМ) предпочтение следует отдать машинно-зависимым языкам, в частности макроязыку, поскольку только в этом случае можно максимально использовать все возможности вычислительной машины. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 6 1 Подготовка учебно-методического пособия В ходе работы было подготовлено учебно-методическое пособие по машинно-зависимым языкам программирования. В данном методическом пособии приведены примеры разработки, затрагивающие основные концепции программирования с использованием машинно-зависимых языков программирования. Рассматриваются следующие этапы: Знакомство с Turbo Debugger – описание основных возможностей приложения. Операции с байтами, которые могут происходить в отладчике Turbo Debugger. Представлены начальные сведения о языке Ассемблер. Затронуты принципы сегментации памяти. Директивы Ассемблер и режимы адресации. Структура написания и принципы записи базовой программы на Ассемблер. Циклически и развлевляющиеся программы. Безусловные и условные переходы. Циклы. Логические инструкци. Регистр флагов для логических команд. Пример использования логических команд. Текст методического указания находится в Приложении А. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 7 ЗАКЛЮЧЕНИЕ На сегодняшний момент язык машинно-зависимые языки программирования являются не самым популярным, но от того не менее значимым средством для написания узкоспециализированных приложений. Язык Ассемблера – это символическое представление машинного языка. Он облегчает процесс программирования по сравнению с программированием в машинных кодах. Программисту не обязательно употреблять настоящие адреса ячеек памяти с размещенными в них данными, участвующими в операции, и вычисляемые результаты, а также адреса тех команд, к которым программа не нестандартными обращается. устройствами Некоторые обработки задачи, данных например, сложных обмен с структур невозможно решить с помощью языков программирования высокого уровня. Это под силу ассемблеру. Изобретение языка программирования высшего уровня позволило нам общаться с машиной, понимать ее. Развилась наука программирования с того времени, как появились машинно-зависимые языки программирования. Большинство современных языков имеет интегрированную среду разработки и поддерживает структурное программирование. Для графических операционных систем, например Windows, требуются более сложные средства программирования, но с помощью простых в обращении языков, таких как Visual Basic, процесс облегчается настолько, что даже начинающие программисты могут работать с графической средой. В ходе выполнения данной работы было разработано учебнометодическое пособие по машинно-зависимым языкам программирования. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 8 СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ 1. Гавриков М. М., Иванченко А. Н., Гринченков Д. В. Теоретические основы разработки и реализации языков программирования. — КноРус, 2013. — 178 с. — ISBN 978-5-406-02430-0. 2. Криницкий Н. А., Миронов Г. А., Фролов Г. Д. Программирование. — ГИФМЛ, 1963. — 384 с. 3. Братчиков И. Л. Синтаксис языков программирования. — Наука, 1975. — 230 с. 4. C++, Turbo Pasckal, QBasik: Эволюция языков программирования http://langprog.far.ru/historylangprog.html. — 27.05.10. 5. Колдаев Виктор Дмитриевич. Архитектура ЭВМ [Текст]: Учебное пособие / Виктор Дмитриевич Колдаев, Сергей Андреевич Лупин. - Москва: Издательский Дом "ФОРУМ"; Москва: ООО "Научно-издательский центр ИНФРА-М", 2013. - 384 с. - ISBN 978-5-8199-0373-5: Б. ц 6. Калашников, О.А. Ассемблер — это просто. Учимся программировать. 2 изд. [Электронный ресурс] / О. Калашников. - Санкт-Петербург: БХВПетербург, 2014. - 336 с.: 7. Пильщиков, Владимир Николаевич. Программирование на языке ассемблера IBM PC [Текст]: [учеб. пособие] / В. Н. Пильщиков. - Москва: ДиалогМифи, 2008. - 286, [2] с. - Библиогр.: с. 281 (6 назв.). 8. Аблязов Р.З. Программирование на ассемблере на платформе x86-64., изд. «ДМК Пресс», ISBN 978-5-94074-676-8? 2011, 304с. 9. Кирнос В. Н. Введение в вычислительную технику. Основы организации ЭВМ и программирование на Ассемблере [Электронный ре-сурс] : учебное пособие / Кирнос В. Н. - Томск :Томский государ-ственный университет систем управления и радиоэлектроники, 2011. - 172 с. - ISBN 9785-4332-0019-7 : Б. ц., ЭБС IPRbooks. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 9 10. Таненбаум, Эндрю С. Архитектура компьютера [Текст] / Э. С. Та- ненбаум ; пер. с англ. Ю. Гороховского, Д. Шинтякова. - 5-е изд. - Москва ; Санкт-Петербург [и др.] : Питер, 2010. - 843, [5] с. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 10 ПРИЛОЖЕНИЕ А Учебно-методическое пособие по машинно-ориентированным языкам программирования. A 1 Знакомство с программой отладчиком Turbo Debugger. A 1.1 Turbo Debugger Турбо отладчик Turbo Debugger представляет собой набор инструментальных средств, позволяющий отлаживать программы на уровне исходного текста и предназначенный для программистов, использующих семейство компиляторов Borland. В пакет отладчика входят набор выполняемых файлов, утилит, справочных текстовых файлов и примеров программ. A 1.1.1 Запуск программы Запуск программы осуществляется файлом td.exe, расположенный в директории BIN каталога BP или BC. A 1.1.2 Структура экрана программы При запуске Turbo Debugger на экране появляется его основное меню и рабочее окно рис.1. Рабочее окно состоит из следующих четырёх окон: • окно команд – CPU; • окно регистров и флагов – Registers; • окно данных - Dump; • окно стека. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 11 Рисунок 1 — основное меню Turbo Debugger В свою очередь окно Registers поделено на две части. В ле-вой его части указано содержимое всех регистров микропроцессора (ax, bx, cx, dx…), а в правой части показаны биты состояния (флаги-c,z,s,o….). Последовательное переключение между окнами можно выполнять с помощью клавиши Tab (или Shift+Tab в обратном порядке). Каждое из окон может быть вызвано самостоятельно на экран, используя пункт меню View и команду соответствующую названию окна (CPU, Registers, Dump). A 1.1.3 Регистры микропроцессора Регистры — это небольшие (несколько байт) именованные области памяти микропроцессора, используемые для временного хранения двоичных данных, к которым необходимо обеспечить быстрый доступ. Каждый регистр может иметь специальное назначение, например, хранить операнды команд микропроцессора, хранить адрес очередной команды программы и т.п. В микропроцессорах Intel для регистров в целом и отдельных групп байт из них принята специальная система обозначений. Например, имеется группа двухбайтовых регистров общего назначения, обозначаемых AX, BX, CX и DX. Например, регистры AX и BX используются микропроцессором для извлечения значений операндов операций сложения и вычитания, а также размещения результатов выполнения соответствующих инструкций. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 12 Как было описано выше, окно Registers поделено на две части. В левой части показано содержимое регистров. Обратим внимание на первые четыре регистра AX, BX, CX, DX, они все равны 0000, четырехзначное число, показанное вслед за именем регистра, является шестнадцатеричным. A 1.2 Операции с байтами В микропроцессорах Intel используются двухбайтовые машинные слова. Каждый регистр общего назначения (AX, BX, CX и DX) может хранить одно машинное слово. Однако имеется возможность оперировать с отдельными байтами этих регистров. В этом случае каждый регистр рассматривается состоящим из старшего (High) и младшего (Low) байтов. Обозначения отдельных байтов из регистров состоят из двух букв. Первая задает имя регистра (A, B, C или D), а вторая указывает, какой это байт регистра. Для обозначения старшего байта используется буква H, а младшего — L. Таким образом, регистр AX можно рассматривать, состоящим из двух однобайтовых регистров AH и AL. Микропроцессор может выполнять арифметические операции над отдельными байтами. A 1.2.1 Умножение беззнаковых величин Умножение двух 16-битных чисел может дать 32-разрядный результат, поэтому инструкция умножения MUL (multiply — умножить) размещает результат в двух регистрах DX и AX. Старшие 16 бит помещаются в регистр DX, а младшие в AX. При выполнении операции умножения одним из множителей всегда является значение из регистра AX. A 1.2.2 Сложение беззнаковых величин Под беззнаковым понимается представление заведомо неотрицательных целых чисел, в котором знаковый бит вводить не требуется. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 13 Пусть необходимо сложить числа 3А7h и 92Ah, записанные в шестнадцатеричной форме (подсчитайте результат). Создадим и выполним инструкцию микропроцессора, позволяющую складывать беззнаковые коды из двух регистров — прибавим число, хранящееся в регистре BX, к числу хранящемуся в AX. Для этого необходимо выполнить следующую последовательность действий. • Занесение операндов. Поместим заданные числа в регистры AX, BX. Для того чтобы изменить содержимое регистра (занести величину), необходимо установить на него курсор в левой части окна Registers и ввести нужное число. • Создание инструкции. Сложение чисел будет производиться при выполнении специальной команды микропроцессора. Чтобы команду можно было выполнить, ее нужно сохранить в основной оперативной памяти компьютера. Для этого вначале нужно определить адрес, где она будет храниться, и только потом ввести саму команду. Для указания адреса необходимо переместится в окно команд (клавиша Tab). а) Ввод адреса. Разместим нашу инструкцию по адресу 100h (с этого адреса отладчик размещает первый байт инструкции, в любом сегменте памяти, который он начал использовать). Если в данный момент курсор находится по другому адресу, то для его перемещения в нужное место нажмите сочетание клавиш Ctrl+G и в диалоговом окне укажите нужный адрес, рис 2. Рисунок 2 — диалоговое окно б) Ввод команды. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 14 Сложение чисел задается ассемблерной командой ADD (английское add означает "сложить" или "добавить"). Поэтому занесите по выбранному адресу инструкцию ADD AX, BX в) Подготовка к выполнению команды. Чтобы выполнить команду, необходимо сообщить микропроцессору адрес нашей инструкции. Переместимся в окно регистров и флагов Registers. Адрес инструкции заносится либо непосредственно в регистр IP (instruction pointer — указатель команды), либо в диалоговое окно при нажатии сочетания клавиш Ctrl+N. При этом в строчке между адресом инструкции и кодом появляется метка-треугольник, обозначающая инструкцию, которая будет выполнена процессором следующей. г) Выполнение команды. Для выполнения инструкции выберем команду Trace into меню Run или нажмем клавишу F7. Команда Trace into выполняет одну инструкцию за шаг. д) Результат выполнения команды. После выполнения команды ADD результат вычисления помещается в регистр AX, где ранее был один из операндов. Поэтому после сложения регистр AX должен содержать число CD1h. A 1.2.3 Вычитание беззнаковых величин Вычитание выполняется с помощью команды SUB (subtract — вычесть). В остальном все этапы выполнения вычисления повторяют действия, которые были описаны для операции сложения. В регистр AX заносится уменьшаемое, а в регистр BX — вычитаемое. Результат выполнения инструкции появится в регистре AX. Если в выражении вычитаемое больше уменьшаемого, результат вычитания беззнаковых (неотрицательных) величин становится отрицательным. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 15 Существует еще одна пара команд увеличения и уменьшения на 1 – Inc (increment) и Dec (decrement). Команда INC аналогична команде: ADD ор,1 т.е. увеличивает свой операнд на 1: op1: = ор1+1, а команда DEC аналогична команде: SUB op,1 т.е. уменьшает операнд на 1: op1: = op1 - 1(единственное отличие: команды INC и DEC не меняют флаг переноса CF). Например, если регистр BX содержал число 0001, то после выполнения команды Inc BX регистр будет содержать 0002. Выгода от команд INC и DEC в том, что они занимают меньше места в памяти и выполняются быстрее, чем соответствующие команды ADD и SUB. A 1.2.4 Деление беззнаковых величин Команды микропроцессора предназначены для выполнения целочисленных операций. Так как деление целых чисел нацело происходит далеко не всегда, то результат деления формируется из двух целых чисел — частного и остатка от деления. Делимое всегда помещается в пару регистров AX, DX, поэтому в инструкции деления DIV (divide — делить) необходимо указать только регистр с делителем. После выполнения деления регистр AX будет содержать частное, а регистр DX — остаток. A 1.2.5 Пересылка (копирование) данных Для изменения содержимого регистров программным путем обычно используют команду MOV move — внести), которая позволяет копировать в один регистр число или содержимое другого регистра. Первый операнд инструкции MOV указывает адресат (куда переслать значение), а второй — пересылаемое значение или регистр, его содержащий. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 16 A 1.2.6 Понятие переполнения Как и в случае умножения, при выполнении сложения результат может выходить за 16-разрядную сетку (четыре шестнадцатеричных числа). Например, результатом сложения четырехзначных чисел FFFFh и 1h будет пятизначное число 10000h, для записи кото-рого слова (двух байт) недостаточно. Если результат выполнения операции (над беззнаковыми ве-личинами!) не может быть полностью размещен в регистре, то гово-рят о возникновении переполнения. При выполнении сложения беззнаковых чисел суть перепол-нения (в двоичном представлении) состоит в том, что в результате сложения двух единиц в старшем разряде возникает единица, выхо-дящая за разрядную сетку результирующего регистра. Естественно, что эта единица в регистр помещена быть не может, и при записи в регистр отсекается. A 1.2.7 Регистр флагов Флаг - это бит, принимающий значение 1 ("флаг установлен"), если выполнено некоторое условие, и значение 0 ("флаг сброшен") в противном случае. В ПК используется 9 флагов, причем конструк-тивно они собраны в один 16-разрядный регистр, называемый реги-стром флагов и обозначаемый как Flags. Эти биты обозначаются буквами C, P, A, Z, S, T, I, D, O. Например, в текстовый редактор загружен текст. Как только вы внесли в текст первое изменение, можно установить в 1 флаг изменений. После сохранения текста значение флага сбрасывается (0). Тогда при выходе из редактора легко проверить, сохранены ли изменения. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 17 A 1.2.8 Флаг переноса Если при сложении беззнаковых чисел происходит переполне-ие (возникает единица переноса за пределы разрядной сетки регистра), то единичка переноса записывается в Carry Flag. В правой половине окна регистров и флагов (Registers) данный флаг обозначается буквой С. Флаг переноса переустанавливается в каждой операции сложения. A 1.2.9 Использование флага переноса I. Сложение с использованием флага переноса. Рассмотренная ранее инструкция сложения ADD выполняет простое сложение двух беззнаковых кодов. Инструкция ADC складывает три числа: два операнда из регистров общего назначения, как и раньше, плюс значение бита флага переноса из регистра флагов. II. Вычитание с использованием флага переноса. При выполнении инструкции SBB из разности операндов вычитается значение флага переноса. Занесите в регистры BX и AX два равных числа, теперь инструкцией SUB произведите вычитание одного числа из другого, в результате чего должен быть установлен флаг нуля Z=1 (Zero Flag). A 1.3 Задание к лабораторной работе Задание 1. Запустить приложение Turbo Debbuger и выполнить переключение между окнами, используя разные приемы. Задание 2. Необходимо сложить числа 3А7h и 92Ah, записанные в шестнадцатеричной форме (подсчитайте результат). Проверим результат, полученный при выполнении сложения. Вычтем из результата сложения одно из ранее использованных слагаемых (для определенности 92Ah). Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 18 Задание 3. Выполните вычитание из нуля единицы (т.е., 0 – 1). Какой результат получен и почему? Задание 4. Введите в регистр AX число 0102h (два байта) и выполните инструкцию — ADD AH, AL. Каков результат выполнения операции, который будет помещен в регистр AH? Задание 5. Выполните умножение чисел 7C4Bh (в регистр AX) и 100h (BX). Каков результат операции и почему? Задание 6. Выполните деление числа 7C4B12h (DX=007Ch, AX=4B12h) на 0100h (BX). Каков результат выполнения операции и почему? Задание 7. С помощью команды MOV поместите числа 1234h и ABCDh, соответственно, в регистры AX и DX. Соответствующие инструкции поместите по адресам 0100h и 0102h. Далее с помощью команды MOV поместите содержимое младшего байта регистра DX в старший байт регистра AX. Задание 8. Выполните сложение чисел FFFFh (AX) и 1h (BX). Каков результат операции? Задание 9. Проследите за изменением состояния флага переноса при последо-вательном выполнении следующих операций 1. FFFF + 1 2. FF00 + 1 Задание 10. Выполните сложение FFFFh и 1. Затем выполните инструкцию: ADC BX, AX. В результате сложения 1 и 0, в регистре BX будет число 2. (надо пояснить, что останется в регистрах после первой операции). Задание 11. Выполните сложение FFFFh и 1. Затем выполните инструкцию: SBB BX, AX. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 19 A 2 Начальные сведения о языке Ассемблер При выполнении программы, микропроцессор взаимодействует с оперативной памятью, где хранятся исполняемая программа и данные, а также с периферийными устройствами. Для организации вычислений микропроцессор i8086 имеет в своём составе 14 шестнадцатиразрядных регистров, которые обеспечивают выполнение программы: Регистры общего назначения: AX(AH, AL), BX(BH, BL), CX(CH, CL), DX(DH, DL) делятся программно на пары однобайтных регистров и могут использоваться для хранения данных. Разбиение на однобайтные регистры позволяет увеличить общее число регистров; SP, BP – указатель и база стека, соответственно, обеспечивают доступ к данным в стеке, могут использоваться для хранения данных, но делать это не рекомендуется, так как при этом возможно нарушение адресации в стеке, особенно при использовании SP. SI, DI – шестнадцатиразрядные регистры для хранения данных. CS, DS, ES, SS – хранят адреса сегментов в памяти, не могут использоваться для хранения данных. IP – регистр инструкций – хранит адрес (смещение) следующей исполняемой команды. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 20 FLAGS – регистр флагов содержит набор битовых флагов, определяющий текущее состояние процессора и результат выполнения предыдущей команды (таблица 1). Таблица 1 — регистр флагов Память, с которой взаимодействует процессор при обработке про-грамм, называется Оперативным Запоминающим Устройством (ОЗУ) или Random Access Memory (RAM). Она состоит из набора однобайтных ячеек, обращение к которым происходит по их номерам (физическим адресам). Число ячеек зависит от ширины шины адреса и составляет для процессора i8086 (ширина шины адреса равна 20) 220 – ячеек (1Мбайт). Для современных процессоров с шириной шины адреса 32 объём ОЗУ может доходить до 4 Гбайт. Данные можно читать или сохранять в ОЗУ байтами, указывая но-мер требуемой ячейки или словами (2 байта), указывая адрес младшей ячейки памяти и вводя специальный префикс. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 21 A 2.1 Сегментация памяти Для обращения к памяти процессор предварительно помещает адрес ячейки в один из своих регистров, но для процессора i8086, очевидно нельзя в шестнадцатиразрядном регистре хранить двадцатиразрядный адрес. Поэтому применяют так называемую сегментацию памяти, которая заключается в том, что истинный, физический адрес ячейки хранится в двух регистрах. Один из них – сегментный, он хранит адрес начала блока памяти, который и называется сегментом. Если к шестнадцати разрядам сегмента мысленно справа дописать четыре двоичных нуля(16+4 = 20), то получим физический адрес начала сегмента в ОЗУ. Второй регистр хранит величину смещения адреса требуемой ячейки от начала сегмента. Адрес ячейки памяти записывается в виде двойного слова (4 байта): <сег-мент>:<смещение>. Сегмент всегда начинается с ячейки, номер которой заканчивается на 4 двоичных (или один шестнадцатеричный) нуля. Минимальная длина сегмента 16 байтов (параграф). Максимальная длина определяется длиной регистра, хранящего смещение и равна 216(64 Кбайта). Пара регистров CS:IP(<сегмент>:<смещение>) определяют адрес следующей команды программы. Для адресации данных используются сегментные регистры DS и ES, а в качестве регистров, хранящих смещение, используются регистры общего назначения BX, SI, DI. Для работы с сегментом стека используют сегментный регистр SS и регистр BP. A 2.2 Структура программы на языке Ассемблер Программа на языке ассемблера представляет собой текст разбитый на строки. Каждая строка либо соответствует машинной команде, либо является директивой ассемблера или макрокомандой. Команды и директивы можно Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 22 набирать как большими, так и малыми латинскими буквами. Русские буквы можно использовать только в комментариях. <имя сегмента> segment команды или директивы <имя сегмента> ends [ <имя сегмента> segment команды или директивы <имя сегмента> ends ] end <метка входа в программу> Директива end < метка входа в программу> отмечает конец текста программы и указывает ассемблеру, где завершить трансляцию. Поэтому директива end должна присутствовать в каждой программе. < метка точки входа > указывает инструкцию, с которой должно начинаться выполнение программы. Каждая программа содержит сегменты данных и команд, но мини-мально должна содержать сегмент команд. Строка программы, в общем случае, состоит из четырех полей: Поле метки — M1 Поле операции — Add Поле операндов — AX, BX Поле комментариев — ;сложение Имена данных, процедур, сегментов или метки команд могут состоять не более чем из 31 латинских букв и цифр, причем первым символом должна быть обязательно буква. Большие и маленькие буквы не различаются. A 2.3 Директивы Ассемблера Директивой называется команда транслятору для выполнения определённых данной директивой действий, сама директива в текст транслированной программы не включается. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 23 Директива задания исходных данных: [<имя>] d<тип> <константа>[,<константа>, <константа>, . . .] <имя> — имя массива данных, по которому к ним можно обратить-ся из команды; d (define) — определяет начало массива данных; <тип> — размер констант, входящих в массив: b — байт, w — Слово (два байта), d — двойное слово, q — учетверённое слово, t — десять байтов; <константа> — числовой или символьный элемент массива данных. В ассемблере используется несколько типов констант: десятичные – последовательность цифр от 0 до 9; шестнадцатеричные – последовательность шестнадцатеричных цифр от 0 до 9 и от А или а до F или f завершающаяся буквой H или h, первой должна быть десятичная цифра или 0; восьмеричные – последовательность цифр от 0 до 7, завершающаяся буквами Q или q; двоичные – последовательность цифр от 0 до 1, завершающаяся буквой B или b; символьные – символ или группа символов, заключённые в кавычки; знак ? – используется для резервирования места для данных. Например, data1 db 123, 0a2h, 75q, 110011b, 'a', 'пример', ?, ? Для заполнения больших массивов используется директива dup (duplicate): <число повторений> dup(<образец>) <число повторений> - задаёт количество размещаемых в памяти данных, определяемых образцом; Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 24 <образец> - любая допустимая группа констант. Например: data2 db 23 dup(1, 2, 'x'), выделяет в памяти 23 · 3=69 байтов и заносит в них образец 1, 2, 'x', 1, 2, 'x', … . Директива использования сегментных регистров по умолчанию: assume <имя сегментного регистра>:<имя сегмента или noth-ing>[, <имя сегментного регистра>:<имя сегмента или nothing>, …] Как отмечалось выше, для задания адреса в памяти требуется два регистра, один из них всегда сегментный, поэтому в команде при обращении к памяти приходится набирать имя сегментного регистра, часто одного и того же. Директива assume позволяет избежать этого. Транслятор сопоставляет имя массива данных и автоматически подставляет сегментный регистр, заданный для сегмента, в котором расположен данный массив. Слово nothing показывает, что данный сегментный р-гистр не адресуется по умолчанию. Директива assume может использо-ваться в программе при каждом изменении сегмента для данного сегментного регистра, но обязательно в начале сегмента, где она задаёт по умолчанию сегментный регистр для сегмента кодов. Например: assume cs:code, ds:data1, es:nothing Здесь code и data1 – имена сегментов кодов и данных, соответ-ственно. A 2.3.1 Режимы адресации Регистровая прямая - операнд находится в регистре. Обозначение - <регистр>, < регистр > - АХ, ВХ, СХ, DX, SI, DI, BP, SP, AL, BL, СL, DL, AH, BH, CH, DH. Пример: mov АХ,SI ; переслать содержимое регистра SI в регистр АХ. Непосредственная - непосредственный операнд (константа) присутствует в команде. Обозначение — < константное выражение > . Пример: Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 25 mov AX, 093Ah ; занести константу 093Ah в регистр АХ. Прямая - исполнительный адрес операнда присутствует в ко-манде. Обозначение - < переменная >+/-< константное выражение >. Пример: mov AX, WW ; переслать в АХ слово памяти с именем WW mov BX, WW+2 ; переслать в ВХ слово памяти отстоящее от переменной с именем WW на 2 байта. Регистровая косвенная - регистр содержит адрес операнда. Обозначение - [< регистр >], < регистр > - ВХ. ВР. SI, DI. Пример: mov [ BX ], CL ; переслать содержимое регистра CL по адресу, находящемуся в регистре ВХ. Регистровая относительная - адрес операнда вычисляется как сумма содержимого регистра и смещения. Обозначение - < переменная >[< регистр >] или [< регистр >]< константное выражение >, < регистр > - SI или DI индексная адресация, ВХ или ВР - базовая адресация. Пример: mov АХ, WW[SI] ; переслать в АХ слово из памяти, адрес которого вычисляется как сумма содержимого регистра SI и смещения WW. Индексно - базовая - адрес операнда вычисляется как сумма содержимых базового и индексного регистров и смещения. Обозначение - [< базов. регистр>][< индексн. регистр>] или <пере-менная >[<базов. регистр >][< индекс. регистр >] или [<базов. регистр >][< индекс. регистр >]< константное выражение, где < индекс. регистр > - SI или DI, < базов. Регистр > - ВХ или ВР. Пример: Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 26 mov [BX+ SI+ 2], CL; переслать содержимое регистра CL по адресу, вы¬числяемому как сумма содержимого регистров ВХ, SI и константы 2. Инструкции пересылки данных и двоичной арифметики. Команды данной группы приведены в таблице 2. Код определяет выполняемое командой действие, операнды показывают адреса ячеек, хранящих исходные данные, необходимые для выполнения команды и адрес ячейки результата. Процессор i8086 и более поздние версии относятся к двухадресным машинам. Это значит, что его команда может содержать не более двух операндов. Если для выполнения команды необходимо иметь два источника данных, например, сложение, то сохранение результата выполнения команды производиться по адресу одного из источников данных. Чтобы показать, какой из операндов будет хранить результат, его обозначают при описании команды как dst (destination назначение), операнд, который используется только как адрес исходных данных, обозначается как src (source – источник). В двухоперандных командах операнд dst указывает, перед выполнением команды, адрес исходного данного, а после выполнения - адрес результата. Таблица 2 Команды пересылки и двоичной арифметики Мнемокод Флаги Действие Код Операнд O S Z A P C ы mo dst, src. - - - - - - пересылка v хch dst, src - - - - - - обмен g add dst, src х х х х х х сложение adc dst, src х х х х х х сложение с переносом inc dst х х х х х sub dst, src х х х х х х вычитание Изм. Лист № докум. Подпись Дата - увеличить на единицу 09.04.04.270000.000 ПЗ Лист 27 Таблица 2 Команды пересылки и двоичной арифметики sbb dst, src х х х х х х вычитание с заемом dec dst х х х х х - уменьшение на единицу neg dst х х х х х х изменение знака rcl dst,счет х - - - - х циклический сдвиг влево х - - - - х циклический сдвиг вправо х - - - - х циклический сдвиг влево х - - - - х циклический сдвиг вправо чик rcr dst,счет чик rol dst,счет чик ror dst,счет чик sal dst,счет х х х u х х арифметический сдвиг влево чик sar dst,счет х х х u х х арифметический сдвиг вправо чик shl dst,счет х х х u х х логический сдвиг влево чик shp dst,счет х х х u х х логический сдвиг вправо чик pus src - - - - - - сохранение слова в стеке h pop dst - - - - - - восстановление слова из стека xlat таблица - - - - - - трансляция байтов из таблицы lea dst, src - - - - - - загрузка исполнительного адреса lds dst, src - - - - - - загрузка указателя с DS les dst, src - - - - - - загрузка указателя с ES Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 28 Таблица 2 Команды пересылки и двоичной арифметики lahf - - - - - - загрузка флагов в АН sahf - r r r r r установка флагов из АН pus х - - - - х сохранение флагов в стеке r r r r r r hf pop восстановление флагов из стека f Примечание: - — Флажок не модифицируется х — Устанавливается или сбрасывается в соответствии с результатом; u — Не определен; r — Восстанавливается прежнее запомненное значение. A 2.4 Запись программы на языке Ассемблер Ниже приведена типичная структура простой программы на ассемблере. data segment //директива начала сегмента данных d1 dw 34h d2 db 10100110b d3 dd 3 dup (?) data ends code segment assume cs: code, ds: data start: mov ax,data mov ds,ax Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 29 quit: mov ax,4c00h int 21h code ends end start Загрузка адреса сегмента данных состоит из двух команд, так как непосредственные данные нельзя заносить прямо в сегментный регистр. Для завершения программы и выхода в DOS имеется несколько возможностей, рекомендуется использовать две команды, начинающиеся с метки quit. Обработка программ в MS-DOS. Обработка программ на языке ассемблера в MS-DOS состоит из следующих этапов: Создать с помощью текстового редактора файл с текстом программы на языке ассемблера. Транслировать программу с помощью ассемблера TASM (или MASM); Скомпоновать программу с помощью компоновщика (редактора связей) TLINK (или LINK). Запустить программу на выполнение. Файл исходного текста программы должен иметь расширение asm. Запуск транслятора осуществляется командой tasm <исходный файл >[,[< объектный файл >][,[< файл листинга >][,[< файл перекрестных ссылок >]]]][;] Все создаваемые транслятором файлы будут иметь разные расши-рения имени, поэтому им можно оставить имя исходного файла: tasm <исходный файл >, , , , ; Точка с запятой показывает, какие файлы должен создать трансля-тор, например, конструкция tasm <исходный файл >; создаст только объектный файл. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 30 Расширение объектного файла по умолчанию obj; расширение файла листинга по умолчанию lst; расширение файла перекрестных ссылок по умолчанию crf. Компоновщик использует, как исходный, объектный файл и создаёт исполняемый файл с расширением по умолчанию exe. Запуск компоновщика осуществляется командой: tlink < объектный файл >[,< исполняемый файл >] В случае сохранения имени исходного файла команда имеет вид: tlink < объектный файл> Для запуска под отладчиком необходимо запустить отладчик и загрузить исполняемый файл. A 2.5 Задание к лабораторной работе Разработать программу реализующую указанную формулу, исполнить программу с несколькими (три - четыре) наборами исходных данных, проверить правильность результатов. 1. Х= А - 5 (В - 2С) + 2 2. Х= - 4А + (В + С) / 4 + 2 3. Х= 7А - 2В - 100 + С 4. Х= - А / 2 + 4 (В + 1) + 3С 5. Х= 5 (А - В) - 2С + 5 6. Х= (А/ 2 + В) / 4 + С - 1 7. Х= - (С + 2А + 4В + В) 8. Х= 6С + (В - С + 1) / 2 9. Х= 2 - В (А + В) + С / 4 10. Х= 2В - 1 + 4 (А - 3С) 11. Х= (2А + В) / 4 - С / 2 + 168 12. Х= 6 (А - 2В + С / 4) + 10 13. Х= 5 (А - В) + С mod 4 14. Х= - (-(С + 2А) * 4В + 38) 15. Х= А - 3 (А + В) + С mod 4 16. Х= 3(А - 2В) +50 – С / 2 17. Х= (3А + 2В) - С / 4 + 217 Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 31 18. Х= 3(С - 2A) + (В - С + 1) / 2 19. Х= (2А + В) / 4 - С / 2 + 168 20. Х= 6 (А - 2В + С / 4) + 10 21. Х= 3 (А - 4В) + С / 4 22. Х= - (-(С + 2А) * 5В - 27) 23. Х= А / 2 - 3 (А + В) + С * 4 24. Х= 3(А - 2В) +50 – С / 2 25. Х= 5А + 2В - B / 4 + 131 Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 32 A 3 Циклические и разветвляющиеся программы Команда передачи, управления служит для передачи управления инструкции, не следующей непосредственно за данной. Управление может передаваться как внутри текущего сегмента кода (внутрисегментная передача управления), так и за его пределы (межсегментная передача управления). Тип передачи управления может быть задан ассемблеру предшествующим адресу перехода ключевым словом NEAR (внутрисегментная) или FAR (межсегментная). A 3.1 Безусловные переходы Инструкция безусловного перехода передаёт управление команде, адрес которой указан в инструкции. Команда безусловного перехода имеет вид jmp [<тип> ptr] операнд. <тип> - тип перехода short (короткий) – смещение 127 байтов вперёд или 128 байтов назад, near (близкий) – смещение в пределах сегмента (64 Кбайта), far (дальний) – в любой сегмент с любым смещением. ptr – приставка, которую можно перевести как указанный в. Если тип не задан, по умолчанию принимается near. Всего можно выделить пять типов безусловных переходов (таблица 1). Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 33 Таблица 1 — Типа команд безусловного перехода A 3.2 Условные переходы Команда условного перехода организует передачу управления при выполнении определённого в команде условия, в противном случае переход осуществляется на команду, следующую за инструкцией условного перехода. Условия определяются текущим состоянием флагов процессора. Каждая из 30 команд условных переходов проверяет определенную комбинацию флагов. Все условные переходы являются короткими, т.е. адрес перехода должен отстоять не далее, чем на -128 или +127 байтов от первого байта следующей команды. Команды условной передачи управления и проверяемые при их выполнении условия приведены в таблице 2. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 34 Таблица 2. Инструкции условной передачи управления Мнемокод условие перехода Смысл Флаги ja/jnbe CF or ZF=0 выше /не ниже и не равно jae/jnb CF=0 выше или равно/не ниже jb/jnae CF=1 ниже/не выше и не равно jbe/jna CF or ZF=1 ниже или равно/не выше je/jz ZF=1 равно/нуль jne/jnz ZF=0 не равно/не нуль jg/jnle (SF xor OF) or больше/не меньше и не равно jge/jnl ZF=0 больше или равно/не меньше jl/jnge SF xor OF=0 меньше/не больше и не равно jle/jng (SF xor OF)=1 меньше или равно/не больше jp/jpe ((SF xor OF) есть паритет/паритет четный jnp/jpo or ZF)=1 нет паритета/паритет нечетный jc PF=1 перенос jnc PF=0 нет переноса jo CF=1 переполнение jno CF=0 нет переполнения jns OF=1 знак + js OF=0 знак - SF=0 SF=1 Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 35 A 3.3 Циклы Инструкция, организующая программный цикл имеет вид: loop[<условие повторения цикла>] <метка короткого перехода> Инструкция loop использует содержимое регистра СХ как счетчик повторений цикла. Команда loop уменьшает содержимое регистра СХ на 1 и передает управление по адресу, определяемому меткой перехода, если содержимое СХ ≠ 0, в противном случае выполняется следующая за LOOP инструкция. Подобно условным переходам инструкции этой группы могут осуществлять только короткие передачи управления, т.е. в пределах от -128 до +127. Добавление к инструкции loop <условие повторения цикла> позволяет ввести дополнительные логические условия на повторение цикла: loope/loopz – повторять, пока ноль; loopne/loopnz – повторять, пока не ноль. Проверка флага ZF осуществляется командой loop. Цикл повторяется, если содержимое СХ ≠ 0 и выполняется соответствующее условие, в противном случае выполняется следующая за loop инструкция. A 3.3.1 Пример выполнения работы Дан масив из десяти слов, содержащих целые числа. Требуется найти максимальное значение в массиве. Текст программы: data segment max dw ? mass dw 10,24,76,479,-347,281,-24,70,124,97 data ends code segment assume cs: code, ds: data Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 36 start: mov ax, data mov ds, ax lea bx, mass mov cx, 10 mov ax, [bx] beg: cmp [bx], ax jl no mov ax, [bx] no: inc bx inc bx loop beg mov max, ax quit: mov ax,4C00h int 21h ; Выход в DOS 1. code ends 2. end start A 3.4 Задание к лабораторной работе Дан массив из десяти знаковых чисел (слов или байт). Требуется: 1. Найти количество отрицательных чисел. Массив байт. 2. Найти сумму всех положительных и отрицательных чисел. Массив слов. 3. Найти сумму абсолютных величин. массив байт. 4. Найти количество положительных чисел. Массив байт. 5. Поменять местами пары соседних чисел. Массив слов. 6. Переставить числа в обратном порядке. Массив байт. 7. Заменить все отрицательные числа нулями. Массив байт. 8. Найти среднее арифметическое чисел. Массив слов. 9. Найти количество чисел больших 10h. Массив слов. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 37 10. Найти наименьшее по абсолютной величине числа. Массив байт. 11. Найти наибольшее отрицательное число. Массив байт. 12. Найти произведение положительных элементов последовательности. Массив слов. 13. Найти среднее арифметическое квадратов ненулевых элементов последовательности. Массив слов. 14. Найти полусумму наибольшего и наименьшего чисел. Массив байт. 15. Найти среднее арифметическое отрицательных элементов последовательности. Массив слов. 16. Найти сколько в массиве чисел больше 12h и меньше 0Afh. Массив байт. 17. Найти есть ли в массиве два нуля, идущих подряд. Массив слов. 18. Найти сумму абсолютных величин, меньших 6. Массив байт. 19. Найти среднее арифметическое чисел больших 10. Массив слов. 20. Найти сколько чисел равно 12h. Массив байт. 21. Заменить все отрицательные числа их модулями. Массив байт. 22. Найти среднее арифметическое положительных чисел. Массив слов. 23. Найти количество чисел меньших 10h. Массив байт. 24. Найти наименьшее среди положительных чисел. Массив слов. 25. Найти наибольшее отрицательное число. Массив байт. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 38 A 4 Применение логических инструкций. Логические команды служат для сброса или установки отдельных бит в байте или слове. Они включают булевы операторы НЕ, И, ИЛИ, исключающее ИЛИ и операцию тестирования, которая устанавливает флаги, но не изменяет значения своих операндов. A 4.1 Логические инструкции. not dst — инструкция not инвертирует все биты байта или слова. and dst, src — инструкция and выполняет операции логическое И двух операндов (байтов или слов) и возвращает результат в операнд-приемник. Бит результата устанавливается в 1, если установлены в 1 оба соответствующих ему бита операндов, и устанавливаются в 0 противном случае. or dst, src — инструкция or выполняет операции логическое ИЛИ двух операторов (байтов или слов) и помещает результат на место операндаприемника. Бит результата устанавливается в 1, если равен 1 хотя бы один из двух соответствующих ему битов операндов и устанавливается в 0 в противном случае. xor dst, src — Инструкция xor выполняет операцию логическое исключающее ИЛИ двух операндов и помещает результат на место операндаприемника. Бит результата устанавливается в 1, если соответствующие ему биты операндов имеют противоположные значения, и устанавливается в 0 в противном случае. test dst, src — Инструкция test выполняет логическое И двух операндов (байтов или слов), модифицирует флаги, но результат не возвращает, т.е. операнды не изменяются. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 39 A 4.1.1 Регистр флагов для логических команд В таблице 1 приведены значения регистра флагов, устанавливаемые логическими командами. Таблица 1 — логические инструкции Примечание: - — флажок не модифицируется; х — Устанавливается или сбрасывается в соответствии с результатом; u — не определен; 0 — Сбрасывается в 0. A 4.2 Примеры использования логических команд. 1. Установить 3 и 0 биты в регистре аl, остальные биты не изменять. or al, 00001001b 2. Сбросить 4 и 6 битвы в регистре al, остальные биты не изменять. and al, 10101111b 3. Инвертировать 2 и 4 биты в регистре al, остальные биты не изменять. xor al, 00010100b 4. Перейти на метку LAB, если установлен 4 бит регистра al, в противном случае продолжить выполнение программы. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 40 test al, 00010000b jnz LAB продолжаем ... LAB: 5. Посчитать число единиц в регистре al, рассматривая байт, как набор бит. ; число сдвигов mov cx, b xor bl, bl ; обнуление BL LL: shl al, 1 ; сдвиг влево на один разряд jnc NO ; переход, если нет переноса ; иначе увеличить BL inc bl NO: loop LL A 4.2.1 Пример выполнения работы. Дан массив из 10 байт. Все байты имеют нулевые старшие биты. Необходимо каждый байт содержащий единицу в нулевом бите дополнить до четного числа единиц установкой седьмого бита. Текст программы: data segment NB db 04h, 07h, 14h, 23h, 04h,38h, 3Fh, 2Ah0Dh, 34h data ends code segment assume cs: code. ds:data START: mov ax, data mov ds, ax lea bx, NB mov cx, 10 BEG: Изм. Лист № докум. mov al, [bx] Подпись Дата 09.04.04.270000.000 ПЗ Лист 41 test al, 1b jz BITOCLR test al, 0ffh jp OK or al, 80h jmp short OK BITOCLR: test al, 0ffh jnp OK or al,80h OK: mov [bx], al loop BEG QUIT: mov ax, 4c00h Int 21h DOS code ends end START A 4.3 Задание к лабораторной работе 1. Дан массив из 10 байт. Посчитать количество байт, в которых сброшены 6 и 4 биты. 2. Дан массив из 8 байт. Рассматривая его, как массив из 64 бит, посчитать количество единиц. 3. Дан массив из 8 байт. Рассматривая его как массив логических значений х0 х1 х2 х3 х4 х5 х6 х7 (true-есть ненулевые биты в байте, false-все биты нулевые), вычислить логическую формулу F = (x7 & x6 & x1) V (x6 & x4 & x2 & x1 & x0) V (x7 & x6 & x3 & x1). 4. Дан массив из 10 байт. Посчитать количество байт с числом единиц в байте равным три. 5. Рассматривая байт как набор логических значений x7 x6 x5 x4 x3 x1 x0 (true -1, false - 0), вычислить логическую формулу F = (x7 & x6 & x3) V (x6 & x4 & x2 & x1) V (x7 & x6 & x2 & x0) Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 42 6. Дан массив из 8 байт. Рассматривая его, как массив из 64 бит посчитать длину самой длинной последовательности единиц. 7. Дан массив из 10 байт. Посчитать количество единиц во всех разрядах, кратных трём: 3, 6, 9, …, 75, 78. 8. Дан массив из 5 байт. Рассматривая его как массив из 8 пятиразрядных слов, найти “исключающее или” всех 8 слов для выражения “10101”. 9. Дан массив из 6 байт. Рассматривая его, как массив из 48 бит, посчитать в нём количество нулей. 10. Дан массив из 8 байт. Рассматривая его, как массив из 64 бит, посчитать количество пар единиц в окружении нулей. Конец последовательности рассматривать как нуль. 11. Дан массив из 7 байт. Рассматривая его, как массив из восьми семибитных слов, посчитать количество слов с нечетным числом нулей в слове. 12. Дан массив из 9 байт. Рассматривая его как массив из 72 бит, посчитать число переходов между нулями и единицами. 13. Дан массив из 3 байт. Рассматривая его, как массив из 24 бит, посчитать количество одиночных единиц в окружении нулей. Конец последовательности рассматривать как нуль. 14. Дан массив из 6 байт. Посчитать количество байт число единиц, в которых не превышает 3. 15. Дан массив из 11 байт. Посчитать количество байт, в которых нет единиц, стоящих рядом. 16. Дан массив из 4 байт. Рассматривая его, как массив из 32 бит посчитать длину самой длинной последовательности нулей. 17. Дан массив из 6 байт. Посчитать количество единиц во всех разрдах, кратных пяти: 5, 10, …, 45. 18. Дан массив из 3 байт. Рассматривая его как массив из 8 трёхразрядных слов, найти “исключающее или” всех 8 слов для выражения “101”. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 43 19. Дан массив из 7 байт. Рассматривая его, как массив из 56 бит, посчитать в нём количество нулей, стоящих после единицы. Конец последовательности рассматривать как нуль. 20. Дан массив из 8 байт. Рассматривая его, как массив из 64 бит, посчитать количество пар единиц в окружении нулей. Конец последовательности рассматривать как нуль. 21. Дан массив из 5 байт. Рассматривая его, как массив из восьми пятибитных слов, посчитать количество слов с чётным числом единиц в слове. 22. Дан массив из 6 байт. Рассматривая его, как массив из 48 бит, посчитать число двух единиц, стоящих между нулями. Конец и начало последовательности рассматривать как нули. 23. Дан массив из 3 байт. Рассматривая его, как массив из 24 бит, посчитать количество одиночных единиц в окружении нулей. Конец последовательности рассматривать как нуль. 24. Дан массив из 6 байт. Посчитать количество байт, число единиц в которых не превышает 3. 25. Дан массив из 11 байт. Посчитать количество байт, в которых нет единиц, стоящих рядом. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 44 A 5 Автоматы-распознаватели. Детерминизация автомата Практически во всех трансляторах (и в компиляторах, и в интерпретаторах) в том или ином виде присутствует большая часть перечисленных ниже процессов: лексический анализ синтаксический анализ семантический анализ генерация внутреннего представления программы оптимизация генерация объектной программы. В конкретных компиляторах порядок этих процессов может быть несколько иным, некоторые из них могут объединяться в одну фазу, другие могут выполнятся в течение всего процесса компиляции. В интерпретаторах и при смешанной стратегии трансляции некоторые этапы могут вообще отсутствовать. A 5.1 Построение лексических анализаторов В этой работе рассматриваются методы и средства, которые обычно используются при построении лексических анализаторов. В основе таких анализаторов лежат регулярные грамматики, поэтому рассмотрим грамматики этого класса более подробно. В дальнейшем под регулярной грамматикой будем понимать леволинейную грамматику. Для грамматик этого типа существует алгоритм определения того, принадлежит ли анализируемая цепочка языку, порождаемому этой грамматикой (алгоритм разбора): Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 45 Первый символ исходной цепочки a1a2...an⊥ заменяем нетерминалом A, для которого в грамматике есть правило вывода A → a1 (другими словами, производим «свертку» терминала a1 к нетерминалу A); Затем многократно (до тех пор, пока не считаем признак конца цепочки) выполняем следующие шаги: полученный на предыдущем шаге нетерминал A и расположенный непосредственно справа от него очередной терминал a i исходной цепочки заменяем нетерминалом B, для которого в грамматике есть правило вывода B → Aai (i = 2, 3,.., n); Это эквивалентно построению дерева разбора восходящим методом: на каждом шаге алгоритма строим один из уровней в дереве разбора, поднимаясь от листьев к корню. При работе этого алгоритма возможны следующие ситуации: прочитана вся цепочка; на каждом шаге находилась единственная нужная «свертка»; на последнем шаге свертка произошла к символу S. Это означает, что исходная цепочка a1a2...an ⊥ ∈ L(G). прочитана вся цепочка; на каждом шаге находилась единственная нужная «свертка»; на последнем шаге «свертка» произошла к символу, отличному от S. Это означает, что исходная цепочка a1a2...an ⊥ L(G). на некотором шаге не нашлось нужной «свертки», т.е. для полученного на предыдущем шаге нетерминала A и расположенного непосредственно справа от него очередного терминала ai исходной цепочки не нашлось нетерминала B, для которого в грамматике было бы правило вывода B → Aai. Это означает, что исходная цепочка a1a2...an ⊥ L(G). на некотором шаге работы алгоритма оказалось, что есть более одной подходящей «свертки», т.е. в грамматике разные нетерминалы имеют правила вывода с одинаковыми правыми частями, и поэтому непонятно, к какому из них производить «свертку». Это говорит о недетерминированности разбора. Анализ этой ситуации будет дан ниже. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 46 Допустим, что разбор на каждом шаге детерминированный. Для того, чтобы быстрее находить правило с подходящей правой частью, зафиксируем все возможные «свертки» (это определяется только грамматикой и не зависит от вида анализируемой цепочки). Это можно сделать в виде таблицы, строки которой помечены нетерминальными символами грамматики, столбцы – терминальными. Значение каждого элемента таблицы – это нетерминальный символ, к которому можно свернуть пару «нетерминал-терминал», которыми помечены соответствующие строка и столбец. Пример 1. Для грамматики G ({a, b, ⊥}, {S, A, B, C}, P, S), такая таблица (таблица 1) будет выглядеть следующим образом: Таблица 1 Знак «-» ставится в том случае, если для пары «терминал-нетерминал» «свертки» нет. Но чаще информацию о возможных свертках представляют в виде диаграммы состояний (ДС) – неупорядоченного ориентированного помеченного графа, который строится следующим образом: Строятся вершины графа, помеченные нетерминалами грамматики (для каждого нетерминала – одну вершину), и еще одну вершину, помеченную символом, отличным от нетерминальных (например, H). Эти вершины называют состояниями. H – начальное состояние. Соединяем эти состояния дугами по следующим правилам: a) для каждого правила грамматики вида W → t соединяем дугой состояния H и W (от H к и помечаем дугу символом t; б) для каждого правила W → Vt соединяем дугой состояния V и W (от V к W) и помечаем дугу символом t; Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 47 Диаграмма состояний для грамматики G представлена на рисунке 1. Рисунок 1 — Диаграмма состояний для грамматики G из примера 1 A 5.2 Алгоритм разбора по диаграмме состояний Алгоритм разбора по диаграмме состояний: объявляем текущим состояние H; затем многократно (до тех пор, пока не считаем признак конца цепочки) выполняем следующие шаги: считываем очередной символ исходной цепочки и переходим из текущего состояния в другое состояние по дуге, помеченной этим символом. Состояние, в которое мы при этом попадаем, становится текущим. При работе этого алгоритма возможны следующие ситуации (аналогичные ситуациям, которые возникают при разборе непосредственно по регулярной грамматике): прочитана вся цепочка; на каждом шаге находилась единственная дуга, помеченная очередным символом анализируемой цепочки; в результате последнего перехода оказались в состоянии S. Это означает, что исходная цепочка принадлежит L(G). прочитана вся цепочка; на каждом шаге находилась единственная «нужная» дуга; в результате последнего шага оказались в состоянии, отличном от S. Это означает, что исходная цепочка не принадлежит L(G). Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 48 на некотором шаге не нашлось дуги, выходящей из текущего состояния и помеченной очередным анализируемым символом. Это означает, что исходная цепочка не принадлежит L(G). на некотором шаге работы алгоритма оказалось, что есть несколько дуг, выходящих из текущего состояния, помеченных очередным анализируемым символом, но ведущих в разные состояния. Это говорит о недетерминированности разбора. Анализ этой ситуации будет приведен ниже. Диаграмма состояний определяет конечный автомат, построенный по регулярной грамматике, который допускает множество цепочек, составляющих язык, определяемый этой грамматикой. Состояния и дуги ДС – это графическое изображение функции переходов конечного автомата из состояния в состояние при условии, что очередной анализируемый символ совпадает с символомметкой дуги. Среди всех состояний выделяется начальное (считается, что в начальный момент своей работы автомат находится в этом состоянии) и конечное (если автомат завершает работу переходом в это состояние, то анализируемая цепочка им допускается). Таким образом, конечный автомат (КА) – это пятерка (K, VT, F, H, S), где K – конечное множество состояний; VT – конечное множество допустимых входных символов; F – отображение множества K × VT → K, определяющее поведение автомата; отображение F часто называют функцией переходов; H ∈ K – начальное состояние; S ∈ K – заключительное состояние (либо конечное множество заключительных состояний). F (A, t) = B означает, что из состояния A по входному символу t происходит переход в состояние B. Конечный автомат допускает цепочку a1a2...an, если F (H, a1) = A1; F(A1, a2) = A2; …; F (An-2, an-1) = An-1; F(An-1, an) = S, где ai ∈ VT, Aj ∈ K, j = 1, 2 , …, n–1; i = 1, 2, ..., n; H – начальное состояние, S – одно из заключительных состояний. Для более удобной работы с диаграммами состояний введем несколько соглашений: Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 49 если из одного состояния в другое выходит несколько дуг, помеченных разными символами, то будем изображать одну дугу, помеченную всеми этими символами; непомеченная дуга будет соответствовать переходу при любом символе, кроме тех, которыми помечены другие дуги, выходящие из этого состояния. введем состояние ошибки (ER); переход в это состояние будет означать, что исходная цепочка языку не принадлежит. A 5.3 Листинг анализатора для регулярной грамматики По диаграмме состояний можно написать анализатор для регулярной грамматики. Для грамматики из примера 1 анализатор будет таким: Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 50 A 5.4 Анализ регулярной грамматики При анализе по регулярной грамматике может оказаться, что несколько нетерминалов имеют одинаковые правые части, и поэтому неясно, к какому из них делать «свертку» (см. описание алгоритма). В терминах диаграммы состояний это означает, что из одного состояния выходит несколько дуг, ведущих в разные состояния, но помеченных одним и тем же символом. Пример 2. Для грамматики G ({a, b, ⊥}, {S, A, B}, P, S), где P: S → A⊥ A → a | Bb B → b | Bb Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 51 Разбор будет недетерминированным (т.к. у нетерминалов A и B есть одинаковые правые части – Bb). Такой грамматике будет соответствовать недетерминированный конечный автомат. Недетерминированный конечный автомат (НКА) – это пятерка (K, VT, F, H, S), где K – конечное множество состояний; VT – конечное множество допустимых входных символов; F – отображение множества K × VT в множество подмножеств K; H ⊂ K – конечное множество начальных состояний; S ⊂ K – конечное множество заключительных состояний. F (A, t) = {B1, B2,..., Bn} означает, что из состояния A по входному символу t можно осуществить переход в любое из состояний Bi, i = 1, 2, ..., n. В этом случае можно предложить алгоритм, который будет перебирать все возможные варианты «сверток» (переходов) один за другим; если цепочка принадлежит языку, то будет найден путь, ведущий к успеху; если будут просмотрены все варианты, и каждый из них будет завершаться неудачей, то цепочка языку не принадлежит. Однако такой алгоритм практически неприемлем, поскольку при переборе вариантов мы, скорее всего, снова окажемся перед проблемой выбора и, следовательно, будем иметь «дерево отложенных вариантов». Один из наиболее важных результатов теории конечных автоматов состоит в том, что класс языков, определяемых недетерминированными конечными автоматами, совпадает с классом языков, определяемых детерминированными конечными автоматами. Это означает, что для любого НКА всегда можно построить детерминированный КА, определяющий тот же язык. A 5.4.1 Алгоритм построения детерминированного КА по НКА Алгоритм построения детерминированного КА по НКА Вход: M = (K, VT, F, H, S) – недетерминированный конечный автомат. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 52 Выход: M’ = (K’, VT, F’, H’, S’) – детерминированный конечный автомат, допускающий тот же язык, что и автомат М. Метод: 1. Множество состояний К’ состоит из всех подмножеств множества К. Каждое состояние из К’ будем обозначать [A1A2...An], где Ai ∈ K. 2. Отображение F’ определим как F’ ([A1A2...An], t) = [B1B2...Bm], где для каждого 1 j m, F(Ai, t) = Bj для каких-либо 1 i n. 3. Пусть H = {H1, H2, ..., Hk}, тогда H’ = [H1, H2, ..., Hk]. 4. Пусть S = {S1, S2, ..., Sp}, тогда S’ – все состояния из K’, имеющие вид [...Si...], Si ∈ S для какого-либо 1 ≤ i ≤ p. В множестве K’ могут оказаться состояния, которые недостижимы из начального состояния, их можно исключить. Пример 2. Пусть задан НКА M = ({H, A, B, S}, {0, 1}, F, {H}, {S}), где F(H, 1) = B, F(B, 0) = A, F(A, 1) = B, F(A, 1) = S, тогда соответствующий детерминированный конечный автомат будет таким: K’ = {[H], [A], [B], [S], [HA], [HB], [HS], [AB], [AS], [BS], [HAB], [HAS], [ABS], [HBS], [HABS]} Достижимыми состояниями в получившемся КА являются [H], [B], [A] и [BS], поэтому остальные состояния удаляются. Таким образом, M’ = ({[H], [B], [A], [BS]}, {0, 1}, F’, H, {[BS]}), где F’([A], 1) = [BS] F’([H], 1) = [B] F’([B], 0) = [A] F’([BS], 0) = [A] A 5.5 Задание к лабораторной работе Общие задания: 1. Дана регулярная грамматика с правилами: S S0 | S1 | P0 | P1 P N. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 53 N 0 | 1 | N0 | N1 Построить по ней диаграмму состояний и использовать ДС для разбора цепочек: 11.010, 0.1, 01, 100. Какой язык порождает эта грамматика? 2. Дана ДС. Необходимо: Осуществить разбор цепочек 1011, 10+011 и 0–101+1. Восстановить регулярную грамматику, по которой была построена данная ДС. Какой язык порождает полученная грамматика? 3. Написать леволинейную регулярную грамматику, эквивалентную данной праволинейной, допускающую детерминированный разбор. Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 54 Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 55 Изм. Лист № докум. Подпись Дата 09.04.04.270000.000 ПЗ Лист 56