Fundamentals: Branching and Looping

Branching and Looping are two very common and very powerful logic control operations. With them the programmer can control what macro commands get executed and which macro commands do not, they allow the program to jump to different parts of the macro, and they allow some parts of the macro to be run multiple times in succession.

Conditional Branching

The IF, ELSEIF, ELSE, ENDIF construction is used for conditional branching. It allows the macro to make a decision about which block of code to run, based on a condition.

IF statements are used when macro code should only be run if a given condition exists.

An IF block has the following format:

IF (evaluation)
	... macro code to run if evaluation is true
ELSEIF (evaluation)
	... macro code to run if evaluation is true
ELSE
   ... macro code to run if evaluation is false
ENDIF

The evaluation, within the parenthesis, must result in a TRUE or FALSE answer. The evaluation is based on the supported list of condition-test operators.

When you use a IF() check, the ENDIF statement is required.

Use any of the following condition-test operators.

Operator Description
= is equal to
<> is not equal to
< is less than
> is greater than
<= is ess than or equal to
>= is greater than or equal to
,AND AND operator (Be sure to include the comma). Example:\

IF (#S=1 ,AND #T=0)
Do something
ENDIF

The IF block only runs if both #S=1 and #T=0.

&& Modern syntax for ",AND". Example:

IF (#S=1 && #T=0)
Do something
ENDIF

The IF block only runs if both #S=1 and #T=0.

,OR OR operator (Be sure to include the comma). Example:\

IF (#S=1 ,OR #T=0)
Do something
ENDIF

The OR block runs if either #S=1 or #T=0.

|| Modern syntax for ",OR". Example:

IF (#S=1 || #T=0)
Do something
ENDIF

The OR block runs if either #S=1 or #T=0.

If the evaluation inside the parenthesis test true, SmartCAM performs the MCL command that immediately follows the IF() command.

If the evaluation tests false, SmartCAM performs the MCL command immediately following the optional ELSE command or the MCL command immediately after the ENDIF, if the ELSE block was not provided.

// Check value of #ITST, display message if value is 0 or not.
			
INTEGER:#ITST=0
IF(#ITST = 0)
   PAUSE[TX="#ITST is set to 0."]
ELSE
   PAUSE[TX="#ITST is not set to 0."]
ENDIF

When this macro is run, the message box will contain the text: #ITST is set to 0.

As mentioned previously, the IF statement checks whether the expression evaluates to True or False. In this case, #ITST was set to 0, so it evaluated as True. Therefore, the macro command right after the IF statement is run and the appropriate message box contents are displayed.

Change the macro and instead use: INTEGER:#ITST=1

Run the macro and this time the expression evaluates to false. Therefore, the message that is displayed is: #ITST is not set to 0.

The ELSE block is optional. If the program needs to run code if a given condition exists, but does not need to do anything if it does not exist, then the ELSE block is not needed.

// Check value of #IST, display message if value is 0, otherwise do nothing
			
INTEGER:#ITST=0
IF (#ITST = 0)
   PAUSE[TX="#ITST is set to 0."]
ENDIF

In this case, since #ITST is set to 0, the message is display. If #ITST is set to an integer other than 0, nothing will be displayed.

The ELSEIF construction allows the programmer to do multiple checks in a single IF block. The syntax is:

IF (evaluation)
   ... macro code to run if evaluation is true
ELSEIF (another evaluation)
   ... macro code to run if 2nd evaluation is true
ELSE
   ... macro code to run if first evaluation is false
ENDIF

Consider the case where the program needs to check and see whether a string variable contains a specific string, but there are multiple possible responses.

// Check for orbit location and return planet name

// Value of ORBIT can be strings: one, two, three, four, five, six, seven, or eight			
STRING:#ORBIT="three"
STRING:#PLANET

IF (#ORBIT="one")
   #PLANET="Mercury"
ELSEIF (#ORBIT="two")
   #PLANET="Venus"
ELSEIF (#ORBIT="three")
   #PLANET="Earth"
ELSEIF (#ORBIT="four")
   #PLANET="Mars"
ELSEIF (#ORBIT="five")
   #PLANET="Jupiter"
ELSEIF (#ORBIT="six")
   #PLANET="Saturn"
ELSEIF (#ORBIT="seven")
   #PLANET="Uranus"
ELSEIF (#ORBIT="eight")
   #PLANET="Neptune"
ELSE
   #PLANET="World"
ENDIF

PAUSE[TX="Hello " + #PLANET]

When run, a message box with "Hello Earth" will be displayed. If the contents of #ORBIT is changed to one of the eight possible strings, the other planet names are used. If the variable does not contain one of the eight possible strings, the message box contains "Hello World".

For string comparisons, you can also use the STREQUAL() macro function. With STREQUAL(), the two strings to compare are provided as arguments. The following two comparisons are the same.

STRING:#A="One"

IF (#A = "One")
   PAUSE[TX="String is Matched"] 
ENDIF

IF (STREQUAL(#A, "One"))
   PAUSE[TX="String is Matched"]
ENDIF

Both string comparisons are case-sensitive. So checking "One" against "one" will not match, as the cases of the two strings to not exactly match.

Expression with Multiple evaluations

The expression can include multiple evaluations, with the overriding rule that the sum total of the evaluations should result in either True or False.

INTEGER:#I1=0
DECIMAL:#D1=3.14

//  Display a message if #T1 is 0 and #D1 is greater than 3.0
IF(#T1=0 && #D1 > 3.0)
   PAUSE[TX="Expression is true"]
ENDIF

The && characters are called logical evaluators and they stand for "AND". The expression is saying if #T1 is equal to 0 AND #D1 is greater than 3.0, then display the message. In this example both subexpressions evaluated to True so the full expression evaluated as true.

INTEGER:#I1=0
DECIMAL:#D1=13.0

//  Display a message if #T1 is 0 and #D1 is greater than 3.0
IF(#T1=0 && #D1 < 12.0)
   PAUSE[TX="Expression is true"]
ENDIF

For this example, the value of #D1 is changed to 13 and the second half of the expression is changed to test to see if #D1 is less than 12. When running this macro, no message will be displayed. While #T1 is equal to 0, #D1 is not less than 12; therefore, the entire expression evaluates to False.

There are cases where you have multiple checks, but only care whether one or the other subexpression evaluates as true. These use the || logical evaluator, which stands for OR.

INTEGER:#I1=0
DECIMAL:#D1=13.0

//  Display a message is #T1 is 0 or #D1 is greater than 3.0
IF(#T1=0 || #D1 < 12.0)
   PAUSE[TX="Expression is true"]
ENDIF

This is the same expression as above, except the logical evaluator is changed to OR. In this case the message is displayed. The check is to see whether #T1=0 OR #D1 < 12; while #D1 is false, #T1 is true and thus the entire expression is true.

You can nest up to 32 IF() and WHILE() checks within a macro.

Conditional Looping

The WHILE, ENDW construction is used to continually execute a block of statements until a particular condition is met. It is useful in cases where the program needs to repeat a series of steps several times; such as searching the process model data list for particular elements or element types, or for creating repeating elements.

A WHILE block has the following format:

WHILE (evaluation)
   ... macro code to run while evaluation is true
ENDW

The evaluation, within the parenthesis, must result in a TRUE or FALSE answer. The evaluation is based on the supported list of condition-test operators. When the evaluation is true, the block of macro code between the WHILE and ENDW statements is run. When the ENDW statement is reached, the macro jumps back up to the WHILE statement and re-checks the expression, if the expression is still True, the block of code will be run again. When the expression is false, the block of code is skipped and execution continues on the first command after the ENDW statement. When WHILE() is used, the ENDW statement is required, to tell SmartCAM where the end of the WHILE() statement commands resides.

Expression evaluation works exactly the same as it does for the IF statement.

Be sure that the comparison arguments, in the WHILE() statement, eventually will test as FALSE. An endless loop occurs if the argument always tests true.

// A simple counter. Starts at zero and leaves the loop at five
		
INTEGER:#ICOUNTER=0
			
WHILE(#ICOUNTER < 5)
   #ICOUNTER = #ICOUNTER + 1
ENDW
PAUSE[TX="ICOUNTER is " + ITOA(#ICOUNTER)]

When run, the message box text will be: ICOUNTER is 5.

ICOUNTER starts at 0 and then enters the WHILE loop. Each time through the loop the value of the counter is incremented by one. On the fifth pass through the loop the value of ICOUNTER reaches 5. At this point ICOUNTER is no longer less than 5 and therefore the expression evaluates as False. So the loop is ended and the next line run is the PAUSE statement.

Since the expression is evaluated before the loop is run, there is a chance the code in between the WHILE and ENDW statements is never run.

INTEGER:#ICOUNTER=6
			
WHILE(#ICOUNTER < 5)
   #ICOUNTER = #ICOUNTER + 1
ENDW
PAUSE[TX="ICOUNTER is " + ITOA(#ICOUNTER)]

This is the same example as above, except the initial seed value of ICOUNTER is set to six. In this instance the loop is never run, ICOUNTER is not less than 5 so the expression is evaluated to false. The macro jumps to the first statement after the ENDW statement and runs from there.

Unconditional Branching

The GOTO, @LABEL construction is used to cause an unconditional branch or jump to another section of a macro program. When a GOTO command is encountered, SmartCAM jumps to the referenced label and continues to process macro commands from there. The macro commands between the GOTO and the LABEL are not run.

GOTO is called an unconditional branch because unlike the IF and WHILE commands, there is no expression to evaluate.

A GOTO command has the following format:

GOTO(LABEL)
   ... macro code that is jumped over
@LABEL
   ... macro code that is run

GOTO is often used to jump out of a WHILE loop before the expression evaluates to false or to jump to an area to gracefully exit a macro when an error is encountered.

INTEGER:#ICNTR=0

//	This is an infinite loop - it will run forever
WHILE(1)
   #ICNTR = #ICNTR + 1
   
   //	When ICNTR > 100 jump out of infinite loop
   IF (#ICNTR > 100)
      GOTO(DONE)
   ENDIF
ENDW

@DONE

In this example, the WHILE loop will run forever. In the loop the variable ICNTR gets incremented by one on each loop. The IF expression checks to see if ICNTR is greater than 100, if so, it used GOTO to jump out of the loop down to the @DONE label. At which time, the macro ends.

The WHILE(1) is a little trick. In SmartCAM TRUE is defined as 1 and FALSE as 0. So just having the number "1" in the expression always evaluates to TRUE.

Related Topics

Arrays

Strings

Macro Development Fundamentals Overview

SmartCAM Automation Overview