Some G-code doesn't spell out its geometry move by move — it computes it. A LinuxCNC or CAM
program can set a variable, evaluate an expression as a coordinate, loop, branch, and call a
subroutine, so a bolt circle is a while loop over an angle instead of twelve explicit G1s. The
parser runs that programming layer, so these files resolve to the real toolpath rather than rendering
empty or partial.
This is the RS274NGC programming layer — the dialect LinuxCNC implements. FDM slicer output never uses it; CNC / CAM output routinely does.
#1–#5399, named #<name> (local) and #<_global> (global). Assign
with #1 = 5; read anywhere a number is expected (X#1). Indirect (##1) and computed
(#[#1 + 1]) references resolve too.[ … ] anywhere a coordinate goes: X[#1 + 2 * SIN[30]]. The full RS274NGC
operator set (+ - * / MOD **, comparisons, AND / OR / XOR) and functions (SIN COS TAN ATAN ABS SQRT FIX FUP ROUND LN EXP …) — trig in degrees, with LinuxCNC MOD / EQ semantics.if / elseif / else / endif, while / endwhile, do /
while, repeat / endrepeat, break / continue.sub / endsub, call [args] (arguments bind to #1–#30 in the call
frame), return. Subroutines may recurse and may be called before they are defined.A bolt circle, computed:
# = 50
# = 40
# = 20
# = 6
# = 0
o100 while [# LT #]
# = [# * 360 / #]
G0 X[# + # * COS[#]] Y[# + # * SIN[#]]
# = [# + 1]
o100 endwhile
The rapids land on the circle: the loop runs and the degree-trig expressions evaluate, so the preview shows the pattern the machine would follow — not an empty plate.

A slightly larger version of the same idea — eight holes, a centre hole, and a computed frame —
rendered from test-data/fixtures/parametric/bolt-circle.ngc.
Nothing in that file lists a hole position; every one is computed.
The interpreter engages only when a program actually uses #, [, or an O-word. Every FDM and
plain-CNC file takes the ordinary parse path and produces byte-for-byte identical output — enabling
this changed nothing for files that don't use it.
Computed geometry is real geometry. When a program runs to completion, the parametricProgram
capability is known: the coordinates are a deterministic function of the program, so the
interpreter computes them — it does not guess. If something is off — a resource limit was reached, an
O-word was unbalanced or unsupported, a condition was malformed — the capability drops to
approximated and a specific warning names exactly what was lost. A non-parametric file reports
unavailable. It never silently renders the wrong thing.
A parametric program is a small program, so it is bounded like one. Two limits (part of the parser's
ParseLimits) keep a hostile or buggy file from hanging the parser:
maxProgramIterations (default 1,000,000) bounds total loop work — an o while [1] stops with a
partial result and a rs274-iteration-limit disclosure.maxCallDepth (default 50) bounds subroutine recursion — runaway or mutual recursion is
disclosed (rs274-call-depth) and skipped, never a stack overflow.There is no eval and no file I/O: the evaluator is a fixed arithmetic grammar over a fixed set of
functions, so an adversarial program can waste only bounded CPU.
M98 P…, or an o<name> call that
resolves to a separate .ngc — are out of scope; the parser does no file I/O.return acts as an early exit from the
subroutine..var file) aren't read — a program is interpreted in
isolation.For the construct-by-construct coverage table and every warning code, see G-code motion & position coverage; for the design and its bounded-execution model, see DD-017.