<<

AeroScript Reference Table of Contents Table of Contents 2 Structure of a Program 5 Comments 6 Preprocessor 7 Text Replacement Macro (#define/#undef) 7 Source File Inclusion (#include) 8 Conditional Inclusion (#if/#ifdef/#ifndef) 8 Data Types and Variables 11 Fundamental Data Types 11 Fundamental Numeric Data Types 11 Fundamental String 11 Fundamental Axis Data Type 11 Fundamental Handle Data Type 12 Aggregate Data Types 12 Array Data Types 12 Structure Data Types 13 Enumerated Data Types 14 Variables 15 Variable Declaration 15 Variable Names 15 Numeric, Axis, and Handle Variable Declaration Syntax 15 String Variable Declaration Syntax 15 Syntax for Declaring Multiple Variables on the Same Line 16 Array Variable Declaration Syntax 16 Structure Variable Definition and Declaration Syntax 16 Definition Syntax 16 Declaration Syntax 17 Member Access Syntax 17 Enumeration Variable Definition and Declaration Syntax 18 Definition 18 Declaration Syntax 19 Enumerator Access Syntax 19 Variable Initialization Syntax 20 Basic Variable Initialization Syntax 20 Array Variable Initialization Syntax 21 Structure Variable Initialization Syntax 22 Enumeration Variable Initialization Syntax 22 Variable Scope 23 Controller Global Variables 23 User-Defined Variables 23 User-Defined Variable Accessibility 23 User-Defined Local Variable Declaration Location 25 Variable Data Type Conversions 26 Properties 27 Property Declaration 27 Property Names 27 Property Declaration 28 Property Usage 28 Expressions 29 Literals 29 Numeric Literals 29 Integer Literals 29 Floating-Point Literals 29 String Literals 30 String Character Escape Sequences 30 Operators and Intrinsic Functions 31 Mathematical, Logical, and Bitwise Operators 31 Assignment and Compound Assignment Operators 31

2 Increment/Decrement Operators 31 Arithmetic Operators 31 Comparison (Relational) Operators 31 Logical Operators 32 Bitwise Operators 32 Member Access Operators 32 String Operators 32 Miscellaneous Operators and Intrinsic Functions 32 Operation Result Data Type 32 Short-Circuiting 33 Operator Precedence 33 Array Manipulation 35 Array Manipulation Overview 35 Advanced Array Manipulation 35 String Manipulation 37 Statements 38 Conditional Execution 38 If Statement 38 Switch Statement 38 Iterative Execution 40 40 40 ForEach Loop 41 Repeat Loop 42 Conditional and Iterative Statement Nesting 42 Labels 42 Unconditional Branching 43 Goto Statement 43 Break Statement 44 Continue Statement 45 45 Wait Statement 46 OnError Statement 47 Functions 48 Aerotech Standard Library API Functions 48 User-Defined Functions 48 User-Defined Function Overview 48 7.2.2: Function Arguments 49 Function Return Value 50 Function Body Definition 51 Function Overloading 51 Calling a Function 53 Simple Function Calling 53 Synchronizing Function Calls With Motion 54 Syntax for Calling a Function Synchronously 56 Declaring a Function That Can Execute Synchronously 56 Blocking and Non-Blocking Motion-Synchronized Function Calls 57 Blocking Motion-Synchronized Function Calls 58 Non-Blocking Motion-Synchronized Function Calls 59 Restrictions When Calling a Function Synchronously 61 Libraries 62 Library Types 62 Automation1 Standard Library 62 Aerotech Extending Libraries 62 User-Defined Libraries 62 Creating a Library 62 Using a Library 64 G-Code (RS-274) Support 65 Supported G-Code Letters 65 E Command 65 F Command 66

3 G-Codes 66 I/J/K Offsets 66 M-Codes 66 N-Codes 67 P Command 67 Q Command 67 R Command 67 S Command 68 Supported G-codes 68 Supported M-codes 70 G-code Specification Rules 70 G-code and Exponential Notation 70 G-code and Hexadecimal Notation 71 Appendix A: Reserved Keywords 72 Appendix B: Axis Naming Conventions 73 Appendix : Valid Identifier Format 74 Appendix : Valid Variable Name Format 75

4 Structure of a Program

The example that follows is a simple program written in the Automation1 programming language. #include"MyDefines.ascript" #define NUM_POS 2 program var $positions[NUM_POS] as real

// Enable and home axes Enable([X, Y, Z]) Home([X, Y, Z])

// Start free-running axis Z MoveFreerun(Z, 100)

// Move X and Y to positions 10 and 20, respectively MoveRapid([X, Y], [10, 20])

// Perform G-code motion on axes X and Y G1 X20 Y10 F100 G1 X30 Y5 G1 X45 Y25 F35

// Dwell for 0.5 seconds using G-code G4 P0.5

// Call a function to get axis positions, perform a trigonometric // function, and then multiply the result by 1000 $positions[0] = Sin(MyFunc(X)) * 1000.0 $positions[1] = Cos(MyFunc(Y)) * 1000.0 end function MyFunc($myAxisas axis) as real return StatusGetAxisItem($myAxis, AxisStatusItem.PositionCommand) end This program example has the elements that follow:

l Preprocessor (e.g., #include "MyDefines.ascript" and #define NUM_POS 2)

l User-Defined Variables (e.g., $positions[])

l Comments (e.g., // Set up axes)

l Aerotech Standard Library API Functions (e.g., Enable(), Home(), Sin(), Cos(), StatusGetAxisItem())

l G-Code (RS-274) Support (e.g., G4, G1)

l Operators and Intrinsic Functions (e.g., =, *)

l User-Defined Functions User-defined functions (e.g., MyFunc())

5 Comments

Comments that you include are ignored during the compilation of source code. Comments can document code or can prevent code from compiling. // Enable axes Enable([X, Y])

/* Home axes Home([X, Y]) */ The syntax of a single-line comment must match the regular expression that follows. ["//";'][^\n]*\n A single-line comment must start with either a double forward slash (//) and semicolon (;), or with a single quote character ('). All characters between the start of a comment and the next new line (or the end-of-file if the comment starts on the last line in the file) are ignored during compilation. You can include single-line comments at the end of a line that contains code. Enable([X, Y]) // Enable axes The syntax of a multi-line comment must match the regular expression that follows. ["/*"].*[^"*/"] That is, a multi-line comment starts with a forward slash followed by an asterisk (/*), contains any number of characters in between (including newlines), and ends with an asterisk followed by a forward slash (*/). Multi-line comments do not need to span multiple lines. They can start and terminate on the same line. /* Everything in this block is ignored by the compiler Enable([X, Y, Z]) Home([X, Y, Z]) BrakeOff([X, Y, Z]) */

Disable([X, Y, Z]) /* Multi-line comment on a single line */

6 Preprocessor

The preprocessor is used to perform certain translation operations on the source program, such as replacing text, conditionally compiling areas of code, or including macros, definitions, or access to a pre-compiled library within a program. Text Replacement Macro (#define/#undef) The #define preprocessor directive is used to define a macro, which associates some value with an identifier. The syntax variations for a #define directive are as follows. #define #define #define (, ...) #define (, ...) The arguments must be valid identifiers (see Appendix C: Valid Identifier Format). Macros have two general purposes:

l They allow text to be substituted in a program before the program is compiled.

l They allow an identifier to be defined, which can be used to perform conditional compilation based on the existence of that identifier. // Define a macro without a token string #define DEBUG_ENABLE

// Define a macro with some replacement text #define MY_ADD(x, y) (x + y)

// Define some macros with replacement strings #define MY_STRING "Hello" #define MY_VALUE 2

// The following is replaced with var $myStr as string = "Hello" var $myStr as string= MY_STRING

#ifdef DEBUG_ENABLE // This code compiles because DEBUG_ENABLE has been #defined Enable([X, Y]) #endif

// The following is replaced with $rglobal[0] = (1 + 2) $rglobal[0] = MY_ADD(1, MY_VALUE) The #define preprocessor directive cannot be used to replace text within string literals. // Define a macro with a token string #define MY_VALUE 3

// Text replacement occurs and $myInt is assigned a value of 3 var $myInt as integer = MY_VALUE

// No text replacement occurs, so $myStr is assigned "MY_VALUE" var $myStr as string = "MY_VALUE"

7 The #undef preprocessor directive can be used to undo a definition that was previously defined with the #define preprocessor directive. The syntax of an #undef preprocessor directive is as follows. #undef Similar to the #define preprocessor directive, the argument must be a valid identifier (see Appendix C: Valid Identifier Format). #define DEBUG_MODE #undef DEBUG_MODE

#ifdef DEBUG_MODE // This code is not compiled because DEBUG_MODE is no longer #defined Enable(X) #endif The backslash character (\) can be used to allow a #define preprocessor directive macro to span multiple lines. #define M300 \ Enable(X) \ Home(X) \ AnalogOutputSet(X, 0, 0.0)

// The following will be replaced with all 3 lines specified in the // above #define macro M300 Source File Inclusion (#include) The #include preprocessor directive is used to directly include the text from another source file into the program in the line directly following the directive. This can be used, for example, to include another program that contains #defines. Only preprocessor directives and comments can be specified in a file that you includes with the #include preprocessor directive. // defines.ascript #define VAL1 123.4 #define VAL2 0xFF // main.ascript #include"defines.ascript"

$rglobal[0] = VAL1 $rglobal[2] = VAL2 Conditional Inclusion (#if/#ifdef/#ifndef) Various preprocessor directives exist to perform conditional compilation of a source program: l #if l #ifdef l #ifndef The #if directive is used to conditionally compile an area of code when a condition evaluates as true (non-zero). The syntax for the #if directive is as follows. #if #endif The expression can contain any of the following:

8 l Integer constants (e.g., 3 or 0xFF) l A subset of operators from the language o Arithmetic operators (e.g., +, -, *, /) o Bitwise operators (e.g., &, |, ~, <<, >>) o Comparison/relational operators (e.g., >, <, >=, <=) o Logical operators (e.g., ||, &&) l Macros created with the #define preprocessor directive l The defined preprocessor operator, which returns 1 if a macro has previously been defined with #define, or 0 if it has not been defined #if (5 > 3) // This block will be included #endif #if 0 // This block will not be included #endif The #elif and #else directives can be used within an #if block. These directives allow code to be conditionally included when the #if conditional is not true or non-zero. Refer to the following example. #define DEBUG_LEVEL 2

#if !defined(DEBUG_LEVEL) // This block will not be included (DEBUG_LEVEL is defined) #elif DEBUG_LEVEL == 1 // This block will not be included (DEBUG_LEVEL is not 1) #else // This block will be included (the other conditions were false) #endif The #ifdef preprocessor directive is used to conditionally compile an area of code when a macro has been previously defined with the #define directive. Similarly, the #ifndef directive is used to perform conditional compilation when a macro has not been previously defined. The syntax for these two directives is as follows. #ifdef #endif #ifndef #endif Similar to the #if preprocessor directive, the #elif and #else preprocessor directives can be used within #ifdef and #ifndef blocks. #define DEBUG_MODE #define LOG_MODE 3

#ifndef DEBUG_MODE // This block will not be included (DEBUG_MODE is defined) #elif (LOG_MODE > 0) // This block will be included (LOG_MODE is 3) #else // This block will not be included (the previous block was included)

9 #endif

10 Data Types and Variables

Data types are used to apply semantic meaning to various things in the language, such as how variables interact and how data is returned from a function. Data types are used to restrict the operations that can be performed upon those things (for example, you can’t use a real value of 2.5 as an index to an array because arrays are indexed by integer values such as 2). Fundamental Data Types Fundamental data types are the basic data types built into the language, from which all variables and more complex data types can be constructed. (Note that the terms “fundamental data type” and “primitive data type” are often used interchangeably in programming language documentation). Fundamental Numeric Data Types Two fundamental numeric data types will exist to handle numbers with different representations. Name Description Range -1.7976931348623158 x 10308 to real 64-bit IEEE floating-point value 1.7976931348623158 x 10308 -9,223,372,036,854,775,808 to integer 64-bit signed integer 9,223,372,036,854,775,807

The real data type is used to represent numbers that have a fractional component, such as 0.5. Positions, velocities, and analog input/output values usually contain fractional components, and therefore should be expressed with a real. The integer data type is used to represent whole numbers that do not have a fractional component, such as 1024. Task indices, array indices, and digital/analog I/O channels should be expressed with an integer. The integer data type is also useful for operating on low-level bit patterns (for example, shifting a mask value such as 0x800 to the right by 3 bits). var $myInt as integer = 0xFF var $myReal as real = 1.23 Fundamental String Data Type The fundamental string data type is used to represent a sequence of Unicode characters. Unicode supports an extremely large set of characters that aren’t supported in the limited set of ASCII characters, such as 安 and ☮ . Unicode characters are stored as UTF-8 code points, and AeroScript automatically handles memory allocation for single-byte ASCII characters and multi-byte Unicode characters. The strings do not need to be null-terminated, and null-terminator character literals are not supported. var $myStr as string(32) = "Hello World! ☺" The maximum number of characters that a string can contain cannot change dynamically as the program executes. This is because the language runs in a real-time environment, where dynamic memory allocation is non-deterministic. Therefore, the capacity (maximum number of characters) in a string should be specified when declaring a string variable. The number of characters that the string actually contains can fluctuate during the execution of a program, but a string can never contain more than the specified maximum number of characters. If a capacity is not specified, a default capacity of 256 characters is used. Fundamental Axis Data Type The fundamental axis data type is used to represent a single axis in the system. A set of multiple axes can be represented by creating an array of axis indices. var $myAxis as axis = X var $myAxisGroup[] as axis = [X, Y] Having an axis data type will allow users to have more control over their motion than they did on the A3200. For example, the axes that are used to perform PVT motion in the following program can be easily modified by changing the first program line. var $myAxes[] as axis = [X, Y]

MovePvt($myAxes, [10, 20], [10, 10], 1) MovePvt($myAxes, [20, 40], [10, 10], 1)

11 MovePvt($myAxes, [30, 60], [10, 10], 1) The @ operator (an ampersand, also known as the “at sign” or “commercial at”) can be used to convert a value into an axis. The value to convert to an axis can be an integer, a real with a whole number value such as 3.0, or a string that contains the name of an axis. var $myAxis as axis = @0 var $myStr as string = "X" var $axis as axis = @$myStr Fundamental Handle Data Type The fundamental handle data type is used to interact with some external resource (such as a file, network socket, shared memory region, or a serial port) through a well-defined interface. The following example shows a handle being used to access a file. var $myFile as handle var $dVal as real

$myFile = FileOpenText("data.txt", FileMode.Read) $dVal = FileTextReadFloat64($myFile) FileClose($myFile) The existence of the handle data type allows the compiler to perform better type checking in order to produce an error when incorrectly using the file, network, or serial port APIs. In addition, the type checking prevents the usage of the handle data type incorrectly, such as in an operation where a handle variable is added to a real variable. Aggregate Data Types An aggregate data type is a data type that can be referenced as a single entity, yet can consist of multiple pieces of data. Arrays and structures are the two aggregate data types that can be used in the language. Array Data Types Arrays are used to store multiple values of the same data type. The data type used by the array can be any existing data type. For example, you can have an array of values with the string, integer, real, or user-defined struct data types, among others. The following example shows the declaration of a 1-dimensional array of integer values and an array of AxisData (a user-defined struct) values. // Array of 3 integers var $positions[3] as integer

// Array of 32 user-defined AxisData structs var $axData[32] as AxisData In addition to 1-dimensional array variables, arrays can also be 2-dimensional or 3-dimensional. The following example shows how you can declare a 2-dimensional array and a 3-dimensional array. // 2-dimensional array of real values var $coeff[3][3]

// 3-dimensional array of real values var $matrix[2][3][3] as real Each element of an array can be individually referenced by its index. Array indices are zero-based, meaning the first element in the array has an index of 0, the second element has an index of 1, and so on, up to one less than the length of the array. For example, a 1-dimensional array that was declared with 3 elements can be accessed with indices 0, 1, and 2. Attempting to access an array element with an out-of-bounds index will result in a runtime error. var $myArray[3] as real = [5.5, 3.7, 3.1]

// Copy the value from the array at index 2 to the array at index 0

12 $myArray[0] = $myArray[2]

// The following results in a runtime error because an out-of-bounds array // index (3) was specified for $myArray, which can only be accessed through // indices 0-2 $myArray[3] = $myArray[0] In the following example, an array of position values is filled by looping over an array of axes. var $axisArray[3] as axis = [X, Y, Z] var $posArray[3] as real var $index as integer for $index = 0 to 2 $posArray[$index] = StatusGetAxisItem($axisArray[$index], AxisStatusItem.PositionCommand) end Structure Data Types A structure (called a struct for short) is an aggregate data type that is user-defined. Structures are useful for grouping a common set of data together, such as a set of gains for an axis, or a set of coefficients for a filter. Each element of a structure can be declared to be any data type that has been previously defined, including fundamental data types or another struct. An example of a user-defined structure is as follows. struct AxisData $pos as real $vel as real $acc as real $miscData[3][3] as integer end Once a struct is defined, variables can be declared with their data type. In addition, they can be used to declare the type of a function argument. One thing to note is that a struct cannot be returned from a function. However, a struct can be created outside of a function and modified within the function by using the ref keyword when declaring the function argument, as shown in the following example. struct Point $x as real $y as real end program var $p1 as Point = [5.5, 10.2] var $p2 as Point = [-1.5, 6.6] var $sum as Point

AddPoints($p1, $p2, $sum) end function AddPoints($a as Point, $b as Point, ref $result as Point) $result.x = $a.x + $b.x $result.y = $a.y + $b.y end

13 Refer to the Structure Variable Definition and Declaration Syntax and Declaration and Structure Variable Initialization Syntax sections for more information. Enumerated Data Types An enumeration or enumerated data type (called an enum for short) is a data type that consists of a set of named values called enumerators. The main purpose of an enum is to perform logic using a set of names rather than using constant numeric values. An example of an enum is as follows. enum Direction North = 0 South = 1 East = 2 West = 3 end var $direction as Direction = Direction.North Once an enum is defined, variables can be declared with their data type. In addition, function arguments and function return types can be an enum type. The following example shows the definition of an enum along with its use in a variable and as a function return type. enum Quadrant None One Two Three Four end program var $quadrant as Quadrant

// Determine which quadrant the point (-5, -6) is in // The function will return Quadrant.Three $quadrant = GetQuadrant(-5, -6) end function GetQuadrant($x as real, $y as real) as Quadrant if (($x == 0) || ($y == 0)) return Quadrant.None elseif ($x > 0) if ($y > 0) return Quadrant.One else // ($y < 0) return Quadrant.Four end else // ($x < 0) if ($y > 0) return Quadrant.Two else // ($y < 0)

14 return Quadrant.Three end end end Refer to the Enumeration Variable Definition and Declaration Syntax and Enumeration Variable Initialization Syntax sections for more information. Variables

Variable Declaration

Variable Names In order to use a program variable, you must first declare it with a name. The name of a variable must match the following regular expression. $[A-Za-z_][A-Za-z0-9_]*

l A variable name must start with a dollar sign ($)

l After the dollar sign ($), it must contain a letter or underscore.

l After the first letter or underscore, it can contain zero or more letters, numbers, or underscores. A variable cannot share the same name as a property declared within the same scope. Refer to Properties for more information. Some names, such as $iglobal, are reserved by the Standard Library in order to refer to controller global variables. These reserved names cannot be used for user-defined variables. See Controller Global Variables for more information. Variable names are case-sensitive. For example, $MYVAR and $myVar refer to different variables.

Numeric, Axis, and Handle Variable Declaration Syntax The simplest syntax for declaring a variable with a fundamental numeric data type is as follows. var as The can refer to either of the fundamental numeric types (integer or real), the fundamental axis type, the fundamental handle type, or some user-defined struct or enum type. var $myInt as integer var $myFloat as real var $myAxis as axis var $myFile as handle If no is specified, then the variable is automatically assigned a data type of real. The following two variable declarations are equivalent. var $myVar var $myVar as real

String Variable Declaration Syntax Variables with the string data type must be declared somewhat differently than numeric variables. To declare a string variable, the following syntax must be used. var as string() The value refers to the maximum number of characters that the string can contain. In order to declare a string that can hold up to 32 characters, for example, use the following code. var $myStr as string(32) A string variable may be declared without a size. If no size is specified, then the compiler will choose a default capacity of 256 characters for the string. var $myStr as string

15 Syntax for Declaring Multiple Variables on the Same Line Multiple variables with the same type can be declared on a single line if they are separated with a comma and are not initialized. var $myVar, $myOtherVar, $myThirdVar as integer var $realVal, $arr[3] as real var $rVal, $realArr[3] var $myStr, $myOtherStr as string(32) However, each variable that is initialized must occupy its own line. See the Structure Variable Initialization Syntax section for more details. var $myInt as integer = 0xBEEF // OK var $a, $b as real = 3 // Causes a compiler error

Array Variable Declaration Syntax Array variables are declared with the following syntax, where is used to represent the number of elements within the array. var [] as The above syntax is used to declare a one-dimensional array, which users will find to be sufficient in many cases. However, two- or three-dimensional arrays can be declared simply by specifying more dimensions to the declaration. var [][] as var [][][] as Keep in mind that variables with a data type of string are declared with their own special syntax, but declaring an array of variables with these types is intuitive. The following shows some examples of variable array declarations. // Create an array of 32 real values var $positions[32]

// Create a 2-dimensional array of integers var $matrix[3][3] as integer

// Create an array of 2 handles var $files[2] as handle

// Create an array of 5 strings (each containing up to 16 characters) var $myStr[5] as string(16)

Structure Variable Definition and Declaration Syntax

Definition Syntax Structure data types are defined with the following syntax. struct as as // ... end The rules for the are similar to other identifiers, and must follow the following regular expression. Other restrictions apply; refer to Appendix C: Valid Identifier Format for more information. [A-Za-z_][A-Za-z0-9_]+ Members of a structure are declared similar to normal variable declarations. However:

l The var keyword is omitted.

l Members cannot be initialized in the definition.

16 Refer to Appendix D: Valid Variable Name Format for the proper way for defining the names of struct members. An example structure data type definition is as follows. struct MotionType $pos as real $vel as real end A struct must be defined at the program global scope. The program global scope exists outside of all statement blocks (such as if or repeat statements), the program block, or function blocks, if they exist. For more information about the program block, refer to the User-Defined Functions section. Note that the elements within a structure data type can be defined with any type as long as that type has been previously defined, including other structures. Elements may also be declared as arrays. See the following for an example. struct MotionType $pos as real $vel as real $acc as real end struct ProfileType $motion[32] as MotionType $mask as integer end

Declaration Syntax Structure variables are declared using the same syntax as declaring a numeric variable. Also, an array of structures may be declared. var as var [] as var [][] as var [][][] as The following example shows both a definition and a declaration of a struct data type. The declaration shows the creation of an array of structures. struct MyType $valA as integer $valB as integer $name as string end var $myVar[3] as MyType

Member Access Syntax Accessing member elements in a structure data type can be done in a similar fashion to many existing languages, by using the dot operator. To keep code readable, accessing member elements of a structure requires that there is only one dollar sign ($) at the beginning of the entire expression instead of before the name of each member or sub-member element. struct MyType2 $iVal as integer $dVal as real end var $tval as MyType2

17 $tval.ival = 1 $tval.dval = 1.23 Note that structures can be nested. That is, a struct can be defined with a member whose data type is that of another struct, and that structure can refer to yet another struct, and so on. This means that there may be multiple levels of indirection, as seen in the following example. struct MyType1 $arr1[10] as integer $arr2[10] as integer end

// The $data member of the following struct is a struct itself (MyType1) struct MyType2 $mask as integer $data as MyType1 end

// The $data member of the following struct is a struct itself (MyType2) struct MyType3 $data as MyType2 $dval as real end

// Declare an array of 3 structures with the type "MyType3" var $myVar[3] as MyType3

// Store a value in a sub-struct member variable $myVar[2].data.data.arr1[4] = 123

Enumeration Variable Definition and Declaration Syntax

Definition Enumerated data types are defined with the following syntax options. enum = = // ... end enum // ... end When declaring an enum, either all enumerator values must be specified, or all enumerator values must be unspecified; otherwise a compilation error will occur. If none of the enumerators are given a value, the compiler will assign values to each enumerator sequentially, starting with a value of 0. // Enum with user-assigned enumerator values enum Color

18 Red = 1 Green = 2 Blue = 3 end // Enum with compiler-assigned enumerator values enum Shape Triangle // Assigned a value of 0 Square // Assigned a value of 1 Circle // Assigned a value of 2 end The rules for the and are similar to other identifiers, and must follow the following regular expression. Other restrictions apply; refer to Appendix C: Valid Identifier Format for more information. [A-Za-z_][A-Za-z0-9_]+ An enum must be defined at the program global scope. The program global scope exists outside of all statement blocks (such as if or repeat statements), the program block, or function blocks, if they exist. For more information about the program block, refer to the User-Defined Functions section. Enumerator values must use the integer data type. Therefore, they can be any valid integer value, including negative numbers. In addition, multiple enumerator values within an enum can have the same value. enum CardSuits None = -1 // Negative enumeration values are acceptable Clubs = 1 << 0 Diamonds = 1 << 1 Hearts = 1 << 2 Spades = 1 << 3 MaxSuit = 1 << 3 // This has the same value as Spades Joker = 3.5 // This produces an error as 3.5 is not an integer end

Declaration Syntax Enumeration variables are declared using the same syntax as declaring a numeric variable. Also, an array of enumerators may be declared. var as var [] as var [][] as var [][][] as The following example shows both a definition and a declaration of an enum data type. The declaration shows the creation of an array of enumerations. enum Level Low Medium High end var $levels[5] as Level

Enumerator Access Syntax An enumerator may be accessed using the following syntax. .

19 The example that follows shows the access of an enumerator value. enum Direction None CW CCW end var $direction as Direction if ($iglobal[0] < 0) $direction = Direction.CCW elseif ($iglobal[0] > 0) $direction = Direction.CW else $direction = Direction.None end Variable Initialization Syntax

Basic Variable Initialization Syntax When a program is downloaded to the controller, the user-defined program variables are initialized to a specific value. If an initial value is specified for a variable with an initializer, the variable will be set to that initial value. var $myValue as real = 3.5 var $myStr as string = "Hello" var $myAxis as axis = X However, if no initial value is specified for a variable, then that variable will be set to a default value. var $myDefault as integer // Gets a value of 0 var $myReal as real // Gets a value of 0.0 var $emptyStr as string // Gets a value of "" The default value of each variable declared with a fundamental data type is listed in the following table. Data Type Default Value integer 0 real 0.0 string "" (empty string) axis None (no axis) handle None (no handle)

There are different ways in which a variable can be initialized, depending on its data type or whether it is an array or struct. The following example shows variable initialization using constant Literals. var $myVar as integer = 123 var $myVar2 as integer = 0xFF var $dval1 = 6.78 var $dval2 = 1.23e-3 var $myArray[2] as integer = [1, 2] var $myStr as string(32) = "Hello World" var $myAxis as axis = @0

20 Variables can also be initialized with expressions. An expression can either be a constant expression, whose value is known at compile time, or a runtime expression, whose value is only known once the program is running. Any variable may be initialized with a constant expression. However, only “stack variables” (i.e., those declared within a function) can be initialized with a runtime expression. // Constant expressions var $numIters as integer = 1024 / 8 var $dpos as real = 2.0 + 2.0 + 2.0 var $str as string = "Hello" var $axis as axis = X // Runtime expressions var $ival as integer = $iglobal[0] var $dval as real = Sin(2.0) var $ypos as integer = $xpos var $pos as real = StatusGetAxisItem(X, AxisStatusItem.PositionCommand) var $str as string = $sglobal[3] var $axis as axis = @$iglobal[1] When declaring multiple variables on the same line, variable initializers cannot be specified. This is to eliminate any possible confusion as to which variable is actually being initialized. // This causes a compiler error var $xVar, $yVar as real = 3

Array Variable Initialization Syntax Array variables may be initialized by using the syntax shown in the following example. Note that multi-dimensional arrays can be initialized as well. var $myArr[3] as integer = [3, 18, 46] var $str[2] as string(8) = ["Hello", "World"] var $myMatrix[2][3] as real = [[1.0, 4.0, 8.0], [3.0, 9.0, 27.0]] When an array variable is initialized, the number of initializers must match the length of the array. // This causes a compiler error because there are too many initializers var $myArr[3] = [1, 2, 3, 4] If a length is not specified for an array variable, the compiler determines the size of the array from the number of specified initializers. If no size is specified for an array variable and there is no initializer, the compiler will throw an error because it is unable to determine the proper size for the array. var $myArr[] as integer = [1, 2, 3, 4] // Array size set to 4 var $badArray[] as real // Compiler error (no initializers) Multi-dimensional arrays can also be initialized without specifying a length for each dimension. However, each array dimension must contain the same number of initializers. // Declares a 2x3 array var $myArray1[][] = [[1, 2, 3], [4, 5, 6]]

// This causes a compiler error because the second dimension does not // contain a consistent number of initializers (2 and 3) var $myArray2[][] = [[0x3F, 0x1C], [0xA0, 0x72, 0xCE]] An array can be initialized with a dimension whose size is zero by specifying an empty initializer, as shown in the following examples. However, an array may not be explicitly given a size of zero. // Declares an array with a length of 0 var $myArray1D[] as real = []

21 // Declares a 2x0 array var $myArray2D[][] as real = [[],[]]

// Produces a compiler error because an explicit array dimension of 0 is // disallowed var $invalidArray[0] as real Most statements, such as function calls and variable assignments, occupy one line each in a program. However, variable array initializations can span multiple lines to prevent the need to specify everything on a single line, making code more readable. var $myArr[2][10] as real = [ [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0], [11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0] ]

Structure Variable Initialization Syntax A struct variable can be initialized similarly to how array variables are initialized. If no initializers are specified, each member of a struct is initialized with its default value, depending on its data type. However, if initializers are specified, then each member of the struct must have an initializer. struct MyType $foo as integer $bar as real end var $myVar as MyType = [1, 2.345] In a struct, member variables that are arrays can be initialized with the typical array initialization syntax. struct MyType $a as axis $b[3] as real end var $myVar as MyType = [X, [2.0, 1.0, 0.5]] Similarly, an array of structs can be initialized. struct Point $x as real $y as real end

// Creates an array of 3 Point structs var $myPoints[] as Points = [[0, 0], [10, 5], [-3, 8]]

Enumeration Variable Initialization Syntax An enum variable can be initialized similarly to how regular numeric variables are initialized. enum Direction Left Right end var $myDirection as Direction = Direction.Left

22 var $directions[3] as Direction = [ Direction.Right, Direction.Right, Direction.Left ] Variable Scope The scope of a variable is the region of a program from which that variable can be accessed.

Controller Global Variables The controller has a set of global array variables that are accessible from every task. These variables can be used to communicate data between tasks. Controller Global Variable Description $rglobal[] Array of controller global variables with the real data type. $iglobal[] Array of controller global variables with the integer data type. Array of controller global variables with the string data type. Each string has a $sglobal[] capacity of 256 bytes.

The $rglobal[] and $iglobal[] variables are initialized to zero when the controller is reset. The $sglobal[] variables are initialized to an empty string ("") when the controller is reset. While $sglobal[] variables have a capacity of 256 bytes, the string buffer needs to be null-terminated, leaving 255 bytes available for AeroScript characters. Additionally, use of multi-byte Unicode characters will consume multiple bytes of the buffer from individual AeroScript characters.

User-Defined Variables

User-Defined Variable Accessibility User-defined variables have a much smaller scope than controller global variables, as they can only be accessed from certain areas within a program. Variables declared outside of the program block are considered to be program global variables. These variables are accessible everywhere within the program block, as well as within each function defined in the program. Refer to the User-Defined Functions section for more information about the program block. var $globalProgVar program // $globalProgVar is accessible here end function Foo() // $globalProgVar is accessible here end Variables declared within the program block are considered to be local variables, and are only accessible within the program block. program var $progVar

// $progVar is accessible here end function Foo() // $progVar is not accessible here end

23 Variables declared within a function body are considered to be local variables, and are only accessible within that function. program // $funcVar is not accessible here end function Foo() var $funcVar

// $funcVar is accessible here end Arguments that are declared for a function are only accessible within the function in which they were declared. program // $funcArg is not accessible here end function Foo($funcArg as real) // $funcArg is accessible here end function Bar($myVal as real) // $funcArg is not accessible here end function Baz($funcArg as real) // $funcArg is accessible here // Note that this is a different $funcArg than the one declared for // the function Foo() end Arguments specified for a function cannot shadow variables with a larger scope. That is, the name of a function argument cannot be the same as the name of a controller global variable or a program global variable. In addition, variables declared within a function cannot shadow function arguments. var $globalProgVar program // ... end

// The following function definition will produce a compiler error because // the $globalProgVar name is already used by a variable with larger // scope function Foo($globalProgVar as real) // ... end function Bar($funcArg as real) // The following variable declaration will produce a compiler error

24 // because the $funcArg name is already used by a variable with larger // scope as a function argument var $funcArg as integer end Variables can be declared within some conditional or iterative blocks (if, while, for, foreach, and repeat). These variables go out of scope at the end of the block in which they were declared. if $iglobal[0] != 0 var $localVar as real = $rglobal[0]

if $localVar < 100.0 // $localVar is accessible here end end

// $localVar is not accessible here since it went out of scope at the end // of the larger if statement block Similar to variables declared as function arguments or variables declared within a function body, variables declared within conditional or iterative blocks cannot shadow variables declared with a larger scope. if $iglobal[0] != 0 var $localVar as real = $rglobal[0]

while $localVar > 0.0 // The following variable declaration will cause a compiler error // because the $localVar name is already used by a variable that // was declared with larger scope var $localVar as integer end end

User-Defined Local Variable Declaration Location As mentioned earlier, variables can be declared outside of the program block. These variables are known as program global variables. All other variables must either be declared within the program block (assuming that it exists, see User-Defined Functions) or within a function body. Variables of this type can be declared anywhere that a statement can be placed. Variable scope rules must be followed, and variables must be declared before they are accessed in the program. // Variables can be declared at the top of a program before any executable // statements var $myInt as integer

Enable(X) Home(X)

// Variables can also be declared after executable statements var $myReal as real

G1 X10 G1 X25 G1 X-10

25 // Variables can be used once they are declared $myReal = 3.14 $rglobal[0] = $myReal

// The following statement will cause a compiler error because $myVar is // being used before it is declared $myVar = 3 var $myVar as integer Variable Data Type Conversions Numeric values can be converted from one type to another through assignments or by passing them as arguments to a function. The following example shows how a real can be converted to an integer. A real may be converted to an integer only if the real value can be represented by an integer. 1,180,591,620,717,411,303,424, or 270, is a whole number; however, it is too large to be able to be represented by an integer, and therefore causes a runtime error when its conversion is attempted. var $rval as real = 3.50 var $ival as integer

// Causes a runtime error because 3.5 is not an integer $ival = $rval

// Okay because Trunc() produces an integer value (as a real) $ival = Trunc($dval) Any integer value can be converted to a real value without causing an error. var $ival as integer var $rval as real

$ival = 5

// Legal conversion from integer to real $rval = $ival However, some very large integer values cannot be represented exactly as a real value, so some loss of precision may occur when performing such a conversion. The following is an example that shows precision loss occurring when converting a large integer value into a real. var $ival as integer var $rval as real

$ival = -9223372036854775808

// This conversion causes some precision loss to occur, making $rval // contain a value of -9223372036854775800 $rval = $ival Note that type conversions can only be used to convert from one numeric type to another numeric type. Non-numeric values cannot be converted to other types. For example, you cannot convert a string to an integer directly through an assignment (although there are API functions that will allow users to do this explicitly).

26 Type conversion may occur automatically when calling a function with arguments that have data types that are able to be converted to the data types that are expected by the function. For example, if a function accepts a single real argument, but an argument with the integer type is specified, the integer value will be implicitly converted to a real (and will cause an error if an invalid conversion occurs). var $intVar as integer = 50

// Sin() expects a real but will accept an integer $rglobal[0] = Sin($intVar) Similar type conversion occurs when a function expects an integer argument, but a real argument is specified. In this case, the type conversion is only allowed if the real value represents a value that can be represented by an integer as well. In the example below, the Foo() function expects an integer argument. The value 5.0 represents a valid integer, and can be passed to the function; however, the value 5.5 does not represent a valid integer, and therefore will cause a runtime error. Note that some of these errors can be caught at compilation time. Refer to Calling a Function for more details. program var $rVal as real = 5.0

$rVal = 5.0

// This is okay, 5.0 can be converted to an integer without loss of data Foo($rVal)

$rVal = 5.5

// This causes a runtime error because 5.5 does not represent an integer Foo($rVal) end function Foo($arg as integer) // ... end Properties

Property Declaration

Property Names In order to use a property, you must first declare it with a name. The name of a property must match the following regular expression. $[A-Za-z_][A-Za-z0-9_]*

l A property name must start with a dollar sign ($)

l After the dollar sign ($), it must contain a letter or underscore.

l After the first letter or underscore, it can contain zero or more letters, numbers, or underscores. A property cannot share the same name as a variable declared within the same scope. Refer to Variables for more information. Some names, such as $iglobal, $rglobal, and $sglobal, are reserved by the Standard Library in order to refer to controller global variables. These reserved names cannot be used for user-defined properties. See Controller Global Variables for more information. Property names are case-sensitive. For example, $MYPROP and $myProp refer to different properties.

27 Property Declaration The syntax for declaring a property is as follows. property as get end

set end end The can refer to either of the fundamental numeric types (integer or real), the fundamental axis type, the fundamental string type, the fundamental handle type, or the fundamental enum type. A get property accessor is used to return a property value, and a set property accessor is used to set a property value. A property can be read-write (i.e., both a get and set accessor are specified), read-only (i.e., only a get accessor is specified), or write-only (i.e., only a set accessor is specified). A get accessor or a set accessor must be specified in a property. A property cannot have multiple get or set accessors. Properties can have indices specified in their declaration. Indices act similarly to function arguments, and can be accessed within the get or set accessors. var $myVar[10] as integer property $myProperty[$index as integer] as real get $myVar[$index] = $value end

set return $myVar[$index] end end

Property Usage Properties can be used like normal variables, with the exception that they cannot be passed as a function argument that was declared with the ref keyword. $myProperty[3] = 1.23

28 Expressions

An expression is a sequence of operators and their operands. An expression produces a result. For example, the expression (3 * 4) produces a result of 12. An expression may also produce side effects. For example, a function may update the value of a controller global variable (which is not directly part of the expression) before returning a value. An expression can consist of one or more of the following.

l Literals (3.0 or "Hello World")

l Variables ($myVar or $iglobal[0])

l Operators and Intrinsic Functions (+ or <<)

l Aerotech Standard Library API Functions (specifically those that return a value, StatusGetAxisItem())

l User-Defined Functions (specifically those that return a value, MyAdd()) Literals A literal is a token with a constant value that is known at compilation time, such as 1.5. This is unlike expressions that are known only at runtime, such as the position command of an axis. Numeric Literals Numeric literals include both integer literals and floating-point literals.

Integer Literals Integer literals are any constant value that can be represented by the fundamental integer data type (integer). Integer literals can be either of the following types. l Decimal literals (base 10) 0|[1-9][0-9]* l Hexadecimal literals (base 16) 0x[0-9A-Fa-f]+ The following example shows proper usage of integer literal types. $ival = 123 $hexval = 0xBEEF $myVal = -0xaf $xorVal = 0xA0A0A0A0 ^ 0xFFFFFFFF

Floating-Point Literals Floating-point literals are any constant value that can be represented by a fundamental floating-point type (real). Floating-point literals include all of the strings that match the following regular expressions. Note that floating-point literals contain a superset of integer literals (for example, 1234 is a valid floating-point literal). [0-9]+[Ee][+-]?[0-9]+ [0-9]*"."[0-9]+([Ee][+-]?[0-9]+)? [0-9]+"."[0-9]*([Ee][+-]?[0-9]+)? The following example shows many different ways that proper floating-point literals can be formed. $fval = 1.0 $myVar = -8 $expVal = 2E+09 $three = 3. $dVal = -1e-3 $someVal = .3 $decimal = 0.25 $oneThousand = 1.e3 Care must be taken when using exponential notation with G-code due to the existence of the E command, which is part of the G-code dialect. Refer to G-code and Exponential Notation for more information.

29 String Literals A string literal is defined as a sequence of zero or more characters surrounded by double quote characters, as described by the following regular expression. \"(\\.|[^\\"])*\" The previous regular expression can be broken down into: l An opening double quote character (") l Any number (zero or more) of the following: o A backslash character (\) followed by any other character o Any character that is not a double quote character (any character except ") l A closing double quote character (") The need for this seemingly odd way of specifying a string literal is due to the need to support escape sequences (such as the newline escape sequence \n) within a string literal. The escape sequence \" inserts a double quote character (") into the text of the string literal itself. Therefore, "Hello\" is an invalid string literal because the trailing double quote character (") is actually part of the escape sequence \", and not the string literal as a whole. The example that follows shows proper usage of string literal types. var $myStr as string(32) = "Hello World!\n" $myStr = StringUpper("abc123") $myStr = "" $myStr = "Hello" + "World"

String Character Escape Sequences In addition to normal printable characters, escape sequences may be used in a string in order to use special characters that can’t be represented with normal keys on a keyboard. Escape sequences can be useful for when a string must be displayed or printed, or be sent to another device (e.g., over a serial communication protocol or through a network socket). // When printed, this string will display as the following: // Hello // World! $myStr = "Hello\nWorld!"

// This string will be indented due to the tab (\t) escape sequence: // Hey $myStr2 = "\tHey" Acceptable escape sequences are as follows. Specifying an invalid escape sequence, such as \c, within a string literal will cause a compiler error. Escape Sequence Meaning \a Alert (“bell”) \b Backspace \f Form feed \n Newline (or line-feed) \r Carriage return \t Horizontal tab \v Vertical tab \" Double quote \\ Backslash \nnn ASCII character with given octal value (n=an octal digit 0-7)1 \xhh ASCII character with given hex value (hh=one or two hex digits 0-F)2 \Uhhhh Unicode 16-bit code point (h=a hex digit 0-F)

30 Escape Sequence Meaning \Uhhhhhhhh Unicode 32-bit code point (h=a hex digit 0-F) 1. Octal escape sequences can only contain up to 3 octal digits. After parsing 3 octal digits, the compiler will continue parsing a string literal as normal, even if there are more octal digits. For example, the "\1024" string will be parsed as "\102" (the ASCII character "B") followed by the character "4", so "B4" is the resulting string literal. Notice that the largest representable octal escape sequence "\777" (511 in decimal) does not represent a valid ASCII character, and the compiler will produce an error if you specify invalid octal escape sequences. 2. Hexadecimal escape sequences may contain any number of hexadecimal characters (0-F). However, this escape sequence can only be used to specify individual bytes, so sequences such as "\xFFFF" that are larger than the range that can be specified within a byte will be considered a compilation error. Operators and Intrinsic Functions

Mathematical, Logical, and Bitwise Operators The following tables show a list of all operators that can be performed with numeric (those having a data type of integer or real) operands.

Assignment and Compound Assignment Operators Assignment operators assign a value to a variable. Therefore, each of these operators must have a variable on the left hand side. However, the right hand side may be any expression whose data type is valid for the variable on the left hand side. Operator Description a = b Simple assignment a += b Addition assignment a -= b Subtraction assignment a *= b Multiplication assignment a /= b Division assignment

Increment/ Decrement Operators Increment and decrement operators increase or decrease a variable by a value of 1, respectively. The operand must be a variable. Operator Description a++ Increment a-- Decrement

Arithmetic Operators Operator Description -a Unary negation +a Unary plus a + b Addition a - b Subtraction a * b Multiplication a / b Division a % b Modulo (Remainder) a ** b Exponentiation (Power)

Comparison (Relational) Operators Operator Description a == b Test equality a != b Test inequality a > b Test greater than a >= b Test greater than or equal to a < b Test less than a <= b Test less than or equal to

31 Logical Operators Operator Description !a Returns true if its operand is false; otherwise returns false a && b Returns true if both of its operands can be converted to true; otherwise returns false Returns true if at least one of its operands can be converted to true; otherwise returns a || b false

Bitwise Operators Note that bitwise operators are only valid on integer operands. However, they are also valid on real operands, provided that the value stored in the real represents a valid integer (e.g., 3.00000). Operator Description a & b Returns a bitwise AND of its two operands a | b Returns a bitwise OR of its two operands a ^ b Returns a bitwise XOR of its two operands ~a Returns a bitwise NOT (complement) of its operand Returns the value of the first operand bitwise shifted left by the value of the second a << b operand Returns the value of the first operand bitwise arithmetically (signed) shifted right by the a >> b value of the second operand

Member Access Operators Operator Description a[b] Array element indexing a.b Structure member access String Operators These operators accept operands with the string data type. Operator Description a = b String assignment a += b String assignment a + b String concatenation Miscellaneous Operators and Intrinsic Functions Operator Description @a Converts operand (integer, real, or string) to an axis length(a) Returns the length (number of elements) of an array operand Operation Result Data Type An operation with two numeric operands of the same type will yield a result of the same type. For example, the addition of an integer and another integer produces an integer. When performing an assignment, arithmetic, or relational operation with two numeric operands, one of the operands may be promoted to a different type before the operation takes place. For example, adding an integer value to a real value produces a result whose type is real. Bitwise operations always produce an integer value, regardless of the types of the operands. A string can only be part of an operation with other string values. For example, you cannot add an integer value to a string value. However, functionality exists in the API to convert between types explicitly. See Variable Type Conversions for more information on this topic. Other data types, such as axis and handle, can only be used in very specific operations. For example, an error will occur during compilation for an operation where an axis is added to an integer, or a handle is multiplied by a real.

32 Short-Circuiting Short-circuiting is when the result of a conditional expression is able to be determined before all of its arguments have been evaluated. This behavior can improve the performance of program execution because in some cases, not all expressions need to be completely evaluated. Two of the logical operators, && (logical AND) and || (logical OR), have short-circuiting behavior. If the first operand to the && operator is false, then the operation returns false regardless of the value of the second operand. The second operand does not have to be evaluated in this case. If the first operand to the || operator is true, then the operation returns true regardless of the second operand. Again, the second operand does not need to be evaluated in this case. if (0 && ($iglobal[0] > 0)) // This code is never executed regardless of the value of $iglobal[0] Enable(X) end if (1 || $rglobal[0]) // This code is always executed regardless of the value of $rglobal[0] Enable(X) end Short-circuiting behavior can be used to avoid side effects. In the following example, MyFunc() will not execute if $rglobal [0] is less than or equal to 0. if (($rglobal[0] > 0) && MyFunc()) // MyFunc() won't execute in the above conditional end Short-circuiting is also commonly used to prevent a value from being used in a conditional expression further to the right, for example, if the programmer knows that evaluating some condition may cause an error. In C/C++, short-circuiting is used in many cases to prevent NULL pointers from being used in an expression. Another example is as follows, where short-circuiting can be used to prevent a division by zero within the conditional expression. if ($rglobal[0] != 0.0) && ((1.0 / $rglobal[0]) < 0.5) // The expression on the right is not evaluated if $rglobal[0] == 0 // ... // ... end Operator Precedence Operator precedence defines the rules for specifying the order in which operators in an expression are evaluated. These rules closely match the mathematical rules for order of operation, but are expanded to include operators that aren’t found in normal mathematics, such as bitwise operators. For example, multiplication has higher precedence than addition. // In the below expression, (2 * 3) is calculated first // The expression then becomes $myVal = $myVal + 6 // (the expression does not become $myVal = ($myVal + 2) * 3) $myVal = $myVal + 2 * 3 Operator associativity is used to determine how to group operands with the same precedence. Left-associative operations, such as addition and multiplication, group operands starting from the left. Right-associative operations, such as exponentiation or variable assignment, group operands starting from the right. // Multiplication is left-associative // The expression below is evaluated as $result = ($valA * $valB) * $valC $result = $valA * $valB * $valC

// Exponentiation is right-associative

33 // The expression below is evaluated as $result = $valA ** ($valB ** $valC) $result = $valA ** $valB ** $valC Parentheses should be used to force operations in an expression to have a specific precedence. In addition, precedence rules vary slightly between languages, and using multiple operators in an expression is error-prone, so parentheses should be used to clarify the intent of an expression. // Multiplication has higher precedence than addition, so $val1 = 11 var $val1 = 1 + 2 * 3 + 4

// Adding parentheses overrides the default precedence, so $val2 = 21 var $val2 = (1 + 2) * (3 + 4) The table that follows shows the precedence of each operator in the language. Operators that are listed higher in the table have precedence over operators that are listed lower in the table. Operators in the same row have the same precedence. Operator Description Associativity a[b] Array element access a() Function call Left-to-right a.b Structure member access a ** b Exponentiation Right-to-left +a Unary plus -a Unary negation !a Logical NOT Right-to-left ~a Bitwise NOT @a Axis index a * b Multiplication a / b Division Left-to-right a % b Modulo a + b Addition Left-to-right a - b Subtraction a << b Bitwise shift left Left-to-right a >> b Bitwise shift right a < b Test less than a <= b Test less than or equal Left-to-right a > b Test greater than a >= b Test greater than or equal a == b Test equality Left-to-right a != b Test inequality a & b Bitwise AND Left-to-right a ^ b Bitwise XOR Left-to-right a | b Bitwise OR Left-to-right a && b Logical AND Left-to-right a || b Logical OR Left-to-right a = b Simple assignment a += b Addition assignment a -= b Subtraction assignment a *= b Multiplication assignment Right-to-left a /= b Division assignment a %= b Modulo assignment a++ Variable increment a-- Variable decrement

34 Array Manipulation

Array Manipulation Overview An array is a data structure that consists of a collection of elements, each having the same data type. Each element in an array can be accessed by its index. Array indices are zero-based, meaning that the first element in an array has an index of 0, and the last element in the array has an index of (array length - 1). // Declare an array of 5 integers var $array[5] as integer

// Set the first element in the array to 10 $array[0] = 10

// Set the last element in the array to 20 $array[4] = 20

// The following causes an error because the array index is out of bounds $array[8] = 30 Array indices may be constant values or the result of an expression. Array indices can be specified with an integer or real value, but they must be whole numbers. var $array[5] as integer var $index as integer

$index = 3

// Set $array[4] to 3 $array[$index + 1] = 5

// This is valid because the index is a whole number // Set $array[3] to 3 $array[3.00000] = 3

// The following will generate an error $array[2.5] = 123 Advanced Array Manipulation Every array has a length (number of elements) that cannot be changed after it is created. Users can retrieve the length of an array by using the intrinsic length() function. This is especially useful in cases where the length of an array is not known, such as when an array is passed into a function that accepts an array of any length. program var $arr1[] as axis = [X, Y, Z] var $arr2[6] as axis = [X, Y, Z, U, A, B]

MyEnable($arr1) MyEnable($arr2) MyEnable([D]) end

35 function MyEnable($axes[] as axis) // The arrays of axes passed in can be any size // Use the length function to get the actual size of the array var $numAxes as integer = length($axes) var $index as integer

for $index = 0 to $numAxes - 1 Enable($axes[$index]) end end The intrinsic length() function behaves in a straightforward way with one-dimensional arrays. However, for multi- dimensional arrays, the length() function returns the number of elements in the dimension that is specified. var $myArray[4][1][7] as real var $len as integer

// Sets $len to 4 because the first dimension of $myArray contains 4 // elements $len = length($myArray)

// Sets $len to 1 because the second dimension of $myArray contains 1 // element $len = length($myArray[0])

// Sets $len to 7 because the third dimension of $myArray contains 7 // elements $len = length($myArray[1][2])

// Causes an error because $myArray[0][0][0] is a scalar (not an array) $len = length($myArray[0][0][0]) As an alternative to finding the length of an array and iterating over each array element by its index in a for loop, a foreach loop can be used to iterate over an array without needing to take its length into account. var $ints[10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] var $sum as integer = 0

// Iterate through each element of $ints[], using $int as the "" foreach var $int in $ints $sum += $int end Multi-dimensional arrays can be considered an “array of arrays.” For example, a variable that is a 3-by-3 array can also be thought of as an array with 3 elements, and each of those elements is itself an array with 3 elements. This is particularly useful in a case like the following scenario. program var $matrix[3][3] as integer = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] var $sum as integer = 0

// SumRow() takes 1D arrays, but $matrix is a 2D array // However, $matrix[0], $matrix[1], and $matrix[2] are each 1D arrays

36 $sum += SumRow($matrix[0]) $sum += SumRow($matrix[1]) $sum += SumRow($matrix[2]) end

// The following function takes a 1-dimensional array and returns its sum function SumRow($row[] as integer) as integer var $sum as integer = 0

foreach var $val in $row $sum += $val end

return $sum end String Manipulation The string data type is immutable, meaning that the value of a string cannot be changed. As a result, each string modification actually results in the creation of a new string. var $myStr as string(32) var $str2 as string

// Assign a string variable to a string "object" $myStr = "Hello"

// Create a new string from the character at index 1 in $myStr ("e") $str2 = StringCharacterAt($myStr, 1)

// Create a new string from a substring of a string // The following sets $str2 to "ello" $str2 = StringSubstring($myStr, 1, StringLength($myStr))

// Modifying a character in a string can be accomplished by creating a new // string from an existing string. The following produces "Yello" $myStr = "Y" + StringSubstring($myStr, 1, 4)

37 Statements Conditional Execution

If Statement The if statement executes a block of code if a specified condition evaluates to true. The various syntax permutations for the if statement are as follows. if end if else end if elseif else end If the condition does not evaluate to true, then code execution branches to the next elseif or else conditional. If none of the conditionals evaluate to true, then the code branches to the code after the end of the if statement. if ($myVar > 20) $myOtherVar = 1 elseif ($myVar < -20) $myOtherVar = 0 else $myOtherVar = -1 end Switch Statement The switch statement allows control to be transferred to one of various sections of code depending on the value of a given expression. The basic syntax of the switch statement is as follows. switch case

case

case

...

38 default end If the value of the matches the value of one of the case values, then the statements under the matching case label will be executed. If the optional default label is specified, and the does not match any of the specified case values, then the statements under the default label will be executed. The must resolve to one of the following primitive data types: l integer l real l axis l enum Each of the values must be a constant value. A constant value is any value that can be determined at the time that the program is compiled. Constants include literals such as 3 or 2.5, as well as simple mathematical expressions containing only literals, such as (5 - 2), (0x1 << 3), or (2.5 + 3.0). The data type of each value must be the same data type as the , or a data type that can be converted to the data type of the . In addition, each of the values must be unique. A constant value may appear in only one case within a switch statement. An optional default label can be used to specify statements that should execute when the does not equal any of the case values. An example of a switch statement is as follows. switch ($myVar) case 0 $rglobal[0] = 0

case 1 $rglobal[0] = $myVar

default $rglobal[0] = -$myVar end Each case or default label must have code specified to execute when the switch expression evaluates to the value of that label. For example, the following switch statement would cause a compilation error because the default label does not have any code specified. switch ($myVar) case 0 $rglobal[0] = $myVar

default // There is no code specified here // This is an error end Unlike switch statements found in other programming languages, the switch statement in this language does not have the concept of fallthrough execution because the end of a code section specified for a case or default label is the next case or default label, or the end specified for the switch. Some other programming languages use the break keyword to denote the end of a block of code within a switch statement, but the break keyword does not have this effect in AeroScript. However, multiple case labels may be specified to execute the same code within a switch statement. In the following example, $iglobal[0] will be set to 0 if the value of $myVar is either 0 or 1. switch ($myVar) case 0

39 case 1 $iglobal[0] = 0

case 2 $iglobal[0] = 1

default $iglobal[0] = 2 end Iterative Execution

While Loop The while loop executes a block of code while a specified condition is true. The syntax of a while loop is as follows. while end The is considered to be true if it evaluates as true (e.g., relational operators such as > and <= evaluate as true/false in a conditional) or if it has a nonzero value (e.g., 2.0). If the specified condition evaluates as false when the while statement is first executed, the block of code in the body of the while statement is never executed. while ($iterations < 100) $myVar[$iterations] = $rglobal[0] $iterations++ end For Loop The for loop executes a block of code in an iterative fashion. The syntax of a for loop is as follows. for = to end for = to step end The is set to the specified , and the loop will continue to iterate until the counter variable reaches the . The must be declared before it can be used in a for loop. for $myVar = 0 to 9 $rglobal[$myVar] = $myVar end The is an optional argument that can be used to determine how much the will increment/decrement with each loop iteration. If the is not specified, the will increment by 1 with each iteration of the loop. // Set only the global real values whose index is even (0, 2, 4, ...) for $myVar = 0 to 9 step 2 $rglobal[$myVar] = $myVar end If the is greater than the (or less than the if the is negative), then the loop will not be entered and code execution will immediately transfer to after the end keyword. for $myVar = 0 to 9 step -1

40 // This code is never executed $rglobal[$myVar] = $myVar end ForEach Loop The foreach loop executes a block of code for each element in a given array variable, in order from the lowest index to the highest index. The syntax of a foreach loop is as follows. foreach var in end The is the variable that is iterated over within the loop. It must be a 1-dimensional, 2-dimensional, or 3- dimensional array variable. The is created to have the same data type as the when the is accessed with the array access operator ([]). For example, if the is a 2- dimensional array of real values, then the will be declared as a 1-dimensional array of real values. The exists only within the foreach loop for which it was specified. The following is an example of using a foreach loop to iterate over each element of a 1-dimensional array variable. var $axes[] as axis = [X, Y, Z]

// Perform the same actions for each axis in the array of axes foreach var $axisin$axes Enable($axis) Home($axis) AnalogOutputSet($axis, 0, 2.5) end The following example shows how a foreach loop can be used to iterate over a 2-dimensional array, which can be useful when performing motion over a predetermined set of positions. In the example, the $point iterator variable is unlike any variable that can be declared normally because it is able to access different arrays within the foreach loop. var $axes[] as axis = [X, Y] var $positions[4][2] = [ [10.0, 20.0], [20.0, 40.0], [30.0, 60.0], [40.0, 80.0] ]

// Enable the axes Enable($axes)

// Iterate over each sub-array in the 2-dimensional $positions[][] variable foreach var $pointin$positions MoveLinear($axes, $point) end A foreach loop can be used to iterate over an array of any data type, including a user-defined struct. struct $positionas real $offsetas real end

41 var $axisData[4] as AxisData foreach var $datain $axisData $data.position = 0.0 $data.offset = 0.0 end Repeat Loop The repeat loop is used to execute a block of code a specified number of times. The syntax of a repeat loop is as follows. repeat end The expression specifies the number of times that the repeat loop will execute. This expression must be an integer expression or a real expression that evaluates to an integer value (for example, 3.0). repeat 10 $rglobal[0] = $rglobal[0] * 2 end The expression will only be evaluated the first time that the repeat loop is executed, and not each time that a loop iteration completes. This means that event if you modify the variable that was specified as the of a repeat loop within the , the number of iterations of the loop will not change. var $myVar as integer = 10 repeat $myVar // This loop repeats 10 times $myVar = $myVar + 1 end If the expression is less than or equal to zero, code execution will never enter the loop and will immediately branch to the end specified for the repeat loop. Conditional and Iterative Statement Nesting Many statements can be nested within each other to give more flexibility. For example, an if statement can be placed inside of a repeat statement, and vice versa. repeat 10 if $myVar == 0 Enable(X) else Disable(X) end end Labels A label can be the target of a Goto Statement. Labels have the following syntax. : The must be a valid identifier (see Appendix C: Valid Identifier Format), and cannot be the same as any of the Appendix A: Reserved Keywords or an axis name. A label can be specified on a line by itself. programStart: RunProgram() goto programStart

42 A label may also directly precede a statement. setIO: AnalogOutputSet(X, 0, 2.5) In addition, multiple labels can be specified on the same line, but must precede any statements on that line. label1: label2: Enable(X) Labels are case-sensitive. For example, myLabel and MYLABEL refer to different labels. It is generally discouraged to use the goto statement, and therefore labels. Refer to the Goto Statement for more information. Unconditional Branching

Goto Statement A goto statement is used to unconditionally transfer program execution to a line of code with a given Labels. The following is the syntax for a goto statement. goto A goto statement must be specified in the same functional region as the destination

l A program block

l A function body

l The program global scope (if no program block is specified) For more information about the program block, refer to the User-Defined Functions section. A goto statement may be defined either before or after the

Dwell(0.5) skipDwell: G1X10 One instance where the goto statement can be useful is breaking out of deeply-nested loops. var $i, $j, $kas integer var $num as integer = 0 for $i = 0 to 9 for $j = 0 to 9 for $k = 0 to 9 if ($rglobal[($i * 100) + ($j * 10) + $k] < 0.0) goto found else $num++ end end

43 end end found: The goto statement cannot be used to transfer control into constructs that require initialization:

l The body of a repeat loop

l The body of a for loop

l The body of a foreach loop

l The body of a function The reason that goto statements cannot be used to transfer control into the listed loops is because the initialization of the loops would not be performed, causing the program to behave incorrectly. For example, using a goto statement to transfer control to the body of a for loop would cause the for loop counter variable to be uninitialized. As an example, the following usage of a goto statement will cause an error during compilation because the code execution would branch over the initialization of the repeat loop. goto myLabel repeat 10 myLabel: Dwell(0.01) end While the goto statement cannot be used to enter certain regions of code, it may still be used to exit those regions. For example, a goto statement may be used to exit a repeat loop. In addition, the goto statement cannot be used to transfer control past the initialization of a variable because the value of a variable cannot be determined. As an example, the following usage of a goto statement will cause an error during compilation. goto myLabel var $myVar as integer = 3 myLabel: $myVar++ The use of the goto statement is generally discouraged as its use can make programs difficult to read or debug. In many cases, the use of a goto statement can be replaced with a proper while, for, or foreach loop. Break Statement Break statements allow for a control flow loop (while, for, foreach, or repeat) to be immediately terminated. The syntax for the break statement is as follows. break The break statement is used to break out of the nearest containing loop. The break statement cannot be used outside of a while, for, foreach, or repeat loop. repeat 5 while ($cnt > 10) $cnt-- if ($iVal == 0) // Break out of the while loop break end end

44 end Continue Statement The continue statement allows for control flow to jump to the beginning of a control flow loop (while, for, foreach, or repeat) to start executing its next iteration, skipping any code remaining in the loop for the current iteration. The syntax for the continue statement is as follows. continue The continue statement is used to branch to the beginning of the nearest containing loop. The continue statement cannot be used outside of a while, for, foreach, or repeat loop. $skipIndex = 10 for $index = 0 to 31 if ($index == $skipIndex) // Skip setting the 10th index continue end

$rglobal[$index] = $index end Return Statement The return statement allows for control flow to exit the current function, returning a value (if specified) to its caller. If the control of execution is within a program block, or is at the program global scope, then a return statement will cause the program to end. The following are the various syntax permutations for the return statement. return return The return syntax without a argument should be used to return early from a function that does not return a value. function SetValue($valueas real) if ($value < 0.0) // Return from the function early to prevent the value from being // Set if it is negative return end

$rglobal[0] = $value end A return statement without a return value can also be specified in a program block, or at the program global scope (if no program block was defined) in order to stop the execution of a program before execution reaches the end. A value cannot be specified to a return statement in these cases. The return syntax should be used to return a value from a function that returns a value. The value returned from a function must match (or be convertible to) the data type of the function return value. function MyFunc() as integer // This is valid because the function returns an integer return 123 end function MyFunc() // This is not valid because the function does not return a value return 123

45 end function MyFunc() as integer // This is not valid because the function has a return with the integer // data type, but a string is being returned return "Hello" end Wait Statement The wait statement is used to wait for a specified condition to evaluate as true before continuing program execution. The syntax for the wait statement is as follows. wait() = wait(, ) The program will wait on the wait statement program line forever until the specified evaluates as true. // Wait forever until $iglobal[0] has a value of 1 wait($iglobal[0] == 1) An optional value, in milliseconds, may be specified. If the continues to evaluate as false for longer than the duration, then the wait statement will return a value of 1. If the evaluates as true before the duration, then the wait statement will return a value of 0. The return value may be ignored. // $timedOut will have a value of 1 if the wait statement executes for // more than 2 seconds (2000 milliseconds) $timedOut = wait($signalVar == 1, 2000)

// The return value of a wait statement may be ignored if the timeout // status is not useful wait($signalVar == 0, 150)

// Specifying a value of "false" for the conditional allows a wait // statement to be used to delay program execution for the specified // timeout wait(false, 1000) The wait statement is , or syntax that makes it easier to express an idea using the language. The following two examples have the same behavior, but the wait statement allows for the code to be expressed more concisely. var $timeout as integer var $timedOut as integer = false

CriticalSectionStart()

$timeout = 100 while (StatusGetAxisItem(X, AxisStatusItem.VelocityCommand) != 0.0) $timeout-- if ($timeout == 0) $timedOut = true break end Dwell(0.001) end

CriticalSectionEnd()

46 if ($timedOut == 1) AppMessageDisplay("A timeout occurred.") end var $timedOut as integer

$timedOut = wait(StatusGetAxisItem(X, AxisStatusItem.VelocityCommand) == 0, 100) if ($timedOut == 1) AppMessageDisplay("A timeout occurred.") end OnError Statement The onerror statement causes the specified function to be executed when a task error occurs during program execution. The syntax of an onerror statement that sets an error handling function is as follows. onerror(()) An onerror statement can be specified without a function to clear any active onerror handler. The syntax for clearing an onerror handler is as follows. onerror() If an onerror handler is active and a task error occurs while a program is active (in either the running, paused, or feedheld states), program execution will immediately branch to the function specified by the when the onerror statement was specified. The function specified by the must not accept any arguments, nor may it return a value. program // Configure the onerror handler to call the ErrorHandler() function if // an error occurs onerror(ErrorHandler())

// Any errors that occur here will cause the ErrorHandler() function to // be executed automatically Enable([X, Y, Z]) Home([X, Y, Z]) MoveLinear([X, Y], [10, 20])

// Disable the active onerror handler onerror() end function ErrorHandler() // Clear errors and start the program again AcknowledgeAll() ProgramRestart() end Errors can be handled within the called function and then the programmer can decide whether to restart program execution or end the program. If the error condition is not cleared within the function, or a new error condition occurs within the function, then the program will terminate.

47 Functions

A function is a sequence of program instructions that perform a specific task, grouped together in a unit. The language has different types of functions – those that are pre-defined in the Aerotech API, such as Home() or Enable(), and those that are user-defined. Aerotech Standard Library API Functions API functions are provided in order to perform common functionality with the controller. They are included in the Standard Library, similar to the libraries commonly packaged with compilers of programming languages such as C or C++. As an example, the Enable() function is defined to be part of the Aerotech Standard Language API by using elements of the language, but is not part of the language itself. “Enable” is not a keyword in AeroScript, but is instead an identifier similar to “printf“ in the C programming language. User-Defined Functions

User-Defined Function Overview Users can define functions to modularize their code, allowing the same set of instructions to be executed multiple times from different locations in the program. An example of a user-defined function is as follows. function MyInit($axes[] as axis) Enable($axes) Home($axes) end A program block must exist in a program that contains function definitions in order to separate the main program from the function definitions. The program block must exist at the program global scope. // Program with function definitions program MyInit([X, Y]) G1 X10 Y10 end function MyInit($axes[] as axis) Enable($axes) Home($axes) end If no functions are defined in a program, then the program block is optional. // Program without function declarations Enable([X, Y]) Home([X, Y]) G1 X10 Y10 G1 X15 Y11 The following syntax is used for defining a function that returns a value. function () as end The must be a valid identifier (see Appendix C: Valid Identifier Format), and cannot be the same as any of the Appendix A: Reserved Keywords or any axis name. The is case-sensitive. For example, both MyFunc and MYFUNC can be used to refer to the same function. A function can also be defined as not having a return value, as seen in the following syntax. function ()

48 end 7.2.2: Function Arguments The is a list of zero or more arguments to pass to a function. Arguments in the list are separated by commas, and can consist of any data type that has been previously defined. // Function without a return value function MySet($indexas integer, $value as real) $rglobal[$index] = $value end

// Function with a return value function MyAdd($val1 as integer, $val2 as integer) as integer return $val1 + $val2 end The syntax for declaring a function argument in the is similar to the declaration of a member of a struct. Refer to Appendix D: Valid Variable Name Format for the proper way for defining the . as [] as [][] as [][][] as By default, arguments are passed to a function as read-only. Attempting to modify a read-only argument within a function will result in a compilation error. However, arguments can be modified within the function if they are specified with the ref modifier, as seen in the following example. program var $counter as integer

// Stores $rglobal[0] into $counter GetCounter($counter) end function GetCounter(ref $counter as integer) $counter = $rglobal[0] end Function arguments that are defined with the ref modifier can only accept variables, not constant literals. In addition, the data type of a variable that is passed to a ref argument must match the data type of that ref argument. For example, a real variable cannot be specified to a ref argument that is defined as being an integer. program var $myVar as real

// The following statement causes a compiler error because variables // passed for arguments with the ref modifier MyFunc(3)

// The following statement is illegal (causes a compiler error) because // the variable $myVar is a real, but the function expects an integer // variable MyFunc($myVar) end

49 function MyFunc(ref $value as integer) $value = $iglobal[0] end A function can either return nothing, or it can return a single scalar (non-array) value. By passing arguments to a function with the ref modifier, you are able to “return” more than one value, including arrays. Controller global variables (such as $rglobal[], $iglobal[], and $sglobal[]) cannot be passed to a function as an argument that was specified with the ref modifier. In addition, a property cannot be passed to a function as an argument that was specified with the ref modifier. The dimensions of array arguments must match those defined in the function definition. program var $matrix1[3][3] as integer var $matrix2[5][5] as integer

// Expected dimensions ([3][3]) and actual dimensions ([3][3]) match FillMatrix($matrix1)

// Error, expected dimensions don't match actual dimensions ([5][5]) FillMatrix($matrix2) end function FillMatrix(ref $matrix[3][3] as integer) // ... end For array arguments in a function, the lengths of each array dimension are optional. Empty brackets can be specified for array dimensions, and the length of each dimension can be determined at runtime. Because the size of array dimensions do not need to be specified for array arguments, users can determine the size of an array dimension at runtime by using the intrinsic length() function. function Foo($axes[] as axis) // Get the number of axes specified var $numAxes as integer = length($axes) end Function Return Value A function can be defined to either return no value or return one value. // Function that returns no value function Foo($value as integer) $iglobal[0] = $value end

// Function that returns a value function Bar($index as integer) as integer return $iglobal[$index] end If a function returns a value, the data type of that value can be any of the fundamental data types (integer, real, string, axis, or handle), or a user-defined enum type. Aggregate data types, such as an array of values or a user-defined struct, cannot be returned from a function. However, aggregate data types can be modified by a function by specifying an argument with the desired data type with the ref modifier.

50 Function Body Definition Local user-defined variables may be declared within a function, and their scope will last until the end of the function. In addition, controller global variables as well as program global variables may be used within a function. Refer to Variable Scope for more information. Something to note is that user variables in a function cannot be declared with a name that matches one of the arguments of the function. The following example shows a case of an improper variable declaration within a function. function MyFunc($inputVal as real) // Illegal declaration because $inputVal is already defined to be a // function argument var $inputVal as real // ... end Array variables declared at the program scope must have dimension sizes that are known at compilation time. However, array variables that are declared within a function may have dimensions whose size is determined by a runtime expression. program var $progArray[3] as integer // OK var $progBad[$iglobal[2]] as real // Error, using runtime expression end function Foo($num as integer) var $subArray[$num] // OK end Function Overloading The concept of function overloading is the ability to create multiple functions that each have the same name but different implementations. To differentiate between multiple functions that have the same name:

l The number arguments must differ, or:

l The data types of arguments must differ In many cases, the compiler will be able to determine which function to call based on the number and data types of arguments that are passed in. program var $myVar as real

// Calls MyPrint() MyPrint()

// Calls MyPrint($input as integer) MyPrint(123)

// Calls MyPrint($input as string) MyPrint("Hello")

// Calls MyPrint($input as integer) // This is because $myVar (a real) can be converted to an integer $myVar = 10.0 MyPrint($myVar)

51 // Causes a compiler error because none of the MyPrint() overloads // accept an argument which can implicitly be converted from an axis MyPrint(X) end function MyPrint() end function MyPrint($input as integer) end function MyPrint($input as string) end In some cases, the compiler cannot determine the correct function to call based on the arguments that were passed to the function. If the compiler cannot make a decision, then a compilation error occurs. program var $result as real var $array[2] as integer

// Can't determine which function to call since [1, 2] can be // interpreted as both an array of integers or an array of real values $result = MyAdd([1, 2])

// Ambiguities can be resolved by specifying a variable with the correct // type to a function; the following will call the first function below $array[0] = 1 $array[1] = 1 $result = MyAdd($array) end

// This function accepts an array of integer values function MyAdd($vals[2] as integer) as integer return $vals[0] + $vals[1] end

// This function accepts an array of real values function MyAdd($vals[2] as real) as real return $vals[0] + $vals[1] end An important thing to note is that the return type of a function cannot be used to differentiate between different overloaded functions. For example, declaring the following set of functions in the same program would be invalid because it is impossible for the compiler to differentiate between them. program // Can't determine which function to call MyAdd(1, 2) end

52 function MyAdd($val1 as integer, $val2 as integer) as integer return $val1 + $val2 end

// Illegal definition function MyAdd($val1 as integer, $val2 as integer) $rglobal[0] = $val1 + $val2 end Note that both Aerotech API functions and user-defined functions may be overloaded provided that proper overloading rules are followed. For example, the Aerotech API Home() command can be overloaded to accept a second argument that is not a list of axes, allowing you to extend the functionality provided by Aerotech. Calling a Function

Simple Function Calling Use the following syntax to call a function. () = () The contains zero or more comma-separated arguments. The arguments should match the types of, or at least be able to be converted to, the types defined in a command definition. For example, a function may accept a single argument with the real type, but the function may be called with an integer if there is no overloaded function that accepts a real argument. There is a small amount of extra execution overhead when passing a real value to a function that accepts an integer argument because the controller must ensure that the real value represents a valid integer value. However, some arguments cannot be implicitly converted from one type to another – for example, a string value cannot be passed to a function that accepts a single real argument. The is not required when calling a function that returns a value. Omitting the can be useful when calling a function whose return value is not significant. program // Ignore the function's return value MyFunc(3.0) end

// This function returns a value function MyFunc($input as real) as real $rglobal[0] = $input

return $rglobal[0] end However, specifying a when the function does not return a value will result in a compilation error. program // This causes a compiler error $rglobal[0] = MyOtherFunc() end

// This function does not return a value function MyOtherFunc() $rglobal[10] = 10 end

53 If a function returns a value, then a call to that function can be used as an expression. For example, a function call can be an argument to another function or an operand in a mathematical expression. program // Move axis X to the position returned by GetNextPos() G1 X(GetNextPos())

// Use the result of MyAdd2(3, 4) as an argument to another call to // MyAdd2() $rglobal[3] = MyAdd2(MyAdd2(3, 4), 5) end

// This function returns a real value function GetNextPos() as real // Store the current value of $rglobal[0] in a local function variable var $pos as real = $rglobal[0]

// Increment $rglobal[0] by 1 $rglobal[0]++

// Return the original value of $rglobal[0] return $pos end

// This function returns an integer value function MyAdd2($val1 as integer, $val2 as integer) as integer // Add the two arguments and return the result return $val1 + $val2 end Synchronizing Function Calls With Motion When you use the velocity blending, cutter radius compensation, or corner rounding features, the controller must execute the program ahead of motion so that it can precalculate the moves and speeds. This operation is known as lookahead. When lookahead is active, user-defined functions are not normally synchronized with motion and will execute before motion functions that you specified in previous program lines. Refer to Lookahead Synchronization for more information. program // Enable velocity blending, which enables lookahead VelocityBlendingOn() MoveLinear(X, 10, 100) MoveLinear(X, 30, 75)

// As a result of lookahead, the controller executes the following // function call before it finishes producing motion for the previous // move SetGlobalVariable(32)

MoveLinear(X, 55, 80)

54 MoveLinear(X, 80, 30) VelocityBlendingOff() end function SetGlobalVariable($value as integer) $iglobal[0] = $value end You can use the sync() statement to synchronize a function call with motion while lookahead is active. Synchronizing a function call with motion will cause the controller to start executing the code in the function when the controller finishes generating motion from the function on the previous program line. This behavior is useful if you want to execute AeroScript code that is synchronized with motion while lookahead is active during a velocity blending, cutter radius compensation, or corner rounding sequence. program VelocityBlendingOn() MoveLinear(X, 10, 100) sync(nonblocking, 2) SetGlobalVariable(32) // Synchronized with motion MoveLinear(X, 55, 80) VelocityBlendingOff() end function SetGlobalVariable($value as integer) $iglobal[0] = $value end You can use the sync() statement to execute a function on the current task or on a different task. The behavior of sync() statements depends on the state of the specified task at the time that the function is called. For example, a sync() statement that executes a function on a task on which lookahead is active can disable lookahead temporarily on that task, which can cause a slowdown to zero velocity during velocity blending, or a change in programmed part geometry in a cutter radius compensation or corner rounding sequence. Refer to the following example for a program that executes synchronized functions on two different tasks, assuming that the program is not run on Task 3. program VelocityBlendingOn() MoveLinear(X, 10, 100) MoveLinear(X, 30, 75)

// Execute SetGlobalVariable() on this task, synchronously with motion sync(nonblocking) SetGlobalVariable(0, 1)

// Execute SetGlobalVariable() on Task 3, synchronously with motion sync(nonblocking, 3) SetGlobalVariable(1, 10)

MoveLinear(X, 55, 80) MoveLinear(X, 80, 30) VelocityBlendingOff() end function SetGlobalVariable($index as integer, $value as integer) $iglobal[$index] = $value end

55 The function that you call with sync() must be a user-defined function that you defined in the same program, or a user- defined function from a library that you import.

Syntax for Calling a Function Synchronously Use the following syntax to use a sync() statement. sync(nonblocking) sync(nonblocking, ) sync(blocking) sync(blocking, ) The syntax of the is the same as a normal function call that is not specified to a sync() statement. Refer to Simple Function Calling for the syntax of a . If you specify the blocking keyword, the controller waits for the called function to finish executing before executing the next program line. If you specify the nonblocking keyword, the program will not wait for the called function to finish executing before executing the next program line. Refer to the Blocking and Non-Blocking Motion-Synchronized Function Calls section for more information. Use the argument to specify the task on which the function will execute. The argument may be any numeric expression. If you do not specify a argument, the controller will execute the function in the sync() statement on the current task. program Enable([X, Y]) Home([X, Y]) VelocityBlendingOn(X) MoveLinear(X, 10, 100)

// Execute StartJogging() synchronously on Task 2 sync(nonblocking, 2) StartJogging(Y)

// Execute SetGlobalVariable() synchronously on the current task sync(nonblocking) SetGlobalVarible(6)

MoveLinear(X, 30, 50) end sync function StartJogging($axis as axis) MoveFreerun($axis, 50) end sync function SetGlobalVariable($value as integer) $iglobal[3] = $value end

Declaring a Function That Can Execute Synchronously A function that you specify in a sync() statement must be defined according to the following rules: l You must specify the sync keyword before the function keyword. l Any function arguments must be one of the following types: o integer o real o axis

56 o handle o enum l Any function arguments have the following restrictions: n The arguments cannot be specified with the ref modifier. n No array, struct, or string arguments are permitted. l You cannot specify a return type for the function. l Program global variables cannot be used within the function. // $globProgVar is a program global variable since it is declared outside // of the program/end block var $globProgVar as real program sync(blocking) Foo(3) end

// This is a valid synchronous function definition sync function SetIGlobal0($value as integer) $iglobal[0] = $value end

// The following synchronous function definition will cause a compiler // error because the ref modifier is used with an argument sync function UpdateValue(ref $value as integer) $value = 3 end

// The following synchronous function definition will cause a compiler // error because the function returns a value sync function GetPosition($axis as axis) as real return StatusGetAxisItem($axis, AxisStatusItem.PositionCommand) end

// The following synchronous function definition will cause a compiler // error because the function accesses a program global variable sync function UpdateProgramVariable($value as real) $globProgVar = $value end

Blocking and Non-Blocking Motion-Synchronized Function Calls Use the blocking keyword in a sync() statement to cause the program to wait for the controller to finish executing the function before executing the next program line in the program. For example, specify the blocking keyword to a sync() statement during a cutter radius compensation or corner rounding sequence to cause the controller to execute the function synchronously with motion without affecting the geometry of the path that you programmed and to prevent further motion in the sequence until the controller finishes executing the function. Use the nonblocking keyword in a sync() statement to cause the controller to execute the next program line in the program to execute without waiting for the function to complete. For example, specify the nonblocking keyword to a

57 sync() statement during a velocity blending sequence to execute the function synchronously with motion. If you execute the function on the current task and the function completes very quickly, or if you execute the function on a different task, you can prevent decelerations to zero velocity during the velocity blending sequence.

Blocking Motion-Synchronized Function Calls Use the blocking keyword in a sync() statement to cause the program to wait for the controller to finish executing the function before executing the next program line in the program. In a cutter radius compensation or corner rounding sequence, if you execute a function from the Functions That Lookahead Cannot Look Through section of Lookahead Synchronization, the controller will temporarily disable lookahead, which can prevent those features from generating the correct motion, such as not rounding corners in a corner rounding sequence. In a cutter radius compensation or corner rounding sequence, you can specify those functions in a function that you call with a sync() statement using the blocking keyword to prevent those functions from temporarily disabling lookahead and causing the controller to generate incorrect motion, while causing the controller to wait for the function to finish executing. Refer to the following example to see how you can use a sync() statement to execute a function synchronously with motion during a cutter radius compensation sequence without affecting the programmed path and waiting until the function completes. program Enable([X, Y, Z]) Home([X, Y, Z])

// Start a cutter radius compensation sequence G44 X Y G43 P0.025 G41 G1 X5 Y5 G1 Y10 G1 X10

// Perform a blocking synchronous function call in the middle of the // cutter radius compensation sequence sync(blocking) TriggerFreerun(Z)

G1 Y-10 G1 X-10

// Deactivate cutter radius compensation G40 X0 Y0 end sync function TriggerFreerun($axis as axis) // MoveFreerun() would normally affect the geometry of the cutter // radius compensation sequence, but executing as part of a sync() // statement causes it to preserve the correct geometry MoveFreerun($axis, 100) end In a velocity blending sequence, use the blocking keyword in a sync() statement to cause the controller to decelerate to zero velocity before executing the specified function. Refer to the following example to see how you can use a sync() statement to execute a function synchronously with motion during a velocity blending sequence while forcing a slowdown to zero velocity. program Enable(X)

58 Home(X)

// Start a velocity blending sequence VelocityBlendingOn() MoveLinear(X, 10, 25)

// Perform a blocking synchronous function call in the middle of the // velocity blending sequence, forcing a slowdown to zero velocity // before the function executes sync(blocking) SetAnalogOutput(Z, 2.5)

MoveLinear(X, 30, 30)

// Deactivate velocity blending VelocityBlendingOn() end sync function TriggerFreerun($axis as axis) // AnalogOutputSet() is synchronized with motion, so specifying it // between the moves in the program above would cause it to execute // without forcing a slowdown to zero velocity; However, calling the // function in a blocking sync() statement forces the controller to // decelerate motion before the function is called MoveFreerun($axis, 100) end

Non-Blocking Motion-Synchronized Function Calls Use the nonblocking keyword in a sync() statement to cause the controller to execute the next program line in the program to execute without waiting for the function to complete. In a cutter radius compensation or corner rounding sequence, if you execute a function from the Functions That Lookahead Cannot Look Through section of Lookahead Synchronization, the controller will temporarily disable lookahead, which can prevent those features from generating the correct motion, such as not rounding corners in a corner rounding sequence. In a cutter radius compensation or corner rounding sequence, you can specify those functions in a function that you call with a sync() statement using the nonblocking keyword to prevent those functions from temporarily disabling lookahead and causing the controller to generate incorrect motion, while causing the controller to execute the next program line before the controller finishes executing the function. Refer to the following example to see how you can use a sync() statement to execute a function synchronously with motion during a cutter radius compensation sequence without affecting the programmed path and immediately continuing program execution without waiting until the function completes. // This program executes on Task 1 program Enable([X, Y, Z]) Home([X, Y, Z])

// Start a cutter radius compensation sequence G44 X Y G43 P0.025 G41 G1 X5 Y5 G1 Y10

59 G1 X10

// Perform a non-blocking synchronous function call in the middle of the // cutter radius compensation sequence; the controller will immediately // start executing the next move (G1 Y-10) without waiting for the // DoMotion() function to finish executing sync(nonblocking, 2) DoMotion(Z)

G1 Y-10 G1 X-10

// Deactivate cutter radius compensation G40 X0 Y0 end sync function DoMotion($axis as axis) MoveAbsolute($axis, 100, 50) WaitForMotionDone($axis) MoveAbsolute($axis, 0, 75) end In a velocity blending sequence, use the nonblocking keyword in a sync() statement to cause the controller to execute the specified function synchronously with motion without decelerating to zero velocity. If you specify the current task to the sync() statement, and the function takes longer than one millisecond to execute, a slowdown to zero velocity can occur. You can specify a different task to the sync() statement to prevent a slowdown to zero velocity in velocity blending mode. Refer to the following example to see how you can use a sync() statement to execute a function synchronously with motion during a velocity blending sequence without affecting the velocity blending that occurs on the X axis, and immediately continuing program execution without waiting until the function completes. program Enable([X, Y]) Home([X, Y])

// Perform motion with velocity blending VelocityBlendingOn() G1 X10 F30 G1 X20 F50

// Perform a non-blocking synchronous function call on Task 2 // Since a call to Home() can take multiple milliseconds to execute, // executing this function on the current task could cause a // deceleration to zero velocity sync(nonblocking, 2) TriggerHome(Y)

// Continue the velocity blending sequence G1 X15 F25 G1 X25 F10

// Disable velocity blending mode

60 VelocityBlendingOff() end sync function TriggerHome($axis as axis) // Home() would normally cause a slowdown to zero velocity when // executed in a velocity blending sequence, but executing it in a // non-blocking synchronous function call causes it to not slow down if // executed on a different task Home($axis) end

Restrictions When Calling a Function Synchronously If the task that you specify to a sync() statement is currently performing an AeroScript operation that is synchronized with motion, an error will occur if the function that you specify to the sync() statement contains an AeroScript operation that is synchronized with motion. For example, if a program on Task 2 is currently executing a MoveLinear() function, you cannot execute a sync() statement that calls a function with a MoveRapid() function on Task 2 at the same time. Refer to the Function Synchronization During Lookahead section of Lookahead Synchronization for operations that are synchronized with motion. If you execute a sync() statement from a task that is currently performing velocity blending, cutter radius compensation, or corner rounding, the function that you execute cannot have any of the same axes that are active as part of those features.

61 Libraries

The base language contains things such as statements (if/while/repeat), operators and intrinsic functions (+, -, /, length ()), labels, function declarations, and literals, among others. A library is a collection of functions, properties, and data types that can be used to extend the language. There are three different types of libraries that exist to extend the language:

l Automation1 Standard Library

l Aerotech-provided extending libraries

l User-defined libraries Library source files can be compiled into binary library files that can be imported (linked to) by source programs or other libraries. The binary library format allows libraries to be distributed without exposing their source code, making them ideal for protection of intellectual property. Libraries can be imported to a program either statically or dynamically. With static linking, the code of the library functions is directly included in the final program executable. With this method, the executable can be distributed without needing to distribute the library as well because the executable has all of the information that it needs to be executed. With dynamic linking, the library must be loaded into the memory of the controller, and the program that linked to it can call functions from the library dynamically. This method is useful when multiple programs executing on the controller share the same library. This is also useful for calling functions in special cases such as from a program running from an immediate command. Library Types

Automation1 Standard Library The Standard Library is a collection of functions that comes standard with every Automation1 motion controller. This library can be used without explicitly including it in programs, and includes functions such as Enable(), Home(), and GearingOn(). Refer to the Automation1 help for or a complete list of functions that are included with AeroScript. Aerotech Extending Libraries Aerotech can provide extending libraries as a way to supplement the Standard Library. These libraries can consist of things that are provided along with a purchased option, or that don’t fit well into the Standard Library. For example, the following things could be placed into a library and provided on an as-needed basis. l Hexapod transformation library l Other customer-specific transformations User-Defined Libraries You can create your own AeroScript libraries as well. This ability is useful for if you have sets of functions that you use in various projects, allowing you to make your functions more modular. In addition, this is useful for OEMs that want to distribute libraries to end users with or without the source code. Creating a Library Libraries are constructed similarly to programs. However, a library cannot be executed directly like a program, therefore a library cannot contain a program block. A library can contain program global variables to maintain state information. These variables cannot be accessed directly by consumers of the library. However, they can be accessed through library functions or properties. var $value as integer

// Function to set the $value variable library function SetValue($newValue as integer) $value = $newValue end

// Function to retrieve the $value variable library function GetValue() as integer

62 return $value end The library keyword can be specified on the same line before function, property, struct, and enum declarations as a means of exporting those concepts from the library. If the library keyword is not used with these declarations, then the concept is not exported from the library, but can still be used internally to the library. The following code shows an example of using the library keyword to export a function from a library, as well as omitting the library keyword to prevent a function from being exported. // This function is visible for consumers of the library library function MyAdd3($a as integer, $b as integer, $c as integer) as integer return MyAdd2($a, MyAdd2($b, $c)) end

// This function is internal to the library and cannot be used directly by // consumers of the library function MyAdd2($a as integer, $b as integer) return $a + $b end If a function is exported from a library by using the library keyword, then all of its arguments (if specified) must have data types that are primitive data types (integer, real, axis, string, handle), or user-defined struct and enum data types that have also been exported with the library keyword. Refer to the following example for more information. // This enum is visible for consumers of the library library enum Suits Spades Hearts Clubs Diamonds end

// This enum is internal to the library enum Directions Up Down Left Right end

// This is a valid exported function since the Suits type is exported library function MyFunc1($arg as Suits) // ... end

// This is not a valid exported function since the Directions type is internal library function MyFunc2($arg as Directions) // ... end A similar concept can be applied to a property that is exported from a library with the library keyword. All property indices (if specified) must have data types that are primitive data types (integer, real, axis, string, handle), or user- defined struct and enum data types that have also been exported with the library keyword.

63 Finally, a similar concept can be applied to a struct that is exported from a library with the library keyword. All struct members must have data types that are primitive data types (integer, real, axis, string, handle), or user-defined struct and enum data types that have also been exported with the library keyword. Using a Library In order to use a library, you must import it into the program or other library from which you wish to call its functions. A library can be imported as either static or dynamic depending on your specific needs. The syntax for importing a library is as follows, where the name of the library is a compiled binary library file with the file extension .a1lib. import ""as static import ""as dynamic All import statements must be placed at the program-level scope of a source file, outside of any program blocks, function blocks, or other block statements such as if, while, and repeat. When using import as dynamic, the dynamic library must be loaded onto the controller before the program that uses the library can call its functions; otherwise a runtime error will occur. If a library imports another library, any functions, properties, structs, or enums that were exported from the imported library will not be exported from the importing library. An example for writing a library and importing it into a program follows. // Library source file (MyLibrary.ascriptlib) library function SetAllAnalogOutputs($axis as axis, $voltage as real) AnalogOutputSet($axis, 0, $voltage) AnalogOutputSet($axis, 1, $voltage) AnalogOutputSet($axis, 2, $voltage) AnalogOutputSet($axis, 3, $voltage) end // Program source file import "MyLibrary.a1lib" as static

SetAllAnalogOutputs(X, 2.5) SetAllAnalogOutputs(Y, 2.5) SetAllAnalogOutputs(Z, 2.5) SetAllAnalogOutputs(U, 2.5)

64 G-Code (RS-274) Support Supported G-Code Letters The following G-code letters are supported by the language. Letter Meaning E Feedrate of Dependent Axes F Feedrate of Dominant Axes G General Function (G-code) I I Offset for G2/G3/G12/G13 J J Offset for G2/G3/G12/G13 K K Offset for G2/G3/G12/G13 M Miscellaneous Function (M-code) N Line number/label (N-code) P Absolute Starting Angle for G2/G3/G12/G13 Q Absolute Ending Angle for G2/G3/G12/G13 R Radius for G2/G3/G12/G13 S Spindle Speed

More details about the G-code letters follow: l Each of these letters is supported by the G-code (RS-274) standard. l These letters are case-insensitive, so that both G1 and g1 mean the same thing. l Most of the remaining letters are allowed to be used as axis names (e.g., X, Y, and Z). Refer to Appendix B: Axis Naming Conventions for more information. l Some additional letters (H and L) are part of the G-code (RS-274) standard but are unused in AeroScript. These letters are reserved for future use. Many concepts in G-code are not whitespace-sensitive. Whitespace between G-code letters and their expressions is optional. For example, each of the following lines of G-code programming have the same meaning. G1X10Y100 G1 X10 Y100 G 1 X 10 Y 100 E Command The E command is used to specify the feedrate for dependent axes when performing coordinated motion. Coordinated motion includes the following types of motion:

l G1, MoveLinear()

l G2, MoveCw()

l G3, MoveCcw()

l G12 and G13 An E command may be specified on its own program line, or it can be specified on the same program line as G-code motion. // Specified on its own line E100

// Specified as part of a move G1 Y50 E100 An E command can either be specified with a constant value or with a numeric expression. // Specified with a constant feedrate E100

// Specified with a numeric expression feedrate

65 E($dependentSpeed) The dependent feedrate is used for coordinated moves that contain only dependent axes. If a coordinated move contains only dominant axes, or a mixture of dominant and dependent axes, then the move will use the dominant feedrate (the F command). F Command The F command is used to specify the feedrate for dominant axes when performing coordinated motion. Coordinated motion includes the following types of motion:

l G1, MoveLinear()

l G2, MoveCw()

l G3, MoveCcw()

l G12 and G13 An F command may be specified on its own program line, or it can be specified on the same program line as G-code motion. // Specified on its own line F100

// Specified as part of a G-code move G41 G1 X10 Y10 F100 An F command can either be specified with a constant value or with a numeric expression. // Specified with a constant feedrate F100

// Specified with a numeric expression feedrate F($mySpeed * 0.1) The dominant feedrate is used for coordinated moves that contain only dominant axes or a mixture of dominant and dependent axes. If a coordinated move contains only dependent axes, then the move will use the dependent feedrate (the E command). G-Codes G-codes are used to configure and perform various types of motion on the controller. G-codes must be specified with a numeric integer constant. Preceding zeros are allowed to be used in the numeric value, making both of the following G-codes equivalent: // The following G-codes are equivalent G1 X10 G01 X10 Refer to the list of Supported G-codes for more information. I/ J/K Offsets The I, J, and K offsets are only applicable with the G2, G3, G12, and G13 G-codes. M-Codes M-codes are used to perform miscellaneous functionality on the controller. M-codes must be specified with a numeric integer constant. Preceding zeros are allowed to be used in the integer value. The following two M-codes are equivalent: l M2 l M02 Refer to the list of Supported M-codes for more information.

66 N-Codes N-codes are used to label a line or a block of G-code. N-codes are optional on G-code lines. If an N-code is specified on a program line that contains G-code concepts, then it must be specified before all other G-codes on the same line. N-codes must be specified with a positive numeric integer constant. Preceding zeros are allowed to be used in the numeric value. l N01G1X10 l N02G1X15 N-codes can be used as an alternative to labels when used in G-code. // Use a label to branch to a specific location in G-code goto myLabel

G1 Y1.3 G1 Y2.2 myLabel: G1 Y3.5

// Use an N-code to branch to a specific location in G-code goto N03

N01G1X2.5 N02G1X3.3 N03G1X7.5 P Command The P command has different meanings depending upon the context in which it is specified. A P command cannot be specified on its own program, and must be specified on the same line as G2, G3, G12, or G13 G-code motion, or with the G4 G-code. l When specified along with the G4 G-code, the numeric value of the P command is used to specify the amount of time that the G4 command will delay execution of the task. l When specified with G2, G3, G12, or G13 G-code motion, the numeric value of the P command is used to specify the absolute starting angle for the G2 or G3 arc move. In both usages, the numeric value specified as part of the P command can be a numeric constant or a numeric expression. G4 P0.1 G4 P$dwellTime G2 P108 Q-18 R1.5 Q Command

The Q command is used to specify the absolute ending angle for a G2, G3, G12, or G13 arc move. A Q command cannot be specified on its own line, and must be specified on the same line as G2, G3, G12, or G13 G-code motion. The numeric value specified as part of a Q command can be a numeric constant or a numeric expression. R Command

The R command is used to specify the radius in an arc move (G2, G3, G12, and G13 G-codes). The R command cannot be specified on its own line. When using G-codes, an R command can only be specified on the same line as a G2, G3, G12, or G13 G-code motion. The numeric value specified as part of an R command can be a numeric constant or a numeric expression. G2 X10 Y0 R5

67 S Command The S command is used to define the speed of the spindle that is active on the current task. Supported G-codes G-Code Description G0 Executes a rapid point-to-point positioning move on the specified axes. G1 Executes a coordinated linear move on the specified axes. Executes a circular arc move in the clockwise direction on the specified axes in the first G2 coordinate plane. Executes a circular arc move in the counterclockwise direction on the specified axes in the first G3 coordinate plane. G4 Suspends the execution of the task for the duration that you specify, in seconds. Causes the G-code motion that you specify on the same program line to immediately G8 accelerate to the programmed feedrate. Causes the G-code motion command that you specify on the same program line to decelerate G9 to zero velocity when the axes get to their target position. Executes a circular arc move in the clockwise direction on the specified axes in the second G12 coordinate plane. Executes a circular arc move in the counterclockwise direction on the specified axes in the G13 second coordinate plane. Configures the set of axes that are used for the first coordinate plane for G2 and G3 G16 commands. Configures the task to use the first set of axes of the first coordinate system for G2 and G3 G17 commands. Configures the task to use the second set of axes of the first coordinate system for G2 and G3 G18 commands. Configures the task to use the third set of axes of the first coordinate system for G2 and G3 G19 commands. Configures the set of axes that are used for the second coordinate plane for G12 and G13 G26 commands. Configures the task to use the first set of axes of the first coordinate system for G12 and G13 G27 commands. Configures the task to use the second set of axes of the second coordinate system for G12 G28 and G13 commands. Configures the task to use the third set of axes of the second coordinate system for G12 and G29 G13 commands. G40 Deactivates Cutter Radius Compensation mode on the task. G41 Activates Cutter Radius Compensation left mode on the task. G-Code Description G42 Activates Cutter Radius Compensation right mode on the task. G43 Specifies the radius that the task uses in Cutter Radius Compensation mode. Specifies the pair of axes that comprise the X-Y plane when Cutter Radius Compensation G44 mode is active on the task. Configures the task to use the acceleration duration that you specify for coordinated motion G60 while operating in time-based ramping mode. Configures the task to use the deceleration duration that you specify for coordinated motion G61 while operating in time-base ramping mode. Configures the task to operate with the sinusoidal acceleration and deceleration ramping type G63 for coordinated motion. Configures the task to operate with the linear acceleration and deceleration ramping type for G64 coordinated motion.

68 G-Code Description Configures the task to use the acceleration rate that you specify for coordinated motion while G65 operating in rate-based ramping mode. Configures the rate that the task uses to perform coordinated motion to decelerate dominant G66 axes. Configures the task to use time-based ramping when accelerating and decelerating axes G67 during coordinated motion. Configures the task to use rate-based ramping when accelerating and decelerating axes during G68 coordinated motion. Configures the task to operate with the S-curve acceleration and deceleration ramping type G69 for coordinated motion. Configures the task to treat distances and feedrates that you specify in G-code commands as G70 being English units. Configures the task to treat distances and feedrates that you specify in G-code commands as G71 being metric units. Configures the task to treat feedrates that you specify in G-code commands as being distance G75 units per minute. Configures the task to treat feedrates that you specify in G-code commands as being distance G76 units per second. Clears the program position offset on the specified axis. The program position will be restored G82 to the current axis position. G90 Configures the task to operate in the absolute target mode. G91 Configures the task to operate in the incremental target mode. G-Code Description Sets the program position of the specified axes. All moves that specify an absolute target- G92 position will be relative to the new program position. Configures the task for inverse time feedrate mode. Values specified to the F command are interpreted as the inverse amount of time that the controller should take to complete the G93 distance specified in the move. Configures the task for normal feedrate mode. Values specified to the F command are G94 interpreted as distance units per unit of time. Configures the task to interpret feedrates that you specify with the F command or the E G95 command as units per spindle revolution. Configures the task to interpret the S command as the tangential speed, or the speed on the G96 surface, of the spindle axis. You must specify surface speed and a radial axis to this command. G97 Configures the task to interpret the S command in velocity units. G98 Enables inverse dominance mode on the task. G99 Disables inverse dominance mode on the task. G100 Disables spindle shutdown mode on the task. G101 Enables spindle shutdown mode on the task. G108 Enables velocity blending mode on the task. G109 Disables velocity blending mode on the task. G114 Enables optional pause mode on the task. G115 Disables optional pause mode on the task. Configures the center point coordinates that you specify to a coordinated arc motion G118 command to be in absolute user units. Configures the task to disable the effects of manual feedrate override (MFO) and the G120 feedhold state during asynchronous motion. Configures the task to enable the effects of manual feedrate override (MFO) and the feedhold G121 state during asynchronous motion. G150 Disables part scaling mode on the task.

69 G-Code Description G151 Enables part scaling mode on the task. Configures the rate that the task uses to perform coordinated motion to accelerate G165 dependent axes. Configures the rate that the task uses to perform coordinated motion to decelerate G166 dependent axes. G-Code Description G359 Sets the wait mode to wait the minimum amount of time between motion blocks. G360 Sets the wait mode to wait for all motion to be done between motion blocks. Sets the wait mode to wait for all motion to be done and for all axes to be in position between G361 motion blocks. Supported M-codes M -Code Description M0 Pauses the current task. Pauses the current task if the optional pause mode is active on the task, or does nothing if M1 optional pause mode is not active. M2 Stops the execution of the program on the current task. Starts motion in the clockwise direction on the spindle axis that is configured for the task. The M3 command is complete after the spindle accelerates to the commanded speed. Starts motion in the counterclockwise direction on the spindle axis that is configured for the M4 task. The command is complete after the spindle accelerates to the commanded speed. M5 Causes the spindle axis that is configured for the task to decelerate to zero speed. M30 Resets the execution of the AeroScript to the first executable line. Resets the execution of the AeroScript to the first executable line. Then it causes the M47 controller to start execution of the program. M48 Disables the use of manual feedrate override (MFO) controls. M49 Enables the use of manual feedrate override (MFO) controls. M50 Disables the use of manual spindle override (MSO) controls. M51 Enables the use of manual spindle override (MSO) controls. Starts motion on the spindle axis that is configured for the task in the clockwise direction. The M103 command does not wait for the spindle to accelerate to the commanded speed. Starts motion on the spindle axis that is configured for the task in the counterclockwise M104 direction. The command does not wait for the spindle to accelerate to the commanded speed. G-code Specification Rules

G-code and Exponential Notation AeroScript has special rules when parsing G-code programs due to the existence of the E command in the G-code dialect, in addition to support for constant floating-point values that are specified with exponential notation, as well as the G- code dialect being whitespace-insensitive. A floating-point value specified with exponential notation must be delimited on both its left and right sides in order to prevent conflicts with the E command in G-code programming. The following examples show how exponential notation and the E command are treated in various circumstances. // E commands E100 E 100

// Exponential notation $myVar = 1e10

70 // Move with Y = 1, E command = 10 G1 Y1E10

// Move with Y = 1, E command = 10 G1 Y1 E10

// Move with Y = 1E10 (no E command) G1 Y 1E10

// Move with Y = 1, E command = 10 G1 Y 1 E 10

// Exponential notation can be enforced by using delimiter characters G1 Y(1E10) G1 Y=1E10 G-code and Hexadecimal Notation In addition to the exceptions that were made for the E command and exponential notation, there are also exceptions when specifying hexadecimal literals in a G-code program. A hexadecimal literal must be delimited on both its left and right sides in order to prevent conflicts with an axis called either X or x that is directly followed by an integer value in G-code. The following examples show how hexadecimal notation and G-code are treated in various circumstances. // G-code X10

// Hexadecimal notation $myVar = 0x10

// Move with Y = 0, X = 10 G1 Y0X10

// Move with Y = 0, X = 10 G1 Y0 X10

// Move with Y = 0x10 (16, no move on X) G1 Y 0X10

// Move with Y = 0, X = 10 G1 Y 0 X 10

// Hexadecimal notation can be enforced by using delimiter characters G1 Y(0X10) G1 Y=0X10

71 Appendix A: Reserved Keywords

The keywords that follow are reserved by the language, and therefore are unable to be used as identifiers such as function names, label names, or user-defined data type (struct) names. These keywords are case-sensitive (i.e., if is valid but IF is not). as false library string axis for nonblocking struct blocking foreach onerror switch break function program sync case get property to continue goto real true default handle ref value dynamic if repeat var else import return wait elseif in set while end integer static enum length step

72 Appendix B: Axis Naming Conventions

Axis names may be any of the following single-character names: A a B b C c D d U u V v W w X x Y y Z z

All other single-character names are reserved for either G-code programming or for future use, including E/e, F/f, G/g, H/h, I/i, J/j, K/k, L/l, M/m, N/n, O/o, P/p, Q/q, R/r, S/s, and T/t. In addition to the valid single-character names listed above, most names that match the following regular expression are valid axis names. [A-Za-z_][A-Za-z0-9_]+ The above regular expression means that an axis name must follow the following rules: l It must start with a letter or underscore. l After the first letter/underscore, it must be followed by one or more letters, numbers, or underscores. In addition to the valid axis names outlined above, there are some further restrictions. Axis names may not match any of the Appendix A: Reserved Keywords of the language. No two axes on the controller can be named the same. In addition, if the name of an axis contains a number, there may not be another axis in the system whose name is a substring of that name. See the following example for the reasoning. // Consider if axes X and X2 exist in the system // The following line is ambiguous (could be interpreted as X(250) or // as X2(50)) G1X250 Axis names may still contain a number as long as the substring restriction mentioned previously is followed. For example, the controller may consist of axes named X1 and X2 as long as no axis with the name X exists on that controller. An axis name cannot end with the character F or f if there are any other axes on the controller whose name is the same without the ending F or f character. For example, if an axis on the controller is named MyAxis, then another axis cannot be named MyAxisF. Axis names are case-sensitive, meaning that the names “X” and “x” refer to different axes.

73 Appendix C: Valid Identifier Format

An identifier is a name that is used to identify various entities in a program: l function names l Labels l User-defined data type (struct and enum) names An identifier must match the following regular expression. [A-Za-z_][A-Za-z0-9_]+ The above regular expression means that an identifier has the following rules: l It must start with a letter or underscore. l It must contain at least one more letter, number, or underscore.

In addition, an identifier has the following restrictions: l It cannot be the same as any of the reserved keywords (see Appendix A: Reserved Keywords). l It cannot be the same as any of the axes used in the system. l It cannot be an axis name followed by an integer literal, e.g., X100 if there is an axis called X. l It cannot be any of the supported Supported G-Code Letters, or a G-code letter followed by an integer literal, such as F100. Identifiers are case-sensitive. For example, an identifier MyLabel is treated as a different identifier than MYLABEL.

74 Appendix D: Valid Variable Name Format

A variable name is a name that is used to identify various entities in a program:

l Variable names

l Function argument names

l Names of struct members A variable name must match the following regular expression. $[A-Za-z_][A-Za-z0-9_]* The above regular expression means that an identifier has the following rules:

l A variable name must start with a dollar sign ($)

l After the dollar sign ($), it must contain a letter or underscore.

l After the first letter or underscore, it can contain zero or more letters, numbers, or underscores. Variable names are case-sensitive. For example, a variable name $myVar is treated as a different variable name than $MYVAR.

75