The following sections define the languages that are understood and interpreted by PathPilot, and is only intended for reference:

To learn about the principles of the control language (so that you can write programs by hand from first principles, for example), we recommend that you consult an introductory textbook on G-code programming.

To create and edit G-code files, we recommend using a text editor like Gedit or Notepad++. Don’t use a word processor to create or edit G-code files, which leaves unseen codes that may cause problems or prevent a G-code file from working.



Subroutines can be looped using the do/while or while/endwhile keyword constructs.


The do/while loop executes a block of code once and continues to execute the code block until the while argument evaluates to true.

Do/while loop example:

#1 = 0 (assign parameter #1 the value of 0)

o100 do

(debug, parameter 1 = #1)

o110 if [#1 EQ 2]

#1 = 3 (assign the value of 3 to parameter #1)

(msg, #1 has been assigned the value of 3)

o100 continue (skip to start of loop)

o110 endif

(some code here)

#1 = [#1 + 1] (increment the test counter)

o100 while [#1 LT 3]



The while/endwhile repeats a set of statements an indefinite number of times, as long as the while argument evaluates to true.

While/endwhile example:

(draw a sawtooth shape)

G00 X1 Y0 (move to start position)

#1 = 1 (assign parameter #1 the value of 0)

F25 (set a feed rate)

o101 while [#1 LT 10]

G01 X0

G01 Y[#1/10] X1

#1 = [#1+1] (increment the test counter)

o101 endwhile

M02 (end program)

The following statements cause an error message and abort the interpreter:

  • A return or endsub not within a sub definition
  • A label on repeat which is defined elsewhere
  • A label on while which is defined elsewhere and not referring to a do
  • A label on if defined elsewhere
  • A undefined label on else or elseif
  • A label on else, elseif or endif not pointing to a matching if
  • A label on break or continue which does not point to a matching while or do
  • A label on endrepeat or endwhile no referring to a corresponding while or repeat



Subroutines can be repeated a finite number of times using the repeat/endrepeat keyword.

Repeat example:

(Mill 5 diagonal shapes)

G91 (Incremental mode)

o103 repeat [5]

… (insert milling code here)

G00 X1 Y1 (diagonal move to next position)

o103 endrepeat

G90 (Absolute mode)



Subroutines can be conditionally executed using the if/endif or the if/else/elseif/endif keyword constructs.


The if/endif conditional will execute a block of code following theif keyword only when the if argument evaluates to true.

If/endif example:

o100 sub

(notice that the if-endif block uses a different number)

o110 if [#2 GT 5]

(some code here)

o110 endif

(some more code here)

o100 endsub


The if/elseif/else/endif conditional will execute the block of code following the if keyword when its argument evaluates to true. If the argument evaluates to false, then the code following each elseif is executed as long as the associated elseif argument evaluates to true. If no elseif keywords are present, or if all elseif arguments evaluate to false, than the code following the else keyword is executed.

If/elseif/endif example:

o102 if [#2 GT 5] (if parameter #2 is greater than 5 set F100)


o102 elseif [#2 LT 2] (else if parameter #2 is less than 2 set F200)


o102 else (else if parameter #2 is 2 through 5 set F150)


o102 endif



Subroutines are identified in a program by a unique subroutine label. The subroutine label is the letter O followed by an integer (with no sign) between 0 and 99999 written with no more than five digits (000009 is not permitted, for example) or a string of characters surrounded by <> symbols.

Examples of valid subroutine labels include:

  • O123
  • O99999
  • O

Subroutine labels may be used in any order but must be unique in a program. Each subroutine label must be followed by a subroutine keyword.

The subroutine keyword defines the action associated with the subroutine label. Valid subroutine keywords and their meanings are as follows:

  • Sub: Begin subroutine definition
  • Endsub: End of subroutine definition
  • Call: Call the subroutine
  • Do/while/endwhile: Execute the subroutine while a condition is true
  • Repeat/endrepeat: Execute the subroutine while a condition is true
  • If/elseif/else/endif: Conditionally execute the subroutine
  • Break: Break out of a while or if/elseif statement
  • Continue: Skip remaining code and restart at top of while or repeat loop
  • Return: Return a value

The sub and endsub keywords are used to define the beginning and end a subroutine. All lines of code between the sub and endsub keywords are considered to be part of the subroutine.

Example of sub, endsub, call:

o100 sub

G53 G00 X0 Y0 Z0 (rapid move to machine home)

o100 endsub

o100 call (call the subroutine here)


Subroutines can either be defined in the program file or in a separate file. If the subroutine is defined in the same file as the main program that calls the subroutine, it must be defined before the call statement. For instance, this is valid:

o100 sub

G53 G00 X0 Y0 Z0 (rapid move to machine home)

o100 endsub

o100 call (call the subroutine here)


But this is not:

o100 call (call the subroutine here)


o100 sub

G53 G00 X0 Y0 Z0 (rapid move to machine home)

o100 endsub

A subroutine can be a separate file, provided the following rules are obeyed:

  • The file must be named the same as your call.
  • The file must include a sub and endsub in the file.
  • The file must be in the directory /subroutines.
  • The file name can include lowercase letters, numbers, dashes, and underscores only.
  • The file can contain only a single subroutine definition.
  • The file must end with the extension .nc.

To execute a subroutine in a program, it must be called. To call a subroutine, program O~ call where ~ is the subroutine name. The subroutine name may be either a named file, a numbered file, or an expression that evaluates to a valid subroutine label.

Expression example: o[#101+2] call

Named file example: o call

Numbered file example: o123 call

O~ call takes up to 30 optional arguments, which are passed to the subroutine as #1, #2 , . . . , #N. Unused parameters from #N+1 to #30 have the same value as in the calling context.

Parameters #1-#30 are local to the subroutine. On return from the subroutine, the values of parameters #1 through #30 (regardless of the number of arguments) are restored to the values they had before the call.

The following calls a subroutine with three arguments: o200 call [1] [2] [3]

Because 1 2 3 is parsed as the number 123, the parameters must be enclosed in square brackets.

Subroutine bodies may be nested. Nested subroutines may only be called after they are defined. They may be called from other functions, and may call themselves recursively if it makes sense to do so. The maximum subroutine nesting level is 10.

Subroutines do not have return values, but they may change the value of parameters above #30 and those changes are visible to the calling G-code. Subroutines may also change the value of global named parameters.

NOTE: File names are lowercase letters only. o is converted to o by the interpreter.



The available functions are:

  • ATAN[Y]/[X]: Four quadrant inverse tangent
  • ABS[arg]: Absolute value
  • ACOS[arg]: Inverse cosine
  • ASIN[arg]: Inverse sine
  • COS[arg]: Cosine
  • EXP[arg]: e raised to the given power (ex)
  • FIX[arg]: Round down to integer
  • FUP[arg]: Round up to integer
  • ROUND[arg]: Round to nearest integer
  • LN[arg]: Base-e logarithm
  • SIN[arg]: Sine
  • SQRT[arg]: Square root
  • TAN[arg]: Tangent
  • EXISTS[arg]: Check named parameter



Binary operators only appear inside expressions. There are three types of binary operators: mathematical, logical, and relational.

There are four basic mathematical operations: addition (+), subtraction (-), multiplication (*), and division (/). In addition, the modulus operation (MOD) finds the remainder after division of one number by another number. The power operation (**) of raising the number on the left of the operation to the power on the right. There are three logical operations: non-exclusive or (OR), exclusive or (XOR), and logical and (AND).

The relational operators are equality (EQ), inequality (NE), strictly greater than (GT), greater than or equal to (GE), strictly less than (LT), and less than or equal to (LE).

Binary operators are divided into several groups according to their precedence as follows, from highest to lowest:

  1. **
  2. * / MOD
  3. + –

If operations in different precedence groups are strung together, operations with a higher precedence are performed before operations with a lower precedence. If an expression contains more than one operation with the same precedence, the operation on the left is performed first.


[2.0 / 3 * 1.5 – 5.5 / 11.0] is equivalent to [[[2.0 / 3] * 1.5] – [5.5 / 11.0]]

which is equivalent to [1.0 – 0.5]

which is


The logical operations and modulus are to be performed on any real numbers, not just on integers. The number zero is equivalent to logical false, and any non-zero number is equivalent to logical true.



An expression is a set of characters starting with a left bracket ([) and ending with a right bracket (]). Located between the brackets are numbers, parameter values, binary operators, functions, and other expressions. An expression is evaluated to produce a number. An example of an expression is:

[1 + acos[0] – [#3 ** [4.0/2]]]

All expressions on a line are evaluated when the line is read and before anything on the line is executed.

Read the following sections for reference: