News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

type of variable

Started by JK, April 04, 2021, 01:06:22 AM

Previous topic - Next topic

jj2007

@LiaoMi: Can you highlight (e.g. in red) the sentence that explains why this works?
if type(a) eq DWORD
echo a is a DWORD
elseif type(a) eq REAL4
echo a is a REAL4
else
echo error
endif

if type(b) eq DWORD
echo b is a DWORD
elseif type(b) eq REAL4
echo b is a REAL4
else
echo error
endif

nidud

#16
deleted

jj2007


nidud

#18
deleted

jj2007

Yep, you are right, the language is absolutely awful and cryptic but it could indeed be interpreted that way. And it appears in a document that is 20 years old and no longer available at Microsoft docs, but ok it is "documented" somewhere.

So finally you did something useful tonight, congrats :thumbsup:

LiaoMi

Hi jj2007,

Operators
Operators are used in expressions. The value of the expression is determined at
assembly time and does not change when the program runs.
Operators should not be confused with processor instructions. The reserved
word ADD is an instruction; the plus sign (+) is an operator. For example,
Amount+2 illustrates a valid use of the plus operator (+). It tells the assembler to
add 2 to the constant value Amount, which might be a value or an address. Contrast
this operation, which occurs at assembly time, with the processor's ADD
instruction. ADD tells the processor at run time to add two numbers and store the
result.

The assembler evaluates expressions that contain more than one operator according
to the following rules:
◆ Operations in parentheses are performed before adjacent operations.
◆ Binary operations of highest precedence are performed first.
◆ Operations of equal precedence are performed from left to right.
◆ Unary operations of equal precedence are performed right to left.
Table 1.3 lists the order of precedence for all operators. Operators on the same line
have equal precedence.

Table 1.3 Operator Precedence
Precedence Operators
1 ( ), [ ]
2 LENGTH, SIZE, WIDTH, MASK, LENGTHOF, SIZEOF
3 . (structure-field-name operator)
4 : (segment-override operator), PTR
5 LROFFSET, OFFSET, SEG, THIS, TYPE
6 HIGH, HIGHWORD, LOW, LOWWORD
7 + ,– (unary)
8 *, /, MOD, SHL, SHR
9 +, – (binary)
10 EQ, NE, LT, LE, GT, GE
11 NOT
12 AND
13 OR, XOR
14 OPATTR, SHORT, .TYPE

In general, the entire document describes the use of types and their meaning. You can get an owned type in almost any case, from any record. I have not tested whether this is the case, but here is one example.

LENGTHOF, SIZEOF, and TYPE for Arrays
When applied to arrays, the LENGTHOF, SIZEOF, and TYPE operators return
information about the length and size of the array and about the type of the
initializers.
The LENGTHOF operator returns the number of elements in the array. The
SIZEOF operator returns the number of bytes used by the initializers in the array
definition. TYPE returns the size of the elements of the array. The following
examples illustrate these operators:

array WORD 40 DUP (5)
larray EQU LENGTHOF array ; 40 elements
sarray EQU SIZEOF array ; 80 bytes
tarray EQU TYPE array ; 2 bytes per element

num DWORD 4, 5, 6, 7, 8, 9, 10, 11
lnum EQU LENGTHOF num ; 8 elements
snum EQU SIZEOF num ; 32 bytes
tnum EQU TYPE num ; 4 bytes per element

warray WORD 40 DUP (40 DUP (5))
len EQU LENGTHOF warray ; 1600 elements
siz EQU SIZEOF warray ; 3200 bytes
typ EQU TYPE warray ; 2 bytes per element


LENGTHOF, SIZEOF, and TYPE for Strings
Because strings are simply arrays of byte elements, the LENGTHOF, SIZEOF,
and TYPE operators behave as you would expect, as illustrated in this example:

msg BYTE "This string extends ",
"over three ",
"lines."
lmsg EQU LENGTHOF msg ; 37 elements
smsg EQU SIZEOF msg ; 37 bytes
tmsg EQU TYPE msg ; 1 byte per element


LENGTHOF, SIZEOF, and TYPE for Structures
The size of a structure determined by SIZEOF is the offset of the last field, plus the
size of the last field, plus any padding required for proper alignment. (For
information about alignment, see "Declaring Structure and Union Types," earlier in
this chapter.)

This example, using the preceding data declarations, shows how to use the
LENGTHOF, SIZEOF, and TYPE operators with structures.

INFO STRUCT
buffer BYTE 100 DUP (?)
crlf BYTE 13, 10
query BYTE 'Filename: '
endmark BYTE 36
drives DISKDRIVES <0, 1, 1>
INFO ENDS

info1 INFO { , , 'Dir' }
lotsof INFO { , , 'file1', , {0,0,0} },
{ , , 'file2', , {0,0,1} },
{ , , 'file3', , {0,0,2} }

sinfo1 EQU SIZEOF info1 ; 116 = number of bytes in
; initializers
linfo1 EQU LENGTHOF info1 ; 1 = number of items
tinfo1 EQU TYPE info1 ; 116 = same as size

slotsof EQU SIZEOF lotsof ; 116 * 3 = number of bytes in
; initializers
llotsof EQU LENGTHOF lotsof ; 3 = number of items
tlotsof EQU TYPE lotsof ; 116 = same as size for structure
; of type INFO


LENGTHOF, SIZEOF, and TYPE for Unions
The size of a union determined by SIZEOF is the size of the longest field plus any
padding required. The length of a union variable determined by LENGTHOF
equals the number of initializers defined inside angle brackets or curly braces.
TYPE returns a value indicating the type of the longest field.
DWB UNION
d DWORD ?
w WORD ?
b BYTE ?
DWB ENDS

num DWB {0FFFFh}
array DWB (100 / SIZEOF DWB) DUP ({0})

snum EQU SIZEOF num ; = 4
lnum EQU LENGTHOF num ; = 1
tnum EQU TYPE num ; = 4

sarray EQU SIZEOF array ; = 100 (4*25)
larray EQU LENGTHOF array ; = 25
tarray EQU TYPE array ; = 4


LENGTHOF, SIZEOF, and TYPE with Records
The SIZEOF and TYPE operators applied to a record name return the number of
bytes used by the record. SIZEOF returns the number of bytes a record variable
occupies. You cannot use LENGTHOF with a record declaration, but you can use
it with defined record variables. LENGTHOF returns the number of records in an
array of records, or 1 for a single record variable. The following example illustrates
these points.
; Record definition
; 9 bits stored in 2 bytes
RGBCOLOR RECORD red:3, green:3, blue:3

mov ax, RGBCOLOR ; Equivalent to "mov ax, 01FFh"
; mov ax, LENGTHOF RGBCOLOR ; Illegal since LENGTHOF can
; apply only to data label
mov ax, SIZEOF RGBCOLOR ; Equivalent to "mov ax, 2"
mov ax, TYPE RGBCOLOR ; Equivalent to "mov ax, 2"

; Record instance
; 8 bits stored in 1 byte
RGBCOLOR2 RECORD red:3, green:3, blue:2
rgb RGBCOLOR2 <1, 1, 1> ; Initialize to 00100101y

mov ax, RGBCOLOR2 ; Equivalent to
; "mov ax, 00FFh"
mov ax, LENGTHOF rgb ; Equivalent to "mov ax, 1"
mov ax, SIZEOF rgb ; Equivalent to "mov ax, 1"
mov ax, TYPE rgb ; Equivalent to "mov ax, 1"

jj2007

#21
Hi LiaoMi,

I just checked the MasmBasic library source: TYPE appears 198 times, opattr a bit more often. No need to explain to me what they do. The real issue is with the cryptic phrase that [censured] nidud found in an obscure old document:

MASM 6.1 recognizes only equivalent qualified types as equal expressions

Normally...
if x eq y
  echo x is the same as y
endif

... means that x and y are constants that have the same numeric value. The exception to this rule is indeed this:

if type(a) eq DWORD
echo a is a DWORD
elseif type(a) eq REAL4
echo a is a REAL4
endif


if a is a DWORD, it's type is 4 (i.e. the numeric value of its type is 4)
if a is a REAL4, it's type is 4

So in both cases we should expect "a is a DWORD".

And yet, Masm and its clones distinguish them from each other: MASM 6.1 recognizes only equivalent qualified types as equal expressions. Which means that under the hood the numeric value 4 (DWORD or REAL4) has a second string property, and that the assembler knows somehow that "EQ" is the wrong operator for this. So instead, it uses (internally)

ifidn type(a), <DWORD>
echo a is a DWORD
elseifidn type(a), <REAL4>
echo a is a REAL4
endif


That is clever, and necessary for many of my macros, but afaik it has not been documented by Micros*t in the last 28 years or so (try a google phrase search for "equivalent qualified types"). MASM 6.1 was released in January 1993...

[Admin]
We don't say naughty things about other members.  :skrewy:

JK

Thanks a lot, i am more than happy with all the answers i got, i learned a lot in this thread (... and please stop arguing  :eusa_pray:)!


As i see it now, TYPE seems to be kind of a Cameleon, internally it holds more information than is returned by this form:
t = TYPE var
t gets only information about the the size of an element, where, as LiaoMi showed, there are differences between, "SIZEOF", "LENGHTOF" and "TYPE"

wheras used in this form
if type(arg) eq DWORD
    echo arg is a    DWORD
  elseif type(arg) eq SDWORD
    echo arg is a    SDWORD
  elseif type(arg) eq REAL4
    echo arg is a    REAL4

the whole information of "TYPE(xx)" (in contrast to the return value) is compared by "EQ". This might be a feature of the compare operator "EQ", or of the usage as "expression" (TYPE(xxx)) or a result of a combination of both.


Bottomline: it might be interesting to know, why it works, but much more important (to me) is to know, that it works, because this is the key to a range of possibilities, i didn´t have before.


JK

jj2007

Quote from: jj2007 on April 05, 2021, 07:42:51 PM
[Admin]
We don't say naughty things about other members.  :skrewy:

I fully agree :thumbsup:

Quote from: nidud on April 05, 2021, 07:03:24 AMIf that was true then you wouldn't be consistently lying.

nidud

#24
deleted

jj2007

It seems really difficult to understand, so I wrote a detailed example - source attached, plain Masm32.

Bottom line is that under the hood the numeric value 4 (type(DWORD) or type(REAL4)) has a second string property.

The type of MyDW is TYPE(MyDW) (useless)
The type of MyR4 is TYPE(MyR4) (useless)
The type of MyDW is 4 (correct but not very useful)
The type of MyR4 is 4 (correct but not very useful)

---- type(x) eq REAL4/DWORD (undocumented but best option) ----
MyDW is NOT a REAL4 (correct)
MyR4 is NOT a DWORD (correct)

---- type(x) eq 4 ----
MyDW is a REAL4 (NOT correct)
MyR4 is a DWORD (NOT correct)
MyDW is a REAL4 (NOT correct)
MyR4 is a DWORD (NOT correct)

---- using ifidn, i.e. string comparison  ----
MyDW is NOT a REAL4 (correct)
MyDW is NOT a DWORD (correct)

HSE

 :biggrin:  TypeConfusion is NOT valid
Equations in Assembly: SmplMath

hutch--

This is all I have ever needed in both 32 and 64 bit MASM.

  ; -------------------------
  ; determine an operand type
  ; -------------------------
    op_type MACRO arg:REQ
      LOCAL result
      result = opattr(arg)
        IF result eq 37         ;; label, either local or global
          EXITM %1
        ELSEIF result eq 42     ;; GLOBAL var
          EXITM %2
        ELSEIF result eq 98     ;; LOCAL  var
          EXITM %3
        ELSEIF result eq 36     ;; immediate operand or constant
          EXITM %4
        ELSEIF result eq 48     ;; register
          EXITM %5
        ELSEIF result eq 805    ;; local procedure in code
          EXITM %6
        ELSEIF result eq 933    ;; external procedure or API call
          EXITM %7
        ENDIF
      EXITM %0                  ;; anything else
    ENDM


I have also got argsize and regsize.

jj2007

Quote from: hutch-- on April 05, 2021, 11:08:10 PM
This is all I have ever needed in both 32 and 64 bit MASM.

Yes, that works fine, and it's ok to distinguish between immediates, registers and global or local variables. Indeed, when I type opa<space> in my editor, it inserts oa = (opattr arg) AND 127, to which I usually add something like
if oa eq atImmediate
...
elseif oa eq atRegister
...
endif


However, opattr tells you "it's a local variable" but it does not tell you whether it's a DWORD, a REAL4 or a QWORD. That's where type kicks in as
if type(myvar) eq DWORD
  fild myvar
elseif type(myvar) eq REAL4
  fld myvar
elseif type(myvar) eq QWORD
  fild myvar
endif

hutch--

I mentioned that I have both data and register sizes working.