Table of Contents

Namespace Hi.NcParsers.ParsingSyntaxs.Siemens

Classes

SiemensCallStatementSyntax

Captures a whole-line Siemens subprogram-call statement into Parsing.SiemensCall for SiemensSubProgramCallSyntax to resolve (inline the file) or safe-skip (structured warning, zero motion). Two shapes are owned:

  • Parenthesized call, any identifierHQ_FC(1,50,75,160), L_39(0.000,0.000), HH_ROBOT(2){ "Name": "HQ_FC", "Args": ["1","50",…] }. The argument grammar (complete quoted runs admitted, quote-aware comma split) is SiemensCycleCallSyntax's, reused verbatim.
  • Bare-word callL9810, L_ZYM91, HH_ROBOTOFF, with an optional repeat count L123 P3{ "Name": "L123", "P": 3 }. Restricted to L-leading or underscore-bearing identifiers on purpose: this syntax runs ahead of FlagSyntax and a generic bare-identifier capture would steal TRAORI-class words before their consumers ever saw them — the same underscore heuristic NamedIdentPattern blessed for assignments (corpus named entities all carry an underscore; controller vocabulary never does). On real Sinumerik any bare identifier can be a by-name call; widening further is a corpus-driven follow-up.

Placement: last of the dedicated statement owners and still before SiemensQuotedStatementSyntax — quoted arguments must reach this capture (paired quotes ride inside the args body; a line whose quotes do not pair falls through whole to the quarantine). ExcludedNames keeps this catch-all from re-owning statements that belong elsewhere (default: WRITE stays with the quoted-statement quarantine; control-flow words are reserved for their future syntaxes). Whole-line anchored: a call mixed with other tokens (L9810 M8) does not match and stays visible in the unparsed warning.

SiemensCycleCallSyntax

Captures whitelisted Siemens cycle calls of the shape NAME(arg1,arg2,…) (or the bare NAME form) from the unparsed line text into a Parsing.NAME sub-object holding the verbatim positional argument strings: CYCLE832(0.05,_ORI_FINISH,0.8)Parsing.CYCLE832 = { “Args”: [“0.05”, “_ORI_FINISH”, “0.8”] }. Empty slots (,,) stay as empty strings; NAME() yields an empty Args array; a bare NAME yields { “Bare”: true } (a marker — empty sub-objects would be swept by intermediate CleanupParsing calls before the consumer runs). A brand Logic syntax consumes the sub-object (e.g. SiemensPathSmoothingSyntax for CYCLE832, SiemensCycle800TiltSyntax for CYCLE800).

Strictly whitelist-based (CycleNames, default CYCLE832 + CYCLE800) — a generic WORD(args) capture would eat OEM/unknown calls (HQ_FC(...), L_39(...)) whose safe-skip handling is a separate work item, and every unlisted call deliberately stays whole in UnparsedText for the visible UnparsedText--Remaining warning.

Must be placed early in the Parsing bundle — before the assignment and tag-value syntaxes: argument tokens standing after ( or , (_ORI_FINISH, or axis-letter shapes like V1) would otherwise be shredded by NamedVarAssignmentSyntax / tag-value captures. Quoted arguments are supported for CYCLE800's swivel-data-record name (CYCLE800(1,"TC1",…)): the args body admits complete "…" runs (which may hide ) or ,) and the comma split is quote-aware; quotes are kept verbatim in the captured arg string so the consumer distinguishes "0" (name) from 0 (number). A line whose quotes do not pair falls through whole to SiemensQuotedStatementSyntax's quarantine.

SiemensDefStatementSyntax

Consumes Sinumerik variable declarations (DEF REAL _X_HOME=155.5, _SAFE_Z / DEF INT N_ST=3) and lowers each declared name into Parsing.Assignments: initialised names carry their initialiser expression text (the Evaluation bundle resolves and routes it into Vars.Named like any named assignment), bare names carry “0” — Sinumerik default-initialises numeric types to zero, so a later G0 Z=_SAFE_Z reads 0 instead of failing vacant.

Must run before NamedVarAssignmentSyntax in the Parsing bundle: on a DEF line that syntax would capture _X_HOME=155.5 but strand DEF REAL (and the comma list) as unparsed residue. Initialiser expressions are delimited by the SiemensExpressionParser longest-valid-prefix rule, so parenthesised arithmetic and whitespace survive; a non-numeric type or unparsable initialiser leaves the whole statement untouched (visible as residue) rather than half-consuming it.

BOOL/CHAR initialise to 0 like INT; STRING declarations are not lowered (string values have no numeric store) — the statement is consumed whole so it cannot shed ghost tokens. The declaration itself leaves no Parsing record: the lowered Assignments entries carry the entire semantic payload, and an inert record would only re-surface as an Unconsumed residue.

SiemensFrameStatementSyntax

Captures a whole Siemens frame statement (TRANS/ATRANS/ROT/AROT/ ROTS/AROTS/SCALE/ASCALE/MIRROR/AMIRROR, bare or with arguments) into a Parsing.<keyword> sub-object. Sinumerik requires frame instructions in a block of their own, so the whole remaining line belongs to the statement.

The consumed keywords (TRANS/ATRANS/ROT/AROT — see SiemensProgrammableFrameSyntax) are captured structured: each argument token becomes a sub-key — glued axis words (X0, Y90.) and equals forms (RPL=45, Z=R5) both supported. Literal values are stored as JSON numbers; non-literal right-hand sides stay strings so VariableEvaluatorSyntax resolves them in the Evaluation stage (AROT Z=R5Parsing.AROT = { "Z": "R5" }). A token outside the modeled grammar makes the whole statement fall back to the verbatim StatementKey capture — never a half-consumed line.

The remaining keywords (ROTS/AROTS/SCALE/ASCALE/MIRROR/AMIRROR — zero corpus occurrences, no simulation) keep the verbatim { "Statement": "<args>" } quarantine; the Logic consumer reports them as recognized-but-not-simulated. Either way the axis words are kept out of reach of the quote/context-blind tag-value syntaxes below, which would otherwise mint them into Parsing.X/Y/Z and let ProgramXyzSyntax turn a frame statement into a very real ghost rapid. Deferred-but-unmodeled must mean "no transform yet", never "extra motion".

Must be placed early in the Parsing bundle — after BlockSkipSyntax, before every assignment / tag-value syntax (the ROT RPL=45 shape would otherwise feed NamedVarAssignmentSyntax).

SiemensGotoParsingSyntax

Captures Siemens GOTOF/GOTOB jump statements whole into Parsing.SiemensGoto. Four forms are recognised, mirroring the Fanuc phrase-level split (IF ... GOTO is one phrase, not an IF composed with a GOTO):

  • GOTOF <label> / GOTOB <label> — unconditional forward / backward jump.
  • IF <cond> GOTOF <label> / IF <cond> GOTOB <label> — the Sinumerik single-line conditional jump (no brackets around the condition).

Placement: inside the whole-statement owner group, after SiemensRepeatParsingSyntax and before SiemensIfParsingSyntax — the IF-jump forms carry a strictly longer prefix than the block IF <cond> phrase, so this owner must win first (the block-IF owner also refuses GOTOF/GOTOB tails defensively). Must run before the assignment syntaxes: IF R1==1 GOTOF LBL1 would otherwise be shredded by the assignment capture (its LHS grammar matches R1 and the first = of ==).

The label is captured as written (LBL1, MARKE_A, or an N<num> block number — both are legal Sinumerik jump targets). The condition string is left for VariableEvaluatorSyntax's pass-2 tree walk; SiemensGotoSyntax consumes the section.

SiemensIfParsingSyntax

Captures the Siemens block-conditional phrases whole into Parsing.SiemensIf: IF <cond> (no brackets on Sinumerik), ELSE, ENDIF. The single-line jump form (IF <cond> GOTOF <label>) belongs to SiemensGotoParsingSyntax, which runs immediately before this owner; a GOTOF/GOTOB tail is additionally refused here so an ordering drift degrades to a visible unparsed warning instead of a silently mis-captured block-IF (the Fanuc (?!GOTO\b) precedent).

Placement: whole-statement owner group, before the assignment syntaxes — a condition like R1==1 would otherwise be shredded by the assignment capture (LHS grammar matches R1 plus the first =). The condition string is left for VariableEvaluatorSyntax's pass-2 walk; SiemensIfSyntax consumes the section and decides the branch.

SiemensLabelSyntax

Consumes a Siemens label at block start (LBL1: — identifier followed by a colon, optionally after the N head index) into a block-root SiemensLabel record. Labels are passive jump targets: in the normal flow the record is pure bookkeeping (no motion, no state), while SiemensRepeatSyntax uses this same syntax as its LabelScanUtil probe and matches candidates on SiemensLabel.Name. Writing the record at the block root (not under Parsing) keeps the passive token out of UnconsumedCheckSyntax's audit without needing a Logic-layer consumer — mirroring how SiemensDefStatementSyntax leaves no Parsing.Def entry behind.

Anchored at the start of the remaining unparsed text, so a label buried mid-line is not captured (Sinumerik allows one label per block, at block start). Text after the colon stays in UnparsedText for the rest of the pipeline — LBL1: G1 X0 executes its trailing motion normally. The probe usage requires this syntax to stay self-sufficient: it reads only UnparsedText and never touches the dependency list.

SiemensLoopParsingSyntax

Captures the Siemens loop-construct phrases whole, one Parsing section per construct family:

  • WHILE <cond> / ENDWHILEParsing.SiemensWhile.
  • FOR <var> = <start> TO <end> / ENDFORParsing.SiemensFor. The start expression is stored as a single-entry Init map keyed by the variable name — the evaluator's pass-2 tree walk rewrites values only, never keys, so the loop variable's name survives even when it collides with a set named variable. Literal start/end bounds are written as numeric JSON values directly (writer decides the node type); expressions stay strings for the evaluator.
  • bare REPEAT / UNTIL <cond>Parsing.SiemensRepeatUntil. Only the label-less form is taken — REPEAT LBL1 ... is the P4 section repeat owned by SiemensRepeatParsingSyntax, which runs earlier in the statement group.
  • LOOP / ENDLOOPParsing.SiemensLoop.

Placement: whole-statement owner group, after SiemensGotoParsingSyntax / SiemensIfParsingSyntax and before the assignment syntaxes — FOR R1=0 TO 10 would otherwise be shredded by the assignment capture (R1=0 is a legal assignment shape and the TO 10 tail strands). SiemensLoopSyntax consumes all four sections against its shared loop-frame stack.

SiemensMcallSyntax

Captures a Siemens MCALL modal-call statement whole into a Parsing.MCALL sub-object: MCALL CYCLE81(500.,327.9137,0.5,324.564,,,0,1,0){ “CycleName”: “CYCLE81”, “Args”: ["500.", …] }; a bare MCALL (modal cancel) → { “Bare”: true }; a parenthesis-less callee (MCALL L123) keeps CycleName without Args. The Logic consumer (SiemensModalCycleSyntax) maps the supported CYCLE8x family onto the shared canned-cycle modal machinery and warns on everything else.

Whole-statement owner: MCALL lines are standalone in the corpus, and owning the full statement keeps the cycle's positional arguments away from the assignment / tag-value syntaxes (same shredding hazard as SiemensCycleCallSyntax, whose argument grammar — including complete quoted runs — is reused verbatim). Must run before SiemensCycleCallSyntax: a whitelisted cycle name after MCALL would otherwise be captured bare-of-context and strand the MCALLL word. A line mixing MCALL with other tokens does not match and falls through whole to the visible unparsed warning.

SiemensMsgSyntax

Consumes a Siemens MSG(“text”) operator display call (or the bare MSG() clear form) from the unparsed line text into a block-root Msg section, and surfaces the text as a Msg–Display system message.

Must be placed before every assignment / tag-value / flag syntax in the Parsing bundle (right after TailCommentSyntax / BlockSkipSyntax): the quoted argument routinely contains NC-shaped tokens (MSG("TOOL=5"), MSG("G54 OK"), MSG("T20 R8.000 CR:2.500")) which the quote-blind consumers downstream would otherwise shred into ghost assignments, flags, or axis words. Consuming the whole call here removes that hazard structurally — the planned fix recorded on NcSyntaxUtil's assignment RHS-boundary notes.

Only the two literal forms are consumed: MSG("...") and MSG(). Non-literal arguments (string concatenation MSG("A"<<R1), variable interpolation) are deliberately left whole in UnparsedText for the visible UnparsedText--Remaining warning — half-eating them would silently lose content.

SiemensProcSyntax

Consumes a Siemens PROC subprogram declaration header (PROC MY_SUB, PROC CONTOUR(REAL X, INT N) SAVE DISPLOF) whole into a block-root SiemensProc record. The header carries no executable state for the simulation — parameter binding to caller arguments is a later work item — but leaving it unparsed would shred the parameter list into ghost axis words the moment the tag-value syntaxes run, so the whole statement is owned here. The verbatim remainder after the name is preserved on Statement for cache-dump readers. Writes at the block root (no Parsing entry) following the SiemensDefStatementSyntax precedent — a record with no Logic consumer must not land in the UnconsumedCheckSyntax audit tree.

Anchored at statement start: Sinumerik requires PROC to be the first statement of a subprogram file, so a mid-line PROC is left alone (visible unparsed warning).

SiemensQuotedStatementSyntax

Quote guard: any line text still carrying a double quote after the literal-form consumers (SiemensMsgSyntax, SiemensToolCallSyntax, SiemensCycleCallSyntax) have run is quarantined whole into Parsing.QuotedStatement = { “Statement”: “<verbatim>” }WRITE(ERROR,“CUTTIME”,“T5 X100”), string-concatenation MSG("..."<<R1), quoted-argument cycles not yet whitelisted.

Every quote-blind syntax below (flags, numbered flags, tag values, assignments) opens a token boundary at the quote→letter transition, so without this guard the string contents get minted into REAL parser state: "G54" inside a WRITE argument silently switches the active work offset, "T5 X100" mints a ghost tool call plus a ghost motion. Quarantining keeps the whole statement visible as one Parsing--Unconsumed entry (QuotedStatement.Statement) with zero state changes — the same deferred-not-corrupted contract as SiemensFrameStatementSyntax. Proper consumers (WRITE, CYCLE800 quoted args) replace this guard per statement family later.

Trade-off, deliberate: on an exotic mixed block the guard also takes the co-resident plain words (a motion word sharing the block with an unconsumed quoted call goes into the quarantine too). Losing them is visible in the warning text; minting false state would be silent — never trade the first for the second. Corpus quoted statements (WRITE, non-literal MSG) are standalone blocks.

SiemensRepeatParsingSyntax

Captures a Siemens REPEAT statement whole into Parsing.SiemensRepeat: REPEAT LBL1 LBL0{ “Start”: “LBL1”, “End”: “LBL0” }, with an optional trailing repetition count (P=3 or P3). The Evaluation consumer (SiemensRepeatSyntax) re-runs the label-bounded section. The single-label form (REPEAT LBL1 — repeat from the label back to the REPEAT line) is captured with End absent; the consumer currently warns it unsupported (corpus count: zero).

Whole-statement owner, anchored at statement start — mixing REPEAT with other tokens on one block does not match and falls through whole to the visible unparsed warning. The end-label alternative refuses a P+digits word so REPEAT LBL1 P3 reads as start-label + count, not as an end label named P3.

SiemensToolCallSyntax

Consumes the Siemens string tool call T=“name” from the unparsed line text into Parsing.T as a string value (quotes stripped). Numeric concatenated calls (T5) stay with the preset's IntegerTagValueSyntax; ToolChangeSyntax accepts either shape.

Must be placed before every tag-value syntax in the Parsing bundle: tool names routinely contain NC-shaped tokens (T="D16R3Z6" — quote-blind consumers would mint ghost Parsing.D/Parsing.Z entries out of the name; (?<=[0-9]) and quote→letter \b boundaries in RegexFlagPrefix both open inside the string). Same structural-consumption rationale as SiemensMsgSyntax.

A second T="..." behind a ; comment (T="M6LWXD-1301";T="M6LWX", real corpus shape) never reaches this syntax — the quote-aware TailCommentSyntax runs earlier and strips it. Tool names are matched verbatim, including non-ASCII bytes from legacy code pages.