News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Non-rejecting loops

Started by jj2007, January 25, 2014, 06:09:07 AM

Previous topic - Next topic

jj2007

While-Wend loops are rejecting, Repeat-Until loops are not.

So far, so trivial. But what about for .. next loops? I thought googling would help, but maybe I'm using the wrong terms. Is there a more technical term than rejecting/non-rejecting loop?

Gfa and VB use rejecting loops. VB example:

Sub TestForLoop()
    Debug.Print "Start"
    For cols = 0 To -1
        Debug.Print Str$(cols)
    Next
    Debug.Print "End"
End Sub


A C loop like for (ct=1;ct<1;ct++){myvar+=1;} is also rejecting, but that case is imho not fully comparable.

What about FreeBasic and PB?

hutch--

If its only the semantics, PB has a DO / LOOP where you set your own conditionals.

DO WHILE (your condition)
LOOP
---
DO
LOOP WHILE (your condition)

jj2007

Thanks, Hutch.

The PBCC page says this:
QuoteFOR Counter = start TO stop [STEP increment]
NEXT
The body of the loop is skipped altogether if the initial value of Counter is greater than stop

FreeBasic is a bit cryptic, "Putting a larger number first will not make a for-next loop count backwards", but that seems to mean it's rejecting, too.

PureBasic does not give info ::)

Anyway, it seems that rejecting is pretty much standard...

Here is a for loop in VS C++ 2010 Express:

        ; for (ct=0x1111;ct<0x2222;ct++){myvar+=0x3333;}
        mov ct, 1111h
        jmp L2
        align 4
L1:     mov eax, ct
        add eax, 1
        mov ct, eax
L2:     cmp ct, 2222h
        jge short L3
        mov eax, myvar
        add eax, 3333h
        mov myvar, eax
        jmp L1
L3:


Same with Pelles C:

        mov ct, 1111h
        jmp L2
        align 4
L1:     add myvar, 3333h
        inc ct
L2:     cmp ct, 2222h
        jl L1

MichaelW

Would not the key difference be in where the exit condition is tested? I think the correct terminology is pre-test loop and post-test loop.

dim as integer i

asm while_wend:
while i < 2
    i += 1
wend

asm do_while_loop:
do while i < 2
    i += 1
loop

asm do_loop_until:
do
   i += 1
loop until i = 2

asm for_next:
for i = 0 to 2
next


.intel_syntax noprefix

#test.bas' compilation started at 19:34:39 (FreeBASIC 0.90.1)

.section .text
.balign 16

.globl _main
_main:
push ebp
mov ebp, esp
and esp, 0xFFFFFFF0
sub esp, 8
push ebx
push esi
push edi
mov dword ptr [ebp-4], 0
call ___main
push 0
push dword ptr [ebp+12]
push dword ptr [ebp+8]
call _fb_Init@12
.Lt_0002:
mov dword ptr [ebp-8], 0
while_wend:
.Lt_0004:
cmp dword ptr [ebp-8], 2
jge .Lt_0005
inc dword ptr [ebp-8]
jmp .Lt_0004
.Lt_0005:
do_while_loop:
.Lt_0006:
cmp dword ptr [ebp-8], 2
jge .Lt_0007
inc dword ptr [ebp-8]
jmp .Lt_0006
.Lt_0007:
do_loop_until:
.Lt_0008:
inc dword ptr [ebp-8]
.Lt_000A:
cmp dword ptr [ebp-8], 2
jne .Lt_0008
.Lt_0009:
for_next:
mov dword ptr [ebp-8], 0
.Lt_000E:
.Lt_000C:
inc dword ptr [ebp-8]
.Lt_000B:
cmp dword ptr [ebp-8], 2
jle .Lt_000E
.Lt_000D:
.Lt_0003:
push 0
call _fb_End@4
mov eax, dword ptr [ebp-4]
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret
#test.bas' compilation took 0.0004873414805022236 secs

Well Microsoft, here's another nice mess you've gotten us into.

hutch--

JJ,

I am not exactly sure what you are after, something like a code design to match the semantics of FOR / NEXT ? I tend to agree with Michael on where the test is performed in the instruction sequence.

Simple example of the loops but not sure it matches what you are after.


IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                      Build this template with "CONSOLE ASSEMBLE AND LINK"
ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include\masm32rt.inc

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    LOCAL cntr  :DWORD
    LOCAL lcnt  :DWORD

  ; ***********************************************

    mov cntr, 0
    mov lcnt, 100

  lp1:              ; one iteration test on exit.
    add cntr, 1
    mov eax, lcnt
    cmp cntr, eax
    jbe lp1
   
  ; ***********************************************

    mov cntr, 0
    mov lcnt, 100
    jmp inhere

  lp2:              ; no iteration test on exit.
    add cntr, 1
  inhere:
    mov eax, lcnt
    cmp cntr, eax
    jbe lp2

  ; ***********************************************

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start

jj2007

Quote from: hutch-- on January 25, 2014, 01:39:56 PM
JJ,

I am not exactly sure what you are after, something like a code design to match the semantics of FOR / NEXT ?

Yes, of course - code design to match the typical Basic For ... Next loop (example here).

I just was not sure what is the Basic standard:
- reject if begin>end, as in While ... Wend
- dive in once even if begin>end, as in Repeat ... Until

It seems that most Basic dialects reject, i.e. use the While ... Wend design; however, Michael's example is confusing me in this respect:

for_next:
mov dword ptr [ebp-8], 0
.Lt_000E:
inc dword ptr [ebp-8]
.Lt_000B:
cmp dword ptr [ebp-8], 2
jle .Lt_000E


This is FreeBasic, right?

MichaelW

Quote from: jj2007 on January 25, 2014, 02:27:06 PM
This is FreeBasic, right?

Yes, the most recent release:

http://www.freebasic.net/forum/viewtopic.php?f=1&t=21382

Compiled with the GAS backend code emitter:

http://www.freebasic.net/wiki/wikka.php?wakka=CompilerOptgen
Well Microsoft, here's another nice mess you've gotten us into.

Gunther

The for next loop is a pure counting loop, not only in BASIC. By the way, is FreeBasic worth a try?

Gunther
You have to know the facts before you can distort them.

jj2007

Quote from: MichaelW on January 25, 2014, 08:22:06 PM
Yes, the most recent release

Mystery solved - it's a clever compiler which drops the pre-test when used with two immediate integers. With variables, the test is there:

jmp short 004015C5
...
jmp short 00401604


loopStart=0
loopEnd=2

asm int 3
asm nop
asm for_next:
for i = loopStart to loopEnd
  print "test 0 to 2"
next

loopStart=2
loopEnd=0
asm int 3
asm nop
asm for_next2:
for i = loopStart to loopEnd
  print "test 2 to 0"
next


... translates to ...

0040158E    ³.  C745 F4 00000000  mov dword ptr [ebp-0C], 0
00401595    ³.  C745 F0 02000000  mov dword ptr [ebp-10], 2
0040159C    ³.  CC                int3
0040159D    ³.  90                nop
0040159E    ³.  8B45 F4           mov eax, [ebp-0C]
004015A1    ³.  8945 F8           mov [ebp-8], eax
004015A4    ³.  8B45 F0           mov eax, [ebp-10]
004015A7    ³.  8945 EC           mov [ebp-14], eax
004015AA    ³. EB 19             jmp short 004015C5
004015AC    ³>  6A 01             Úpush 1
004015AE    ³.  6A 0B             ³push 0B                        ; ÚArg2 = 0B
004015B0    ³.  68 04504000       ³push offset 00405004           ; ³Arg1 = ASCII "test 0 to 2"
004015B5    ³.  E8 36010000       ³call 004016F0                  ; ÀLoopsMW.004016F0
004015BA    ³.  50                ³push eax
004015BB    ³.  6A 00             ³push 0
004015BD    ³.  E8 0E020000       ³call 004017D0
004015C2    ³.  FF45 F8           ³inc dword ptr [ebp-8]
004015C5    ³>  8B45 EC           +mov eax, [ebp-14]
004015C8    ³.  3945 F8           ³cmp [ebp-8], eax
004015CB    ³. 7E DF             Àjle short 004015AC
004015CD    ³.  C745 F4 02000000  mov dword ptr [ebp-0C], 2
004015D4    ³.  C745 F0 00000000  mov dword ptr [ebp-10], 0
004015DB    ³.  CC                int3
004015DC    ³.  90                nop
004015DD    ³.  8B45 F4           mov eax, [ebp-0C]
004015E0    ³.  8945 F8           mov [ebp-8], eax
004015E3    ³.  8B45 F0           mov eax, [ebp-10]
004015E6    ³.  8945 EC           mov [ebp-14], eax
004015E9    ³. EB 19             jmp short 00401604
004015EB    ³>  6A 01             Úpush 1
004015ED    ³.  6A 0B             ³push 0B                        ; ÚArg2 = 0B
004015EF    ³.  68 10504000       ³push offset 00405010           ; ³Arg1 = ASCII "test 2 to 0"
004015F4    ³.  E8 F7000000       ³call 004016F0                  ; ÀLoopsMW.004016F0
004015F9    ³.  50                ³push eax
004015FA    ³.  6A 00             ³push 0
004015FC    ³.  E8 CF010000       ³call 004017D0
00401601    ³.  FF45 F8           ³inc dword ptr [ebp-8]
00401604    ³>  8B45 EC           +mov eax, [ebp-14]
00401607    ³.  3945 F8           ³cmp [ebp-8], eax
0040160A    ³. 7E DF             Àjle short 004015EB

dedndave

i recall that IBM BASIC had FOR..TO..STEP..NEXT
you could set the STEP to a negative value if you wanted to run backwards
FOR N=10 TO 1 STEP -1
...
NEXT

MichaelW

Quote from: Gunther on January 25, 2014, 09:20:59 PM
By the way, is FreeBasic worth a try?
I think so, if you like the BASIC syntax, or at least the FreeBASIC version of it that incorporates multiple C-like features.

Well Microsoft, here's another nice mess you've gotten us into.

Gunther

Michael,

Quote from: MichaelW on January 26, 2014, 12:13:38 AM
I think so, if you like the BASIC syntax, or at least the FreeBASIC version of it that incorporates multiple C-like features.

thank you for the answer. Can one link in external assembly language procedures or is to use the inline assembler?

Gunther
You have to know the facts before you can distort them.

MichaelW

Quote from: Gunther on January 26, 2014, 03:22:39 AM
Can one link in external assembly language procedures or is to use the inline assembler?

Either, the Win32 and Linux ports use stdcall as the default and the DOS port uses cdecl, and even with the GCC backend you can use Intel syntax for inline assembly, along with GAS macros, directives, etc.
Well Microsoft, here's another nice mess you've gotten us into.

Gunther

Michael,

Quote from: MichaelW on January 26, 2014, 05:15:49 AM
Either, the Win32 and Linux ports use stdcall as the default and the DOS port uses cdecl, and even with the GCC backend you can use Intel syntax for inline assembly, along with GAS macros, directives, etc.

that's good news. I'll give it a try.

Gunther
You have to know the facts before you can distort them.

jj2007

Quote from: dedndave on January 25, 2014, 09:52:44 PM
i recall that IBM BASIC had FOR..TO..STEP..NEXT
you could set the STEP to a negative value if you wanted to run backwards
FOR N=10 TO 1 STEP -1
...
NEXT


Most Basic dialects do have STEP. I've looked into that, it would be feasible for MasmBasic's For ... Next loop, but it's a bit complex.

However, you gave me a REALLY good idea:

  fld xInit                       ; REAL8 123.456 on FPU
  fstp x1
  .Repeat
        fld x1
        fadd FP8(0.0005)          ; add 0.0005 to x1 (initially 123.456)
        fstp x1
        PrintLine Str$(x1)
  .Until IsTrue(x1 ge x2)        ; until x1 greater or equal x2 = 123.457


Works like a charm, and allowed are eq, ne, lt, gt, le, ge, i.e. same notation as in the macro language (of course, <, >, <>, <= and >= are off limits because of Masm's bad habit to treat <> as string delimiters...)

Testbed attached.