## Syntax

All CFL block consists of a series of instructions. Each instruction tells CFL what to do. An expression terminates when it reaches a semicolon (;) or no more text follows.

Instruction Instruction Instruction Instruction Instruction; Instruction Instruction Instruction Instruction Instruction; Instruction Instruction Instruction Instruction // Comment on Instruction

**White Space**

When writing CFL, the use of spacing makes formulas easier to read. Adding blank lines between logical areas or indenting related instructions can help. In CFL, these extra spaces, tabs, line returns, and blank lines are known as white space because those characters simply act as aids. CFL ignores white space. Thus, it does not slow computations down.

**Comments**

**Comments** describe what is going on. The author may thoroughly understand their own work, but when they return for maintenance in six months, they often forgot the intricacies of their own creation. Just like white space, CFL ignores all comments, regardless of how lengthy they are.

A **single-line comment** is created by typing in two slashes (*). Comments go at the end of a line of code. *

//'' Declare x : 3*4 ; '' //'' Explain what x is used for here ''

A **multi-line comment** begins with an open curly bracket ({) and ends with a closed curly bracket (}).

{The multi-line comment is very useful when comments span multiple lines and using slashes is counter productive.}

Adding comments to code aids understanding, but commenting is excessive and even confusing if used for every line. Comments, like white space, should be used judiciously.

**Blocks**

A **block** is a group of CFL expressions. They are denoted by BEGIN and END keywords. Blocks combine multiple expressions. The main rule to remember is that for every BEGIN, there must be an END.

BEGIN Declare Circumference PI * \Radius^2; IF Circumference> 3 SqFeet THEN "Too Big" ELSE "Just Right" ENDIF END

Note the use of white space to aid the reader in their understanding.

## Data Types

CFL works with a number of data types. The most common types are numbers and strings.

**Number Type**

**Number types** store numeric information. All mathematical operations require a number type. In CFL, numeric data is written in a series of numbers, with an optional decimal place between the numbers.

Thousand separators, currency symbols, and other text are **not** valid when writing a number in CFL.

Examples of valid numbers (in the US) are:

56937.34 1344 584. 0.984737594

Examples of invalid numbers are:

1,024,037 10E7 $122.85 3.45.68

Internally, the numbers are stored as floating point numbers and maintain 15-16 significant places.

The value to the left of a decimal point is the integer. The portion to the right of the decimal point is the fractional part.

3.1416

Integer Fractional

Understanding mathematic vocabulary is an important part of using CFL code.

**String Types**

**String types**, or **strings**, describe information that is stored as text within CFL. Strings are written between single or double-quote symbols and may be of any length. Single quotes can nest inside double quotes, and vice-versa.

Examples of valid strings are:

"This is a string!" "" 'That was an empty string.' "0.984737594" 'John said, "Cool!" ' 'Don''t do that!'

Examples of invalid strings are:

I forgot the quotes! "John said, "Oops" "

Each letter, space, number, or symbol in a string is called a **character**. The length of a string is the total number of characters it contains.

**Boolean**

**Boolean types** are commonly used to evaluate conditions, but can also be used to store information.

Boolean types are either logical, binary, true/false, yes/no, or 1/0 types. They store one of two states. One state is normally TRUE or YES. Likewise, the other state is normally FALSE or NO. In CFL, the constants TRUE, YES, FALSE, and NO are valid Boolean values.

Examples of valid Boolean expressions are:

TRUE (Color "Red") or (Name "Tigers") NO Quantity> 16

Examples of invalid Boolean expressions are:

MAYBE (no such predefined keyword) "YES" (since it is in quotes, this is a string, not a Boolean value)

CFL treats Booleans as a special case of the number type mentioned already. Zero (0) is considered NO or FALSE, whereas one ^{1)} )</sup> is considered to be YES or TRUE.

**DateTime Types**

**DateTime types** store dates and times. In CFL, adding and subtracting DateTime types determines the number of days/hours/minutes between two events.

For portability purposes, the format for DateTime data in CFL does not vary by region. DateTime types begin and end with the number sign (#).

Examples of valid DateTime expressions are:

#03/15/2005# #1/18/05 3:12 PM# #12/31/2004 23:59:59.99# #11:52 AM#

Examples of invalid DateTime expressions are:

#2005-03-14# #1/05 5:30 PM# #1/1/01 23.15#

CFL treats DateTime as a special case of the number type mentioned already. The integer portion stores the number of days from December 30, 1899. The fractional portion stores the fraction of the day since Midnight of the previous morning.

## Expressions and Operators

An **expression** is an instruction that performs some kind of calculation (using **operators**) and returns a value. CFL supports all expressions and operators listed on the following pages.

**Numeric Operators**

Operator | Description | Example | |||||

- | Subtraction | 4 – 3 1 | |||||

% | Percentage | 35 % 0.35 | |||||

* | Multiplication | 6 * 7 42 | |||||

/ | Division | 24 / 4 6 | |||||

\ | Exponentiation | 2\ | 3 8 | ||||
---|---|---|---|---|---|---|---|

+ | Addition | 3 + 4 7 | |||||

< | Less Than | 4 < 6.5 | |||||

Greater Than | 7 > 5 | ||||||

> | Greater Than or Equal To | ||||||

BitAND | Binary AND | 10 BitAND 7 2 | |||||

BitNOT | Binary Negation | BitNot 10 (2\ | 32 - 10) | ||||

BitOR | Binary OR | 10 BitOR 7 15 | |||||

BitXOR | Binary XOR | 10 BitXOR 7 14 | |||||

MOD | Modulus Division (remainder) | 7 mod 3 1 |

BitOR, BitAND, and BitNOT are binary functions that deal with the individual bits (binary digits) in a number. The number 7 in binary is “0111”. The number 10 in binary is “1010”. Coverage of binary numbers is beyond the scope of this reference. If not familiar with them, they should be avoided in expressions.

Additionally, BitNOT results may vary for 32 and 64-bit systems. Very large numbers may display as negative values. If many BitNOT statements are used, they should be counter-balanced with BitAND (with a number like (2\^16 - 1)) to “clean up” the higher-order bits.

**String Operators**

Operator | Description | Example |
|||

* | Replication | “E1” * 3 “E1E1E1” | |||

/+ | Line Concatenation Combines two strings with a line break between If either value is blank, no line break is added and the other value is returned | “Line 1” /+ “Line 2” “Line 1 Line 2” |
|||

+ | Concatenation | “Ho” + “use” “House” | |||

< | Less Than | “Green” < “Grocer” | |||

Greater Than | “Red” > “Apple” | ||||

> | Greater Than or Equal To | ||||

InList[] | Acts like the IN operator in SQL | Order.StatusText InList [“WIP”, “Built”, “Sale”] |

**Boolean Operators**

Operator | Description | Example |
|||

AND | Logical AND | False | |||

NOT | Negation | ( Not (3 4) ) True | |||

OR | Logical OR | ^{2)} )</sup> True |
|||

XOR | Logical XOR | ^{3)} )</sup> True |

**DateTime Operators**

Operator | Description | Example |
|||

- | Subtraction | ||||

* | Multiplication | ||||

/ | Division | ||||

+ | Addition | ||||

< | Less Than | ||||

Greater Than | |||||

> | Greater Than or Equal To | ||||

MOD | Modulus Division (remainder) |

**Operator Precedence**

When an expression contains more than one operator, CFL uses a set of rules to determine which operator to evaluate first, second, third, and so on, until the entire expression is evaluated. Each **operator** has a built-in priority, or **precedence**, which the compiler uses to determine the operator to evaluate next.

Look at the following expression:

3 + 4 * 5

At first glance, many would think this evaluates to 35. This would be correct if CFL simply evaluated from left to right and did the addition first and the multiplication second. However, since multiplication has higher operator precedence than addition, multiplication is done first. CFL will evaluate 4*5 and then add this result (20) to 3 and get 23. Parentheses override operator precedence. For example:

( 3 + 4 ) * 5

This expression would indeed evaluate to 35 because parenthesis have a higher precedence than multiplication (or anything else for that matter).

CFL recognizes the following operator precedence:

Priority | Category | Operators |
|||

Highest | Grouping | Parenthesis, Functions | |||

2nd Highest | Unary | +, -, Not, BitNot, % | |||

3rd Highest | Units | Per, In, *, /, Units | |||

Exponentiation | \ | ||||

Multiplicative | *, /, Mod | ||||

3rd Lowest | Additive | +, - , And, Or, XOR, BitOr, BitAnd, BitXOR | |||

2nd Lowest | Relational | , , , | |||

Lowest | Assignment |

When operands are between operators of the same precedence, then operations are performed from left to right, with the exception of unary and assignment operators. Therefore,

3 * 4 / 0 * 5

is equivalent to ( ( ( 3 * 4 ) / 0 ) * 5 ), and gives an error, due to division by zero, whereas the expression

3 * 4 / 5 * 0

will not give an error.

**Temporary Variables** Complex formulas are easier (and usually faster) if they are broken down into steps. Temporary variables are ideal for such occasions. Temporary variables are created within the CFL block and do not retain their values after the evaluation of the block is complete. (This is in contrast to Global Variables, which is discussed later.) Temporary variables use the “DECLARE” keyword and can be assigned a value immediately or upon later use, as in this example:

// First, convert the temperature Global Variable to Centigrade Declare Centigrade := (Temperature – 32) * 5/9 ; Declare ExpansionText ; // Calculate the expansion coefficient for the C temperature Declare Expansion := \Centigrade^1.5 / 6.17323 ; ExpansionText := "Expansion of " + ToString( Expansion ) + "nm / Y" ; // Now repeat the expansion text 2 times as the result ExpansionText + " ! " + ExpansionText + " ! "

Note that the assignment operator is the colon-equals, and not just the equal sign as in some programming languages. This is to prevent confusion with the comparison operator. In this example, the temporary variable “Centigrade” converted the global variable “Temperature” to degrees C. From this, CFL calculated the expansion coefficient. This entire calculation could not be done in one step, and the multiple-step approach makes the logic easier to follow. As in the example above, temporary variables are not limited to numbers. They can be any of the CFL data types, including Objects!

// First, define our local object reference variables Declare Referral := 'None'; Declare Salesperson := 'None'; // Assign the 'Referral' variable IF TransactionUDFIsAssigned('Referred By Customer') THEN Referral := TransactionUDFObject('Reffered By Customer'); ENDIF; // Assign the referring Sales person Salesperson := Referral.Company.Salesperson1.IDAsString; SetTransactionUDFObjectID( "InitialSalesperson", Salesperson ); // Output referral and salesperson Referral + "referred by " + Salesperson

**Units** One of the most powerful features of CFL is the built-in support for units. Units are written in CFL just as in high-school science: after the number or variable they modify.

Declare WorkingPrice := Area in SqFeet * 5; MaxSize := IF ( Height <3 SqMeters ) THEN 500 millimeters ELSE 0.95 meters ENDIF ; Declare TooBig := ( MaxSize*MaxSize> 24 SqInches ) ; IF ( 12 inches = 1 foot ) THEN "Elementary" ELSE "Error" ENDIF

Here are some simple rules to remember about using units:

- Units apply to the number or variable immediately before them.
- Variables are stored internally in their own units. Units are not needed when multiplying or adding variables, only when working with numbers or numbers compared to variables.

Area : Height * Width ; // Does not require \units Area : Height * 12 inches ; //Numbers always need \units Area : 24 * 48 SqInches ; // Still a number, add the \units IF Height> 5 SqFeet THEN …//required \here IF Height> 5 Feet*Feet THEN … // and \here IF Height in SqFeet> 5 THEN …//here a different \approach IF Height> Width THEN … // not here, both \variables

- Either the singular form (like inch) or the plural form (like inches) can be used. Both are identical.
- For square and cubic dimensions, precede the unit with “Sq” or “Cu” to make the square or cubic unit of that version. Alternately, “Unit*Unit” for the square or “Unit*Unit*Unit” for the cubic can be used.

9 SqFeet : 3 Feet * 3 Feet ; //Standard \Form 9 SqFeet : 9 Feet*Feet ; // Alternate \Form 27 CuFeet : 3 Feet * 3 Feet * 3 Feet; //Standard \Form 27 CuFeet : 27 Feet*Feet*Feet ; // Alternate \Form

- The keywords IN and PER can be used to modify the meaning of the unit. These keywords can also be used to combine units with other units.

Here is one set of equivalent expressions. FinalPrice : Area * 5 PER SqFeet ; FinalPrice : Area IN SqFeet * 5 ; //Here is a slightly tougher form of equivalence … ElapsedTime : Distance / 12 miles PER hour ; ElapsedTime : Distance IN Miles / 12 PER hour ;

The units defined in CFL include the following:

Measure | Unit | Accepted Abbreviations |
|||

Area | Square Centimeter | SqCentimeter, SqCentimeters, SqCentimetre, SqCentimetres | |||

Area | Square Foot | SqFoot, SqFeet | |||

Area | Square Inch | SqInch, SqInches | |||

Area | Square Meter | SqMeter, SqMeters, SqMetre, SqMetres | |||

Area | Square Millimeter | SqMillimeter, SqMillimeters, SqMillimetre, SqMillimetres | |||

Area | Square Yard | SqYard, SqYards | |||

Discrete | (none) | N/A | |||

Discrete | Each | Each | |||

Discrete | Impression | Impression, Impressions | |||

Discrete | Page | Page, Pages | |||

Discrete | Piece | Piece, Pieces | |||

Discrete | Sheet | Sheet, Sheets | |||

Length | Centimeter | Centimeter, Centimeters, Centimetre, Centimetres | |||

Length | Foot | Foot, Feet | |||

Length | Inch | Inch, Inches | |||

Length | Meter | Meter, Meters, Metre, Metres | |||

Length | Millimeter | Millimeter, Millimeters, Millimetre, Millimetres | |||

Length | Yard | Yard, Yards | |||

Time | Day | Day, Days | |||

Time | Hour | Hour, Hours | |||

Time | Minute | Minute, Minutes | |||

Time | Second | Second, Seconds | |||

Volume | Cubic Centimeter | CuCentimeter, CuCentimeters, CuCentimetre, CuCentimetres | |||

Volume | Cubic Foot | CuFoot, CuFeet | |||

Volume | Cubic Inch | CuInch, CuInches | |||

Volume | Cubic Meter | CuMeter, CuMeters, CuMetre, CuMetres | |||

Volume | Cubic Millimeter | CuMillimeter, CuMillimeters, CuMillimetre, CuMillimetres | |||

Volume | Cubic Yard | CuYard, CuYards | |||

Volume | Cup | Cup, Cups | |||

Volume | Gallon | Gallon, Gallons | |||

Volume | Liter | Liter, Liters, Litre, Litres | |||

Volume | Milliliter | Milliliter, Milliliters, Millilitre, Millilitres | |||

Volume | Pint | Pint, Pints | |||

Volume | Quart | Quart, Quarts | |||

Weight | FluidOunce | FluidOunce, FluidOunces | |||

Weight | Gram | Gram, Grams | |||

Weight | Kilogram | Kilogram, Kilograms | |||

Weight | Milligram | Milligram, Milligrams | |||

Weight | Ounce | Ounce, Ounces | |||

Weight | Pound | Pound, Pounds | |||

Weight | Ton | Ton, Tons |

Expressions using units are found throughout the rest of this reference. After a bit of practice with using units, CFL's easy-to-use unit syntax is mastered in no time.

### CONTROL (BRANCHING) OPERATIONS

#### IF THEN

Using **IF** statements can alter the path calculations use to determine their result. The IF statement enables a user to test for a Boolean logical condition in the program, and if that condition is true, the program returns some expression contained in that branch. If the condition is false, then the program returns an expression in a different branch. The syntax for the IF statement is as follows. Since white space does not matter, a different style can be used.

IF condition THEN TrueExpression ; ELSE FalseExpression ; ENDIF

Translation: If the condition is true, then TrueExpression will be evaluated. If condition is false, then FalseExpression will be evaluated. The condition can be any expression that returns a Boolean value. An example of the IF statement may help illustrate the how this all works in practice.

IF (Height> SheetHeight) or (Width> SheetWidth) THEN PiecesPerSheet := 0 ; ELSE Declare SheetsHigh = Int( SheetHeight / Height ) ; Declare SheetsAcross = Int( SheetWidth / Width ) ; PiecesPerSheet := SheetsHigh * SheetsAcross ; ENDIF ; // Now return PiecesPerSheet as our Answer PiecesPerSheet ;

There is no limit to one expression for TrueExpression or FalseExpression. Rather, CFL uses everything between THEN and ELSE as the TrueExpression and everything between the ELSE and ENDIF as the FalseExpression.

An IF statement can also be placed within another IF statement; the inner IF is then said to be **nested** within the other. The following syntax shows a nested IF statement.

IF condition THEN IF condition THEN TrueTrueExpression ; ELSE TrueFalseExpression ; ENDIF ; ELSE FalseExpression ; ENDIF ;

It is considered good syntax to index nested IF's so that they can be easily followed. There is no limit to the number of nested statements that can be created in CFL.

### CASE

The **CASE** statement is similar to an IF statement, but provides an unlimited number of branches instead of just two. The syntax of the CASE statement is as follows:

CASE [ TestExpression ] IS TestExpression1 THEN Expression1 TestExpression2 THEN Expression2 TestExpression3 THEN Expression3 … TestExpressionX THEN ExpressionX ELSE FalseExpression ENDCASE ;

The CASE statement works like a long string of IF statements.

- TestExpression is compared to TestExpression1.
- If they are equal, Expression1 is evaluated and returned. (The CASE comparison is an approximate equal, not an exact equal. If an exact equal is required, IF statements must be used.)
- If they are not equal, then TestExpression is compared to TestExpression2. If these are equal, Expression2 is evaluated and returned.
- This process continues until all TestExpressionX are compared. If none is found to match, then the FalseExpression located between the ELSE and ENDCASE is evaluated.
- The expressions to be compared may be any data types. If TestExpression is omitted, then CFL defaults to TRUE. This enables use of the CASE statement even when not comparing similar items. Rather, each TestExpressionX is evaluated as a Boolean expression. When the first true TestExpressionX is found, its corresponding ExpressionX is evaluated and the case statement ends.

Two examples may help illustrate the usage:

CASE Quantity IS 1 THEN "One" 2 THEN "Two" 3 THEN "Three" ELSE "More" ENDCASE

The secod form allows more flexibility in what is compared, allowing each evaluation to be conducted with different arguments until one is successfully found. It can be used to replace a complicated IF/THEN/ELSEIF/ELSEIF type statement.

CASE IS Quantity1 THEN "One" Quantity*24 THEN "Two" Sqr(Quantity)9 THEN "Three" ELSE "More" ENDCASE

### LOOPING OPERATIONS

#### FOR

Use **For** statements to create a loop that that executes a fixed number of times. This is most often used for looping through child items, parts, or modifiers on a line item.

The syntax for the FOR statement is as follows. Since white space does not matter, a different style can be used.

FOR variable : startingnumber TO endingnumber [STEP increment] [MAXCOUNT maxloops] DO ExpressionBlock ; ENDFOR;

An alternate form of the FOR statement counts down and looks like this:

FOR variable : startingnumber DOWNTO endingnumber [STEP increment] [MAXCOUNT maxloops] DO ExpressionBlock ; ENDFOR;

The pieces of the FOR statement are:

**variable**. This is an actual variable and must be declared (with a DECLARE variablename; statement) before the FOR statement. This is called the loop variable.**startingnumber**. The value is assigned to variable at the start of the FOR statement.**endingnumber**. The value that sets the maximum value for variable.minimum value in the case of the DOWNTO variant**increment**. The value to increment/decrement variable by each iteration of the loop. This defaults to 1.0 if not specified.**maxloops**. This optional identifier sets a maximum number of loops that the loop will perform. If this limit is reached, execution automatically moved to the line of CFL following the loop.

At the start of every loop (except the first), the loop variable is increased by the increment value (which defaults to 1)decreased by the increment value in the case of DOWNTO variant . If the loop variable is then less than or equal to the ending variablegreater than or equal to in the case of the DOWNTO variant , the ExpressionBlock is skipped else is is run and the process repeats.

An example of the FOR statement follows:

//// This is some helpful code to put in the products warning message Declare i; Declare S := ''; FOR i := 0 TO Parts.SonCount-1 DO IF (Parts[i].TrackInventory = "True") AND (Parts[i].QuantityAvailable <Parts[i].YellowNotificationPoint) THEN S:= S + (Parts[i].PartCode) + " is below the yellow level of " + ToString(Parts[i].YellowNotificationPoint ) ELSE "" ENDIF; ENDFOR; // The value of any CFL statement is the value of the last computation/display // Now we need to return our value as the value of this function. // S;

Another example of the FOR Statement follows:

// This is code loops through the index of all parts and displays the part code and part description. // Additional CFL can be embedded as needed, you can use IF statements and other things to filter the results that appear. Declare i; Declare S := ''; FOR i := 0 TO Parts.SonCount-1 DO S:= S + (Parts[i].PartCode) + " is the part name and " + (Parts[i].Description) + " is the description of the part. " + HTMLRETURN ENDFOR; // To display the results of our FOR statement we need to notate S; below since it was a declared variable above. S;

The increasing FOR statement can be rewritten using a WHILE loop as follows:

variable := startingnumber; WHILE variable <= endingnumber DO ExpressionBlock; variable := variable + increment; ENDWHILE

### REPEAT UNTIL

Use **REPEAT** statements to create loops that executes once and then continues as long as some condition is true.

The syntax for the REPEAT statement is as follows. Since white space does not matter, a different style can be used.

REPEAT ExpressionBlock ; UNTIL (condition) [MAXCOUNT = maxloops];

The pieces of the WHILE statement are:

**condition**.**maxloops**. This optional identifier sets a maximum number of loops that the loop will perform. If this limit is reached, execution automatically moved to the line of CFL following the loop.

An example of the WHILE statement follows:

[[code|]] ===WHILE=== Use **WHILE** statements to create loops that execute if and while something is true. The syntax for the WHILE statement is as follows. Since white space does not matter, a different style can be used.

WHILE (condition) [MAXCOUNT = maxloops] DO

ExpressionBlock;

ENDWHILE;

The pieces of the WHILE statement are: * **condition**. * **maxloops**. This optional identifier sets a maximum number of loops that the loop will perform. If this limit is reached, execution automatically moved to the line of CFL following the loop.

^{1)}

^{2)}

^{3)}