Share

Macro user guide

This example shows you how to use the PowerMill macro programming language to create a macro which prints the words of the counting song "Ten Green Bottles".

Basic macro

This shows you how to create and run a basic macro using PowerMill's programming language.

  1. In a text editor such as WordPad enter:

     PRINT "10 green bottles sitting on the wall"
     PRINT "10 green bottles sitting on the wall"
     PRINT "And if 1 green bottle should accidentally fall"
     PRINT "There will be 9 green bottles sitting on the wall"
  2. Save the file as example.mac.

  3. In PowerMill, click View tab > Window panel > User Interface > Command Window.

  4. From the Macro context menu, select Run. This displays the Select Macro to Run dialog.

  5. Move to the appropriate directory, select example.mac, and click Open. The macro runs and the command windows displays the text enclosed in quotations marks (") in the macro.

    image

Adding macro variables

The first two lines of example.mac are the same. To minimise repetition (and for ease of maintenance) it is good practise to write the line once and recall it whenever it is needed. To do this you must create a local variable to hold the line of text.

You can create different types of variables in PowerMill. To store a line of text you must use a STRING variable.

  1. Open example.mac in your text editor and change it to:

     // Create a variable to hold the first line
     STRING bottles = "10 green bottles sitting on the wall"
     PRINT $bottles
     PRINT $bottles
     PRINT "And if 1 green bottle should accidentally fall"
     PRINT "There will be 9 green bottles sitting on the wall"
    Note: The first line is a comment which explains the second line.
  2. Save the file as example.mac.

  3. In PowerMill, Run the Macro. The command windows displays the same as before:

    image

You should be aware of several issues with variables:

  • You must define all local variables before they are used, in this case STRING bottles = "10 green bottles sitting on the wall" defines the local variable bottles.

  • The variable bottles is a local variable, so is only valid within the macro where it is defined. It is not a PowerMill variable. Typing it into the command window gives an error.

    image

  • When you have defined a local variable you can use it as many times as you want in a macro.

  • You can define as many local variables as you want in a macro.

Adding macro loops

There are two lines of the macro which are the same: PRINT $bottles. This is acceptable in this case because the line only appears twice, but if you wanted to repeat it 5 or 20 times it would be better to use a loop. PowerMill has three looping statements:

This example uses the WHILE statement to repeat the command 5 times.

  1. Open example.mac in your text editor and change it to:

     // Create a variable to hold the first line
     STRING bottles = "10 green bottles sitting on the wall"
    
     // Create a variable to hold the number of times
     // you want to print the first line.
     // In this case, 5
     INT Count = 5
    
     // Repeat while the condition Count is greater than 0 
     WHILE Count > 0 {
         // Print the line
         PRINT $bottles
         // Reduce the count by 1
         $Count = Count - 1
     }
    
     // Print the last two lines
     PRINT "And if 1 green bottle should accidentally fall"
     PRINT "There will be 9 green bottles sitting on the wall"
    Note: $Count = Count - 1 is an assignment statement which is why the variable ($Count) to the left of = must be prefixed with $.
    Note: The empty lines are not necessary, but they make it easier to read the macro.
  2. Save the file as example.mac.

  3. In PowerMill, Run the Macro. The command windows displays:

    image]

    Note: Changing INT Count = 5 to INT Count = 10 prints 10 green bottles sitting on the wall ten times, rather than five.

Running macros with arguments

The loop you added to example.mac works well if you always want to print 10 green bottles sitting on the wall the same number of times. However, if you want to change the number of repetitions at run time, rather than editing the macro each time, it is much better to write the macro so it is given the number of repetitions. To do this you need to create a Main FUNCTION.

  1. Open example.mac in your text editor and change it to:

     // Create a Main FUNCTION to hold the number of times
     // you want to print the first line.
     FUNCTION Main (INT Count) {
    
         // Create a variable to hold the first line
         STRING bottles = "10 green bottles sitting on the wall"
    
         // Repeat while the condition Count is greater than 0
         WHILE Count > 0 {
             // Print the line
             PRINT $bottles
             // Reduce the count by 1
             $Count = Count - 1
         }
    
         // Print the last two lines
         PRINT "If 1 green bottle should accidentally fall"
         PRINT "There will be 9 green bottles sitting on the wall"
     }
  2. Save the file as example.mac.

  3. To run the macro you cannot select Run from the Macro context menu, as you need to give a value for Count. Therefore, in the command window type:

    MACRO example.mac 5

    Where 5 is the value for Count. The command windows displays:

    image

    Note: If you get a warning that the macro cannot be found, check you have created the necessary macro path.

Adding your own functions

As well as a Main function you can create your own functions. This is useful as a way of separating out a block of code. You can use functions:

  • to build up a library of useful operations

  • to make a macro more understandable.

Note: You can call a function any number of times within a macro.

This example separates out the printing of the first line into its own function so that the Main function is more understandable.

  1. Open example.mac in your text editor and change it to:

     FUNCTION PrintBottles(INT Count) {
    
         // Create a variable to hold the first line
         STRING bottles = "10 green bottles sitting on the wall"
    
         // Repeat while the condition Count is greater than 0
         WHILE Count > 0 {
             // Print the line
             PRINT \$bottles
             // Reduce the count by 1
             $Count = Count - 1
         }
     }
    
     FUNCTION Main (INT Count) {
    
         // Print the first line Count number of times
         CALL PrintBottles(Count)
    
         // Print the last two lines
         PRINT "If 1 green bottle should accidentally fall"
         PRINT "There will be 9 green bottles sitting on the wall"
     }
  2. Save the macro.

  3. Run the macro by typing MACRO example.mac 5 in the command window.

    image

    This produces the same result as before.

Note: The order of functions in a macro is irrelevant. For example, it does not matter whether the Main function is before or after the PrintBottles function.
Note: It is important that each function name is unique and that the macro has a function called Main.
Note: You can have any number of functions in a macro.

Decision making in macros

The macro example.mac runs provided that you enter a positive argument. However, if you always want the 10 green bottles sitting on the wall line printed at least once use:

  • A DO - WHILE loop as it executes all the commands before testing the conditional expression.

  • An IF statement.

DO - WHILE loop

  1. Edit the PrintBottles function in example.mac to:

     FUNCTION PrintBottles(INT Count) {
    
         // Create a variable to hold the first line
         STRING bottles = "10 green bottles sitting on the wall"
    
         // Repeat while the condition Count is greater than 0
         DO {
             // Print the line
             PRINT $bottles
             // Reduce the count by 1
             $Count = Count - 1
             } WHILE Count \> 0
         }

    The main function remains unchanged:

     FUNCTION Main (INT Count) {
    
         // Print the first line Count number of times
         CALL PrintBottles(Count)
    
         // Print the last two lines
         PRINT "And if 1 green bottle should accidentally fall"
         PRINT "There will be 9 green bottles sitting on the wall"
     }
  2. Type MACRO example.mac 0 in the command window.

    image

    The 10 green bottles sitting on the wall line is printed once.

IF statement

You can use an IF statement to ensure the 10 green bottles sitting on the wall line is printed at least twice.

  1. Edit the Main function in example.mac to:

     FUNCTION Main (INT Count) {
    
         // Make sure that Count is at least two
         IF Count < 2 {
             $Count = 2
         }
    
         // Print the first line Count number of times
         CALL PrintBottles(Count)
    
         // Print the last two lines
         PRINT "And if 1 green bottle should accidentally fall"
         PRINT "There will be 9 green bottles sitting on the wall"
     }

    The PrintBottles function remains unchanged:

     FUNCTION PrintBottles(INT Count) {
    
         // Create a variable to hold the first line
         STRING bottles = "10 green bottles sitting on the wall"
    
         // Repeat while the condition Count is greater than 0
         WHILE Count > 0 {
             // Print the line
             PRINT $bottles
             // Reduce the count by 1
             $Count = Count - 1
         }
     }
  2. Type MACRO example.mac 0 in the command window.

    images

    The 10 green bottles sitting on the wall line is printed twice.

More on functions in macros

So far you have only printed the first verse of the counting song "Ten Green Bottles". To make your macro print out all the verses you must change the PrintBottles function so it takes two arguments:

  • Count for the number of times "X green bottles" is printed.

  • Number for the number of bottles.

  1. Edit the PrintBottles function in example.mac to:

     FUNCTION PrintBottles(INT Count, INT Number) {
         // Create a variable to hold the first line
         STRING bottles = String(Number) + " green bottles sitting on the wall"
    
         // Repeat while the condition Count is greater than 0
         WHILE Count > 0 {
             // Print the line
             PRINT $bottles
             // Reduce the count by 1
             $Count = Count - 1
         }
     }

    This adds a second argument to the PrintBottles function. It then uses a parameter function to convert the Number to a string value, STRING (Number). It is then concatenated (+)with green bottles sitting on the wall to make up the bottles string.

  2. Edit the Main function in example.mac to:

     FUNCTION Main (INT Count) {
         // Make sure that Count is at least two
         IF Count < 2 {
             $Count = 2
         }
    
         // Start with ten bottles
         INT Bottles = 10
    
         WHILE Bottles > 0 {
             // Print the first line 'Count' number of times
             CALL PrintBottles(Count, Bottles)
             // Count down Bottles
             $Bottles = $Bottles - 1
             // Build the number of 'bottles_left' string
             STRING bottles_left = "There will be " + string(Bottles) + " green bottles sitting on the wall"
             // Print the last two lines
             PRINT "If 1 green bottle should accidentally fall"
             PRINT $bottles_left
         }
     }
  3. Type MACRO example.mac 2 in the command window.

    images

Note: In Main when you CALL PrintBottles you give it two arguments Count and Bottles whilst within the PrintBottles function the Bottles argument is referred to as Number. The parameters passed to a function do not have to have the same names as they are called within the function.
Note: The order you call the arguments is important.
Note: Any changes made to the value of a parameter within a function does not alter the value of parameter in the calling function unless the parameter is defined as an OUTPUT value.

Using the SWITCH statement

So far you have used numerals to print the quantity of bottles but it would be better to use words. So, instead of printing 10 green bottles … print Ten green bottles ….

One way of doing this is to use a large IF - ELSEIF chain to select the text representation of the number. Another way is to use the SWITCH statement.

SWITCH Number {
    CASE 10
        $Text = "Ten"
        BREAK
    CASE 9
        $Text = "Nine"
        BREAK
    CASE 8
        $Text = "Eight"
        BREAK
    CASE 7
        $Text = "Seven"
        BREAK
    CASE 6
        $Text = "Six"
        BREAK
    CASE 5
        $Text = "Five"
        BREAK
    CASE 4
        $Text = "Four"
        BREAK
    CASE 3
        $Text = "Three"
        BREAK
    CASE 2
        $Text = "Two"
        BREAK
    CASE 1
        $Text = "One"
        BREAK
    DEFAULT
        $Text = "No"
        BREAK
}

The switch statement matches the value of its argument (in this case Number) with a corresponding case value and executes all the subsequent lines until it encounters a BREAK statement. If no matching value is found the DEFAULT is selected (in this case No).

Note: DEFAULT is an optional step.

Returning values from macros

This shows you how to create an OUTPUT variable from a SWITCH statement.

  1. Create a new function called NumberStr containing the SWITCH statement in Using the SWITCH statement and a first line of:

     FUNCTION NumberStr(INT Number, OUTPUT STRING Text) {

    and a last line of:

     }
  2. Edit the PrintBottles function in example.mac to:

     FUNCTION PrintBottles(INT Count INT Number) {
    
         // Convert Number into a string
         STRING TextNumber = ''
         CALL NumberStr(Number,TextNumber)
    
         // Create a variable to hold the first line
         STRING bottles = TextNumber + " green bottles sitting on the wall"
    
         // Repeat while the condition Count is greater than 0
         WHILE Count > 0 {
             // Print the line
             PRINT $bottles
             // Reduce the count by 1
             $Count = Count - 1
         }
     }

    This adds the OUTPUT variable to the PrintBottles function.

  3. Edit the Main function in example.mac to:

     FUNCTION Main (INT Count) {
    
         // Make sure that Count is at least two
         IF Count < 2 {
             $Count = 2
         }
    
         // Start with ten bottles
         INT Bottles = 10
    
         WHILE Bottles > 0 {
             // Print the first line Count number of times
             CALL PrintBottles(Count, Bottles)
             // Countdown Bottles
             $Bottles = $Bottles - 1
    
             // Convert Bottles to string
             STRING BottlesNumber = ''
             CALL NumberStr(Bottles, BottlesNumber)
    
             // Build the number of bottles left string
             STRING bottles_left = "There will be " + lcase(BottlesNumber) + " green bottles sitting on the wall"
             // Print the last two lines
             PRINT "If one green bottle should accidentally fall"
             PRINT $bottles_left
         }
     }

    The BottlesNumber variable is declared in the WHILE loop of the MAIN function.

    Note: Each code block or function can define its own set of local variables; the scope of the variable is from its declaration to the end of the enclosing block or function.
  4. Add the NumberStr function into example.mac.

     FUNCTION PrintBottles(INT Count, INT Number) {
    
         // Convert Number into a string
         STRING TextNumber = ''
         CALL NumberStr(Number,TextNumber)
    
         // Create a variable to hold the first line
         STRING bottles = TextNumber + " green bottles sitting on the wall"
    
         // Repeat while the condition Count is greater than 0
         WHILE Count > 0 {
             // Print the line
             PRINT $bottles
             // Reduce the count by 1
             $Count = Count - 1
         }
     }
    
     FUNCTION Main (INT Count) {
    
         // Make sure that Count is at least two
         IF Count < 2 {
         $Count = 2
         }
    
         // Start with ten bottles
         INT Bottles = 10
    
         WHILE Bottles > 0 {
             // Print the first line Count number of times
             CALL PrintBottles(Count, Bottles)
             // Countdown Bottles
             $Bottles = $Bottles - 1
    
             // Convert Bottles to string
             STRING BottlesNumber = ''
             CALL NumberStr(Bottles, BottlesNumber)
    
             // Build the number of bottles left string
             STRING bottles_left = "There will be " + lcase(BottlesNumber) + " green bottles sitting on the wall"
             // Print the last two lines
             PRINT "If one green bottle should accidentally fall"
             PRINT $bottles_left
         }
     }
    
     FUNCTION NumberStr(INT Number, OUTPUT STRING Text) {
         SWITCH Number {
             CASE 10
                 $Text = "Ten"
                 BREAK
             CASE 9
                 $Text = "Nine"
                 BREAK
             CASE 8
                 $Text = "Eight"
                 BREAK
             CASE 7
                 $Text = "Seven"
                 BREAK
             CASE 6
                 $Text = "Six"
                 BREAK
             CASE 5
                 $Text = "Five"
                 BREAK
             CASE 4
                 $Text = "Four"
                 BREAK
             CASE 3
                 $Text = "Three"
                 BREAK
             CASE 2
                 $Text = "Two"
                 BREAK
             CASE 1
                 $Text = "One"
                 BREAK
             DEFAULT
                 $Text = "No"
                 BREAK
         }
     }

To run the macro, type MACRO example.mac 2 in the command window.

image

Using a FOREACH loop in a macro

This example shows you how to use a FOREACH loop to control the number of bottles rather than a WHILE loop.

  1. Edit the Main function in example.mac to:

     FUNCTION Main (INT Count) {
    
         // Make sure that Count is at least two
         IF Count < 2 {
             $Count = 2
         }
    
         FOREACH Bottles IN {10,9,8,7,6,5,4,3,2,1} {
             // Print the first line Count number of times
             CALL PrintBottles(Count, Bottles)
             // Countdown Bottles
             $Bottles = $Bottles - 1
    
             // Convert Bottles to string
             STRING BottlesNumber = ''
             CALL NumberStr(Bottles, BottlesNumber)
    
             // Build the number of bottles left string
             STRING bottles_left = "There will be " + lcase(BottlesNumber) + " green bottles sitting on the wall"
             // Print the last two lines
             PRINT "If one green bottle should accidentally fall"
             PRINT $bottles_left
         }
     }

    The rest of example.mac remains unaltered.

     FUNCTION PrintBottles(INT Count, INT Number) {
    
         // Convert Number into a string
         STRING TextNumber = ''
         CALL NumberStr(Number,TextNumber)
    
         // Create a variable to hold the first line
         STRING bottles = TextNumber + " green bottles sitting on the wall"
    
         // Repeat while the condition Count is greater than 0 WHILE Count > 0 {
             // Print the line
             PRINT $bottles
             // Reduce the count by 1
             $Count = Count - 1
         }
     }
    
     FUNCTION Main (INT Count) {
    
         // Make sure that Count is at least two
         IF Count < 2 {
         $Count = 2
         }
    
         FOREACH Bottles IN {10,9,8,7,6,5,4,3,2,1} {
             // Print the first line Count number of times
             CALL PrintBottles(Count, Bottles)
             // Countdown Bottles
             $Bottles = $Bottles - 1
    
             // Convert Bottles to string
             STRING BottlesNumber = ''
             CALL NumberStr(Bottles, BottlesNumber)
    
             // Build the number of bottles left string
             STRING bottles_left = "There will be " + lcase(BottlesNumber) + " green bottles sitting on the wall"
             // Print the last two lines
             PRINT "If one green bottle should accidentally fall"
             PRINT $bottles_left
         }
     }
    
     FUNCTION NumberStr(INT Number, OUTPUT STRING Text) {
         SWITCH Number {
             CASE 10
                 $Text = "Ten"
                 BREAK
             CASE 9
                 $Text = "Nine"
                 BREAK
             CASE 8
                 $Text = "Eight"
                 BREAK
             CASE 7
                 $Text = "Seven"
                 BREAK
             CASE 6
                 $Text = "Six"
                 BREAK
             CASE 5
                 $Text = "Five"
                 BREAK
             CASE 4
                 $Text = "Four"
                 BREAK
             CASE 3
                 $Text = "Three"
                 BREAK
             CASE 2
                 $Text = "Two"
                 BREAK
             CASE 1
                 $Text = "One"
                 BREAK
             DEFAULT
                 $Text = "No"
                 BREAK
         }
     }
Note: You do not need to declare the type or initial value of the Bottles variable as the FOREACH loop handles this.

To run the macro, type MACRO example.mac 2 in the command window.

image

This gives exactly the same output as the Returning values from macros example. It shows you an alternative way of creating the same output.

Using arrays in a FOREACH loop

This example shows you how to use an array in a FOREACH loop, rather than using a list, to control the number of bottles.

  1. Edit the Main function in example.mac to:

     FUNCTION Main (INT Count) {
    
         // Make sure that Count is at least two
         IF Count < 2 {
             $Count = 2
         }
    
         // Define an array of bottle numbers
         INT ARRAY BottleArray[10] = {10,9,8,7,6,5,4,3,2,1}
    
         FOREACH Bottles IN BottleArray {
             // Print the first line Count number of times
             CALL PrintBottles(Count, Bottles)
             // Count down Bottles
             $Bottles = $Bottles - 1
    
             // Convert Bottles to string
             STRING BottlesNumber = ''
             CALL NumberStr(Bottles, BottlesNumber)
    
             // Build the number of bottles left string
             STRING bottles_left = "There will be " + lcase(BottlesNumber) + " green bottles sitting on the wall"
    
             // Print the last two lines
             PRINT "If one green bottle should accidentally fall"
             PRINT $bottles_left
         }
     }

    The rest of example.mac remains unaltered.

  2. Type MACRO example.mac 2 in the command window.

    image

    This gives exactly the same output as the Returning values from macros example. It shows you an alternative way of creating the same output.

Pausing a macro for user interaction

You can pause a running macro to allow user input, such as the selection of surfaces or curves. The command to do this is:

MACRO PAUSE "User help instructions"

This displays a dialog containing the supplied text and a button to allow the user to RESUME the macro.

When the macro is paused, users can perform any actions within PowerMill, with the exception of running another macro. The current macro remains paused until the user clicks the RESUME button. If the user closes the dialog, by clicking the dialog close icon image, this ends any currently running macros, including the paused macro.

For example:

GET EXAMPLES 'cowling.dgk'
ROTATE TRANSFORM TOP
CREATE TOOL ; BALLNOSED
EDIT TOOL ; DIAMETER 10
EDIT BLOCK RESET
CREATE BOUNDARY ; SELECTED
STRING Msg = "Select surfaces for boundary, and press"+crlf+"RESUME when ready to continue"
EDIT BLOCK RESET
MACRO PAUSE $Msg
EDIT BOUNDARY ; CALCULATE

If you do not enter a string after MACRO PAUSE the macro pauses but does not display a RESUME dialog. To resume the macro either type MACRO RUN or provide another mechanism to continue the macro.

Was this information helpful?