; ================== source-file: _repcount.asm ======================
COMMENT ~
Purpose: Counters and FOR-loops in Assembly Language for Visual Prolog.

To compile: - Use Turbo Assembler (TASM) version 5 or higher, with
              the command-line:   TASM32 /p /z /w2 /m2 /ml %1.asm

Author: George A. Stathis (c) 2005.   
(Permission also granted to ENB Ltd, for use of this code).

License:
  All use of this code is permitted, without restrictions, provided that
  the author is mentioned in any applications making use of this code.

%%%%%%%%%%%% Visual Prolog Global Declarations:
GLOBAL PREDICATES
 nondeterm repcount(INTEGER initial_value,INTEGER out_value)
                      -(i,o) language c
 nondeterm repcount(INTEGER initialVal,INTEGER finalVal,INTEGER outVal)
                      -(i,i,o) language c
~
; =====================================================================
IDEAL       ; Use IDEAL mode, in Turbo Assembler 5.*
P586        ; Enable Pentium instructions
MODEL FLAT  ; Use Flat Memory Model (32-bit access)
CODESEG     ; Code-segment starts here
ALIGN 4     ; Use 4-byte alignment

public _repcount_0
public _repcount_1

extrn _RUN_Fail:near         ; Visual Prolog's "failure"
extrn _RUN_StackBTrack:near  ; Visual Prolog's "Stack BackTrack point"
extrn _RUN_JmpReturn1:near   ; Visual Prolog's "Return to Backtrack pt"

; =====================================================================
; Variant which acts like a general-purpose counter in an endless loop:
; =====================================================================
PROC _repcount_0 near            ; repcount(Initial_value,OUT) -(i,o)
ENTER        8,0                        
ARG minval:dword, outval:dword
LOCAL prev:dword
        mov  edx,[minval]     ; minimum value in EDX as counter (ARG 1)        
@@Lp0:  mov  ecx,[outval]     ; output value                    (ARG 2)
        mov  [ecx],edx        ; produce output
        inc  edx              ; increment counter EDX
        mov  [prev],edx       ; store resulting value in a local variable
        call _RUN_StackBTrack ; stack a backtrack point in Visual Prolog
        mov  edx,[prev]    ; restore the counter from the local variable
        or   eax,eax       ; check the result of "RUN_StackBTrack"
        jne  @@Lp0         ; if not zero, repeat!
; -----------------------------
        call _RUN_JmpReturn1  ; call Visual Prolog function 'JmpReturn'
LEAVE
ENDP _repcount_0


; ======================================================================
; Variant which acts like a "FOR-loop" between initial and final values:
; ======================================================================
PROC _repcount_1 near     ; repcount(InitValue,MaxValue,OUT) -(i,i,o)
ENTER        8,0                        
ARG minval:dword, maxval:dword, outval:dword
LOCAL prev:dword
        mov  edx,[minval] ; minimum value in EDX as counter (ARG 1)        
@@Lp0:  mov  ecx,[outval] ; output value                    (ARG 3)
        mov  [ecx],edx    ; produce output
        inc  edx          ; increment counter EDX
        mov  ecx,[maxval] ; maximum value in ECX            (ARG 2)
        cmp  edx,ecx      ; compare counter_value to max_value
        ja   @@XX         ; if max_value exceeded, exit with failure!
; -------------------------
        mov  [prev],edx   ; store the resulting value in local variable
        call _RUN_StackBTrack ; stack a backtrack point in Visual Prolog
        mov  edx,[prev]   ; restore the counter from the local variable
        or   eax,eax      ; check the result of "RUN_StackBTrack"
        jne  @@Lp0        ; if not zero, repeat!
; ----------------------------
        call _RUN_JmpReturn1 ; call Visual Prolog function 'JmpReturn'
@@XX:   call _RUN_Fail       ; call Visual Prolog's "fail"
LEAVE
ENDP _repcount_1

        END

; ================ VISUAL PROLOG TEST-PROGRAM: =================
%USAGE:   Compile the following as an "EASYWIN" project:

GLOBAL PREDICATES
  nondeterm repcount(INTEGER init_value,INTEGER out_value)
                        -(i,o) language c
PREDICATES
  test(INTEGER)

CLAUSES
  test(1):- repcount(1,X),
        random(100,Num), write(X,"th random number: ",Num), nl,
        write("PRESS ESCAPE to EXIT, any other key to go on!\n"),
        readchar(CH), CH = '\27', !.

  test(2):- repcount(1,10,X),
        random(100,Num), write(X,"th random number: ",Num), nl, fail.
  test(2).

GOAL
  write("\nFirst, testing repcount(Min,OUT) -(i,o):\n\n"),
  test(1), write("\nNow a test for repcount(Min,Max,OUT):\n"),
  test(2), readchar(_).