3.ЭЛЕМЕНТЫ ДАННЫХ И ВЫРАЖЕНИЯ.
3.1.Набор знаков языка ассемблера.
Ассемблер работает с перечисленными ниже знаками символьных кодов ASCII и знаками альтернативной кодировки.
Знаки, используемые в символьных именах (символах) языка.
1.Латинские буквы и буквы кирилицы (кирилица допустима если не действует ключ /-r-us или директива .NRUS) .
2.Цифры от 0 до 9 (символ не может начинаться с цифры).
3.Знаки:
$ - знак денежной единицы (входит в символ только вместе с другими знаками);
[ - правая квадратная скобка;
] - левая квадратная скобка;
- обратная дробная черта;
- стрелка вверх;
- подчеркивание;
- знак фунта стерлингов.
4."." - точка, зарезервирована для использования в символах системных программ и библиотек.
Специальные знаки:
5.Знаки, используемые в термах выражений ассемблера.
- Цифры от 0 до 9 и буквы А В С D Е F; используются в числах,- *
$ - знак денежной единицы; представляет собой ссылку на программный счетчик адресов;
" - парные кавычки;индикатор символьного кода для двух или одного символа;
6.Разделительные и ограничительные знаки:
" "ДАВ - (коды 32 и 9) пробел и табулятор; необходимы как разделители между полями строки языка ассемблера;
в выражениях могут лишь отделять символьные имена друг от друга, а аргументы в поле операндов не отделяют,
и служат для выделения фрагментов текста для обеспечения лучшей читаемости программы;
, - запятая; необходима для отделения аргументов команд и директив в поле операндов;
<> - парные угловые скобки; используются в любом месте программы для выделения выражения, которое будет об-
рабатываться как терм;
: - двоеточие; необходимо для определения метки, если она отделена от начала строки пробелами или табулято-
рами;
7. Знаки операций.
В языке ассемблера допустимы унарные и бинарные операции. Унарные операции выполняются над одним термом(ар-
гументом или операндом). Унарная операция относится к тому терму, которому она предшествует.
+ - унарный плюс и бинарное сложение;
- - унарный минус и бинарное вычитание;
2~ - двойка и стрелка вверх; унарная операция возведения двойки в степень;
* - звездочка; арифметическое умножение;
/ - дробная черта; арифметическое деление;
& - коммерческое "И"; поразрядное логическое "И";
@ - коммерческое "ЭТ"; поразрядное логическое "ИЛИ";
! - восклицательный знак; поразрядное логическое исключающее "ИЛИ"( X0R );
8. Знаки временного изменения основания системы счисления числа.
% - процент; указатель двоичного числа;
# - решетка; указатель шестнадцатеричного числа;
9. Прочие знаки.
()- левая круглая скобка и правая круглая скобка; используются в аргументах команд Z80 для задания режима ад-
ресации и определения конкретной команды Z80 в соответствии со стандартом, принятым для мнемонического
обозначения команд Z80 .
3.2.Символы языка ассемблера.
Символы языка строятся из знаков, приведенных в п. 3.1., и об этом уже говорилось частично в п. 2.1.1...
В языке имеются символы двух типов: постоянные символы и символы, определяемые пользователем. Соответственно
этому ассемблер имеет таблицы символов трех типов:
PST - таблица постоянных символов,
UST - таблица символов пользователя
PST содержит все постоянные символы языка: мнемоники инструкций и регистров Z80, директив и команд ассемб-
лера. Эти символы не нуждаются в своем определении в программе, т.к. PST входит в сам транслятор.
Таблица UST заполняется при трансляции исходной программы в момент определения соответствующих символов и
построена по принципу бинарного дерева без оптимизации его ветвей-, что позволяет достичь хорошего быстродейс-
твия при трансляции. В связи с этим не рекомендуется располагать определяемые символы на протяжении достаточно
больших участков текста программы в строго алфавитном порядке (чтобы избежать вырождения бинарного дерева в
линейный список и замедления поиска).
Удобным способом избежать расположения меток в алфавитном порядке явилось бы применение локальных цифровых
символов типа 1$, 2$ и т.д., которые планируется реализовать во второй версии ассемблера.
Символы, определяемые пользователем, могут использоваться как метки, либо как константы, определяемые че-
рез директиву прямого присваивания EQU.
Кроме того, возможно их определение как глобальных или локальных символов, различающееся по области види-
мости.
Обычным образом определенные буквенно-цифровые символы интерпретируются ассемблером как локальные и видны
лишь внутри транслируемого модуля.
Если в одном модуле будет определено несколько локальных символов с одинаковыми первыми 6 знаками, то это
вызовет ошибку 4. В этом случае верным будет считаться первое определение, однако, второй проход трансляции
будет блокирован и объектный код не будет создан.
Удобно бы было использовать локальные цифровые символы, область видимости которых ограничена двумя нецифро-
выми символами.
Информация о символах, начинающихся знаком "$", записывается в объектный файл и, таким образом, становится
доступной компоновщику для использования при связывании объектных модулей в загрузочный.
При встрече двух одинаковых глобальных символов в разных модулях компоновщик также предупредит о многократ-
ном определении, но, в отличие от ассемблера, будет работать до конца, создав загрузочную программу со значе-
нием этих глобальных символов, равным значению в первом встретившемся из компонуемых модулей.
3.3.Числа.
Все числа в исходной программе интерпретируются в десятичной системе счисления,если нет специальных указа-
ний относительно системы. Переполнение двухбайтового размера числа вызовет округление числа до двух байт и со-
общение об ошибке номер 51, если не возникнет более серьезная ошибка 44 (см.ниже ).
Два специальных знака % и # меняют систему счисления числа, перед которым они стоят,следующим образом:
% - двоичное число. Переполнение свыше 16 цифровых знаков вызовет ошибку 44. При этом прекращается вычисле-
ние выражения, в котором стоит число, и его результат остается непредсказуемым.
# - шестнадцатиричное число. Переполнение свыше 16 цифровых знаков вызовет ошибку 44,как и в предидущем
случае, а свыше 4 знаков - ошибку 51. В последнем случае результат определится по младшим 4 цифровым знакам,
что соответствует двухбайтовому числу.
3.4.Термы.
Терм является компонентой выражения. Он может быть:
1.Числом (со значением в пределах 0-65536).
2.Символом; символы интерпретируются согласно следующим правилам:
- $ означает использование текущего счетчика адресов программы;
- символ, определенный пользователем, помещается в таблицу символов пользователя (UST);используется значение
символа из этой таблицы; это может быть метка, либо константа, определенная через директиву EQU;
- неопределенному символу, встретившемуся в поле операнда команды Z80 или директивы размещения блока данных
присваивается значение 0 и перемещаемость внешнего символа; если такой символ определен как локальный, то
он вызовет сообщение об ошибке 50.
- неопределенный символ, встретившийся в поле операнда директивы EQU, вызовет сообщение об ошибке 13 и прек-
ращение вычислений данного выражения, если на втором проходе потребовалось использование символа, стояще-
го в поле метки данной директивы EQU; значение такого символа и выражения с ним считается произвольным;
3.Одним либо двумя знаками в символьном коде ASCII или альтернативной кодировке, заключенными в кавычки,
например:"А","Яй" или "Ц";
4.Выражением, заключенным в угловые скобки; любая часть выражения, заключенная в угловые скобки обрабатывает-
ся прежде, остальной части; угловые скобки используются для изменения порядка слева направо обработки выраже-
ний (для отличия а+Ь*с от а+<Ь*с> )или для придания знака унарной операции всему выражению (например, -<а+Ь+с>
или 2~<а+Ь> ,где 2~-унарный оператор степени );
3.5.Выражения.
Выражение является комбинацией термов, разделенных знаками операций. Принята инфиксная форма записи выраже-
ния т.е. когда знаки операции располагаются между своими термами, а для нескольких следующих подряд унарных
операторов допускается префиксная запись, когда каждый унарный оператор действует на свой аргумент, стоящий
справа (см. примеры в ^гом же пункте). При нарушении такой формы записи возникает ошибка 33. Пробелы в выраже-
нии служат не обязательными разделителями термов, и их число не ограничено.
Несколько слов скажем об отличиях в действии унарных и бинарных операторах, затем назовем все допустимые
операторы выражений ассемблера и, далее, поговорим о перемещаемости выражений.
Выражения обрабатываются слева направо, за исключением унарных операций, которые имеют больший приоритет об-
работки, например, для унарного оператора 2~:
2+2~3*2 дает значение 20
2+8*2 дает значение 20
Каждый составной терм выражения обрабатывается целиком, что позволяет менять установленный порядок выполне-
ния операций слева направо с помощью угловых скобок, например:
5*< 4+ < 3-<2@1> > > = 20
Глубина стека калькулятора ограничена 64 словами, что на практике вполне достаточно.
Запись подряд нескольких унарных операторов интерпретируется ассемблером как префиксная запись, например:
2+2~2~3 эквивалентно 2 + < 2~<2~3> > ,
что дает значение 258; здесь аргументами бинарного оператора "+" являются 2 и 2~2~3, аргументом первого унар-
ного 2~ - 2~3, а аргументом второго унарного оператора 2" будет число 3.
2+2~3~4 эквивалентно 2 + < 2~<3~4> >,
что вызовет ошибку 27, т.к. оператора 3" не существует в ассемблере.
-2~10+24 эквивалентно < -<2~10> > + 24 , что дает значение 1000;
Знаки + и - интерпретируются как знаки унарных операций только, если они стоят в начале терма, или выражения,
например:
в строке LD HL,-ABC-10 первый минус унарен и его аргументом является символ ABC, а второй минус бинарен и его
аргументы - это -ABC и 10;
в выражении 2~-<-АВС> первый минус бинарен, а второй унарен; поскольку перед бинарным минусом стоит оператор
2~, а не аргумент, то этим нарушается инфиксная скобочная форма записи выражений, что приведет к ошибке 33;
избежать ошибки можно, сделав первый минус унарным:
2~< -<-АВС> >
В выражениях можно использовать следующие знаки унарных операций (операторов):
+ унарный плюс, не меняет знака терма (+А есть само А);
- унарный минус, меняет знак терма (-А есть противоположное значение А в дополнительном коде), например: -1
есть 65535 ;
2~ степень двойки, возводит число два в степень, заданную значением терма, например, 2~10 есть 1024.
и следующие бинарные операторы:
+ сложение;
- вычитание;
& поразрядное логическое "и";
@ поразрядное логическое "или";
! поразрядное логическое исключающее "или";
* умножение;
/ деление; результат целый;
? функция MOD: А?В=А-< <А/В>*В >
Примеры выражений, при условии, что stepl равна 0, step2 равна 1, а $МЕТ не определена :
выражение результат
2~stepl @ 2~step2 3
#1234?256+<#1234/256*256> #1234
-<1+2*3-4> -5
+ 1 26
%1000000001 ! 65535 %1111110111111110
"ab"&<2~5*256+2~5!65535> "АВ"
#100-$МЕТ*2 О
В последнем примере результат выражения временно полагается равным 0 до его корректировки компоновщиком.
Все вычисления ведутся в двоичном дополнительном 16 разрядном коде. Поэтому значение выражения не может
превосходить 16-разрядной величины.
Предупреждения об ошибках переполнения возникают только, в операции умножения, если переполнение может при-
вести к неверному знаку результата (при превышении результата умножения двух соответствующих положительных ве-
личин значения 32767= =#7FFF).(см.пример в описании ошибки 15). Возникновение ошибки переполнения в аналогич-
ной ситуации при сложении и вычитании (изменение знака) не идентифицируется, т.к. дополнительная кодировка га-
рантирует верность 16 младших разрядов результата этих операций, как в интерпретации чисел без знака , так и в
знаковой их интерпретации. Но при комбинировании сложения и вычитания с делением следует соблюдать осторож-
ность, т.к. деление предполагает только знаковую интерпретацию чисел (когда числа > 32767 интерпретируются как
отрицательные ) . Например:
#1+#FFFF-#FFFE = #10000-#FFFE = 2 ,
в беззнаковой интерпретации,но в знаковой будет то же самое:
1+ <-1>- <-2> = 0- <-2> = 2
в связи с этим бывает полезно иметь возможность определять знак терма, чтобы правильно использовать операции
деления и умножения. Такая возможность есть в ассемблере. Побочным эффектом деления на ноль является вычисле-
ние некой обратной знаковой функции:
А/0= -1 для А >= 0
А/0= +1 для А < 0
Воспользовавшись этим, можно, например, корректно работать с неким адресом буфера $BUF при вычислении его
старшего байта $HBUF, не зависимо от конкретного значения (знака числа $BUF):
$HBUF EQU <$BUF-#8000/256+#80>*
*<$BUF/0+l/2> + <$BUF/256*<-$BUF/0+l/2>>
;для $В11Ротриц. для $BUF полож.
На самом деле выражение должно быть записано в одну строку.
Здесь терм <$BUF/0+l/2> равен 0 для $BUF<=#7FFF, и он равен 1 при $BUF>#7FFF, а для терма <-$BUF/0+l/2> все
будет как раз наоборот. В результате, используя данные термы в качестве сомножителей, можно вычислять $HBUF по
разным формулам для положительных и отрицательных значений $BUF.
3.5.1.Перемещаемость при вычислении выражений.
Вычисление выражения включает определение его перемещаемости, т.е. зависимости его значения от изменения ад-
реса компоновки (и загрузки) модуля, в которое входит данное выражение.
Результирующее значение выражения может быть любым из четырех типов, описываемых ниже абсолютным, относитель-
ным, внешним или сложным относительным.
Выражение (и его значение) является абсолютным,если его значение фиксировано, не зависит от адреса компонов-
ки.
Следующие выражения имеют абсолютные значения:
- выражения, термы которых являются числами или знаками символьного кода;
- относительное выражение или терм минус относительный терм, поскольку такое выражение преобразуется ассемб-
лером к концу анализа выражения в единичный терм - абсолютное число;
В листинге трансляции такие выражения не помечаются, т.е. после их значения в поле кода листинга стоит про-
бел.
Например, в следующем фрагменте, значения выражения МЕТ2-МЕТ1 и значение аргумента команды короткого безус-
ловного перехода будут абсолютными:
адр код стр текст программы
О 18 3 1 JR MED2
2 2 МЕТ1
2 21 3 0 3 LD HL,МЕТ2-МЕТ1
5 4 МЕТ2
Выражение является относительным, если для коррекции его значения при компоновке достаточно добавить к нему
базовый адрес модуля, в котором это выражение встретилось. Такими являются следующие выражения и термы:
- выражения, состоящие из одного простого терма-метки или терма-символа программного счетчика адресов.
- относительное выражение плюс (минус) абсолютный терм.
Значения таких выражений, выводимые в листинге в поле кода,помечаются знаком г.
Информация о них занимает дополнительно к 1 или 2 байтам, индицируемым в поле кода листинга, еще 2 байта.
адр код стр текст программы
О ООО 1 Ml DEFS 160
АО 21 0 Ог 2 М2 LD HL,M1
A3 11 А6 Or 3 LD DE,МЗ+<М2-М1>
A6 ООО 4 МЗ DEFS М2-М1
Выражение является сложным относительным, если выполняется одно из следующих условий:
- величина, получаемая в результате вычисления выражения,требует более, чем одно перемещение; например, если
относительные термы МЕТ1 и МЕТ2 образуют выражение вида МЕТ1+МЕТ2, то будут выполнены два перемещения ком-
поновщиком, (т.е. к значению выражения будет добавлен адрес компоновки модуля два раза );
- перемещение должно быть выполнено с обратным знаком, т.е. значение адреса компоновки модуля должно вычи-
таться, из значения выражения один или несколько раз, например -МЕТ1, где МЕТ1 - относительный терм;
Значения таких выражений, выводимые в листинге в поле кода,помечаются знаком т, и им временно присваивается
нулевое значение до окончательной обработки их компоновщиком. Информация о них занимает дополнительно к 1 или
2 байтам, индицируемым в поле кода листинга, еще 6 байт.
Выражение является внешним в следующих случаях:
- оно содержит неопределенный в данном модуле символ (предполагается, что он будет определен как глобальный
символ в другом модуле);
- операция, отличная от сложения, вычитания или изменения знака, применяется к относительной величине.
Значения таких выражений, выводимые в листинге в поле кода,помечаются знаком д, и им временно присваивается
нулевое значение до окончательной обработки их компоновщиком.
Такие выражения не могут быть вычислены ассемблером и записываются в объектный файл в постфиксной форме для
передачи компоновщику, практически целиком. Если же левые термы выражения не являются внешними, то они буду!
вычислены и выражение запишется в объектный файл в укороченном виде (это не касается выражений с неопределены-
ми символами). Например, следующее выражение будет частично вычислено ассемблером: LENG2-LENG1+BUFF/256 , где
LENG1 и LENG2 - относительные термы; а это запишется в объектный файл целиком:
BUFF/256+LENG2-LENG1 ,
т.к. терм <LENG2-LENG1> не является внешним (он абсолютный) и, поэтому, может быть вычислен, если стоит в вы-
ражении слева.
3.6.Программный счетчик адресов.
Символ $ зарезервирован для использования в качестве идентификатора текущего счетчика адресов в программе
на ассемблере.
В начале каждого прохода его значение полагается равным нулю. После трансляции любого оператора ассемблер-
ной строки он получает значение, равное сумме предыдущего и длины оттранслированного оператора (команды Z80
или блока данных). Кроме того, в директивах DEFB и DEFW, он получает соответствующее приращение при трансляции
каждого аргумента этих директив.
Таким образом, при использовании этого символа в поле операнда инструкции Z80 он обозначает адрес первого
байта инструкции. При использовании его в поле операнда директивы ассемблера он представляет адрес текущего
байта, слова или блока данных (в директиве DEFS).