flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > Get size and element of list

Author
Thread Post new topic Reply to topic
SPTH



Joined: 24 Jul 2004
Posts: 91
SPTH
Hey,

lets say, I have dynamically created a symbolic list via a macro like this:
Code:
list equ
macro append item
{
  match any, list \{ list equ list,item \}
  match , list \{ list equ item \}
}
append 3
append 6
append 2
append 9
    


Lets say, my list now looks like this:

Code:
list equ 3,6,2,9
    


Is there a way that I can get the length of this list? (Well, this problem could be solve with a other way too).

like:
Code:
len_of_list equ §somefunction(list)
    

len_of_list=4

But the more important: Can I get for instance the second element of this list?

like:
Code:
element_number equ 2
list_element equ §somefunction(list, element_number)
    

list_element=6

The second one would be very important.

Thanks for any hints!
Post 20 Apr 2011, 01:59
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17716
Location: In your JS exploiting you and your system
revolution
To count the items you can enumerate the list with forward and/or reverse.

To get a specific item from the list you also enumerate and then set a label to just the desired item.

But you can't do it the way you show above. fasm doesn't support macro functions. Use a the macro loop directives, forward and reverse.
Post 20 Apr 2011, 02:07
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17716
Location: In your JS exploiting you and your system
revolution
You might also be interested in this topic:

http://board.flatassembler.net/topic.php?t=12012
Post 20 Apr 2011, 02:13
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Code:
list       equ
list.count equ 0

macro append item
{
  match any, list \{ list equ list,item \}
  match , list \{ list equ item \}

; Keep count here so we don't have to make expensive re-calculations when needed
  rept 1 n:list.count+1\{list.count equ n\}
}
append 3
append 6
append 2
append 9

macro getItem index*, out* ; Index lower bound is 1. Exceeding upper bound returns last element
{
local _list

  match any, list \{_list equ any, END\}

  rept index\{
       match item=,any,_list\\{
             out equ item
             _list equ any
       \\}
  \}
}

macro getListSize out*
{
  match value, list.count\{out equ value\}
}

; In both cases, the pseudo IntToStr will fail with values greater than 9
getItem 3, output
display 'The 3rd element is: ', output+'0', 13, 10

getListSize output
display 'Number of elements in the list is: ', output+'0', 13, 10    
Is this what you need?
Post 20 Apr 2011, 02:27
View user's profile Send private message Reply with quote
SPTH



Joined: 24 Jul 2004
Posts: 91
SPTH
Thank you revolution for the incredible fast answere.

I found a quite beautiful way to determine the elements in a list

Code:
testlist equ 13,14,15,16 
virtual
        ls: db testlist
        len = $ - ls
end virtual
    


but I will try it with your forward and reverse suggestions too, maybe that can be done even more easy.

Thanks for the suggestion to the second question. I hope this works. If yes, I'll post my solution, otherwise I will continue asking ;)

[edit]
Thanks also to you LocoDelAssembly, have not seen your answere before!
Awesome that this board is so active, even at this time.

I'm going to try the suggestions now!
[/edit]


Last edited by SPTH on 20 Apr 2011, 03:16; edited 1 time in total
Post 20 Apr 2011, 02:29
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
SPTH wrote:

Thanks also to you LocoDelAssembly, have not seen your answere before!
Awesome that this board is so active, even at this time.
Yeah, revolution is super very active and I also haven't seen his answer before replying, it took me some time to get the code right Razz
Post 20 Apr 2011, 02:43
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17716
Location: In your JS exploiting you and your system
revolution
But LocoDelAssembly's answer was considerably more comprehensive, as usual. And I forgot about rept Embarassed
Post 20 Apr 2011, 02:45
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Still, your (or Tomasz's? or I didn't understand at all?) idea of using numbers could be better:
Code:
list       equ
list.count equ 0

macro append item
{
  rept 1 n:list.count+1\{
       list.count equ n
       list\#n equ item
  \}
}

macro getItem index*, out* ; Index lower bound is 1
{
  match value, list#index \{out equ value\}
}

macro getListSize out*
{
  match value, list.count\{out equ value\}
}

append 3
append 6
append 2
append 9
append 7

; In both cases, the pseudo IntToStr will fail with values greater than 9
getItem 3, output
display 'The 3rd element is: ', output+'0', 13, 10

getListSize output
display 'Number of elements in the list is: ', output+'0', 13, 10    
But perhaps this breaks a requirement over the list structure?
Post 20 Apr 2011, 02:53
View user's profile Send private message Reply with quote
SPTH



Joined: 24 Jul 2004
Posts: 91
SPTH
LocoDelAssembly wrote:
Code:
list       equ
list.count equ 0

macro append item
{
  match any, list \{ list equ list,item \}
  match , list \{ list equ item \}

; Keep count here so we don't have to make expensive re-calculations when needed
  rept 1 n:list.count+1\{list.count equ n\}
}
append 3
append 6
append 2
append 9

macro getItem index*, out* ; Index lower bound is 1. Exceeding upper bound returns last element
{
local _list

  match any, list \{_list equ any, END\}

  rept index\{
       match item=,any,_list\\{
             out equ item
             _list equ any
       \\}
  \}
}

macro getListSize out*
{
  match value, list.count\{out equ value\}
}

; In both cases, the pseudo IntToStr will fail with values greater than 9
getItem 3, output
display 'The 3rd element is: ', output+'0', 13, 10

getListSize output
display 'Number of elements in the list is: ', output+'0', 13, 10    
Is this what you need?


This is exacty what I need, thank you!
I tried to understand the code, the way you count is cool rept 1 n:list.count+1, counting one time starting from the desired value - clever how one works with that macro language. I really like such stuff :)

Unfortunatly I dont really get the main part:
Code:
  rept index\{
       match item=,any,_list\\{
             out equ item  ; at least this line is clear ;)
             _list equ any
       \\}
  \}
    


i see that you repeat it 'index'-times. and each time the _list will be decreased by the first element. But I dont get how this happens. Could you please give a short explanation?! What exactly is this match doing?

Ah I see there is a second solution. I'll analyse that one now!

Thanks alot to both of you! Fast answeres makes coding even more fun ;)
Post 20 Apr 2011, 03:14
View user's profile Send private message Reply with quote
SPTH



Joined: 24 Jul 2004
Posts: 91
SPTH
LocoDelAssembly wrote:
Still, your (or Tomasz's? or I didn't understand at all?) idea of using numbers could be better:
Code:
list       equ
list.count equ 0

macro append item
{
  rept 1 n:list.count+1\{
       list.count equ n
       list\#n equ item
  \}
}

macro getItem index*, out* ; Index lower bound is 1
{
  match value, list#index \{out equ value\}
}

macro getListSize out*
{
  match value, list.count\{out equ value\}
}

append 3
append 6
append 2
append 9
append 7

; In both cases, the pseudo IntToStr will fail with values greater than 9
getItem 3, output
display 'The 3rd element is: ', output+'0', 13, 10

getListSize output
display 'Number of elements in the list is: ', output+'0', 13, 10    
But perhaps this breaks a requirement over the list structure?


Haha this is exactly the workaround that I tried before posting here. I could not make it work - match does not like me so far... :)
Post 20 Apr 2011, 03:19
View user's profile Send private message Reply with quote
SPTH



Joined: 24 Jul 2004
Posts: 91
SPTH
The second solution with the definition of new symbols does not work if I will use it like this:

Code:
nnn equ 3
getItem nnn, output  
    


It gives an error: "Undefined symbol listnnn". The compiler somehow does not translate the value.

It works for the first solution - so I'll use the first one.

And I'm reading about forward and reverse now.

Thanks again!
Post 20 Apr 2011, 03:28
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17716
Location: In your JS exploiting you and your system
revolution
SPTH wrote:
The second solution with the definition of new symbols does not work if I will use it like this:

Code:
nnn equ 3
getItem nnn, output  
    


It gives an error: "Undefined symbol listnnn". The compiler somehow does not translate the value.
If you want to pass indirect values within a macro then you need to use match.
Code:
match abc,nnn {getItem abc, output}    
Post 20 Apr 2011, 03:56
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
SPTH wrote:
Could you please give a short explanation?! What exactly is this match doing?
On each step, item is set to the head element, the comma is discarded, and "any" is set to the reminder of the list.
So, suppose the index is two, then this would happen
Code:
;First iteration
any equ 6,2,9 ; <- The equ here doesn't really happen, it is just for the explanation
out equ 3
_list equ 6,2,9 ; Notice I'm using the exact value as "_list equ any" would be indirect and hence not representing the real behavior

; Second and last iteration
any equ 2,9
out equ 6 ; Overwrites previous item value (still recoverable with "restore item")
_list equ 2,9
    
Note that "any" is not a special word, you can use whatever you want (even nothing), and the last symbol receives all the unprocessed content (which in this case is everything after the first comma in _list). Note that if after the last "=something" you don't place a symbol, then match's input argument will have to end with that something, otherwise it won't match and hence the block won't be executed.

Hope I didn't make a mistake in the explanation.
Post 20 Apr 2011, 04:22
View user's profile Send private message Reply with quote
SPTH



Joined: 24 Jul 2004
Posts: 91
SPTH
LocoDelAssembly - I think I understand it now, got confused by the three variables.

OK, I have nearly finished what I want (filling a list and returning a random element) - but there is a problem.

In macro GetRndElement RndElement* , the RndNum cant be used as argument for getListItem...

This needs the whole code i guess to understand it, but its mainly copy-paste from here ;)

Code:
RndSymbol=%t AND 0xFFFFFFFF
macro NewRndSymbol
{
    RndSymbol = ((RndSymbol*214013+2531011) AND 0xFFFFFFFF)
}


macro getListSize list*, out*
{
    local start
    virtual
        start: db list
        out = $ - start
    end virtual
}


macro getListItem list*, index*, out* 
{
    local _list
    match any, list \{_list EQU any, END\}
    rept index
    \{
        match item=,any,_list
        \\{
            out EQU item
            _list EQU any
        \\}
    \}
}


FillList.list EQU
macro FillList number*
{
    db 0x1           ; this has to be written to the output every time it runs...

    match any, FillList.list \{ FillList.list EQU FillList.list,number \}
    match , FillList.list \{ FillList.list EQU number \}
}

macro GetRndElement RndElement*
{
    NewRndSymbol

    getListSize FillList.list, size
    RndNum EQU (RndSymbol MOD size)
    display 'RndNumber: ',RndNum+'0', 13,10
;    RndNum EQU 3                             ; If i uncomment this, it works!
;    match rnd, RndNum \{ getListItem FillList.list, rnd, RndElement \} ; not work eighter
    getListItem FillList.list, RndNum, RndElement
}



; Filling the list

FillList 'a'
FillList 'b'
FillList 'c'
FillList 'd'
FillList 'e'

; Listsize - works!
getListSize FillList.list, size
display 'ListSize: ',size+'0'
display 13,10

; Get 3rd List item - works!
num EQU 3
getListItem FillList.list, num, element
display 'list[',num+'0',']: ', element
display 13,10

; Get random list item
GetRndElement RndItem
display 'Element: ',RndItem
    


Any idea why there is an error message "Invalid value", and how this can be solved? Anything I tried did not work.

Thanks alot for your help!
Post 20 Apr 2011, 05:29
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Unfortunately, %t (and using "=" rather than equ or define) won't work with preprocessor features as them are interpreted at different stages.

Still, if the list will be of numbers or strings only and you can tolerate having the value available not earlier than the assembler stage then something like this could be done:
Code:
list       equ
list.count equ 0

macro append item
{
  match any, list \{ list equ list,item \}
  match , list \{ list equ item \}

; Keep count here so we don't have to make expensive re-calculations when needed
  rept 1 n:list.count+1\{list.count equ n\}
}

macro getItem index*, out* ; Index lower bound is 1. Exceeding upper bound returns last element
{
local _list

  match any, list \{_list equ any, END\}

  rept index\{
       match item=,any,_list\\{
             out equ item
             _list equ any
       \\}
  \}
}

macro getListSize out*
{
  match value, list.count\{out equ value\}
}

macro getRandomItem out* ; NOTE: Output only usable at the assembler stage
{
;assuming the list is made of numbers
virtual at 0
  dq list
  load output qword from ((%t shl 3) and $7FFF'FFFF) mod $
end virtual
}

append 3
append 6
append 2
append 9
append 7

; In both cases, the pseudo IntToStr will fail with values greater than 9
getRandomItem output
display 'The random element is: ', output+'0', 13, 10

getListSize output
display 'Number of elements in the list is: ', output+'0', 13, 10    


PS: And actually, lists of heterogeneous types would still be possible, but append would need an extra parameter to assist in type detection.
Post 20 Apr 2011, 06:10
View user's profile Send private message Reply with quote
SPTH



Joined: 24 Jul 2004
Posts: 91
SPTH
Hmm, ok i thought that something like that would be the cause of the problem.

Your solution works quite good (its only numbers, i just need that random elements late, ...).

The only thing is that I need to generate 100s of random elements from a list - and %t seems to change only every second. That means I need to include some kind of LCG or something like that (just as I did before). I hope this works with your solution too.

Unfortunatly I have no time at the moment, but I will try it in a few hours.

Thanks again!
Post 20 Apr 2011, 06:53
View user's profile Send private message Reply with quote
SPTH



Joined: 24 Jul 2004
Posts: 91
SPTH
I tried it now, it works very good, also with a LCG. And its much smaller than the direct attempt before.

Thanks for that!
Post 20 Apr 2011, 18:52
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-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.