#### Компилятор ZX Assembler++
(для эмулятора EmuZWin)
(С) by Vladimir Kladov, 2003-2006

Начиная с версии 2.7, компилятор ZXAsm++ вынесен в отдельную DLL, и его исходный код (на языке Pascal, Delphi) опубликован полностью (т.е. он теперь может быть использован в других эмуляторах Spectrum или может быть построен самостоятельный кросс-компилятор на его основе).

Исходный код на языке должен быть написан с соблюдением следующих правил.

- Каждая строка может содержать один или несколько операторов или директив, либо один оператор или директива может располагаться на нескольких строках (с отдельными ограничениями, которые оговариваются ниже в кажлом случае особо). Комментарий (до конца строки) начинается с символа ';'. Так же, строка считается комментарием, если первый печатный символ в строке - это '*' (и символ '*' при этом не может считаться знаком умножения от перенесенного с предыдущей строки выражения).
  Примечание: при расцветке строки в редакторе ассемблера EmuZWin, строка-комментарий, начатая символом '*', раскрашивается как не-комментарий - это можно использовать для создания разноцветных комментариев.
- Любая строка может начинаться с метки (но метка в строке может быть только одна). Метка должна быть идентификатором, т.е. начинаться с буквы (русские буквы разрешаются) или одного из специальных символов '@','_','!','~','%','$','!', '\', '[', ']'. Прочие символы должны быть из того же набора, так же в продолжении идентификатора разрешаются цифры и знак '#'.
- Метка может быть (необязательно) отделена от помеченного ею оператора символом ':', но это необязательно - достаточно пробелов (сохранено для совместимости). В качестве метки не может использоваться идентификатор, который совпадает с зарезервированным словом - кодом инструкции или директивой, которая не имеет (или может не иметь) операндов, например, WHILE.
- Оператор без метки может начинаться с левого края строки (пробелы необязательны). Если в строке размещается несколько операторов или директив, они могут быть отделены друг от друга символом ':' (но это так же необязательно - если из записи очевидно, где завершается оператор и начинается следующий, разделителем могут быть пробелы).
- Регистр в метках чувствителен. (Т.е. Abc, abc и ABC суть различные имена). Но коды операций, директивы, имена регистров и флаги условий (Z, NZ, и т.п.) и шестнадцатеричные цифры к регистру букв нечувствительны.
- Числовые константы обычно (но не всегда!) начинаются с символов цифр 0..9 (шестнадцатеричные числа распознаются даже если начинаются с шестнадцатеричных цифр A..F, если завершаются один из маркеров шестнадцатеричной системы счисления: H или h или .H или .h). База системы счисления по умолчанию всегда десятичная (исключение - директива DEFD), но если в константе без указания маркера системы счисления встретилась хотя бы одна шестнадцатеричная цифра 'a'..'f', для константы используется база 16. Аналогично, разрешаются двоичные числа (например, 00001001.B), завершающиеся маркером '.B' или '.b' , и восьмеричные числа, с суффиксом базы '.O' или '.o' (так же допускаются суффиксы .D для десятичных и .H для шестнадцатеричных):например 71.O - это восьмеричное, равное 39.H (=57.D=111001.B). Так же, шестнадцатеричные числа разрешаются в форме #xxxx (начинаются с символа '#' с последующими шестнадцатеричными числами) или $xxxx (но в последнем случае - только при включении соответствующей опции в компиляторе). И, для двоичных чисел, допускается формат %xxxx (где x=0,1).
  Если идентификатор все еще не определен после первого прохода компиляции, и он содержит только шестнадцатеричные цифры, то он считается шестнадцатеричным числом. (Т.е. можно кратко написать OUT FE вместо OUT (FE),A)
- Строковые константы заключаются в одинарные ( ' ) или двойные ( " ) кавычки, для кодирования самих кавычек ' или ", следует использовать в качестве ограничителей противоположные кавычки. Одно- или двух-символьные строки могут использоваться где угодно как числа (второй символ в такой строке представляет старший байт 16-битного слова, т.е., например: 'AB' = $4241).
- Практически везде, где встречаются числа, смещения, непосредственные операнды, и т.п. - могут использоваться выражения. (Поскольку в командах для косвенной адресации используются круглые скобки, то чтобы отличить непосредственную константу от адреса, следует перед скобкой поставить знак '+', например - тогда оно будет считаться числом, в отличие от адреса).
- В выражениях может использоваться встроенная функция sizeof(имя структуры) как обычная константа (см. ниже директиву STRUCT).
- Специальная метка '.' (единственный символ точки) означает "адрес самой команды". Специальная метка '$' означает "адрес следующей инструкции".
- Разрешаются локальные метки. стартующие с одного из 6 символов '.', '_', '@', '!', '?', '\' (каждый из этих символов разрешается отдельно в опциях ассемблера как символ начала локальной метки). Локальные метки никогда не проверяются на дублирование. Для перехода на ближайшую локальную метку (или для использования ее в выражениях) обычным образом записывается ее имя, используется ближайшая такая метка. Но если в окрестностях оператора есть две таких метки, одна выше, а другая ниже по тексту, используется вторая (для поиска метки сначала просматриваются вперед). Для указания направления перехода, используйте локальное имя с префиксом B[local] или F[local] (B - back, т.е. назад, F - forward, т.е. вперед, или в нижнем регистре b[local] и f[local], так же возможно использовать символы '<' и '>', но только в инструкциях GOTO, JP и JR, и для этих префиксов, разрешается только целая метка, а не выражение).
- В выражениях, разрешаются следующие бинарные операции:
  + сложение
  - вычитание
  * умножение
  / деление
  % остаток
  & "И"
  | "Или"
  ^ "Исключающее Или"
  < меньше (true=1, false=0)
  <= меньше или равно
  > больше
  >= больше или равно
  <> или != или ~= не равно
  = равно
  << сдвиг влево
  >> сдвиг вправо
- Скобки могут использоваться для контроля порядка вычислений как обычно. Если скобок нет, используются приоритеты операций, от высших к низшим:
  << >>
  * / %
  + -
  & ^
  |
  < > <= >= = <>

Ассемблер понимает следующие директивы. (В обозначениях префиксный символ '#' используется для обозначения операндов, на месте которых могут быть любые допустимые числовые выражения). Так как большинство операторов и директив могут быть продолжены на следующей строке, только в директивах с ограничением на это правило сделаны соответствующие пометки.

ORG | ENTRYPOINT | EQU | x=y | .=y, $=y | ENUM | DEFINE | DEFB | DEFM | DEFW | DEFS
DEFG | DEFD | ENCODE | CTEXT | FILE | INCLUDE | MACRO | ERROR | DISPLAY | PROC | DUP
FOR | IF | IFcond | LONGIFcond | WHILE | LONGWHILE | WHILEB | BREAK | CONTINUE | GOTO | PUSH
POP | POPNOINVERT | POPINVERT | END |  |  |  |  |  |  |

    ORG [{ RAMn | ROMn },] #target_address [, #dest_address ]
    Задает целевой адрес ассемблирования (т.е. адрес текущей инструкции во время
    исполнения) и адрес размещения инструкций при ассемблировании (он может
    отличаться от адреса инструкции, если команды размещаются первоначально не в
    тех адресах, по которым будут исполняться, или, например, не в том банке
    памяти, который сейчас виден по адресу C000).

    RAMn или ROMn могут использоваться для указания банка ОЗУ ( RAM n (n=0..7) )
    или банка ПЗУ (ROM n (n=0..1) ). n может быть выражением.

    Все имена, используемые в выражениях в данной директиве, должны быть известны
    уже на первом проходе компиляции, ссылки вперед здесь недопустимы - но только
    если не выключена опция Strong Address Control в опциях ассемблера).
    ENTRYPOINT #expr
    Задает точку входа в программу (устанавливает PC в указанное значение в случае
    успешной компиляции).
    label[:] EQU #expression
    Задает константу label. Метка label должна быть уникальной, так же как и обычная
    метка.
    label[:] = #expression
    Задает переменную label и приравнивает ей значение выражения. Разрешается
    переопределять такую переменную с помощью оператора = сколько угодно раз
    в коде (т.е. уникальность метки label в этом случае не требуется, в отличие
    от директивы EQU).
    Примечание: после каждого шага компиляции, такие переменные сохраняют значение,
    полученное при последнем присваивании. Это может использоваться для каких-то
    вычислений на втором или третьем проходе компилятора, когда код генерируется
    окончательно.
    . = #expression
    или
    $ = #expression
    Специальная форма присваивания, где в левой части используется символ '.' или
    '$'. В результате, последующий код будет компилироваться с адреса, указанного
    выражением. Фактически, такой оператор эквивалентен ORG №addr, с той разницей,
    что данный адрес не попадает в список ORG-ов, доступных для быстрой установки
    регистра PC из ассемблера.
    ENUM label1[=#expr1][,label2[=#expr2]]...
    Создает набор констант label1, label2, ... Если выражения expr2, expr3, и т.д.
    опущены, то следующая константа вычисляется как значение предыдущей + 1. Если
    опущено #expr1, то первой константе в списке присваивается значение 0.
    label[:] DEFINE any text to the end of line
    Переопределяет идентификатор. В последующем этот идентификатор замещается
    указанной строкой везде в тексте. Об использовании макро-параметров,
    имен, переопределенных директивой DEFINE или переменных препроцессорного
    цикла FOR смотрите ниже.
    DEFB [[(#repeat_count1)]{#expr1|'string1'|?}][,[(#repeat_count2)][{#expr2|'string2'}]]...
    Определяет список байтов. Для строк в кавычках, для каждого символа создается
    свой байт. Если выше по тексту задана директива ENCODE, все символы перекодируются
    перед записью в память в соответствии с этой директивой. По умолчанию,
    DEFB 'abc',0 будет откомпилировано в 4 байта 61h,62h,63h,0. Если для значения
    задан повторитель (repeat_count), значение повторяется указанное число раз (если 0
    или меньше, оно не генерируется вообще).
    Если вместо значения используется одиночный символ '?', байт в памяти не инициализируется
    и в процессе компиляции пропускается.
    DEFM[{ #expression | 'string' }] [, [{ #expression | 'string' }] ]...
    Список байтов - аналогично директиве DEFB, отличие только в том, что
    в последнем байте строки бит 7 установлен. Т.е.,
    DEFM 'abc' компилируется в 4 байта: 61h,62h,E3h.
    DEFW [[(#repeat_count1)]{#expr1}][,[(#repeat_count2)][{#expr2}]]...
    Список 16-битных слов. Очень похож на DEFB, но для размещения каждого значения
    требуется в памяти 2 байта памяти (как обычно, младший значащий байт размещается
    первым - LSB).
    DEFS #repeat_count [, { #expression | 'string' | "string" } ]...

    Список байтов, как в директиве DEFB, но весь список повторяется указанное
    первым операндом число раз. Эквивалентно DUP #repeat_count DEFB list EDUP
    Если имеется только #repeat_count без значений, в памяти образуется заданное
    повторителем число нулевых байтов.
    DEFG ssssssss [ ssssssss ]...

    Особая директива для задания шрифтов (или двоичных значений байтов).
    Символ '.' представляет в записи 0, любой другой символ 1. Для разделения
    байтов используются пробелы. Числовые константы, начинающиеся с десятичной
    цифры, однако, считываются именно как числа. Если следующая строка стартует
    с одного из символов '.', 'x' или 'X', то предполагается, что DEFG занимает
    несколько строк, и в этом случае байты помещаются в память по столбцам, а не
    один за другим. Например:

    DEFG ........ .X......
    DEFG .XXXXX.. .X......
    DEFG ......X. .XXXXX..
    DEFG ..XXXXX. .X....X.
    DEFG .X....X. .X....X.
    DEFG ..XXXX.X .XXXXX..
    DEFG ........ ........
    (компилируется в 0,40h,7Ch,40h, и т.д.)
    или:
    DEFG ........ .X......
         .XXXXX.. .X......
         ......X. .XXXXX..
         ..XXXXX. .X....X.
         .X....X. .X....X.
         ..XXXX.X .XXXXX..
         ........ ........
    (в этом случае порядок другой: 0,7Ch,2,3Eh,42h,3Dh,0,40h, т.е. байты размещаются
    по колонкам).
    DEFD xxxxxx [[,] xxxxxx ]...

    Директива для определения упакованных шестнадцатеричных. Например, DEFD 1234567890
    эквивалентно DEFB 12h,34h,56h,78h,90h. Если элемент стартует не с шестнадцатеричной
    цифры, то он считается обычным выражением (и занимает 1 байт, как в директиве DEFB).
    ENCODE #from1,#to1[,#from,#to]...

    Директива для перекодирования символов в строках (например, может использоваться
    для перекодирования русских букв в заданные значения или похожие по начертанию
    латинские буквы). Перекодировка указанных символов действует до следующей пере-
    кодировки этих символов или до конца исходного текста. #fromN и #toN могут быть
    выражениями, результат которых считается кодом символа в ANSI.
    CTEXT text
    text
    ...
    text
    ENDTEXT

    Компактное кодирование сплошного текста. В завершающем символе каждой строки
    устанавливается бит 7 (если строка пустая, то по крайней мере один пробел
    формируется, с установленным битом 7, т.е. байт с кодом A0h). Финальный маркер
    ENDTEXT должен начинаться в самой крайней левой позиции строки.
    label[:] STRUCT
    [label1[:]] {DEFB|DEFW|struct_name} [(#repeat_count)[?]]
    ...
    [labelN[:]] {ESTRUCT|ENDSTRUCT}
    Создает константы label.label1, label.label2, ... которые могут позднее использоваться
    как обычные константы. label1 получает значение 0, и последующие поля - в зависимости
    от размера всех предыдущих полей структуры. Имена полей так же можно использовать
    как отдельные имена label1, label2 и т.д.
    Примечание: для компиляции структуры используется тот же алгоритм, что и обычно для
    компиляции операторов, но только при этом ничего не кладется в память, так что для
    задания размеров полей могут использоваться в том числе любые команды Z80 или директивы
    ассемблера.
    FILE filepath[,start[,length]]
    Путь задает имя бинарного файла для непосредственной загрузки байтов в память
    (могут использоваться двойные кавычки: "filepath"). Размер файла  или указанный
    размер порции файла не должен превышать 65536. Вместо пути к файлу так же можно
    задать директорию, которая в этом случае добавляется в список директорий для
    поиска включаемых файлов.
    INCLUDE filepath
    Путь задает имя файла с текстом, который "вставляется" в этом месте кода вместо
    директивы INCLUDE. Путь может быть заключен в двойные кавычки. Если путь представляет
    собой директорию, то эта директория добавляется в список директорий для поиска включаемых
    файлов.
    label[:] MACRO paramlist
      ...
    [label2[:]] {ENDM|ENDMACRO|EMAC}
    Определяет макро-команду с именем label. Список параметров paramlist может
    содержать:
    - во-первых, список фиксированных параметров (т.е. они должны при вызове
    макрокоманды указываться в том же порядке);
    - во-вторых, опциональные (необязательные) именованные параметры в форме
    name=[default].
    Для именованных параметров, они могут при вызове макрокоманды передаваться
    в любом порядке (но в этом случае обязательно в формате name=value).
    Именованные параметры, для которых в заголовке макрокоманды задано значение
    по умолчанию, при вызове макрокоманды могут быть опущены.
    Значением параметра может быть числовая константа, идентификатор, выражение,
    строка (но если в строке используются двойные кавычки, то значение подставляется
    без кавычек).
    Макроопределение может быть задано в любом месте исходного текста (т.е.
    обращения вперед на макрос, расположенный ниже, допускаются).
    В теле макрокоманды все сложносоставные конструкции (такие как IF ... EIF)
    должны быть завершены, пересечения уровней вложенности не допускаются.
    Если макрокоманда используется более чем однократно, все объявленные в
    ней метки должны быть локальными.
    Об использовании параметров макрокоманд, переопределений DEFINE и переменной
    препроцессорного цикла FOR смотрите ниже.
    ERROR [#severity],'text'[,#passes]
    или
    ERROR [#severity],"text"[,#passes]

    Генерирует ошибку, заданную пользователем. Может использоваться, например, в
    макроопределениях для проверки допустимости параметров.
    severity: 0 - warning (предупрежедение: текст попадает в список сообщений, но
    компиляция продолжается); 1 - обычный error (код более не генерируется, но
    компиляция может еще некоторое время продолжаться); 2 или выше - fatal error,
    компиляция останавливается немедленно.
    Если #passes не задано, сообщение показывается на всех проходах компиляции.
    Если оно задано, то значение выражения используется как двоичная маска: бит 0
    устанавливается, чтобы сообщение показывалось на проходе 1, бит 1 - на проходе
    2, и бит 2 - на проходе 3. Т.е. например, если passes = 2, то сообщение будет
    отображаться только на первом проходе компиляции, а если pass = 6 - то на втором
    и третьем (при его наличии) проходах.
    DISPLAY 'text'[,#expr[,#passes]]
    или
    DISPLAY "text"[,#expr[,#passes]]
    или
    DISPLAY #expr[,#passes]
    или
    DISPLAY "text",#expr[,"text"[,#expr]]...[,#passes]

    Показывает указанные текстовые сообщения и значения выражений #expr (если
    заданы) в виде строки.
    Аналогично директиве ERROR, #passes (если присутствует) задает маску флажков,
    определяющих, на каких проходах компилятора показывать данное сообщение.
    label[:] PROC
      ...
    [label2[:]] {ENDP|ENDPROC|EPROC}
    Задает процедуру. Фактически, всего лишь ограничивает видимость локальных меток,
    заданных между PROC и ENDPROC. Процедуры могут быть вложены друг в друга, и
    уровень допустимой вложенности ничем не ограничен.
    DUP #expr
      ...
    {EDUP|ENDDUP}
    Дублирует все операторы, расположенные между DUP n и  EDUP, число раз, заданное
    выражением #expr (но если #expr <= 0, то все операторы не компилируются вообще,
    как если бы их и не было в коде).
    FOR var=values
      ...
    {EFOR|ENDFOR}
    Дублирует все операторы между заголовком до финального ENDFOR столько раз,
    сколько всевозможных значений перечислено в списке для переменной цикла var,
    на каждом шаге присваивая этой переменной очередное значение из списка, как
    если бы имя var определялось директивой DEFINE.
    Список значений может содержать любые выражения, строки, заключенные в одинарные
    и двойные кавычки (во втором случае значение подставляется без кавычек),
    а так же среди прочего перечень значений в виде #from TO #to [STEP #step].
    В последнем случае сначала переменной присваивается значение выражения #from,
    и оно на каждом проходе увеличивает свое значение на #step (по умолчанию - на 1),
    пока не превзойдет (при отрицательном #step - пока станет меньше) значения
    выражения #to.

    Об использовании параметров макрокоманд, переопределений DEFINE и переменной
    препроцессорного цикла FOR смотрите ниже.
    IF #expr [THEN]
      ...
    [ELSEIF #expr1 [THEN]
      ...]...
    [ELSE
      ...]
    {EIF|ENDIF}
    Оператор условной компиляции определяет, какая именно ветка конструкции будет
    компилироваться в зависимости от значения выражений #expr, #expr1, ... (Но
    компилироваться всегда будет только одна ветка, а если ни одна из веток IF
    или ELSEIF не компилировалась, только тогда компилируется - при ее наличии -
    завершающая ветка ELSE).
    IFcond [THEN]
      ...
    [ELSE
      ...]
    {EIF|ENDIF}
    Псевдо-оператор для генерации условных переходов в программе. cond - это один из
    допустимых флажков (Z,NZ,C,NC,PO,PE,P,M). Он генерирует переход в обход ветки
    THEN (на ELSE или на конец оператора) по условию, противоположному заданному флажком,
    а при наличии ветки ELSE - по завершении ветки THEN так же генерируется безусловный
    переход на конец оператора. При возможности, используются короткие переходы (JR).
    LONGIFcond [THEN]
      ...
    [LONGELSE
      ...]
    {EIF|ENDIF}
    То же самое, что IF, но всегда используются длинные переходы, причем префикс LONG
    отдельно перед IF задает переход в обход ветки THEN, а префикс LONG перед ELSE
    задает, что будет создан длинный переход в обход ветки ELSE. Допускается комбинировать
    LONGIF с ELSE, и IF с LONGELSE.
    [label[:]] WHILE
      ...
    {EWHILE|EWHILEB|EWHILENZ|EWHILEZ|EWHILENC|EWHILEC|EWHILEPO|EWHILEPE|EWHILEP|EWHILEM}
    (в предыдущих версиях именовалась LOOP...ELOOP|ELOOPB, при желании их можно использовать:
    LOOP DEFINE WHILE
    ELOOP DEFINE EWHILE
    ELOOPB DEFINE EWHILEB - для обеспечения работоспособности прежнего кода)
    Создает бесконечный цикл (случай EWHILE), обычный цикл DJNZ (случай ELOOPB) или
    условный цикл (случай EWHILEcond).
    Если DJNZ не может быть использован (ELOOPB) по причине слишком большой дистанции,
    генерируется почти эквивалентная последовательность инструкций:
    DEC B:JP NZ,loop (4 байта). Везде внутри цикла разрешаются операторы BREAK [label]
    и CONTINUE [label] для немедленного завершения или для продолжения цикла (для
    продолжения по CONTINUE в цикле EWHILEB с того места, где уменьшается регистр B,
    и проверяется на равенство нулю, используйте WHILEB ... EWHILEB).
    Использование метки в операторах BREAK и CONTINUE позволяет выйти за пределы
    вложенного цикла, показывая, к какому именно уровню относятся эти операторы.
    [label[:]] LONGWHILE
      ...
    {EWHILE|EWHILEB|EWHILENZ|EWHILEZ|EWHILENC|EWHILEC|EWHILEPO|EWHILEPE|EWHILEP|EWHILEM}
    То же, что и WHILE, но для перехода всегда генерируются длинные инструкции JP.
    [label[:]] WHILEB
      ...
    {EWHILEB}
    Создает обычный цикл с командой DJNZ. Эквивалентно WHILE ... EWHILEB, но оператор
    CONTINUE, относящийся к данному циклу, выполняет переход на саму команду DJNZ, а
    на на WHILE.
    BREAK [label]

    См. директиву WHILE выше.
    CONTINUE [label]

    См. директиву WHILE выше.
    GOTO [cond,][label]

    Эквивалент инструкции JR/JP, но по возможности компилятор использует короткие
    переходы (JR). Важное ограничение: любое выражение не может использоваться в
    качестве операнда, а только метка, локальная или глобальная.
    PUSH rp1[,rp2]...
    или
    PUSH rp1 [rp2]...

    Генерирует последовательность команд PUSH rp1:PUSH rp2:... для всех перечисленных
    регистровых пар (допускаются AF,BC,DE,HL,IX,IY как обычно).
    POP rp1[[,]rp2]...
    или
    POP rp1 [rp2]...

    Генерирует последовательсть ...:POP rp2:POP rp1 (по умолчанию, регистровые пары
    выталкиваются из стека в инвертированном порядке. Используйте директивы POPNOINVERT
    и POPINVERT для управления этим порядком.
    POPNOINVERT

    Не инвертировать порядок регистровых пар для директивы POP. См. директиву POP выше.
    POPINVERT

    Не инвертировать порядок регистровых пар для директивы POP (по умолчанию).
    См. директиву POP выше.
    END

    Завершает компиляцию. Любой текст ниже этой директивы игнорируется.

Использование макро-параметров (в теле макро), имен, переопределенных директивой DEFINE и переменной препроцессорного цикла FOR.

Где угодно в своей области видимости такой идентификатор в тексте замещается своим значением как строкой. Видимость области зависит от вида переменной (для переменной цикла FOR - до конца цикла, для параметра макроса - до конца тела макроса, для имени, определенного директивой DEFINE - до конца исходного текста (или до следующего переопределения этого имени другой директивой DEFINE).
Для того, чтобы возможно было использовать определения непосредственно состыковывая их с другими идентификаторами и числами, используется запись вида .name или name. или .name. - При замене значения в этом случае точка удаляется (для того, чтобы точка осталась в тексте, необходимо писать две точки подряд).
Имеется возможность работать только с подстрокой значения, записывая обращение к подстроке параметра в виде: "name"[ nnn ] или "name"[ nnn, LLL ] , где nnn и LLL - целые неотрицательные десятичные числа. nnn=1 означает обращение к первому символу, LLL может использоваться для задания длины подстроки (если > 1). Важно: символ '[' должен быть записан немедленно после закрывающей кавычки '"', без пробелов между ними.
Значения таких переменных могут использоваться в операциях сравнения в виде:
"name1" op "name2" или "name1" op string (где op может быть одной из операций сравнения
=, <>, <, <=, >, >=). Например, IF "RP" = DE THEN ...

    Список операций Z80 в порядке алфавита.

    ADC HL, { BC | DE | HL | SP }
    ADC IX, { BC | DE | IX | SP }
    ADC IY, { BC | DE | IY | SP }
    ADC [ A, ] { B | C | D | E | H | L | M | (HL) | A |
                 IXH | IXL | (IX±#offset ) | (IY±#offset) |
                 #expression }
    ADD HL, { BC | DE | HL | SP }
    ADD IX, { BC | DE | IX | SP }
    ADD IY, { BC | DE | IY | SP }
    ADD [ A, ] { B | C | D | E | H | L | M | (HL) | A |
                 IXH | IXL | (IX±#offset ) | (IY±#offset) |
                 #expression }
    AND [ A, ] { B | C | D | E | H | L | M | (HL) | A |
                 IXH | IXL | (IX±#offset ) | (IY±#offset) |
                 #expression }
    BIT #number, { B | C | D | E | H | L | M | (HL) | A |
                 IXH | IXL | (IX±#offset ) | (IY±#offset) }
    BIT #number, { (IX±#offset ) | (IY±#offset) },
                 { B | C | D | E | H | L | A }
    CALL [ { NZ | Z | NC | C | PO | PE | P | M }, ] #address
    CCF
    CP  [ A, ] { B | C | D | E | H | L | M | (HL) | A |
                 IXH | IXL | (IX±#offset ) | (IY±#offset) |
                 #expression }
    CPD
    CPDR
    CPI
    CPIR
    CPL
    DAA
    DI
    DEC { B | C | D | E | H | L | M | (HL) | A | IXH | IXL | IYH | IYL |
          ( {IX|IY}±#offset ) }
    DI
    DJNZ #address
    EI
    EX (SP), { HL | IX | IY }
    EX AF, AF'
    EX DE, { HL | IX | IY }
    EXX
    HALT
    IM0 | IM1 | IM2 | IM #n
    IN [ A, ] { (#port) | (C) }
    IN { B | C | D | E | H | L | F | A }, (C)
    INC { B | C | D | E | H | L | M | (HL) | A | IXH | IXL | IYH | IYL |
          ( {IX|IY}±#offset ) }
    IND
    INDR
    INI
    INIR
    JP [ { NZ | Z | NC | C | PO | PE | P | M }, ] #address
    JR [ { NZ | Z | NC | C }, ] #address
    LD A, { I | R | B | C | D | E | H | L | M | (HL ) | A |
            #expression | IXH | IXL | IYH | IYL |
           (IX±#offset) | (IY±#offset) | (BC) | (DE) | (#address) }
    LD { B | C | D | E | H | L | M | (HL) },
       { B | C | D | E | H | L | M | A | #expression }
    LD { B | C | D | E | IXH | IXL | A | (IX±#offset) },
       { B | C | D | E | IXH | IXL | A | #expression }
    LD { B | C | D | E | IYH | IYL | A | (IY±#offset) },
       { B | C | D | E | IYH | IYL | A | #expression }
    LD { B | C | D | E | IXH | IXL | A },
       { B | C | D | E | IXH | IXL | A | (IX±#offset) }
    LD { B | C | D | E | IYH | IYL | A },
       { B | C | D | E | IYH | IYL | A | (IY±#offset) }
    LD { I | R }, A
    LD { BC | DE | HL | SP | IX | IY }, { #expression | ( #address ) }
    LD ( #address ), { BC | DE | HL | SP | IX | IY }
    LDD
    LDDR
    LDI
    LDIR
    NEG
    NOP
    OR  [ A, ] { B | C | D | E | H | L | M | (HL) | A |
                 IXH | IXL | (IX±#offset ) | (IY±#offset) |
                 #expression }
    OUT { (#port) | (C) } [, A ]
    OUT (C), { B | C | D | E | H | L | F | A }
    OUTD
    OTDR
    OUTI
    OTIR
    POP  { BC | DE | HL | AF | IX | IY }
    PUSH { BC | DE | HL | AF | IX | IY }
    RES #number, { B | C | D | E | H | L | M | (HL) | A |
                 IXH | IXL | (IX±#offset ) | (IY±#offset) }
    RES #number, { (IX±#offset ) | (IY±#offset) },
                 { B | C | D | E | H | L | A }
    RET [ { NZ | Z | NC | C | PO | PE | P | M | N | I } ]
    RETI
    RETN
    RL  { B | C | D | E | H | L | M | (HL) | A |
        IXH | IXL | (IX±#offset ) | (IY±#offset) }
    RLA
    RLC { B | C | D | E | H | L | M | (HL) | A |
        IXH | IXL | (IX±#offset ) | (IY±#offset) }
    RLCA
    RLD
    RR  { B | C | D | E | H | L | M | (HL) | A |
        IXH | IXL | (IX±#offset ) | (IY±#offset) }
    RRA
    RRC { B | C | D | E | H | L | M | (HL) | A |
        IXH | IXL | (IX±#offset ) | (IY±#offset) }
    RRCA
    RRD
    RST #expression ;
        (allowed following values:
         0..7 and also 8, 16, 24, 32, 40, 48, 56 - decimal)
    SBC HL, { BC | DE | HL | SP }
    SBC [ A, ] { B | C | D | E | H | L | M | (HL) | A |
                 IXH | IXL | (IX±#offset ) | (IY±#offset) |
                 #expression }
    SCF
    SET #number, { B | C | D | E | H | L | M | (HL) | A |
                 IXH | IXL | (IX±#offset ) | (IY±#offset) }
    SET #number, { (IX±#offset ) | (IY±#offset) },
                 { B | C | D | E | H | L | A }
    SLA { B | C | D | E | H | L | M | (HL) | A |
        IXH | IXL | (IX±#offset ) | (IY±#offset) }
    SLA { (IX±#offset ) | (IY±#offset) },
        { B | C | D | E | H | L | A }
    SLI { B | C | D | E | H | L | M | (HL) | A |
        IXH | IXL | (IX±#offset ) | (IY±#offset) }
    SLI { (IX±#offset ) | (IY±#offset) },
        { B | C | D | E | H | L | A }
    SLL { B | C | D | E | H | L | M | (HL) | A |
        IXH | IXL | (IX±#offset ) | (IY±#offset) }
    SLL { (IX±#offset ) | (IY±#offset) },
        { B | C | D | E | H | L | A }
    SRA { B | C | D | E | H | L | M | (HL) | A |
        IXH | IXL | (IX±#offset ) | (IY±#offset) }
    SRL { B | C | D | E | H | L | M | (HL) | A |
        IXH | IXL | (IX±#offset ) | (IY±#offset) }
    SRL { (IX±#offset ) | (IY±#offset) },
        { B | C | D | E | H | L | A }
    SUB [ A, ] { B | C | D | E | H | L | M | (HL) | A |
                 IXH | IXL | (IX±#offset ) | (IY±#offset) |
                 #expression }
    XOR [ A, ] { B | C | D | E | H | L | M | (HL) | A |
                 IXH | IXL | (IX±#offset ) | (IY±#offset) |
                 #expression }

В версии 2.3 Build 1.5:

Введены дополнительные правила, позволяющие компилировать код, полученный в результате работы дизассемблера:

- любой текст после запятой в скобках при адресайии ячейки в памяти считается комментарием. Например:
LD HL, (0FFFEh,здесь любой текст).
- Любой текст после запятой после последнего операнда в инструкции считается комментарием. E.g. LD HL,0FFFEh,any text here.
В версии 2.7:

Добавлена возможность записывать команды в стиле C - - для Z80.

В операторах C--, все имена регистров считаются зарезервированными переменными:
A, A', F, F', B, B', C, C', D, D', E, E', H, H', L, L', I, R, IXL, IXH, IYL, IYH
AF, AF', BC, BC', DE, DE', HL, HL', IX, IY, SP
Так же, название флажка CF является зарезервированным:
CF

Операторы C-- могут отделаяться друг от друга и от обычных ассемблерных инструкций и директив пробелами и символом ':' как обычно.

При использовании любой регистровой пары или регистра в качестве левого или правого операнда, к нему можно применить или суффиксный, или постфиксный автоинкремент или автодекремент, операнд в памяти, адресуемой регистрами HL, IX или IY так же может быть инкрементирован или декрементирован. Все операнды, кроме SP, при автоинкременте увеличиваются или уменьшаются на 1 (только SP - на 2).

Оператор присваивания в стиле C-- имеет вид: dest=expression. Здесь dest может задавать операнд в регистре или в памяти, а выражение может быть либо обычным выражением (тогда имеется в виду загрузка непосредственной константы) или опять же регистром или операндом в памяти (операнд в памяти не может присутствовать одновременно в левой и правой частях присваивания). Допускается присваивание двухбайтных значений, в тех случаях, когда это требуется, компилятор генерирует две команды LD. Примеры:

A=B | LD A,B
A=(HL) | LD A,(HL)
A=(IX+10) | LD A,(IX+10)
(16384)=SP | LD (16384), SP
(IX)=HL | LD (IX+0),L:LD (IX+1),H
BC=HL | LD B,H:LD C,L

BC'=BC | PUSH BC:EXX:POP BC:EXX
(IX)=DE | LD (IX),E:LD (IX+1),D
(HL)=BC | LD (HL),C:INC HL:LD (HL),B:DEC HL
(HL++)=BC | LD (HL),C:INC HL:LD (HL),B
SP=DE | EX DE,HL:LD SP,HL:EX DE,HL
SP=HL' | EXX:LD SP,HL:EXX
SP=IY | LD SP,IY

Допускается однооперандный оператор C-- для применения операции ++ или -- , например:.:

A++ | INC A
HL-- | DEC HL
(++HL)-- | INC HL:DEC (HL)
(IX+5)++ | INC (IX+5)

Другие возможные виды операторов:
= (присваивание)
& ("и") | ("или") ^ ("исключающее или")
+ (сложение) +CF+ (ADC)
- (вычитание) -CF- (SBC)
r<<CF (сдвиг влево по кругу, RLC) r<< (RL)
r>>CF (сдвиг вправо по кругу, RRC) r>> RR
>< (обмен)
? (сравнение)

Примеры использования:

A=A+5 | ADD A,5
A+B | ADD A,B
A-C-CF | SBC A,C
&E | AND A,E
|(HL) | OR A,(HL)
A?(IX+100) | CP A,(IX+100)

Как можно заметить, A=A op opd2 может быть сокращено до A op opd2 или даже op opd2 (в последнем случае будьте аккуратнее, завершая предыдущую инструкцию: компилятор может решить, что данная команда является продолжением выражения).

A'^E | EX AF,AF':XOR A,E:EX AF,AF'

Для случая 16-разрядных арифметических операций все то же самое:

HL=HL+DE | ADD HL,DE
HL+BC | ADD HL, BC
IX+DE'+CF | EXX:ADC IX, DE:EXX
IY+HL | EX DE,HL:ADD IY,DE:EX DE,HL

Несколько примеров операций сдвига:

A<< | RLA
>>CF | RRCA
B<<- | SLA B
E'>>- | EXX:SRA E:EXX
A'<<CF | EX AF,AF':RLCA:EX AF,AF'

Несколько примеров операций обмена:

HL><DE | EX DE,HL
(SP)><DE | EX DE,HL:EX (SP),HL:EX DE,HL
IX><BC | PUSH IX:PUSH BC:POP IX:POP BC
DE><HL' | PUSH DE:EXX:PUSH HL:EXX:POP DE:EXX:POP HL:EXX
AF><AF' | EX AF,AF'

http://bonanzas.rinet.ru mailto: bonanzas@online.sinor.ru