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 take rotary words on SoftNc. The G73–G89 family expands XYZ / R / Q /
F / P / K strokes, and a repeat block carrying an A / B / C word indexes the table and drills
again, the way a control does: a rotary-only repeat fires the cycle, a mixed block pre-positions
XYZ and the table in one simultaneous move before the strokes, and under G68.2 without RTCP the
feature frame stays pinned in machine space so the hole stays put while the workpiece turns. Under
G91 only the words the block itself spoke are increments. The hold that 3.2.24 placed on these
programs is lifted;
EnableSoftNcRunner = falseis no longer needed for them. - A rotary word under modal G91 is an increment on SoftNc. A bare A / B / C word follows the
block's modal positioning onto the same anchor + delta path as Siemens
IC()and klartextIC+:G91 … C20.thenC20.leaves the table at 40. A per-word directive (C=AC(90),ACP/ACN,IC()) still beats the modal state, and a spokenG91 B270.stays a +270° traverse instead of folding to −90°. AG91 G28rotary intermediate anchors on the previous modal angle, then returns home. HardNc keeps its absolute reading of a rotary word under G91 and warns. The programmed deltas are recorded in IncrementalWords, beside the RotaryWords the block spoke.
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.