More Conditionals and Loops

The previous chapter introduced the If conditional and the While…Wend loop. This chapter introduces the following control structures, which are typically useful in more complex macros:

The For…Next Loop

You use the For…Next loop when you want to carry out a group of instructions a specific number of times. Here is the syntax (the arguments in brackets are optional):

For CounterVariable = Start To End [Step Increment]
Series of instructions
Next [CounterVariable]

Word carries out the instructions between For and Next as many times as it takes for the CounterVariable to increment from the Start value to the End value. The CounterVariable is incremented each time Word runs the Next instruction following the instructions. The Increment indicates how much to increment the counter; if this is omitted, as is often the case, the counter is incremented by 1.

Examples

The following example displays in the status bar the numbers from 1 to 12, one at a time:


For dozen = 1 To 12            'Loop 12 times
    Print dozen                'Display the value in the status bar
Next dozen                    'Return to the For statement to repeat loop

The initial value of dozen is 1, as set in the For instruction. During the first iteration, the Print statement displays 1 (the value of dozen) in the status bar; during the next iteration, it displays 2; during the next, 3; and so on until month reaches 12 — the end of the loop and the last number displayed in the status bar.

The following example creates a document with a sample sentence formatted in each available font:


For count = 1 To CountFonts()        'Loop for the number of fonts
    fname$ = Font$(count)            'Place a font name in "fname$"
    Font fname$                        'Apply formatting with this font
    Insert "This is " + fname$ + "."    'Insert sentence
    InsertPara                        'Insert paragraph mark
Next count

The CountFonts() function returns the number of available fonts. Because this value is the end value of the loop, the number of times the loop will repeat is equivalent to the number of available fonts. The Font$() function returns the name of the current font from the list of available fonts. In the example, the instruction Font$(count) returns the font whose position in the list of fonts corresponds to the value of count.

Several functions begin with "Count" and work much like CountFonts() does: They return the number of macros, AutoText entries, styles, and so on. These functions are often used to control For…Next loops just as CountFonts() does in the previous example.

You can nest a For…Next loop by placing it within another For…Next loop. The following example uses a nested loop to create a simple calendar based on a 360-day year:


For months = 1 To 12             'Loop 12 times
    For days = 1 To 30            'Loop 30 times
        Insert Str$(days)         'Insert "days" as a string
    Next days                    'Return to "For days = 1..."
    InsertPara                    'Insert a paragraph mark
Next months                        'Return to "For months = 1..."

The outside loop repeats 12 times, corresponding to the months of the year. Then, for each month, the inside loop repeats for the 30 days in the month. The Insert instruction uses the Str$() function to convert the value stored in the numeric variable day into a string, then inserts it into a document (you cannot use the Insert statement to insert a numeric value).

You can set up For¼Next statements in many ways. The following table provides some examples of different start and end values and their possible increment values.

Example

Result

For dozens = 0 To 144 Step 12

The variable dozens increments from 0 (zero) to 144 in steps of 12.

For countdown = 10 To 1 Step -1

The variable countdown decrements from 10 to 1 in steps of –1.

For loop = start To finish Step size

The variable loop increments or decrements from the value of the variable start to the value of the variable finish in steps equal to the variable size.

For count = count To count + 10

The initial value of the variable count is increased by 10 in steps of 1 (the default increment).


Note that the For…Next loop increment (the value after Step) can be a positive or negative number — positive numbers increase the counter, and negative numbers decrease it. If the end value is larger than the start value (for example, For x = 1 To 10), the increment must be positive. Likewise, if the end value is smaller (for example, For x = 10 To 1), the increment must be negative.

The Select Case Conditional

Select Case is useful when you want to test many different conditions or a range of conditions. It's similar to the If conditional, but is more efficient for testing multiple conditions. Here is the syntax (arguments in brackets are optional):

Select Case Expression
Case CaseExpression
Series of instruction(s)
[Case Else
Series of instruction(s)]
End Select

A SelectCase conditional can contain any number of Case instructions. The result of the Expression is compared with the CaseExpression values in every given Case instruction until a match is found. If a match is found, the instructions following the appropriate Case instruction are carried out. If there is no match, the instructions following Case Else are carried out. If there is no Case Else instruction and no match is found, Word displays an error message. To be safe, you should include a Case Else instruction — even if no statements follow it and it has no effect — to ensure that Word doesn't generate an error, regardless of the value of Expression. In CaseExpression, you can use the Is keyword when you want to use logical operators to compare Expression with a value. For example, Case Is > 5. You use the To keyword to test for a range of values. For example, Case 10 To 20 (10 and 20 are included in the range).

Examples

A macro that creates a calendar needs to determine how many days are in each month. Four of the months contain 30 days, February has 28 (in non-leap years), and the remaining months have 31 days. In the following example, the Select Case instruction tests the value of the month variable and then assigns the appropriate value to the lastday variable. The month variable is a number from 1 to 12 that corresponds to a month of the year.


Select Case month                'Select the value of month
    Case 4,6,9,11                'If month is 4,6,9, or 11
        lastday = 30                'the month has 30 days
    Case 2                        'If month is 2 (February)
        lastday = 28                'the month has 28 days
    Case Else                    'Otherwise
        lastday = 31                'the month has 31 days
End Select

Note that the first Case instruction has several values, separated by commas. If month equals any one of these values, the instruction following the Case instruction (lastday = 30) is carried out.

The following example uses the StyleName$() function to return the name of the style applied to the paragraph that contains the insertion point. Each Case instruction proposes a style name to match the one returned by StyleName$(). If the style name matches the proposed style, the instruction following the Case instruction is carried out.


Select Case StyleName$()                    'Select the current stylename
    Case "ListItem1"                        'If it's "ListItem1"
        ToolsBulletsNumbers .Type = 0    'add a bullet
    Case "ListItem2"                        'If it's "ListItem2"
        StartOfLine                        'go to the start of the line
        Insert "-" + Chr$(9)                'and insert a hyphen and a tab
    Case Else                            'Otherwise
        MsgBox "Not a list style"        'display a message
End Select

The following example demonstrates how you can use the Is and To keywords in Case instructions to test for a range of values. The example uses the Rnd() function to generate a random number from 0 (zero) to 10. The Case instructions test the number generated by Rnd() and display a corresponding message.


Select Case Int(Rnd() * 10)         'Select a random number from 0 to 10
    Case 0,1,3                    'If it is 0, 1, or 3
        Print "0, 1, or 3"        'print this message
    Case Is > 8                    'If it is greater than 8
        Print "Greater than 8"    'print this message
    Case 4 To 8                     'If it is between 4 and 8
        Print "Between 4 and 8"    'print this message
    Case Else                     'Otherwise
        Print "It's 2"             'print this message
End Select

The second Case instruction uses the Is keyword and the greater than (>) operator to test for any value greater than 8. The third Case instruction uses the To keyword to test for a value that falls in the range of values between 4 and 8.

The Goto Statement

Goto isn't a conditional or a loop, but it is included in this section because, like a conditional or loop, it controls the flow of a macro — the order in which Word interprets a macro's instructions. Goto tells Word to go to a line in the macro and carry out the instructions from that line forward. Among programmers, Goto is infamous for having the potential to create difficult-to-read code, often referred to as "spaghetti code" because it can make the flow of a program tangled and difficult to follow. Used sparingly, though, Goto can be useful in some situations. Also, it is usually necessary in WordBasic to use Goto with error-handling instructions (for information on error handling, see Chapter 7, "The Well-Behaved Macro").

Here is the syntax for Goto:

Goto Label

Word goes to the line in the macro that starts with Label, which must be within the same subroutine or user-defined function as the Goto instruction (see "Subroutines and User-Defined Functions" later in this chapter). A line label must begin at the start of a line (it cannot be preceded by a space or tab character) and end with a colon (:). The rules for Label names are the same as those for variable names (see "Variables" in Chapter 3, "WordBasic Fundamentals").

You can also use a line number with a Goto instruction instead of a label, although it's unusual to use line numbers in WordBasic macros. Line numbers are supported primarily for compatibility with old Basic programs in which line numbers were required. Like a label, a line number must begin at the start of a line; the line number can be as high as 32759. Unlike a text label, a line number does not need a colon following it.

The following example uses the InputBox$() function to request a social security number, then tests to see whether the number typed by the user is longer than 11 characters. If it is, the example displays a message box that asks the user to try entering the social security number again.


tryagain:
answer$ = InputBox$("Please enter your social security number: ")
If Len(answer$) > 11 Then
    MsgBox "Too many characters. Please try again."
    Goto tryagain
End If

The Goto instruction sends Word to the tryagain: label, so that the entire sequence of instructions is repeated. Note that when the Goto instruction refers to the tryagain: label, the ending colon (:) is dropped.

Nesting Conditionals and Loops

It's often useful to nest conditionals and loops — that is, to place a conditional or loop within another conditional or loop. The following example uses an If conditional within a Select Case conditional to assign 29 to the lastday variable if month is 2 (February) and it's a leap year:

Select Case this month 'Select the value of month

Case 4,6,9,11 'If month is 4,6,9, or 11

lastday = 30 'the month has 30 days

Case 2 'If month is 2 (February)

If leapyear = 1 Then 'If it's a leap year

lastday = 29 'the month has 29 days

Else 'Otherwise

lastday = 28 'the month has 28 days

End If 'End of If conditional

Case Else 'Otherwise

lastday = 31 'the month has 31 days

End Select

WordBasic supports up to 16 levels of nesting. Generally, though, it's best to limit nesting to no more than three or four levels; the more levels you use, the more obscure the logic of the macro can become.