Author Topic: type of variable  (Read 4459 times)

JK

  • Member
  • **
  • Posts: 132
type of variable
« on: April 04, 2021, 01:06:22 AM »
How could i retrieve the type of a variable in code or in a macro?

The "TYPE" operator returns the size of a register or variable in bytes, but there are still ambiguities. A REAL4 returns 4, which is the same as for a DWORD. The same goes for REAL8 and QWORD and for REAL10 and TWORD. A structure of 16 bytes size (e.g RECT) cannot be distinguished from an OWORD.

So how to decide for sure what is what (a structure, a REAL4/8/10, an integer variable of DWORD, QWORD, TWORD or QWORD size)?


JK

Vortex

  • Member
  • *****
  • Posts: 2583
Re: type of variable
« Reply #1 on: April 04, 2021, 01:37:16 AM »
Quote
Testing for Argument Type and Environment

Macros can expand conditional blocks of code by testing for argument type with the OPATTR operator. OPATTR returns a single word constant that indicates the type and scope of an expression, like this:

OPATTR expression

If expression is not valid or is forward-referenced, OPATTR returns a 0. Otherwise, the return value incorporates the bit flags shown in the table below.

OPATTR serves as an enhanced version of the .TYPE operator, which returns only the low byte (bits 0 - 7) shown in the table. Bits 11 - 15 of the return value are undefined.

Bit Set If expression


0 References a code label

1 Is a memory variable or has a relocatable data label

2 Is an immediate value

3 Uses direct memory addressing

4 Is a register value

5 References no undefined symbols and is without error

6 Is relative to SS

7 References an external label

8 - 10 Has the following language type: 000 - No language type 001 - C 010 - SYSCALL 011 - STDCALL 100 - Pascal 101 - FORTRAN 110 - Basic

http://www.massmind.org/techref/language/masm/masmc09.htm

JK

  • Member
  • **
  • Posts: 132
Re: type of variable
« Reply #2 on: April 04, 2021, 02:53:55 AM »
Thanks, i know "OPATTR", but it cannot solve my problem.

Suppose i have an argument of a procedure and i want to process this argument in a macro. Different types of arguments would require different processing. I would like to tell from the argument alone, what type of argument it is. The "TYPE" operator allows only for a limited decision, i cannot distinguish e.g between "DWORD" and "REAL4", because "4" is returned for both.



jj2007

  • Member
  • *****
  • Posts: 11551
  • Assembler is fun ;-)
    • MasmBasic
Re: type of variable
« Reply #3 on: April 04, 2021, 04:46:07 AM »
Check \Masm32\MasmBasic\MasmBasic.inc for the string elseif type(tmp$) eq

nidud

  • Member
  • *****
  • Posts: 2215
    • https://github.com/nidud/asmc
Re: type of variable
« Reply #4 on: April 04, 2021, 05:27:22 AM »
.inline types args:vararg {
    for arg,<args>
        %echo typeid(arg)
        endm
        }

    .code

main proc

  local f:real4, pf:ptr real4, d:dword

    types(f, d, pf, 1, 1.0)
    ret

main endp

    end

REAL4
DWORD
PREAL4
IMM32
IMMFLT

jj2007

  • Member
  • *****
  • Posts: 11551
  • Assembler is fun ;-)
    • MasmBasic

JK

  • Member
  • **
  • Posts: 132
Re: type of variable
« Reply #6 on: April 04, 2021, 08:18:40 PM »
@nidud,

thanks, exactly what i need. "TYPEID" is ASMC specific i suppose ...


@jj,

thanks a lot, i finally got it! If i use "TYPE" like this:
Code: [Select]
var_type = TYPE varthen var_type is the same for DWORD, SDWORD and REAL4

but if i use it like this:
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
then indeed i can keep those types apart - great! With this info i can create something similar to nidud´s TYPEID for ml/ml64 and UASM too.


BTW, where is this behavior documented?

MS´s documentation is lousy (https://docs.microsoft.com/en-us/cpp/assembler/masm/operator-type?view=msvc-160).
The funniest thing about it is this text at the bottom of the page
Quote
Is this page helpful?
Do they really ask this after presenting ... ehm - nothing?


Thanks again to both of you
JK

jj2007

  • Member
  • *****
  • Posts: 11551
  • Assembler is fun ;-)
    • MasmBasic
Re: type of variable
« Reply #7 on: April 04, 2021, 08:43:01 PM »
BTW, where is this behavior documented?

Nowhere afaik - I found it by trial and error. It's needed for Str$(any number) :cool:

nidud

  • Member
  • *****
  • Posts: 2215
    • https://github.com/nidud/asmc
Re: type of variable
« Reply #8 on: April 05, 2021, 12:03:56 AM »
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)))

jj2007

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


Error A2102: Symbol not defined : typeof

nidud

  • Member
  • *****
  • Posts: 2215
    • https://github.com/nidud/asmc
Re: type of variable
« Reply #10 on: April 05, 2021, 04:01:09 AM »
Error A2102: Symbol not defined : typeof

 :biggrin:

That's not a Masm compatible error.

ML64 -c test.asm

Microsoft (R) Macro Assembler (x64) Version 14.00.24210.0
Copyright (C) Microsoft Corporation.  All rights reserved.

 Assembling: test.asm
-1
-1
0
test.asm(9) : error A2006:undefined symbol : typeof

ASMC64 test.asm

Asmc Macro Assembler (x64) Version 2.32.28
Copyright (C) The Asmc Contributors. All Rights Reserved.
Portions Copyright (C) 1984-2002 Sybase, Inc. All Rights Reserved.                                   
 Assembling: test.asm
-1
-1
0
test.asm(9) : error A2006: undefined symbol : type -- use option /Znk for Masm keywords

ASMC64 /Znk test.asm

-1
-1 -- (a[4] eq b) -- size, type and offset is the same.
0
-1

jj2007

  • Member
  • *****
  • Posts: 11551
  • Assembler is fun ;-)
    • MasmBasic
Re: type of variable
« Reply #11 on: April 05, 2021, 05:09:57 AM »
Did you read what the post was all about? You are only demonstrating that MASM and AsmC are no longer compatible, thanks to your weird decision to abolish the MASM keyword type...

nidud

  • Member
  • *****
  • Posts: 2215
    • https://github.com/nidud/asmc
Re: type of variable
« Reply #12 on: April 05, 2021, 07:03:24 AM »
Did you read what the post was all about?

I did, both JK's and yours, as I usually do. The missing documentation you refer to obviously relates to IF and EQ as used in your sample. I provided an explanation for the EQ operator, documentation, and a sample on how it works.

Quote
You are only demonstrating that MASM and AsmC are no longer compatible,

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

thanks, exactly what i need. "TYPEID" is ASMC specific i suppose ...

Yes, it's used as in C++ to reference functions based on arguments used, as they may have the same name with different input.

jj2007

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

Output: 2x4, which is not helpful when deciding if, for example, fld or fild should be used for these variables. What we were discussing is this sequence, which works like a charm but is not documented:
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


Output:
Code: [Select]
a is a DWORD
b is a REAL4

I hope you get it now.

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

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

LiaoMi

  • Member
  • ****
  • Posts: 922
Re: type of variable
« Reply #14 on: April 05, 2021, 08:41:06 AM »
Microsoft Corporation - Microsoft Macro Assembler 6.11 Reference Manual_Programmers Guide-Microsoft Corporation (1992)

Testing for Argument Type and Environment
Macros can expand conditional blocks of code by testing for argument type with the
OPATTR operator. OPATTR returns a single word constant that indicates the
type and scope of an expression, like this:

OPATTR expression

If expression is not valid or is forward-referenced, OPATTR returns a 0.
Otherwise, the return value incorporates the bit flags shown in the table below.

OPATTR serves as an enhanced version of the .TYPE operator, which returns
only the low byte (bits 0 – 7) shown in the table. Bits 11 – 15 of the return value are
undefined.
Bit Set If expression
0 References a code label
1 Is a memory variable or has a relocatable data label
2 Is an immediate value
3 Uses direct memory addressing
4 Is a register value
5 References no undefined symbols and is without error
6 Is relative to SS
7 References an external label
8–10 Has the following language type:
◆ 000 — No language type
◆ 001 — C
◆ 010 —SYSCALL
◆ 011 —STDCALL
◆ 100 — Pascal
◆ 101 — FORTRAN
◆ 110 — Basic
A macro can use OPATTR to determine if an argument is a constant, a register, or
a memory operand. With this information, the macro can conditionally generate the
most efficient code depending on argument type.
For example, given a constant argument, a macro can test it for 0. Depending on the
argument’s value, the code can select the most effective method to load the value
into a register:

Code: [Select]
IF CONST
mov bx, CONST ; If CONST > 0, move into BX
ELSE
sub bx, bx ; More efficient if CONST = 0
ENDIF

The second method is faster than the first, yet has the same result (with the
byproduct of changing the processor flags).
The following macro illustrates some techniques using OPATTR by loading an
address into a specified offset register:

Code: [Select]
load MACRO reg:REQ, adr:REQ
IF (OPATTR (adr)) AND 00010000y ;; Register
IFDIFI reg, adr ;; Don’t load register
mov reg, adr ;; onto itself
ENDIF
ELSEIF (OPATTR (adr)) AND 00000100y
mov reg, adr ;; Constant
ELSEIF (TYPE (adr) EQ BYTE) OR (TYPE (adr) EQ SBYTE)
mov reg, OFFSET adr ;; Bytes
ELSEIF (SIZE (TYPE (adr)) EQ 2
mov reg, adr ;; Near pointer
ELSEIF (SIZE (TYPE (adr)) EQ 4
mov reg, WORD PTR adr[0] ;; Far pointer
mov ds, WORD PTR adr[2]
ELSE
.ERR <Illegal argument>
ENDIF
ENDM

TYPE with Forward References

MASM 5.1 evaluates .TYPE on both assembly passes. This means it yields zero on
the first pass and nonzero on the second pass, if applied to an expression that
forward-references a symbol.
MASM 6.1 evaluates .TYPE only on the first assembly pass. As a result, if the
operand references a symbol that has not yet been defined, .TYPE yields a value of
zero. This means that .TYPE, if used in a conditional-assembly construction, may
yield different results in MASM 6.1 than in MASM 5.1.

Comparing Types Using EQ and NE with OPTION M510
With OPTION M510, the assembler converts types to a constant value before
comparisons with EQ and NE. Code types are converted to values of 0FFFFh
(near) or 0FFFEh (far). If OPTION M510 is not enabled, the assembler converts
types to constants only when comparing them with constants. Thus, MASM 6.1
recognizes only equivalent qualified types as equal expressions.

For existing MASM 5.1 code, these distinctions affect only the use of the TYPE
operator in conjunction with EQ and NE. The following example illustrates how
the assembler compares types with and without compatibility mode:
Code: [Select]
MYSTRUCT STRUC
f1 DB 0
f2 DB 0
MYSTRUCT ENDS
; With OPTION M510
val = (TYPE MYSTRUCT) EQ WORD ; True: 2 EQ 2
val = 2 EQ WORD ; True: 2 EQ 2
val = WORD EQ WORD ; True: 2 EQ 2
val = SWORD EQ WORD ; True: 2 EQ 2
; Without OPTION M510
val = (TYPE MYSTRUCT) EQ WORD ; False: MyStruct NE WORD
val = 2 EQ WORD ; True: 2 EQ 2
val = WORD EQ WORD ; True: WORD EQ WORD
val = SWORD EQ WORD ; False: SWORD NE WORD

Use of Constant and PTR as a Type with OPTION M510
You can use a constant as the left operand to PTR in compatibility mode.
Otherwise, you must use a type expression. With OPTION M510, a constant must
have a value of 1 (BYTE), 2 (WORD), 4 (DWORD), 6 (FWORD), 8
(QWORD) or 10 (TBYTE). The assembler treats the constant as the
parenthesized type. Note that the TYPE operator yields a type expression, but the
SIZE operator yields a constant.
Code: [Select]
; With OPTION M510
MyData DW 0
mov WORD PTR [bx], 10 ; Legal
mov (TYPE MyData) PTR [bx], 10 ; Legal
mov (SIZE MyData) PTR [bx], 10 ; Legal
mov 2 ptr [bx], 10 ; Legal
; Without OPTION M510
MyData WORD 0
mov WORD PTR [bx], 10 ; Legal
mov (TYPE MyData) PTR [bx], 10 ; Legal
; mov (SIZE MyData) PTR [bx], 10 ; Illegal
; mov 2 PTR [bx], 10 ; Illegal
« Last Edit: April 05, 2021, 09:32:13 PM by LiaoMi »