Chestnut Labs G-code Preview
    Preparing search index...

    Parametric programs (RS274NGC)

    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.

    • Parameters — numbered #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.
    • Expressions[ … ] 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.
    • Control flow (O-words)if / elseif / else / endif, while / endwhile, do / while, repeat / endrepeat, break / continue.
    • Subroutines — in-file 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 CNC toolpath of holes on a circle plus a centre hole and a square frame, all computed by a parametric program, cut moves in pink and rapid moves in blue

    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.

    • In-file subroutines only. External subprogram files — Fanuc 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 values aren't propagated to the caller yet; return acts as an early exit from the subroutine.
    • Persistent parameters (LinuxCNC's .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.