Please help me to create macro which performs check if its argument is a float.
My current not-working draft:
Quote
ISFLOAT? MACRO arg
FORC c,<&arg>
%echo c
IFIDN c , <.>
%echo arg is FLOAT!
ENDIF
ENDM
ENDM
You were pretty <close> ;)
include \masm32\include\masm32rt.inc
ISFLOAT? MACRO arg
FORC c,<&arg>
%echo c
IFIDN <c> , <.>
%echo arg is FLOAT!
ENDIF
ENDM
ENDM
IsFloat MACRO arg
if @InStr(1, <arg>, <.>)
EXITM <100>
elseif @InStr(1, <arg>, <xmm>) eq 1
EXITM <112>
elseif (opattr arg) eq 36
EXITM <101>
elseif (opattr arg) eq 48
EXITM <111>
elseifndef arg
EXITM <-77>
elseif type(arg) eq DWORD
EXITM <102>
elseif type(arg) eq QWORD
EXITM <103>
elseif type(arg) eq REAL4
EXITM <104>
elseif type(arg) eq REAL8
EXITM <105>
elseif type(arg) eq REAL10
EXITM <106>
else
.err @CatStr(<## unknown type ">, <arg>, <" in line >, %@Line, < ##>
endif
ENDM
.code
mydw dd 123
myqw dq 123
myr4 REAL4 123.456
myr8 REAL8 123.456
myr10 REAL10 123.456
start:
ISFLOAT? 123.456
print str$(IsFloat(123.456)), 9, "immediate real", 13, 10
print str$(IsFloat(123)), 9, "immediate integer", 13, 10
print str$(IsFloat(mydw)), 9, "dword", 13, 10
print str$(IsFloat(myqw)), 9, "qword", 13, 10
print str$(IsFloat(myr4)), 9, "real4", 13, 10
print str$(IsFloat(myr8)), 9, "real8", 13, 10
print str$(IsFloat(myr10)), 9, "real10", 13, 10
print str$(IsFloat(undefined)), 9, "undefined", 13, 10
print str$(IsFloat(abcde)), 9, "undefined", 13, 10
print str$(IsFloat(0abcdeh)), 9, "hex", 13, 10
print str$(IsFloat(eax)), 9, "reg32", 13, 10
print str$(IsFloat(xmm0)), 9, "xmm", 13, 10
exit
end start
Thanks , Jochen :t
I think your IsFloat is a whole GetType macro :t
The solution is so simple. I'm ashamed
P.S.: Still there's a little work for me to be done: check if arg is not qouted string with dot(s)
DBC REAL4 0.0
DEF DWORD 0
k0 equ type(DBC) eq DWORD
k1 equ type(DBC) eq REAL4
k2 equ type(DBC) eq SDWORD
% echo @CatStr(<result 1:>,%k0,<,result 2:>,%k1,<,result 3:>,%k2)
k01 equ type(DEF) eq DWORD
k11 equ type(DEF) eq REAL4
k21 equ type(DEF) eq SDWORD
% echo @CatStr(<result 1:>,%k01,<,result 2:>,%k11,<,result 3:>,%k21)
Quote
result 1:0,result 2:-1,result 3:0
result 1:-1,result 2:0,result 3:0
0=FALSE and -1=TRUE
Thank you, mabdelouahab
Very non standart solution :t
First working version . Macro returns 1 if arg is FLOAT and 0 otherwise so it can be used like this:
Quote
IF ISFLOAT?(arg)
; do something
ENDIF
include \masm32\include\masm32rt.inc
ISFLOAT? MACRO arg
IF @InStr(1, <arg>, <.>)
quot SUBSTR <arg>,1,1
IFIDN quot,<">
%echo arg is not FLOAT!
EXITM <0>
ENDIF
%echo arg is FLOAT!
EXITM <1>
ENDIF
%echo arg is not FLOAT!
EXITM <0>
ENDM
.code
start:
ISFLOAT?(2435.56767)
ISFLOAT?(1.5)
ISFLOAT?(3.0)
ISFLOAT?("dsfg.dsf")
ISFLOAT?(7777h)
ISFLOAT?(0)
.err
end start
Thank you , Jochen and mabdelouahab for quick replies !
structure.member also float? You should at least test that the first character (or the second in case of sign +-) is a digit 0-9.
Remarks that quot is "global", which might be not intended?
I thought that structure.member will be resolved to its offset , won't it?
Didn't think that quot is global
Thanks for noting these points. I'd work on it
Oops, really
include \masm32\include\masm32rt.inc
ISFLOAT? MACRO arg
IF @InStr(1, <arg>, <.>)
q SUBSTR <arg>,1,1
IFIDN q,<">
%echo arg is not FLOAT!
EXITM <0>
ENDIF
%echo arg is FLOAT!
EXITM <1>
ENDIF
%echo arg is not FLOAT!
EXITM <0>
ENDM
mys struct
dw1 dd ?
dw2 dd ?
item1 db ?
item2 db ?
mys ends
.data
mysinst mys<1,2,3,4>
.code
start:
ISFLOAT?(mysinst.dw1)
.err
end start
output:
Quote
mysinst.dw1 is FLOAT!
'quot' is replaced by 'q'
I'll think about what's better
- to add in-macro checks adviced by Qword
- or to write separate macros : ISSIGNED? and ISNUM?
Quote from: GoneFishing on October 19, 2015, 12:30:10 AM
I thought that structure.member will resolve to offset , won't it?
In an arithmetic expression yes, but that's not the case for you macro. Also, thought the case that a memory operand is used, e.g.: mem.x.
What you can do: if OPATTR does not return 0, than it can't be an FP literal (I guess that is what you want to test for). After that you could test for digits and the decimal dot.
Quote from: GoneFishing on October 19, 2015, 12:30:10 AMDidn't think that quot is global
the name quote is used as text macro while assembling- that is what I mean (so it might cause name conflicts) -> use macro-LOCAL or use an unique pre/postfix.
e.g.
ISFLOAT? MACRO arg:=<invalidToken?$?$?$>
IF OPATTR arg
EXITM <0>
ENDIF
iflt_str TEXTEQU <&arg >
iflt_c1 SUBSTR iflt_str,1,1
iflt_c2 SUBSTR iflt_str,2,1
iflt_pos1 INSTR iflt_str,<.>
iflt_pos2 INSTR <+-0123456789>,iflt_c1
iflt_pos3 INSTR <0123456789>,iflt_c2
;; if (sign and digit and dot) OR (digit and dot)
IF (iflt_pos2 LE 2 AND iflt_pos3 NE 0 AND iflt_pos1 NE 0) OR (iflt_pos2 GT 2 AND iflt_pos1 NE 0)
EXITM <-1>
ELSE
EXITM <0>
ENDIF
endm
Quote:=<invalidToken?$?$?$>
Never seen this expression before
Can't get your macro working here . Possibly it's
QuoteIF OPATTR arg
EXITM <0>
ENDIF
part affecting it. We want to catch immediate operands which are OPATTR = 24h
Quote from: GoneFishing on October 19, 2015, 01:21:28 AMWe want to catch immediate operands which are OPATTR = 24h
FP literals are not recognized by OPATTR, only integers. You must distinguish between them in some form, e.g. by having two macros or by different return values. (The above macro does only detect FP literals)
Quote from: GoneFishing on October 19, 2015, 01:21:28 AM
Quote:=<invalidToken?$?$?$>
Never seen this expression before
that is the default value for arg, just to point out that the macro should fail for blank input. Could be removed, because it seems like that OPATTR has no problem with a missing argument.
include \masm32\include\masm32rt.inc
ISFLOAT?QW MACRO arg:=<invalidToken?$?$?$>
IF OPATTR arg
EXITM <0>
ENDIF
iflt_str TEXTEQU <&arg >
iflt_c1 SUBSTR iflt_str,1,1
iflt_c2 SUBSTR iflt_str,2,1
iflt_pos1 INSTR iflt_str,<.>
iflt_pos2 INSTR <+-0123456789>,iflt_c1
iflt_pos3 INSTR <0123456789>,iflt_c2
;; if (sign and digit and dot) OR (digit and dot)
IF (iflt_pos2 LE 2 AND iflt_pos3 NE 0 AND iflt_pos1 NE 0) OR (iflt_pos2 GT 2 AND iflt_pos1 NE 0)
EXITM <-1>
ELSE
EXITM <0>
ENDM
ISFLOAT? MACRO arg
IF @InStr(1, <arg>, <.>)
q SUBSTR <arg>,1,1
IFIDN q,<">
%echo arg is not FLOAT!
EXITM <0>
ENDIF
%echo arg is FLOAT!
EXITM <1>
ENDIF
%echo arg is not FLOAT!
EXITM <0>
ENDM
mys struct
dw1 dd ?
dw2 dd ?
item1 db ?
item2 db ?
mys ends
.data
mysinst mys<5,2,3,4>
.code
start:
if ISFLOAT?(mysinst.dw1)
%echo mysinst.dw1 is mistakenly taken as a float
endif
if ISFLOAT?QW(-7.4)
%echo QWORD IS MACRO WIZARD
endif
.err
end start
Your macro gives no output in example above . But why?
P.S.: Really, OPATTR for float is 0 . Thank you for clarification
Quote from: GoneFishing on October 19, 2015, 01:46:57 AMYour macro gives no output in example above . But why?
Thought the ECHOs were just used for debugging purpose. Just add them as you need.
Excuse me , I meant that this condition was not met:
Quote
if ISFLOAT?QW(-7.4)
%echo QWORD IS MACRO WIZARD
endif
Quote from: GoneFishing on October 19, 2015, 01:57:24 AM
Excuse me , I meant that this condition was not met:
Quoteif ISFLOAT?QW(-7.4)
does work here (ML v6&8,jWasm). However, in the code from your previous post there is a missing ENDIF (I guess copy&past error).
I'm so sorry ,as a poor noob can only be
yes, it was copy-paste error
now I've got expected line
QuoteQWORD IS MACRO WIZARD
Thanks :t
We were sorting out structure members. Now new question erises : what if that structure member is FLOAT and we need it?
I have another weak macro-embrion :
ISNUM? MACRO arg
ch SUBSTR <arg>,1,1
if @INSTR(1, <0123456789>,<ch>)
%echo ch is numeric
endif
ENDM
if ISNUM?(1.0)
%echo -----------
endif
Got:
QuoteISFLOAT.asm(87) : Error A2243: Invalid symbol type in expression: ISNUM?
What's wrong with it?
You are using it as a function, so you need to return something:
ISNUM? MACRO arg
ch SUBSTR <arg>,1,1
if @INSTR(1, <0123456789>,<ch>)
%echo ch is numeric
EXITM <1>
else
EXITM <0>
endif
ENDM
Indeed, Jochen ! Thanks
Probably I ran out of oxigen in my BLACK CHAMBER LOL ... and totally out of beer since yesterday :biggrin:
ISNUM? MACRO arg
chr SUBSTR <arg>,1,1
if @INSTR( 1,<0123456789>,<chr>)
%echo is numeric
EXITM <1>
endif
%echo ch is not numeric
EXITM <0>
ENDM
if ISNUM?(1.0)
%echo -----------
endif
getting weird reply :
Quote
ch is not numeric
Got it!
Instead of
Quoteif @INSTR( 1,<0123456789>,<chr>)
I need
Quoteif @INSTR( <0123456789>,<chr>)
Your last version throws an error with ML. Try this:
include \masm32\include\masm32rt.inc
ISNUM? MACRO arg
LOCAL chr, ins
chr SUBSTR <arg>,1,1
ins INSTR <0123456789>, chr ; no good: if @InStr(1, <0123456789>, chr)
if ins
% echo chr is numeric
EXITM <1>
else
% echo chr is not numeric
EXITM <0>
endif
ENDM
.code
start:
if ISNUM?(1.0)
% echo -----------
endif
.err ; don't run this code
exit
end start
EDIT: Tim found an error in my code - corrected version above. The built-in @InStr() macro often plays foul, in my experience it is safer to use e.g. ins INSTR <string>, <match> :(
Attention also to this trap:
chr SUBSTR <arg>,1,1
ins INSTR <0123456789>, <chr>
With arg=1.0, you expect ins>0, right? Nope, it won't find the 1 in <0123456789>, simply because you are not passing 1 - you are passing <1>...! chr is already a text item, so the correct version is
chr SUBSTR <arg>,1,1
ins INSTR <0123456789>, chr
Quote from: jj2007 on October 19, 2015, 03:01:27 AM
Your last version throws an error with ML.
Yes. didn't notice it.
I'd take a break for developing good habbits. It take efforts to start coding again, Jochen.
GoneFishing,
before starting coding, it might be useful to have a list of requirements. Currently I see these points:
- Def.: true is 1, false is 0 (I would recommend true = -1 BTW)
- return true if FP literal; e.g. 3.0E8
- return true if REAL4/8/10 variable
- if none of the above applies, return false
Any other points? The third point can be done using OPATTR (see previous posts).
What I see critical, is that your macro accepts FP literals and variables, but in later code FP literals maybe requires a special handling. For that reason, I would separate the test for literals and memory operands.
BTW: as already said, do not declare text macros with names like "q" and "ch", unless they are LOCAL!
Ok, Qword, I'm agree today's session was too spontaneous , without proper planning work .
Points you see are even more complete than I've taken into consideration.
For the timebeing I would not talk about FP literals since they require special handling .
By the way, we didn't consider the possibility when REAL4/8/10 variable resides inside the structure.
For example:
Quote
mystructure STRUCT
f1 REAL10
f2 REAL10
mystructure ENDS
.data
mys mystructure<1.0,1.0>
your and my current code will not recognize float in mys.f1:
Quoteif ISFLOAT?(mys.f1)
; ...
Point about using LOCAL is taken .
Again , thank you for the help .
deleted
Quote from: GoneFishing on October 19, 2015, 03:10:50 AMI'd take a break for developing good habits. It takes efforts to start coding again, Jochen.
Yes, I know, but don't forget the fun factor ;-)
Please note my edits to reply #22 - there was a bug.
Thank you, Jochen . Corrected now .
First mile stone. Code contains only few tests out of all possible .
-----------------------------------------------------
NOTE:
-----------------------------------------------------
--- FP literals are NOT SUPPORTED yet
--- float members of structure are not identified as floats
--- hex format 3F800000r mentioned by nidud is NOT SUPPORTED yet
-----------------------------------------------------
ISFLOAT.ASM:
include \masm32\include\masm32rt.inc
;-----------------
; ISSIGNED? MACRO: returns TRUE if the argument has '+' or '-' sign
;-----------------
ISSIGNED? MACRO arg
LOCAL sign
sign SUBSTR <arg>,1,1
IFIDN sign,<+> ; if first charachter is "+"
%echo arg is SIGNED ; exit with TRUE
EXITM <-1>
ELSEIFIDN sign,<->
%echo arg is SIGNED ; or if first charachter is "-"
EXITM <-1> ; return TRUE
ELSE
%echo arg is NOT SIGNED
%echo -----------
EXITM <0> ; otherwise return FALSE
ENDIF
ENDM
;-----------------
; ISNUM? MACRO: returns TRUE if the character at <position> is numeric
;-----------------
ISNUM? MACRO arg, position:=<1>
LOCAL chr, pos
chr SUBSTR <arg>,1,position
pos INSTR <0123456789>,chr
IF pos ; if the character at <position> is numeric
%echo chr is numeric
EXITM <-1> ; return TRUE
ENDIF
%echo chr is not numeric
%echo -----------
EXITM <0> ; otherwise return FALSE
ENDM
;-----------------
; ISFLOAT? MACRO: returns TRUE if the argument is REAL4/8/10
;-----------------
ISFLOAT? MACRO arg
LOCAL quote
IF @InStr(1, <arg>, <.>) ; if argument has dot ->
quote SUBSTR <arg>,1,1
IFIDN quote,<"> ; and its first character is quote ->
%echo arg is not FLOAT!
%echo ----------- ; then argument is a string ->
EXITM <0> ; return FALSE
ENDIF ; if it's not a quote ->
;----------------------
IF ISNUM?(arg) ; check if it's numeric ->
%echo arg is FLOAT!; if so ->
%echo -----------
EXITM <-1> ; return TRUE
;---------------------- ; if the first character is
ELSE ; not numeric ->
IF ISSIGNED?(arg) ; check if it's "+" or "-",if so ->
IF ISNUM?(arg,2) ; check if the next character
%echo arg is FLOAT! ; is numeric ->
%echo ----------- ; if so ->
EXITM <-1> ; return TRUE
;---------------------- ; if second character
ELSE ; is not numeric ->
%echo arg is not FLOAT!
%echo -----------
EXITM <0> ; return FALSE
ENDIF ; END IF ISNUM?(arg,2)
;----------------------
ENDIF ; END IF ISSIGNED?(arg)
;----------------------
ENDIF ; END IF ISNUM?(arg)
;----------------------
ENDIF ; if argument has no dot ->
%echo arg is not FLOAT!
%echo -----------
EXITM <0> ; return FALSE
ENDM
;-----------------
;ISFLOAT?QW MACRO: written by QWORD , 10h lines of code
;-----------------
ISFLOAT?QW MACRO arg:=<invalidToken?$?$?$>
IF OPATTR arg
EXITM <0>
ENDIF
iflt_str TEXTEQU <&arg >
iflt_c1 SUBSTR iflt_str,1,1
iflt_c2 SUBSTR iflt_str,2,1
iflt_pos1 INSTR iflt_str,<.>
iflt_pos2 INSTR <+-0123456789>,iflt_c1
iflt_pos3 INSTR <0123456789>,iflt_c2
;; if (sign and digit and dot) OR (digit and dot)
IF (iflt_pos2 LE 2 AND iflt_pos3 NE 0 AND iflt_pos1 NE 0) OR (iflt_pos2 GT 2 AND iflt_pos1 NE 0)
EXITM <-1>
ELSE
EXITM <0>
ENDIF
ENDM
;--------------------
; mystructure STRUCT: for testing
;--------------------
mystructure STRUCT
f1 REAL10 ?
f2 REAL10 ?
item1 DD ?
item2 DD ?
mystructure ENDS
.data
mys mystructure<5.0,2.7,3,4>
.code
start:
;-----------------
; ISFLOAT? tests:
;-----------------
IF ISFLOAT?(mys.item1)
%echo mys.item1 is taken as a float
%echo -----------
ENDIF
IF ISFLOAT?(-mys.f1)
%echo mys.f1 is taken as a float by mistake
%echo -----------
ENDIF
IF ISFLOAT?QW(-7.4)
%echo QWORD IS MACRO WIZARD
%echo -----------
ENDIF
;-----------------
; ISSIGNED? tests:
;-----------------
IF ISSIGNED?(-13245.345)
%echo -----------
ENDIF
IF ISSIGNED?(+13245.345)
%echo -----------
ENDIF
IF ISSIGNED?(13245.345)
%echo -----------
ENDIF
;-----------------
; ISNUM? tests:
;-----------------
IF ISNUM?(1.0)
%echo -----------
ENDIF
IF ISNUM?("sad.saa")
%echo -----------
ENDIF
IF ISNUM?(1234)
%echo -----------
ENDIF
;-----------------
.ERR ; FORCE ERROR
;-----------------
end start
quickly worked out:
;
; Returns true for any REAL4/8/10 variable or decimal FP literal
;
ISFLOAT? MACRO arg
; handle memory operands and integer values
IF (OPATTR arg) AND 2
IF (TYPE arg) EQ (TYPE REAL4) OR (TYPE arg) EQ (TYPE REAL8) OR (TYPE arg) EQ (TYPE REAL10)
EXITM <-1>
ENDIF
EXITM <0>
ELSEIF OPATTR arg
EXITM <0>
ENDIF
;; Test for valid FP literal
;;
;; Used state machine
;; state | end state | description
;; ------+-----------+------------
;; 1 | no | initial state
;; 2 | no | sign
;; 3 | no | integer digits
;; 4 | yes | decimal dot and (optional) fraction digits
;; 5 | no | exponent indicator
;; 6 | no | exponent sign
;; 7 | yes | exponent digits
;;
;; Transitions
;; state | characters | new state
;; ------+------------+------------
;; 1 | +- | 2
;; 1 | 0-9 | 3
;; 2 | 0-9 | 3
;; 3 | 0-9 | 3
;; 3 | . | 4
;; 4 | 0-9 | 4
;; 4 | eE | 5
;; 5 | +- | 6
;; 5 | 0-9 | 7
;; 6 | 0-9 | 7
;; 7 | 0-9 | 7
;;
isflt_pos = 1
isflt_state = 1
FORC char,<&arg>
; %echo CHAR <char>, STATE: @CatStr(%isflt_state), POS: @CatStr(%isflt_pos)
isflt_sigma SUBSTR <23 3344567 7 7>,isflt_state*2-1,2
isflt_pos INSTR isflt_pos,<+-0123456789.0123456789Ee+-0123456789>,<&char>
isflt_new_state SUBSTR <02233333333334444444444455667777777777>,isflt_pos+1,1
isflt_transition INSTR isflt_sigma,isflt_new_state
IFE isflt_transition
isflt_state = 0
EXITM
ENDIF
isflt_state = isflt_new_state
isflt_pos = @SubStr(<03030303030303030303030314141414141414141414142626282828282828282828282828>,%isflt_pos*2-1,2)
ENDM
IF isflt_state EQ 4 OR isflt_state EQ 7
EXITM <-1>
ENDIF
EXITM <0>
ENDM
The pattern test is implemented as state machine.
Thank you , Qword
Though I must confess I hardly can understand what you're doing in your macro . You're operating such esoteric for me concepts like STATE MACHINE, FP literal ... I afraid understanding it will require lots of additional reading. Maybe you could advice me some not-too-complicated paper to read ?
Quote from: GoneFishing on October 20, 2015, 01:26:08 AMMaybe you could advice me some not-too-complicated paper to read ?
regarding macros: read MASM programmer's guide, chapter 9 (use the forum search to find it). For state machines, see Wikipedia (when ignoring the formal part, actual very intuitive)
macros - i look to qWord and Jochen for that - lol
but, state machines i do know (google for "finite state machine")
(http://www.ni.com/cms/images/devzone/tut/a/45ee74b4584.gif)