Author Topic: type of variable  (Read 4460 times)

jj2007

  • Member
  • *****
  • Posts: 11551
  • Assembler is fun ;-)
    • MasmBasic
Re: type of variable
« Reply #15 on: April 05, 2021, 08:55:30 AM »
@LiaoMi: Can you highlight (e.g. in red) the sentence that explains why this works?
Code: [Select]
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

  • Member
  • *****
  • Posts: 2215
    • https://github.com/nidud/asmc
Re: type of variable
« Reply #16 on: April 05, 2021, 09:36:58 AM »
Your example is entirely useless. This is what we were discussing:

Code: [Select]
include \masm32\include\masm32rt.inc

.data
a dd 1
b REAL4 2.0

%echo @CatStr(%typeof(a))
%echo @CatStr(%typeof(b))

.code
start:
  exit
end start

That is not my example so that is a lie. Here's my example:

BTW, where is this behavior documented?

The EQ operator compare type, size, and offset.

a dd 1.0
b dd 2.0

    %echo @CatStr(%(a eq a))
    %echo @CatStr(%(a[4] eq b))
    %echo @CatStr(%(a eq b))
    %echo @CatStr(%(typeof(a) eq typeof(b)))


You may notice the green color in typeof there to separate the Masm keyword from the Asmc keyword, but as you know, Asmc handles both of these.

The TYPE operator return size to the user but (as already explained) can also be used as an expression. An IF (and EQ) expression includes 3 things: size, type, and offset, so when used in the sample above all these three things are compared, hence the difference.

Quote
What we were discussing is this sequence, which works like a charm but is not documented:

Here's the actual sequence:

IF expression1 EQ expression2

And you claim that the documentation for the directive IF and the operator EQ is missing.

Quote
If that was true then you wouldn't be consistently lying.

When you have no more arguments, you throw insults. You are a troll.

 :biggrin:

trolling:

Just downloaded the latest version to do my occasional tests:
- works fine with the RichMasm source (21k lines)
- chokes several times with error A2006: undefined symbol : type with the MasmBasic source

Any chance to fix that one day?

And breaking a key function like type is a no-no. At least you could make /Znk the default.

name is not a reserved word in Asmc.

Sure?

*** Assemble using AsmC /Znk ***
 Assembling: tmp_file.asm
tmp_file.asm(9) : error A2016: expression expected

Error A2102: Symbol not defined : typeof

jj2007

  • Member
  • *****
  • Posts: 11551
  • Assembler is fun ;-)
    • MasmBasic
Re: type of variable
« Reply #17 on: April 05, 2021, 09:39:01 AM »
You are drunk, nidud :tongue:

nidud

  • Member
  • *****
  • Posts: 2215
    • https://github.com/nidud/asmc
Re: type of variable
« Reply #18 on: April 05, 2021, 09:55:18 AM »
@LiaoMi: Can you highlight (e.g. in red) the sentence that explains why this works?

MASM 6.1 recognizes only equivalent qualified types as equal expressions.

jj2007

  • Member
  • *****
  • Posts: 11551
  • Assembler is fun ;-)
    • MasmBasic
Re: type of variable
« Reply #19 on: April 05, 2021, 09:58:58 AM »
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

  • Member
  • ****
  • Posts: 922
Re: type of variable
« Reply #20 on: April 05, 2021, 07:22:20 PM »
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:

Code: [Select]
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:

Code: [Select]
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.

Code: [Select]
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.
Code: [Select]
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.
Code: [Select]
; 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

  • Member
  • *****
  • Posts: 11551
  • Assembler is fun ;-)
    • MasmBasic
Re: type of variable
« Reply #21 on: April 05, 2021, 07:42:51 PM »
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...
Code: [Select]
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:

Code: [Select]
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)

Code: [Select]
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:
« Last Edit: April 05, 2021, 08:35:05 PM by hutch-- »

JK

  • Member
  • **
  • Posts: 132
Re: type of variable
« Reply #22 on: April 05, 2021, 09:31:43 PM »
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:
Code: [Select]
t = TYPE vart 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
Code: [Select]
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

  • Member
  • *****
  • Posts: 11551
  • Assembler is fun ;-)
    • MasmBasic
Re: type of variable
« Reply #23 on: April 05, 2021, 09:34:05 PM »
[Admin]
We don't say naughty things about other members.  :skrewy:

I fully agree :thumbsup:

If that was true then you wouldn't be consistently lying.

nidud

  • Member
  • *****
  • Posts: 2215
    • https://github.com/nidud/asmc
Re: type of variable
« Reply #24 on: April 05, 2021, 10:00:36 PM »
I just checked the MasmBasic library source: TYPE appears 198 times, opattr a bit more often.

So you done all this and still don't know what a type is?

Quote
No need to explain to me what they do.

Never the less it was clearly needed so I did. You responded as per usual with your childish bullshit.

Quote
The real issue is with the cryptic phrase that our socially crippled programming genius nidud found in an obscure old document:

MASM 6.1 recognizes only equivalent qualified types as equal expressions

The MASM manual is obviously relevant here but that was not provided by me. I provided documentations for the directive and operator used in your sample, explained how it works and then proved this with an example.

a dd 1.0
b dd 2.0

expressionoffsetsizetype
40?const
DWORD04unsigned
SDWORD04signed
REAL404float
a04unsigned
b44unsigned

The expression evaluation depends on input so if one is a const value size will be used.

expr1 EQ expr2offsetsizetyperesult
SDWORD eq DWORDxx-false
QDWORD eq DWORDx-xfalse
a eq b-xxfalse
a eq axxxtrue
a[4] eq bxxxtrue
sizeof(a) eq 4xxxtrue
typeof(a) eq 4xxxtrue
a eq 4---error

Quote
Normally...
Code: [Select]
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.

It depends what x and y is. You may convert them to a const value by using sizeof().

jj2007

  • Member
  • *****
  • Posts: 11551
  • Assembler is fun ;-)
    • MasmBasic
Re: type of variable
« Reply #25 on: April 05, 2021, 10:52:08 PM »
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.

Code: [Select]
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

  • Member
  • *****
  • Posts: 1743
  • <AMD>< 7-32>
Re: type of variable
« Reply #26 on: April 05, 2021, 11:00:56 PM »
 :biggrin:  TypeConfusion is NOT valid

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 8497
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: type of variable
« Reply #27 on: April 05, 2021, 11:08:10 PM »
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.
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

jj2007

  • Member
  • *****
  • Posts: 11551
  • Assembler is fun ;-)
    • MasmBasic
Re: type of variable
« Reply #28 on: April 05, 2021, 11:17:38 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
Code: [Select]
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
Code: [Select]
if type(myvar) eq DWORD
  fild myvar
elseif type(myvar) eq REAL4
  fld myvar
elseif type(myvar) eq QWORD
  fild myvar
endif

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 8497
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: type of variable
« Reply #29 on: April 05, 2021, 11:41:41 PM »
I mentioned that I have both data and register sizes working.
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy: