C-like for() statement using macros

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

C-like for() statement using macros

Post by counting_pine »

This is a 'CFOR' macro that on use, runs the 'start' statement and sets up a while loop. It also creates a corresponding 'CNEXT_' macro - which is used for running the 'step' and marking the end of the loop.

Unfortunately you cannot nest CFOR statements, because CNEXT_ can only hold one definition. On the plus side, the macro is designed to prevent nesting attempts from compiling:

- CFOR expects the CNEXT_ macro not to exist. If you try to nest CFOR (and the 'step' statement is different), you will get a Duplicated Definition error.
- CNEXT_ #undef's itself when used, ensuring that it can't be used afterwards without using CFOR again.

For convenience, a CNEXT #define is also included, to prevent having to put '()' after it.

A couple of examples:

Code: Select all

#macro CFOR(start,cond,step)
  #macro CNEXT_()
    step
    wend
    #undef CNEXT_
  #endmacro
start: while cond
#endmacro
#define CNEXT CNEXT_()

dim i as integer

CFOR(i = 0, i < 10, i += 1)
  print i
CNEXT
print

CFOR(i = 1, i <= 256, i shl= 1)
  print i
CNEXT
anonymous1337
Posts: 5494
Joined: Sep 12, 2005 20:06
Location: California

Re: C-like for() statement using macros

Post by anonymous1337 »

Excuse the formatting. I'm using https://www.jdoodle.com/execute-freebasic-online to write and test this with.

I'd consider 6 levels deep sufficient for most programs. If you're using this to assist with automated conversions, I would consider it...

Code: Select all

#macro CFOR(start,cond,step)
  #ifndef CNEXT_
      #macro CNEXT_()
        step
        wend
        #undef CNEXT_
      #endmacro
  #else
    #ifndef CNEXT2_
      #macro CNEXT2_()
        step
        wend
        #undef CNEXT2_
      #endmacro
      #else
    #ifndef CNEXT3_
      #macro CNEXT3_()
        step
        wend
        #undef CNEXT3_
      #endmacro
    #endif
    #endif
  #endif
start: while cond
#endmacro
#macro CNEXT_exec()
    #ifndef CNEXT2_
        CNEXT_()
    #else
        #ifndef CNEXT3_
            CNEXT2_()
            #else
        #ifndef CNEXT4_
            CNEXT3_()
        #endif
        #endif
    #endif
#endmacro
#define CNEXT CNEXT_exec()

dim i as integer
dim j as integer
dim k as integer

CFOR(i = 1, i < 3, i += 1)
    print i
    CFOR(j = 1, j < 3, j += 1)
        print i*j
        CFOR(k = 1, k < 3, k += 1)
            print i*j*k
        CNEXT
    CNEXT
CNEXT
print

CFOR(i = 1, i <= 256, i shl= 1)
  print i
CNEXT
Output:

Code: Select all

 1
 1
 1
 2
 2
 2
 4
 2
 2
 2
 4
 4
 4
 8

 1
 2
 4
 8
 16
 32
 64
 128
 256
Would be neat to look here: https://www.boost.org/doc/libs/1_45_0/l ... index.html

And do something like this: https://www.boost.org/doc/libs/1_45_0/l ... slots.html

But tbh that stuff is giving me a headache trying to reason about it. I *think* I comprehend the article itself, but I don't think I could actually implement it in a spare time's worth of experimentation.

EDIT: Skimming Boost's source code and it's surprisingly naive. I think what's above is close to the right approach. You can define more macros to help you uh... define more macros... so like this pattern can be abstracted out a bit, but that seems to only be useful for the purpose of having a mechanism for defining other recursive / repetitive macros. Not sure we need any more layers of abstraction for this...
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: C-like for() statement using macros

Post by counting_pine »

Hey, thanks anonymous1337, that’s a pretty neat extension of the idea. I didn’t think of that.
It’s interesting to see what the preprocessor can be capable of.
IchMagBier
Posts: 52
Joined: Jan 13, 2018 8:47
Location: Germany
Contact:

Re: C-like for() statement using macros

Post by IchMagBier »

I use python-like for loops in my codes. I guess that's easier to achieve.

Code: Select all

#define in(start,end) as integer=start to end

for i in(0,10)
	print i
next
dafhi
Posts: 1641
Joined: Jun 04, 2005 9:51

Re: C-like for() statement using macros

Post by dafhi »

nice one, counting_pine! .. atm i'm experimenting with

wfor(i, 1, 10)
wend
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: C-like for() statement using macros

Post by jj2007 »

I use this in my code:

Code: Select all

for i=0 to 10
   print i
next
dafhi
Posts: 1641
Joined: Jun 04, 2005 9:51

Re: C-like for() statement using macros

Post by dafhi »

fb don't let u for-next .members
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: C-like for() statement using macros

Post by paul doe »

jj2007 wrote:I use this in my code:

Code: Select all

for i=0 to 10
   print i
next
Indeed, but the point is to be able to evaluate the 'step' parameter, like C does:

Code: Select all

CFOR(i = 1, i <= 256, i shl= 1)
  print i
CNEXT

Code: Select all

#include <stdio.h>

int main( void )
{
	for( int i = 1; i <= 256; i <<= 1 )
	  printf( "%d\n", i );
  
  return( 0 );
}
Of course, I'd simply use a DO-LOOP construct, but talk about tastes... =D
Last edited by paul doe on Aug 21, 2018 15:23, edited 1 time in total.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: C-like for() statement using macros

Post by MrSwiss »

dafhi wrote:fb don't let u for-next .members
???
Don't understand the point you're trying to make.

Example for .member in For loop:

Code: Select all

Sub History.add_str( _                  ' add a new string (deleting oldest one, if needed)
    ByRef nst   As Const String _       ' string to add, read only
    )
    With This   ' always add new string at lower bound (aka: at the top, in a up-counting loop)
        If .psz(.ub) <> 0 Then DeAllocate(.psz(.ub))' kill the oldest string (free the memory)
        For m As Integer = .ub To .lb + 1 Step -1   ' copy ptr's values to new location (in array)
            .psz(m) = .psz(m - 1)       ' push all remaining, one position down (0 becomes 1 etc.)
        Next
        .psz(.lb) = Allocate(Len(nst) + 1)  ' allocate memory for the new string
        *.psz(.lb) = nst + Chr(0)       ' copy string data & terminator
    End With
End Sub
Excerpt from: History (a MRU Type)
dafhi
Posts: 1641
Joined: Jun 04, 2005 9:51

Re: C-like for() statement using macros

Post by dafhi »

Code: Select all

type t
    as long       i
    declare sub   mysub
End Type
sub t.mysub
    i = 1
    for i = 1 to 2
      
    Next
End Sub
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: C-like for() statement using macros

Post by MrSwiss »

Iterator can't be a .member (but: start / stop / step, are all OK).

Sorry, but to have the iterator in the type, makes no sense to me.
(it can be declared 'on the fly' in the For loop)
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: C-like for() statement using macros

Post by jj2007 »

paul doe wrote:

Code: Select all

CFOR(i = 1, i <= 256, i shl= 1)
Of course, I'd simply use a DO-LOOP construct, but talk about tastes... =D
Why do something simple if you have a chance to confuse your colleagues? ;-)

Code: Select all

  mov i,1
  .Repeat
	Print Str$(i), " "
	shl i, 1
  .Until i>256
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: C-like for() statement using macros

Post by deltarho[1859] »

I am reminded of the quip: Why use a sentence when a paragraph will do?
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: C-like for() statement using macros

Post by dodicat »

Using a label in a macro with repeat calls.
(The parsed fb code uses labels anyway for for loops.)
The scope is needed only for different variables, not for labels.

Code: Select all

 

#macro forloop(a,b,c,instruction)
scope
a
#define labl  label:
labl
instruction
c
if b then goto labl
#undef label
end scope
#endmacro


forloop(dim as long x=1,x<10,x+=1,print x;)
print

forloop(dim as long x=-1,x<=3,x+=1,print x^3)
print

forloop(dim as double d=1,d<12,d+=2,print d;tab(7);"Square root =  ";sqr(d))
sleep
print
   
dafhi
Posts: 1641
Joined: Jun 04, 2005 9:51

Re: C-like for() statement using macros

Post by dafhi »

the macro madman.

a little slower than for, except -O 3
Post Reply