;..............................................................................;
;
;        If - expression, test, value, goto
;
;   This macro implements an if construct. The expression will be evaluated,
; its value compared to the given value, and if the test succeeds execution
; continues at 'goto'. Otherwise execution will continue until an EndWhile
; macro is encountered.
;
;   The expression may be a register, simple variable, or complex expression.
; If the 'goto' label is preceeded by a '!' then it is assumed that a long
; branch is necessary.
;
; Sample calls:
;
;   If X,'<>',#50,DoneIf             - if x<>50 then goto DoneIf
;   If Var1,'=',Var2,!DoneIf         - if var1=var2 then branch long to DoneIf
;   If '(Var1.+Var2)','>',Var3,Quit  - if var1+var2>var3 then goto Quit
;
; The following test conditions are supported and must be quoted:
;
;   '=', '>', '>=', '<', '<=', '<>'
;
;   A complex expression must be quoted and placed in paranthesis to work
; correctly.
;
;..............................................................................;
          MACRO
&lab      IF_    &exp,&test,&value,&goto
&lab	; 
          lclc     &cc
          lclc     &first
		  lclc	&newexp
		  lclc &WorkAroundApplesBuggyAssembler
		  
		  
&newexp		setc	&exp

&first    setc	&substr(&newexp,1,1)
		IF	(&newexp = 'x') or (&newexp = 'y') or (&newexp = 'a') GOTO .register
		IF	(&newexp = 'X') or (&newexp = 'Y') or (&newexp = 'A') GOTO .register
		IF	(&first = '(') GOTO .expression
.simplevar
          lda      &newexp
          cmp      &value
		GOTO .dotest

          mexit
.expression
&newexp      setc	&substr(&newexp,2,&len(&newexp)-2)
          eval     &newexp
          cmp      &value
		GOTO .dotest

.register
&WorkAroundApplesBuggyAssembler setc &concat('cp',&newexp)
.;          cp&newexp   &value		**SIGH!!!!!!**
		&WorkAroundApplesBuggyAssembler &value
		GOTO .dotest

.dotest
		IF (&test = '=') GOTO .doeq
		IF (&test = '<') GOTO .dolt
		IF (&test = '>=') GOTO .doge
		IF (&test = '<>') GOTO .done
		IF (&test = '<=') GOTO .dole
		IF (&test = '>') GOTO .dogt
		IF (&test = '²') GOTO .dole
		IF (&test = '³') GOTO .doge
		IF (&test = '­') GOTO .done
		macerr 'IF_: unrecognized comparison Ò',&test,'Ó (make sure it's not in quotes).'
          mexit
.doeq
&cc       setc     'eq'
		GOTO .goto

.dolt
&cc       setc     'lt'
		GOTO .goto

.doge
&cc       setc     'ge'
		GOTO .goto

.done
&cc       setc     'ne'
		GOTO .goto

.dole
&cc       setc     'le'
		GOTO .goto

.dogt
&cc       setc     'gt'
		GOTO .goto

          mexit
.goto
          jump     &cc,&goto
          mexit
          MEND
;..............................................................................;
;
;         jump       - Branch on condition code to short/long label
;
; Generic jump macro. If label starts with ! will do long jump else short.
;
;..............................................................................;
          MACRO
&lab      jump     &cc,&label
&lab	; 
          lclc     &a

&a        setc	&substr(&label,1,1)
		IF (&a = '!') GOTO .long
          b&cc    &label
          mexit
.long
&a        setc	&substr(&label,2,&len(&label)-1)
          j&cc     &a
          mexit
          MEND

;..............................................................................;
;
;        While - expression, test, value, resume
;
;   This macro implements a while construct. The expression will be evaluated,
; its value compared to the given value, and if the test fails execution will
; continue at 'resume'. Otherwise execution will continue until an EndWhile
; macro is encountered.
;
;   The expression may be a register, simple variable, or complex expression.
; If the 'resume' label is preceeded by a '!' then it is assumed that a long
; branch is necessary.
;
; Sample calls:
;
;   While X,'<>',#50                    - loop until x register = 50
;   While Var1,'=',Var2                 - loop until var1<>var2, then jump long
;   While '(Var1.+Var2)','>',Var3       - loop until var1+var2<=var3
;
; The following test conditions are supported and must be quoted:
;
;   '=', '>', '>=', '<', '<=', '<>'
;
;   A complex expression must be quoted and placed in paranthesis to work
; correctly.
;
; Note: Up to 10 levels of local while nesting are supported.
;
;..............................................................................;
               MACRO
&lab           while_ &exp,&test,&value
&lab	; 

               lclc     &long
.;		IF	(&nbr(&wcnt) > 0) GOTO .past
               gbla     &wcnt
               gblc     &while[10]
               gbla     &wnum[10]
			   
			IF (&wcnt = 10) THEN
			 	macerr 'Too many levels of nested While_'s (max. 10).'
				mexit
			ENDIF
.past
&wcnt          seta     &wcnt+1
&while[&wcnt]  setc     &concat('~A',&i2s(&sysindex))
&wnum[&wcnt]   seta     &wnum[&wcnt]+1
~A&i2s(&sysindex)		; 
               if_       &exp,&test,&value,&concat('~B',&i2s(&sysindex))
               brl      &concat('~W',&concat(&i2s(&wcnt),&i2s(&wnum[&wcnt])))
~B&i2s(&sysindex)		; 
               mexit
               MEND
;..............................................................................;
;
;        EndWhile
;
;   This macro will return control back to the latest while loop encountered.
;..............................................................................;
               MACRO
&lab           endwhile_
&lab	; 

               gbla     &wcnt
               gblc     &while[10]
               gbla     &wnum[10]

			IF (&wcnt = 0) THEN
				macerr 'Unexpected EndWhile_.'
				mexit
			ENDIF

               brl      &while[&wcnt]
~W&i2s(&wcnt)&i2s(&wnum[&wcnt])	; 
&wcnt          seta     &wcnt-1
               mexit
               MEND
;..............................................................................;
;
;          Repeat
;
;    This macro will set a label to the start of a repeat/until loop for the
; current lexical level.
;..............................................................................;
               MACRO
&lab           repeat_
&lab	; 
.;		IF	(&nbr(&rcnt) > 0) GOTO .past
               gbla     &rcnt
               gblc     &repeat[10]
.past
&rcnt          seta     &rcnt+1
&repeat[&rcnt] setc     &concat('~A',&i2s(&sysindex))
~A&i2s(&sysindex)	; 
               mexit
               MEND

;..............................................................................;
;
;          Until      &exp,&test,&value
;
;    If the expression evaluates to true then exit else return to the
; last seen repeat.
;..............................................................................;
               MACRO
&lab           until_    &exp,&test,&value
&lab	; 
               gbla     &rcnt
               gblc     &repeat[10]
               if_       &exp,&test,&value,&concat('~B',&i2s(&sysindex))
               brl      &repeat[&rcnt]
~B&i2s(&sysindex)	; 
&rcnt          seta     &rcnt-1
               mexit
               MEND

;..............................................................................;
;
;          FOR   variable, initial value, final value, step size
;
;   This macros implements a primitive FOR type construct. The specified
; variable may be either a register ('X','Y','A') or a memory location. The
; variable is currently assumed to be of word size. It will get loaded with
; the initial value specified. Execution will loop between the FOR and NEXT
; macros until the variable exceeds the final value, each pass through the
; loop the variable or register as the case may be is offset by the given
; step size. Step size may be positive or negative but must be word size.
;..............................................................................;
                 MACRO
&lab             for_        &var,&init,&final,&step
&lab	; 
.;		IF	(&nbr(&fcnt) > 0) GOTO .past
                 gbla       &fcnt
                 gblc       &for[10]
                 gblc       &forstep[10]
                 gblc       &forfinal[10]
                 gblc       &forvar[10]
.past
&fcnt            seta       &fcnt+1
&for[&fcnt]      setc       &concat('~A',&i2s(&sysindex))
&forstep[&fcnt]  setc       &step
&forfinal[&fcnt] setc       &final
		IF	(&var = 'x') or (&var = 'X') GOTO .initx
		IF	(&var = 'y') or (&var = 'Y') GOTO .inity
                 lda        &init
&forvar[&fcnt]   setc       'A'
		IF	(&var = 'a') or (&var = 'A') GOTO .quit
                 sta        &var
&forvar[&fcnt]   setc       &var
		GOTO .quit

.initx
                 ldx        &init
&forvar[&fcnt]   setc       'X'
		GOTO .quit

.inity
                 ldy        &init
&forvar[&fcnt]   setc       'Y'
.quit
~A&i2s(&sysindex)	; 
                 mexit
                 MEND
;..............................................................................;
;
;          NEXT
;
;    See description under FOR.
;
;..............................................................................;
                 MACRO
&lab             next_
&lab	; 
                 gbla       &fcnt
                 gblc       &for[10]
                 gblc       &forstep[10]
                 gblc       &forfinal[10]
                 gblc       &forvar[10]
		IF	(&forvar[&fcnt] = 'A') GOTO .nextA
		IF	(&forvar[&fcnt] = 'X') GOTO .nextX
		IF	(&forvar[&fcnt] = 'Y') GOTO .nextY
                 lda        &forvar[&fcnt]
		GOTO .nextA

.nextX
                 txa
		GOTO .nextA

.nextY
                 tya
.nextA
		IF	(&forstep[&fcnt] = '#1') GOTO .incA
		IF	(&forstep[&fcnt] = '#-1') GOTO .decA
                 clc
                 adc        &forstep[&fcnt]
		GOTO .donextA

.decA
                 dec        a
		GOTO .donextA

.incA
                 inc        a
.donextA
		IF	(&forvar[&fcnt] = 'X') GOTO .setx
		IF	(&forvar[&fcnt] = 'Y') GOTO .sety
		IF	(&forvar[&fcnt] = 'A') GOTO .checkit
                 sta        &forvar[&fcnt]
		GOTO .checkit

.setx
                 tax
		GOTO .checkit

.sety
                 tay
		GOTO .checkit

.checkit
                 cmp        &forfinal[&fcnt]
                 bgt        ~F&i2s(&sysindex)
                 brl        &for[&fcnt]
.quit
~F&i2s(&sysindex)	; 
&fcnt            seta       &fcnt-1
                 mexit
                 MEND
