flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > Some questions about Fasm preprocessor...

Author
Thread Post new topic Reply to topic
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 29 Dec 2005, 18:40
Hi,

I'm pretty new to Fasm, but I understand a lot of tricks, especially the preprocessor, which is a bit complicated.

First (stupid) question: How can you signal Fasm an error has occured? Like in C you can use #error, but is there something similar in Fasm?

Second (advanced) question: Let's say this macro:

Code:
macro xxx p1, p2
{
  match a1:b1, p1 \{
   match a2:b2, p2 \\{
    ; some stuff
   \\}
  \}
}    


The reason I did 2 matches is because b1 (or b2) can be a numerical expression, which has multiple symbols (like 1+2+3).. I can't just simply use match a1:b1 a2:b2, p1 p2.

This macro should be called like this:
Code:
xxx ah:5, al:2    

Though these two match directives I used will do the job (i.e a1 and a2 will be registers), I want to split the ah or al into 2 parameters, like a1a containing the symbol a (from ah), and a1b to contain h (from ah).. Same for b1a and b1b. It seems there's no way to do this with match directive, or am I too stupid to see it?


Third question: This is about the # operator.. I try using
Code:
irps rx, a b c d \\\{
 match =rx =rx, a1a b1a \\\\{
  reg@ equ rx#x ; here I want to be something like [b]a[/b]x, [b]b[/b]x, ...
                ; you know, append a 'x' to the symbol parameters ([b]a b c d[/b])...
                ; It just doesn't work?  How am I supposed to do that?
  \\\\}
 \\\}    


Is it a bug in the # operator? How does it really work? I'm a bit confused.

Thank you in advance
Post 29 Dec 2005, 18:40
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 29 Dec 2005, 19:16
The_Grey_Beast wrote:
How can you signal Fasm an error has occured? Like in C you can use #error, but is there something similar in Fasm?

There is no such feature, because you need to specify in which compialtion stage error should happen.

You can signal it during preprocessing, during parsing and during assembling, with some code that causes error in that stage. To cause preprocessor error you can use "macro}", for parsing error some undefined instruction like "sdkgsdkijgksdjfgdkjgkjg", for assembling error some invalid instruction/directive operands: "mov a,b,c,d,e,f,g,h,__undefined_symbol".

(You need to understand how FASM compilation process work to know what happens in each stage)

Question 2: There is no way to do this, symbol is conidered as entity, it cannot be divided. .... well, there is very ugly way to accmomplish this with "load" feature, but i rather won't even show it...
btw, this was much easier question than first one...

Question 3: You need to escape "#" operator too, because you must know during which macro unroll it happens. See this code:
Code:
macro a arg{
  match x, arg \{
    _#x:
    _\#x:
  \}
}
a name    
generates:
Code:
_x:
_name:    
Post 29 Dec 2005, 19:16
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 29 Dec 2005, 20:36
Thanks alot Very Happy

Regarding first question: Wouldn't it be nice to have such directive? like .err, or %err, etc?

Regarding second question: this method also works, without load directive:

ah equ a h
al equ a l
bh equ b h
bl equ b l
...

should've used irps again, but...
Is this a reliable method, I mean, without bugs, etc..

Regarding third question: Thanks ALOT.. it works Very Happy
Post 29 Dec 2005, 20:36
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 29 Dec 2005, 21:52
1. During which part should it work - preprocessing, parsing or assembling. And when you understand FASM's multi-pass assembling mechanism, you will find out that it isn't possible.

2. hehe, yes. This is the "art" of fasm's preprocessor, you can find simple soltion. What do you need it for? There can be even more simple and straightforward way.
Post 29 Dec 2005, 21:52
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 29 Dec 2005, 22:26
vid wrote:
hehe, yes. This is the "art" of fasm's preprocessor, you can find simple soltion. What do you need it for? There can be even more simple and straightforward way.


I'd like to do something like a packed instruction.

pkmov ah:5, al:3, bx:5

will actually compile

mov ax, ( 5 shl 8 ) + 5
mov bx, 5

of course, the value after the ':' symbol must be a numeric constant. this packs a list of constants into 'optimized' instructions.

this code

pkmov ch:4, dx:1, ah:5, bx:3, al:1

will compile

mov ch, 4
mov dx, 1
mov ax, ( 5 shl 8 ) + 1
mov bx, 3

the examples should be pretty self-explanatory, 'cause I can't explain better in words.
of course, this is just my 'ideal' macro. derivations and ideas are welcome.. my macro doesn't even work, so I don't think it's well-built Confused


The method with equ should be like this:

irps r, a b c d \{
r\#h equ r h
r\#l equ r l \}

of course, it must be used again before closing macro, to restore the symbolic constants. This, apparently, right now works for the ah/al packing method (i.e packs it into 16-bit register like ax).. I dunno how to do it for eax, like:

pkmov eax:10, ah:2

should replace the high-byte in the 16-bit register for eax (ah) with 2, because it's defined after eax:10.. something like:

mov eax, 10
mov ah, 2

but packed into one instruction... something like:

mov eax, (10 and 0xFFFF00FF) + ( 2 shl 8 )

i know it may be confusing, but that's why I asked the question in the first place.. if there's an obvious solution, this question might be stupid.

thanks again Smile
Post 29 Dec 2005, 22:26
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8354
Location: Kraków, Poland
Tomasz Grysztar 29 Dec 2005, 23:28
Very interesting idea for a macro... Here's how I tried to implement it, using generally much more "classical" fasm methods, with only one "match" to allow the syntax you needed. I made it work just like in your examples, this:
Code:
pkmov ch:4, dx:1, ah:5, bx:3, al:1    

generates the instructions:
Code:
mov ax,501h
mov ch,4
mov dx,1
mov bx,3    

and this:
Code:
pkmov eax:10, ah:2    

generates the:
Code:
mov eax,20Ah    


And here are the macros:
Code:
macro store@pkmov code,reg,value
{
  if reg in <al,bl,cl,dl>
   value@pkmov = byte value
   offset@pkmov = 0
   bytemask@pkmov = 1
   bitmask@pkmov = 0FFh
  else if reg in <ah,bh,ch,dh>
   value@pkmov = byte value
   offset@pkmov = 1
   bytemask@pkmov = 1
   bitmask@pkmov = 0FFh
  else if reg in <ax,bx,cx,dx,si,di,sp,bp>
   value@pkmov = word value
   offset@pkmov = 0
   bytemask@pkmov = 11b
   bitmask@pkmov = 0FFFFh
  else
   value@pkmov = dword value
   offset@pkmov = 0
   bytemask@pkmov = 1111b
   bitmask@pkmov = 0FFFFFFFFh
  end if

  if mask@pkmov and 1111b shl (code*4)
   r#code#@pkmov = ( r#code#@pkmov and not (bitmask@pkmov shl (offset@pkmov*8)) ) or (value@pkmov shl (offset@pkmov*8))
  else
   r#code#@pkmov = value@pkmov shl (offset@pkmov*8)
  end if

  mask@pkmov = mask@pkmov or bytemask@pkmov shl (code*4+offset@pkmov)
}

macro make@pkmov code,reg32,reg16,reg8h,reg8l
{
  valuemask@pkmov = (mask@pkmov shr (code*4)) and 1111b
  if valuemask@pkmov = 1 & (~ reg8l eq )
   mov reg8l,r#code#@pkmov
  else if valuemask@pkmov = 10b & (~ reg8h eq)
   mov reg8h,r#code#@pkmov shr 8
  else if valuemask@pkmov & ~ valuemask@pkmov and 1100b
   mov reg16,r#code#@pkmov
  else if valuemask@pkmov
   mov reg32,r#code#@pkmov
  end if
}

macro pkmov [def]
{
  common
   mask@pkmov = 0
  forward
   match reg:value, def
   \{ if reg in <eax,ax,ah,al>
       store@pkmov 0,reg,value
      else if reg in <ecx,cx,ch,cl>
       store@pkmov 1,reg,value
      else if reg in <edx,dx,dh,dl>
       store@pkmov 2,reg,value
      else if reg in <ebx,bx,bh,bl>
       store@pkmov 3,reg,value
      else if reg in <esi,si>
       store@pkmov 4,reg,value
      else if reg in <edi,di>
       store@pkmov 5,reg,value
      else if reg in <esp,sp>
       store@pkmov 6,reg,value
      else if reg in <ebp,bp>
       store@pkmov 7,reg,value
      end if \}
  common
   make@pkmov 0,eax,ax,ah,al
   make@pkmov 1,ecx,cx,ch,cl
   make@pkmov 2,edx,dx,dh,dl
   make@pkmov 3,ebx,bx,bh,bl
   make@pkmov 4,esi,si
   make@pkmov 5,edi,di
   make@pkmov 6,esp,sp
   make@pkmov 7,ebp,bp
}    


The last macro can be also made shorter this way:
Code:
regs0@pkmov equ eax,ax,ah,al
regs1@pkmov equ ecx,cx,ch,cl
regs2@pkmov equ edx,dx,dh,dl
regs3@pkmov equ ebx,bx,bh,bl
regs4@pkmov equ esi,si
regs5@pkmov equ edi,di
regs6@pkmov equ esp,sp
regs7@pkmov equ ebp,bp

macro pkmov [def]
{
  common
   mask@pkmov = 0
  forward
   match reg:value, def
   \{ rept 8 i:0
      \\{ if reg in <regs\\#i\\#@pkmov>
           store@pkmov i,reg,value
          end if \\} \}
  common
   rept 8 i:0
   \{ match regs, regs\#i\#@pkmov
      \\{ make@pkmov i,regs \\} \}
}    

but I'm not sure whether it's really better.
Post 29 Dec 2005, 23:28
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 30 Dec 2005, 00:46
someone is killing time behind computer instead of sleeping in late night... tell me about it Wink
Post 30 Dec 2005, 00:46
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8354
Location: Kraków, Poland
Tomasz Grysztar 30 Dec 2005, 15:54
Well, went to bed just about the time you wrote it. Wink

And, by the way:
vid wrote:

for parsing error some undefined instruction like "sdkgsdkijgksdjfgdkjgkjg"

This will cause an error in assembly stage. I actually tried to reduce the errors signalized at parsing stage to minimum, to prevent problems with incorrect expressions etc. inside the "if" blocks. Yeah, this can be also solved with the partial "if" processing by the parser - I'm working on this, as it seems the parser should even be able to skip parsing the whole "if" blocks in some cases. But the other reason for moving signaling the errors into assembly stage is that the errors will occurs more accordingly to their order in source. So generally the most of the errors you can get are either from preprocessor or later from the assembler.

So, after so massive rewrite and update of preprocessor during the recent versions, I may move to redesign some parts or even the whole of the parser - and this time with the rule in mind, that parser shouldn't signalize any errors on its own at all. The parsing stage has to be the transparent transition from the preprocessing to assembly, and for the fasm's user only knowledge of those two should be important.

But, back to the errors topic - even though there shouldn't be any errors signalized by the parser stage, you've got some different type of errors singnalized by assembler - the "critical" ones, that are signalized immediately when encountered, and "recoverable" ones, that are not signalized when assembler plans to do one more pass (so it may happen they get fixed in the next pass). The illegal instruction from your sample is the "critical" error, while something like "times x nop" where value of "x" is -1 is an example of "recoverable" error.

More on this topic you can find here: http://board.flatassembler.net/topic.php?t=3805
Post 30 Dec 2005, 15:54
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8354
Location: Kraków, Poland
Tomasz Grysztar 30 Dec 2005, 21:56
I have started the promised parser improvements and now I just realized that with the errors I have actually to do the opposite: if I want parser to be able to skip parsing the "if" blocks that can be determined to have false conditions during the parsing stage, I have to move the "structural" errors signalizing (like cross-nesting of "if" and "repeat") into the parser. So I bet we will still have some parser-specific errors.

I will try it and see what results it gives. So far I have made parser to precalculate the parts of logical expressions that can be determined at the parsing stage ("eq", "eqtype" and "in" operators) and reduce them to minimal forms. This allowed also to optimize and clean up the logical expression calculator that is later used by assembler - look out for the 1.65.0 dev. release to check it out.
Post 30 Dec 2005, 21:56
View user's profile Send private message Visit poster's website Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 31 Dec 2005, 14:30
Tomasz Grysztar wrote:
Very interesting idea for a macro... Here's how I tried to implement it, using generally much more "classical" fasm methods, with only one "match" to allow the syntax you needed. I made it work just like in your examples, this:
Code:
pkmov ch:4, dx:1, ah:5, bx:3, al:1    

generates the instructions:
Code:
mov ax,501h
mov ch,4
mov dx,1
mov bx,3    

and this:
Code:
pkmov eax:10, ah:2    

generates the:
Code:
mov eax,20Ah    


And here are the macros:
Code:
macro store@pkmov code,reg,value
{
  if reg in <al,bl,cl,dl>
   value@pkmov = byte value
   offset@pkmov = 0
   bytemask@pkmov = 1
   bitmask@pkmov = 0FFh
  else if reg in <ah,bh,ch,dh>
   value@pkmov = byte value
   offset@pkmov = 1
   bytemask@pkmov = 1
   bitmask@pkmov = 0FFh
  else if reg in <ax,bx,cx,dx,si,di,sp,bp>
   value@pkmov = word value
   offset@pkmov = 0
   bytemask@pkmov = 11b
   bitmask@pkmov = 0FFFFh
  else
   value@pkmov = dword value
   offset@pkmov = 0
   bytemask@pkmov = 1111b
   bitmask@pkmov = 0FFFFFFFFh
  end if

  if mask@pkmov and 1111b shl (code*4)
   r#code#@pkmov = ( r#code#@pkmov and not (bitmask@pkmov shl (offset@pkmov*8)) ) or (value@pkmov shl (offset@pkmov*8))
  else
   r#code#@pkmov = value@pkmov shl (offset@pkmov*8)
  end if

  mask@pkmov = mask@pkmov or bytemask@pkmov shl (code*4+offset@pkmov)
}

macro make@pkmov code,reg32,reg16,reg8h,reg8l
{
  valuemask@pkmov = (mask@pkmov shr (code*4)) and 1111b
  if valuemask@pkmov = 1 & (~ reg8l eq )
   mov reg8l,r#code#@pkmov
  else if valuemask@pkmov = 10b & (~ reg8h eq)
   mov reg8h,r#code#@pkmov shr 8
  else if valuemask@pkmov & ~ valuemask@pkmov and 1100b
   mov reg16,r#code#@pkmov
  else if valuemask@pkmov
   mov reg32,r#code#@pkmov
  end if
}

macro pkmov [def]
{
  common
   mask@pkmov = 0
  forward
   match reg:value, def
   \{ if reg in <eax,ax,ah,al>
       store@pkmov 0,reg,value
      else if reg in <ecx,cx,ch,cl>
       store@pkmov 1,reg,value
      else if reg in <edx,dx,dh,dl>
       store@pkmov 2,reg,value
      else if reg in <ebx,bx,bh,bl>
       store@pkmov 3,reg,value
      else if reg in <esi,si>
       store@pkmov 4,reg,value
      else if reg in <edi,di>
       store@pkmov 5,reg,value
      else if reg in <esp,sp>
       store@pkmov 6,reg,value
      else if reg in <ebp,bp>
       store@pkmov 7,reg,value
      end if \}
  common
   make@pkmov 0,eax,ax,ah,al
   make@pkmov 1,ecx,cx,ch,cl
   make@pkmov 2,edx,dx,dh,dl
   make@pkmov 3,ebx,bx,bh,bl
   make@pkmov 4,esi,si
   make@pkmov 5,edi,di
   make@pkmov 6,esp,sp
   make@pkmov 7,ebp,bp
}    


The last macro can be also made shorter this way:
Code:
regs0@pkmov equ eax,ax,ah,al
regs1@pkmov equ ecx,cx,ch,cl
regs2@pkmov equ edx,dx,dh,dl
regs3@pkmov equ ebx,bx,bh,bl
regs4@pkmov equ esi,si
regs5@pkmov equ edi,di
regs6@pkmov equ esp,sp
regs7@pkmov equ ebp,bp

macro pkmov [def]
{
  common
   mask@pkmov = 0
  forward
   match reg:value, def
   \{ rept 8 i:0
      \\{ if reg in <regs\\#i\\#@pkmov>
           store@pkmov i,reg,value
          end if \\} \}
  common
   rept 8 i:0
   \{ match regs, regs\#i\#@pkmov
      \\{ make@pkmov i,regs \\} \}
}    

but I'm not sure whether it's really better.


Cool Cool thanks

one more question: the equ defines symbolic constants.. but it also replaces the symbolic constants with their values on the right side of equ before defining them. this makes growing list of symbols possible. Smile

but, isn't there an alternative to it, without replacing the symbolic constants, thus:

Code:
a equ something
b equ a b c d  ; initially, I would like to pass this as "a b c d"
               ; without replacing a with something...
match a b c d, b { display `a#`b#`c#`d }    


this code displays 'somethingbcd', and it's not what I wanted, of course...
I would like to pass b as parameter to irps, for example, but without replacing symbolic constants... I tried with macro directive, but match doesn't work there.

Code:
a equ something
macro b { a b c d }
match a b c d, b { display `a#`b#`c#`d }    


apparently, the match directive does not replace b with macro definition at this stage.. is there a way to accomplish this (maybe a nasty trick Smile ).

thanks again for your help Smile
Post 31 Dec 2005, 14:30
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8354
Location: Kraków, Poland
Tomasz Grysztar 31 Dec 2005, 16:30
I am aware of this problem and there is no solution for it yet.
Post 31 Dec 2005, 16:30
View user's profile Send private message Visit poster's website Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 31 Dec 2005, 17:24
Maybe a new directive should work? should be simple to do (simpler than the standard equ at least Smile )

like const? or define? dunno, just some names Wink

or try unrolling macros at match directive?
Post 31 Dec 2005, 17:24
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8354
Location: Kraków, Poland
Tomasz Grysztar 01 Jan 2006, 10:42
Macroinstructions as implemented by fasm are supposed to replace the instruction mnemonics and are recognized only as the whole instructions, and produce multiple lines from the single line which invokes them. For this reason fasm cannot recognize macro inside the arguments/other line contents.

So for solving this problem the only possible solution is some alternative to "equ" that wouldn't replace symbolic constants in the value before assigning it. "define" might be the right choice, however I haven't yet proposed it since till this discussion nobody else complained about this problem and I didn't want to breed too much directives when not really necessary. On the other hand, I would be able to improve the "struct" macro and fix some of its issues with the directive like that - so I guess I will now seriosly consider adding it in the next release.
Post 01 Jan 2006, 10:42
View user's profile Send private message Visit poster's website Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 02 Jan 2006, 12:40
something like this works: b equ 'a b c d'

quoted strings are not replaced with symbolic constants, but I can't find a way to 'unquote' the string... the ` operator seems to only 'add' quotes to a name, but wouldn't be nice to have it 'remove' quotes if there is a quoted string. I know, most assemblers/compilers don't do this, but why not make Fasm better? It's a simple feature, and should be no problem adding some cmps to see if string is quoted string (in fasm's source code, I mean Wink ) .. something like this:
Code:
b equ 'a b c d'
match any, b { irps r, `any \{ ... \} }    


alternatively, it could also be declared as:
Code:
b equ 'a b c d'
b equ `b    

without the need to use the ` operator everywhere Smile
is there a reason not to make ` operator 'unquote' quoted strings?


seems there is no way to 're' define some constants to original values with equ.. when you define something, that name cannot be used in other equ's (I mean literally), because it would be replaced.

or try adding the = symbol like in match - make it mean something literally, without replacing symbolic constants. == should be used for literal = symbol. something like:
Code:
b equ =a =b =c =d    

will actually make b be a b c d. this works without new directive. should not be that hard, since match uses this syntax.. it's similar to it Smile

or are these ideas stupid Laughing

struc improvements would be nice. good luck Smile
Post 02 Jan 2006, 12:40
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8354
Location: Kraków, Poland
Tomasz Grysztar 02 Jan 2006, 13:19
I did mean improvements of the "struct" macro, not the "struc" directive.

There no way to "unquote" the string, and it would be quite problematic, but there's now the "define" directive in fasm 1.65... (see below).

As to restoring the symbolic constants to the original values, the oldest solution was like this:
Code:
_x equ x
x equ something different
; ...
x equ _x ; restores the original value    

And also check out the restore directive!

But now with fasm 1.65 it can be just:
Code:
define x x    
Post 02 Jan 2006, 13:19
View user's profile Send private message Visit poster's website Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 02 Jan 2006, 13:31
Sorry about struc confusion.. I mistyped it. I know struc is not even a macro, it's a preprocessor directive, isn't it? I meant the Win32 struct macro. sorry Embarassed

how does define work.. does it push like equ (i mean, does it work with restore?).

Code:
x equ something
define x something else
restore x    


will x contain something from equ previous?
If you haven't done documentation for define (didn't check it), I can help out. Sure, only if you want. Wink


Keep up the good work Very Happy Cool Very Happy
Post 02 Jan 2006, 13:31
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8354
Location: Kraków, Poland
Tomasz Grysztar 02 Jan 2006, 13:34
Yes, the DEFINE makes the same kind of definition like EQU, so RESTORE will work just like if you used EQU instead. The only difference is that DEFINE takes the literal value.
Post 02 Jan 2006, 13:34
View user's profile Send private message Visit poster's website Reply with quote
Borsuc



Joined: 29 Dec 2005
Posts: 2465
Location: Bucharest, Romania
Borsuc 02 Jan 2006, 13:45
Cool Cool Thanks Very Happy

fix idea was also nice. Smile
Post 02 Jan 2006, 13:45
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.