**Машинный язык** - это комбинация строго организованных последовательностей 0 и 1. Компьютер понимает только свой машинный язык. В 50-е годы XX века программисты стали использовать символический аналог машинного языка, который назвали **языком ассемблера**. Этот язык точно отображает особенности машинного языка, поэтому для каждого типа компьютера он свой. **Алфавит ассемблера:** - Все латинские буквы: A-Z, a-z (прописные и строчные эквивалентны) - Цифры: 0-9 - Специальные знаки: \_, \?, \@, \$, \& - Разделители: ,, ., \[, \], (, ), <, >, {, }, +, /, \*, %, !, "", \\, =, #, ^ **Идентификатор** - это последовательность допустимых символов для обозначения имен переменных и методов. Длина может составлять 256 символов, а транслятор воспринимает первые 32 символа. Идентификатор не может начинаться с цифры. Точка может быть только первым символом. **Ключевые слова** - это служебные символы языка ассемблер, к которым относятся названия регистров и операторы. Целые числа могут записываться в десятичной, двоичной, 16-ричной, реже в восьмеричной системе счисления. Символы и строки заключаются либо в одинарные, либо в двойные кавычки. В качестве символов можно использовать русские буквы. В строках прописные и строчные символы не эквивалентны. **Программа на языке ассемблер** - это последовательность предложений, каждый из которых записывается в отельной строке. Переносить на другую строку **нельзя**. По смыслу все предложения делятся на 3 группы: - Комментарии - Команды - Директивы ## Комментарии **Комментарием** считается любая строка, начинающаяся со знака ;, либо пустая строка. Также допустим многострочный комментарий, который начинается со слова `COMMENT <маркер><текст>`, где `COMMENT` - директива языка ассемблер. Маркер - это любой символ, кроме пробела. Концом комментария считается конец строки, в которой снова в любой позиции встретился этот же маркер. ```asm COMMENT * это все является комментарием к примеру * и это тоже ``` Многострочный комментарий обычно используется для временного исключения фрагмента программы. ## Команды **Предложения-команды** - это символьная форма записи машинных команд. Синтаксис команд: `[<метка>:] <мнемокод> [<операнды>] [;<комментарий>]` **Мнемокод** - это служебное слово, указывающее в символьной форме операцию, которую должна выполнить команда. ## Директивы **Директивы** - это приказы ассемблеру со следующим синтаксисом: `[<имя>] <название директивы> [<операнды>] [;<комментарий>]`. Например: ```asm X DB 1, -2, OFFh; массив X, состоящий из трех элементов ``` #### Директивы определения данных размером в байт, слово и двойное слово **DB** - директива определения данных размером в байт. Синтаксис: `[<имя>] DB <операнд>{, <операнд>}`. Встречая такую директиву, ассемблер вычисляет операнды и записывает их значения в последовательные байты памяти. Первому из этих байтов даётся указанное имя, по которому на этот байт можно ссылаться из других мест программы. Существует два основных способа задания операндов: 1) **?** - знак неопределенного значения: ```asm X DB ? ``` Для переменной X отводится 1 байт памяти, в который ничего не записывается. Выделив байт под переменную, ассемблер запоминает его адрес. Когда в тексте программы встретится данное имя, ассемблер заменит его на адрес, который принято называть значением имени X. Размер переменной в памяти называется **типом имени переменной**. Тогда значение и тип имени переменной однозначно определяют ячейку, обозначаемую этим именем. В ассемблере есть оператор типа `TYPE <имя>`. Значением этого оператора является размер ячейки, выделенной под переменную в байтах: ```asm TYPE X ; = BYTE = 1 ``` 2) Константное выражение от -128 до 255: ```asm A DB 254 ; 0FEh B DB 17h ; 17h C DB "*" ; 2Ah ``` При описании переменной-массива имя даётся его первому элементу, остальные остаются безымянными: ```asm M DB 2 DB -2 DB ? DB "*" ``` или: ```asm N DB 2, -2, ?, "*" ``` ![Хранение массива в памяти](../Pictures/03_01.%20Хранение%20массива%20в%20памяти.png) Таким образом, в памяти будет выделено 4 ячейки памяти размером в байт: ```asm TYPE M ; = 1 ``` Для ссылок на другие байты массива используют ссылки вида `M+k`, где `k` - целое число. Т. е., `M+1` - адрес байта со значением `FE`: ```asm M + 1 ; адрес байта со значением FE M + 3 ; адрес байта со значением '*' (2A) ``` Если несколько соседних операндов - символы, их можно объединить в строку: ```asm S DB 'a' DB 'b' DB 'c' ``` также возможны другие варианты написания: ```asm S DB 'abc' S DB 'a', 'b', 'c' S DB 'ab', 'c' S DB 'a', 'bc' ; TYPE S = 1 ``` Если необходимо описать байтовый массив, состоящий из нескольких байтовых элементов, можно использовать конструкцию повторения - `DUP()`: ```asm R DB 0,0,0,0,0,0,0,0 R DB 8 DUP(0) ``` где 8 - коэффициент повторения, `DUP` - служебное слово, в круглых скобках - повторяемая величина. Точно также можно описать двумерный массив: ```asm G DB 10 DUP(20 DUP(?)) ``` **DW** - директива определения данных размером в слово. ```asm A DW ? ; TYPE A = 1 B DW 1234h ; TYPE B = 2 C DW -2 ; TYPE C = 2 S1 DW `01` ; TYPE S1 = 2 E DW 40000, 3 DUP(?) ; TYPE E = 2 ``` В качестве операнда директивы `DW` может быть указано адресное выражение, то есть выражение, значение которого является адрес: ```asm C DB ? D DW C ``` Ассемблер записывает в слово, выделенное под переменную `D`, адрес переменной `C`, который становится начальным значением переменной `D`. **DD** - директива определения данных размером в двойное слово. Диапазон значений: - Целые числа: от $−2^{31}$ до $2^{32}−1$ - Константные выражения от $−2^{15}$ до $2^{16}−1$, т.к. все выражения вычисляются в области 16-битовых чисел ```asm A DD ? ; TYPE A = 4 B DD 123456h ; TYPE B = 4 C DD 33 DUP(?) ; TYPE C = 4 C DB ? D DD C ``` Ассемблер заменяет имя переменной `C` на адресную пару? состоящую из сегмента и смещения имени внутри сегмента. #### Директива эквивалентности ```asm <имя> EQU <операнд> ``` Операнд может быть: 1. **Операнд-имя**. Если в правой части директивы указанно имя регистра, переменной или константы, тогда имя слева объявляется синонимом данного имени, и все последующие вхождения в текст программы этого имени-синонима ассемблер будет заменять на имя, указанное справа: ```asm A DW ? B EQU A C DW B ; эквивалентно C DW A ``` 2. **Операнд - константное выражение**: ```asm N EQU 100 ; N - константа со значением 100 K EQU 2*N-1 ; K - константа со значением 199 ``` Все последующие вхождения в текст программы имени константы ассемблер будет заменять на значение этой константы. 3. **Операнд - любой текст**: ```asm S EQU "Привет" ``` #### Директива присваивания Эта директива определяет константу с именем, указанным слева и числовым значением, равным значению выражения справа. Однако, данная константа может менять свое значение. ```asm K = 10 A DW K ; эквивалентно A DW 10 K = K + 4 B DB k ; эквивалентно B DB 14 ``` **Пример 1:** чему равны переменные `A`, `B`? ```asm K = 1 N EQU K A DW N K = 2 B DB N ; N = 1 ; A = 1 ; B = 2 ``` **Пример 2:** чему равны переменные `C`, `D`? ```asm K = 1 N EQU K + 10 C DW N K = 2 D DW N ; N = 11 ; C = 11 ; D = 11 ``` Выражения ассемблера вычисляются не во время выполнения программы, а во время ее трансляции, в отличие от языков программирования высокого уровня. Встретив в тексте программы выражение, ассемблер вычисляет его и полученное значение записывает в программу. Поэтому в выражениях нельзя использовать величины, которые станут известны во время выполнения программы. **Приоритет операций:** 1. (), \[\], LENGHT, SIZE, WIDTH, MASK 2. . 3. : 4. PTR, OFFSET, SEG, TYPE, THIS 5. HIGH, LOW 6. Одноместные +, - 7. \[\] \*, /, MOD, SHL, SHR 8. Двуместные +, - 9. EQ, NE, LT, GT, GE 10. NOT 11. AND 12. OR, XOR 13. SHORT, TYPE