Brand NC language coverage
The SoftNc pipeline is the default NC engine, and this is where most of the release went.
Siemens SINUMERIK
Real .mpf / .spf programs replay end to end, not an ISO subset. At 3.1.175 a program that declared
its tool as T="NAME", shifted with SUPA, computed with R-parameters, called L-subprograms or
looped with WHILE was not interpreted past that point.
- Modal vocabulary —
SUPA/G153suppress all frames for one block;T="NAME"string tool calls withDcutting-edge offsets resolved through SiemensToolOffsetTable ($TC_DPlengths and radius plus additive wear);G70/G71units; path smoothing (G60x/G64x,FNORM/SOFT/FFWON/COMP*/UPATH,CYCLE832);MSG()andSTOPRE;CR=andTURN=arcs. Tail comments became quote-aware, so a;insideMSG("A;B")no longer truncates the block, and the preset stops misreadingLandG74as Fanuc-family codes. - Evaluation — SiemensExpressionParser feeds the
shared expression engine, so
Z=R63+150andX=SIN(R10)*20drive motion. SiemensRParameterTable holds R0–R999 as per-case project data,DEF REAL/INTdeclarations lower into assignments, and$P_UIFR[n,axis,TR]binds both ways to SiemensFrameTable. Any other$-variable is recorded with an unsupported note rather than dropped. - Five axis — SiemensProgrammableFrameSyntax simulates
TRANS/ATRANS/ROT/AROT(withRPL=) and the solid-angle formsROTS/AROTSinto the tilt-transform chain in Sinumerik RPY order (ROTS/AROTSbehave asROT/AROT: at most two angles, first-named axis first); SiemensTraoriSyntax makesTRAORIa real RTCP mode, the sibling of ISO G43.4, withTRAFOOFhanding the offset back; SiemensCycle800TiltSyntax decodesCYCLE800's MODE bits for all four swivel modes.SCALE/MIRROR/CROTSare recognized and reported (SiemensFrame--Unsupported), not simulated. - Calls — L-prefixed and named subprogram calls resolve against
SubProgramFolderConfig (
{name}.SPF, then.MPF, then the bare name) and inline with theirPrepetition count;M17/RETpop a frame;REPEATre-runs a labelled slice;MCALL CYCLE81/82/83/85maps onto the shared canned-cycle machinery;PROCheaders and labels are claimed whole. - Control flow —
GOTOF/GOTOB,IF/ELSE/ENDIF, andWHILE/FOR/REPEAT-UNTIL/LOOP. Runaway programs are bounded rather than hanging the session: SiemensGotoIterationDependency caps jumps per (file, label) and SiemensLoopIterationDependency caps iterations per (file, loop-entry line); over the cap the construct warns and falls through. - Per-word coordinate functions —
AC()/IC()/DC()/ACP()/ACN(), including onI/J/Kcircle centres.G90 C=IC(360/17)is one incremental index inside an absolute program. Direction resolution lives in McAbcCyclicPathSyntax:ACP()takes the[anchor, anchor+360)window,ACN()the(anchor-360, anchor]window,DC()the shortest swing, with the exact 180° tie going negative. On a machine-coordinate block the increment is a distance in the machine frame, because MachineCoordSelectSyntax is ordered ahead of IncrementalResolveSyntax in all five brand presets — Fanuc, Mazak, Syntec, Siemens and Heidenhain — soG53 X=IC(10)andSUPA Y=IC(-10)add the raw word to the previous machine position rather than being re-based through the program frame first. That order is not something a saved-file patch can express: a project saved before 3.2.21 keeps the old order for that block shape until its pipeline is re-created from the brand preset. - Coded positions —
CAC/CIC/CDC/CACP/CACNtake a 1-based indexing position number rather than a coordinate, resolved against IIndexingPositionConfig, implemented by SiemensMachineDataTable from the real machine data (the MD30500 axis assignment, the MD10910 / MD10930 position tables, the equidistant MD30501–30503 definition). G74/G75fixed-point return is claimed as a whole block, so its dummy axis values no longer mint a rapid to the coordinates written in the block and itsFnever reaches the modal feedrate.- OEM auxiliary M-codes — the preset declares
M12/M13/M22/M23andM330/M331note-only, so each occurrence voicesDeclaredMCode--UnmodeledEffectsinstead of an unknown-code warning, without inventing simulated effects. A machine's own table overrides a declaration when the real effects are known.
Heidenhain
Both dialects play on one preset, HeidenhainNcRunner.
- Klartext motion and setup — the
Lstatement and its axis words,FMAX,M91as a one-shot machine-coordinate move,TOOL CALLwired to tool change and spindle speed with the table height andDL. Datum handling follows TNC semantics:CYCL DEF 247sets the preset andCYCL DEF 7is an additive shift on top of it, composing as separate transform-chain entries instead of replacing each other, resolved against HeidenhainDatumTable. Arcs (CCpole plusCstatement,DR-= CW, closed arc = full circle),RL/RR/R0radius compensation, theM126/M127rotary-wrap state,M140 MBretract, andCYCL DEF 32 TOLERANCE. HeidenhainLnOrientationSyntax resolves anLNvector block into rotary axes through the same RTCP machinery the rotary-word programs use:Tpresent plusM128/FUNCTION TCPMkeeps the tool on T;Tabsent plus RTCP holds the tool on the surface normal N; RTCP inactive ignores T (Orientation-Vector--IgnoredNoTcpm), as the control does. ACblock never states its own centre: each in-plane component comes from theCCblock's own axis word, else from the previousCCsection's same axis, else from the arc's own start point. A bareCCis the one spelling that states all of them at once — it takes the last programmed position, read at theCCblock, and replaces the modal centre rather than inheriting it. A centre that lands on the arc's own start point leaves the block with no radius, so it warnsArc-CircleCenter--OnStartPointand is degraded to a linear move to the endpoint. - Klartext incremental axis words — the
I-prefixed word (IX+20,IY-15, rotaryIC+90) is the same axis word as its absolute twin, read as a distance from the last programmed position. It is per word rather than per block:L X+60 IY-10mixes an absolute X with an incremental Y and stamps only the Y. One shared grab serves five statement heads —L,C,CC,LNandCYCL CALL POS— each writing the value under the plain axis key of its own section plus a"PositioningOverride": { "Y": "Incremental" }entry on the block root. That is the same per-word section the SiemensIC()wrapper writes, so the existing resolve consumers convert it and no second incremental mechanism exists. Coverage differs by head:L,CandLNtake the whole axis tag list, rotary included, whileCCandCYCL CALL POStakeX/Y/Zonly — aCCnever positions a rotary axis, and the stamp is keyed by axis on the block root, where a rotary letter would read as a rotary word of the block. The sign is optional (L IX5), aQreference resolves behind the prefix (L IZ+Q2), and the glued post-processed runLIX+20IY-15parses. Before these words were read the plain grab could not see theXinsideIX— its prefix guard demands a word boundary, a digit or whitespace before the tag, andIis a word character — soL X+60 IY-10took the X and dropped the Y: a motion to the wrong place, not a missing one. - What an incremental word is measured from depends on the statement. An
L/C/LNendpoint and aCCcentre are distances from the last programmed tool position, soCC IX+0 IY+11is a stated centre resolved against that position — never against the previous centre — and it is no longer the spelling whose coordinates the parser could not read.CYCL CALL POShas its own reference: anIX/IY/IZword there is a distance from the coordinates the previousCYCL CALL POSprogrammed, which is the control's own rule behind its error 1A0-0108. An axis that no earlier call programmed has no reference: the control refuses the call, and the simulation warnsHeidenhainCyclCall--IncrementalNoReferenceand falls back to the last programmed position. A tool move between the two calls makes the two candidate references differ, and that divergence warnsHeidenhainCyclCall--IncrementalAfterMove, the control's stated reference winning. WithM91on the block the increment is a machine-frame distance, per the ordering note under Siemens above. A rotary increment is a signed traverse the wrap pass keeps verbatim —IC+270from 75° stays 345° instead of folding into the ±180° shortest-path window, while an absolute rotary word on the same block still folds. TheCYCL DEF 7datum-shiftIwords are a different mechanism:CYCL DEF 7.2 IY+5shifts by the value on top of the shift last valid, stays under prefixed keys in the cycle's own record, and writes no per-word stamp at all. - Q-parameters — HeidenhainExpressionParser lexes
Q/QR/QL/QS, theDIVkeyword of FN 4 and the prefixSQRTof FN 5, soFQ1reaches the feedrate,L X+Q2reaches the program XYZ andTOOL CALL SQ3reaches the spindle speed. HeidenhainQParameterTable holds Q0–Q99 free and QR0–QR499 permanent parameters as per-case project data. Unimplemented opcodes (FN 14 / 16 / 18…) are claimed and reported rather than half-read, so anFN 18 SYSREADtarget stays vacant instead of taking a fabricated value. FN 9–12 conditional jumps execute, with a (file, label)-keyed iteration cap. - Tilt and RTCP —
PLANE(SPATIAL fully composed withSEQ/COORD ROT/TABLE ROTandSTAY/MOVE/TURNpositioning; VECTOR structurally captured; EULER / POINTS / RELATIV / AXIAL / PROJECTED consumed and warned with the previous tilt retained, so aPLANE AXIAL B+45B word can never be mistaken for a rotary axis command),FUNCTION TCPM, and realM128/M129tool-centre-point control. A centre-referencedFUNCTION TCPM REFPNT(TIP-CENTER/CENTER-CENTER) is recorded and reported (Orientation-RefPoint--CntNotSimulated) rather than silently read as TIP-TIP. - Cycles and calls —
CYCL DEF 2xxbodies with their Q parameters mirrored into the block assignments, cycles 200 / 232 / 251 / 252 / 253 mapped onto the shared G81 / G82 / G83 slots,CYCL CALL/CYCL CALL POS/M99/M89splitting call-once from modal firing,CALL LBLinlining up toLBL 0,CALL LBL n REP mas a section repeat, andCALL PGMresolved by file name. The multi-line tilde continuation form is joined at segmentation (JoinTildeContinuations, on by default). - Post-processed spellings — some post-processors write a whole klartext body with no separators
at all, which used to yield zero motion. Glued line shapes (
LX-26.3Y+43.1,FMAXM03M08,…R0FMAX) and the detached feed spelling (F 20000) now parse, withM140,M128andPLANE MOVEwidening their ownFcapture so a retract or feed-limit value cannot leak into the modal feedrate.BLK FORMis recorded as a brand-neutral stock declaration without replacing the project workpiece setup, and the klartextSTOPword joinsM00/M01. - DIN/ISO dialect —
%tape header,Nblock numbers,T+M06, absoluteI/J/Karc centres with the modal pole carried forward, the ISO label family (G98 L<n>definitions and the head-anchoredL<n>,<m>call mapping the comma count ontoREP),G247 Q339stamping the same datum preset asCYCL DEF 247,G54with axis words read as a datum-shift declaration, andG70/G71.
Fanuc and ISO common
- Polar coordinate interpolation —
G12.1/G13.1on the SoftNc pipeline. Before this a polar section parsed silently wrong: theXword (a diameter) and theCword (a hypothetical Cartesian axis in mm) were consumed as ordinary XYZ and rotary degrees. ProgramRxczSyntax halvesXfrom diameter, resolves G90/G91, writes the polar and derived Cartesian positions and the machine C angle, and classifies motion into polar linear and polar arc — the latter emitting ActMcPolarSpiralContour, which keeps spiral geometry in central polar coordinates and stays continuous across ±180°.G41/G42compensation is resolved on the hypothetical plane, a C-axis speed clamp applies, and YA / ZB axis pairs are supported. PolarGCodeCheckSyntax scans for incompatible G codes before the mode syntaxes consume them. - Custom Macro B —
#varassignment with range-routed stores (#1–#33local per macro frame,#100–#499volatile cleared on M02/M30,#500–#999retained and persisted in the project,#3000–#3999system-control), boolean and logical operators,IF[..]GOTO n,IF[..]THEN <stmt>,WHILE[..]DO m / END mwith a bounded-loop watchdog, and position and tool-offset system variables.M98 P_ L_,M198external call,M99return andM99 P{seq}early return;G65one-shot macro call with A–Z →#1–#26argument binding, andG66/G67modal macro. - Additional work coordinate systems —
G54.1 Pn, also writtenG54 Pn, resolves against the extended table (P1–P48). A selected row nobody has entered reportsCoord-WorkOffset--AdditionalZero.G59.1–G59.9have a provider on the Fanuc, Mazak and Syntec presets. See Work Coordinates and ISO core. - Fanuc / Syntec unit codes and G05.
G71is the metric spelling ofG21;G70is the inch spelling ofG20and reportsUnit--InchNotSupportedrather than silently switching units.G05.1 Q1/Q0is AICC / Nano Smoothing (recognized). BareG05 P{n}is a different feature (HPCC) and is consumed without changing programmed coordinates, reported under theHpcc--*ids. - Canned-cycle repeats do not take rotary words on SoftNc. The G73–G89 family expands XYZ / R / Q / F / P / K strokes. An A / B / C word on a repeat is not taken: a rotary-only repeat does not fire the cycle, a mixed block drops the rotary word, and under G68.2 the hole follows the table. Not finished on this line, see Adoption status on the release-note page. The HardNc fallback indexes those blocks the way a control does.
Cross-brand
- A shared
DwellSyntaxconsumesG4andG04with the dialect held on the instance: Fanuc-familyX/Useconds,Pmilliseconds,Sspindle revolutions; the Siemens instance readsFseconds andSrevolutions. Capturing theG04spelling fixes a real defect — the un-captured spelling fell through to the flag and axis syntaxes, where a FanucG04 X0.5dwell time became a ghost X motion word. - Machine-declared M-codes — IMCodeDeclarationConfig and
MCodeEffects let a machine state what its own OEM codes do (composite
spindle+coolant codes, a tool-change trigger, turret
T-word semantics), and MCodeExpansionSyntax expands a declared code into the canonical ISO flags the shared consumers already understand. - Custom spindle M-codes drive the spindle direction through a machine-level
ISpindleControlConfig; ISO
M03/M04/M05remain the built-in fallback. AnSgreater than zero with no direction ever issued assumes clockwise and emitsSpindleDirection--AssumedCw, so the physics gate no longer silently produces zero mechanics for a whole file. - Tool changes synthesize their axis travel. ToolChangeMotionSyntax overlays the per-axis tooling position from IToolingMcConfig onto the current pose (a NaN or missing axis stays put) and stamps a one-item rapid compound motion, and ToolChangeSemantic moves behind CompoundMotionSemantic so the tooling step lands at the tooling point. Programs that retract on their own overlay to a zero-length move and emit nothing extra.
- Per-brand pivot gates. PivotTransformationSyntax reverts to the ISO/Fanuc vocabulary (G43.4 plus the G68.x family), SiemensPivotTransformationSyntax gates TRAORI / CYCLE800, and HeidenhainPivotTransformationSyntax gates the M128 / PLANE vocabulary. All three compose the identical entry through the shared PivotTransformUtil. Exactly one brand gate belongs in a pipeline list — never register two.
- Controller presets are writable and shipped. A controller resource file is one serialized
SoftNcRunner — the whole pipeline that decides how a brand's NC code is
interpreted. ControllerPresetWriter serializes the built-in brand presets
(
CreateBrandPreset,WriteBrandPresetFile, WriteAllBrandPresetFiles) underResource/Controller/with the.Controllerextension, and HiNc-Resource ships all five so the load browser starts populated. The static brand properties remain the source of truth; the files are regenerable snapshots. Writing needs noXFactoryregistration — reading one back does, because the loader drops unregistered pipeline entries silently rather than failing the load. - Saved pipelines back-fill their system-wired dependencies on load. A project saved before a system-wired dependency existed never self-healed by round-tripping, because re-saving stamped a fresh API version on the same incomplete list. The SoftNcRunner XML constructor now appends the missing ones after the legacy version patches. A runner rehydrated from an older file still keeps the syntax list it was saved with, though — take the regenerated preset, or a fresh NcRunnerSuit built from it, rather than expecting an old file to grow new syntaxes.
- Machine-coordinate and tilted-plane failures report. G53 and G53.1 record their source G-code
on the parsed block and emit
Coord-MachCoord--005/--006/--007on paths that used to fail silently. A G68.2 tilted plane the machine cannot reach emitsCoord-Tilt--001/--002, with a tool-axis-only IK retry that avoids a spurious warning on a machine with fewer than three rotary axes. - Session-global sentence indexing.
SyntaxPiece.SentenceIndexused to be assigned by two independent sequences, so indices collided as soon as a call was inlined mid-stream. The new SentenceIndexCounterDependency supplies every index at one chokepoint, so values are session-globally unique and strictly increasing in execution order, including nested and repeated calls. - Inline plays can loop and jump, and playing a file no longer holds it open. Inline NC-code plays
stamp their pieces with the command title as a pseudo-path, and every control-flow re-segmentation
re-read the host file by that path — the existence check always failed, so loops fell through
without looping.
RunNcnow registers the raw lines on NcLineSourceDependency and LabelScanUtil reads memory first, disk second. M02/M30/END PGMis a reset edge. SoftNc models program-end as the edge between that block and the next, so a concatenated multi-program file does not keep TCP, tilt, CRC or a canned cycle alive into the next program. Each modal owner writes an explicit cancel section on the successor (G49 / G69 / G40 / G80); the end-of-program block itself still runs under the modal state it executed with. HardNc still carries G43.4 acrossM02— see Results that change on upgrade.