Определение типа операнда на этапе компиляции (MASM 4.0)

Известно, что в MASM 4.0 имеются несколько операторов, которые позволяют на этапе компиляции статически определить тип операнда, его длину (в количестве элементов) и размер (в байтах). Есть только одно «но», операторы type, length и size применимы только к описанным именам, а с регистрами они «беспомощны»: type ax = abs. Тем не менее, часто бывает, что в статически настраиваемом макроблоке необходимо работать не только с именами (константы, адреса, метки), но и с регистрами. Причем дополнительный оператор .type также отказывается работать с регистрами, причисляя их к прочим константным выражениям. Для решения этой задачи ниже предлагается макроопределение, позволяющее на этапе компиляции определеить «класс» операнда (регистр, метка, адрес, константа) и размер в байтах. В случае констант под «размером» понимается минимальное количество байт, необходимое для представления значения константного выражения.

Для начала вводится блок описания констант перечисления типов:

; константное выражение --- это целое число, имя константы, к.в., имя сегмента, имя поля, имя структуры)
; биты размерности
SZ_BYTE    equ  1
SZ_WORD    equ  2
SZ_DWORD   equ  4
; биты типа
TP_CNST    equ  1 shl 8
TP_ADDR    equ  1 shl 9
TP_LABEL   equ  1 shl 10
TP_REG     equ  1 shl 11
; регистровые биты
TP_COMREG  equ  1 shl 12
TP_INDXREG equ  1 shl 13
TP_SEGREG  equ  1 shl 14
 

Далее, макроопределение TYPE_:

; Определение размера op в байтах, где op --- имя регистра, адреса памяти, или константы
; Если op имя регистра, в typ возвращается его тип: общего назначения (1) или сегментный (2).
TYPE_ macro op, typ
  typ = type op
  ife typ
    ;; op оказался регистром, константой, именем сегмента, именем структуры или именем поля записи
    SIZETCOMP op, typ, TP_REG+TP_COMREG+SZ_BYTE, <A,a,B,b,C,c,D,d>,   <H,h,L,l>
    SIZETCOMP op, typ, TP_REG+TP_COMREG+SZ_WORD, <A,a,C,c,D,d>,       <X,x>
    SIZETCOMP op, typ, TP_REG+TP_COMREG+TP_INDXREG+SZ_WORD, <S,s,D,d>,<I,i>
    SIZETCOMP op, typ, TP_REG+TP_COMREG+SZ_WORD, <S,s>,               <P,p>
    SIZETCOMP op, typ, TP_REG+TP_COMREG+TP_INDXREG+SZ_WORD, <B,b>,    <X,x,P,p>
    SIZETCOMP op, typ, TP_REG+TP_SEGREG+SZ_WORD, <C,c,D,d,E,e,S,s>,   <S,s>
    ife typ
      ;; если op не имя регистра, значит константа
      if op LT 256
        typ = TP_CNST + SZ_BYTE
      else
        typ = TP_CNST + SZ_WORD
      endif
    endif
  else
    if typ LT 0
      typ = -typ + TP_LABEL
    else
      typ =  typ + TP_ADDR
    endif
  endif
endm
 
SIZETCOMP macro reg, typ, typ_, HighPart, LowPart
  irp highchar, <HighPart>
    irp lowchar, <LowPart>
      ifidn <reg>, <highchar&&&lowchar>
        typ = typ_
      endif
    endm
  endm
endm
 

Таким образом получается, что размер операнда в байтах кодируется в младшем байте результата typ, а «класс» операнда — в старшем байте. Макроопределение различает метки, адреса, регистры (общего назначения, индексные и сегментные), константные выражения.