Namespace Hi.NcParsers.ParsingSyntaxs.Siemens
Classes
- SiemensCallStatementSyntax
Captures a whole-line Siemens subprogram-call statement into
Parsing.SiemensCallfor SiemensSubProgramCallSyntax to resolve (inline the file) or safe-skip (structured warning, zero motion). Two shapes are owned:- Parenthesized call, any identifier —
HQ_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 call —
L9810,L_ZYM91,HH_ROBOTOFF, with an optional repeat countL123 P3→{ "Name": "L123", "P": 3 }. Restricted toL-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:
WRITEstays 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.- Parenthesized call, any identifier —
- SiemensCycleCallSyntax
Captures whitelisted Siemens cycle calls of the shape
NAME(arg1,arg2,…)(or the bareNAMEform) from the unparsed line text into aParsing.NAMEsub-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 emptyArgsarray; a bareNAMEyields{ “Bare”: true }(a marker — empty sub-objects would be swept by intermediateCleanupParsingcalls 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 genericWORD(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 visibleUnparsedText--Remainingwarning.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 likeV1) 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) from0(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 intoParsing.Assignments: initialised names carry their initialiser expression text (the Evaluation bundle resolves and routes it intoVars.Namedlike any named assignment), bare names carry“0”— Sinumerik default-initialises numeric types to zero, so a laterG0 Z=_SAFE_Zreads 0 instead of failing vacant.Must run before NamedVarAssignmentSyntax in the Parsing bundle: on a DEF line that syntax would capture
_X_HOME=155.5but strandDEF 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/CHARinitialise to 0 like INT;STRINGdeclarations 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 aParsing.<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=R5→Parsing.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 intoParsing.X/Y/Zand 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=45shape would otherwise feed NamedVarAssignmentSyntax).
- SiemensGotoParsingSyntax
Captures Siemens
GOTOF/GOTOBjump statements whole intoParsing.SiemensGoto. Four forms are recognised, mirroring the Fanuc phrase-level split (IF ... GOTOis 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 LBL1would otherwise be shredded by the assignment capture (its LHS grammar matchesR1and the first=of==).The label is captured as written (
LBL1,MARKE_A, or anN<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==1would otherwise be shredded by the assignment capture (LHS grammar matchesR1plus 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 theNhead 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 onSiemensLabel.Name. Writing the record at the block root (not underParsing) keeps the passive token out of UnconsumedCheckSyntax's audit without needing a Logic-layer consumer — mirroring how SiemensDefStatementSyntax leaves noParsing.Defentry 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 X0executes 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>/ENDWHILE→Parsing.SiemensWhile.FOR <var> = <start> TO <end>/ENDFOR→Parsing.SiemensFor. The start expression is stored as a single-entryInitmap 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/ENDLOOP→Parsing.SiemensLoop.
Placement: whole-statement owner group, after SiemensGotoParsingSyntax / SiemensIfParsingSyntax and before the assignment syntaxes —
FOR R1=0 TO 10would otherwise be shredded by the assignment capture (R1=0is a legal assignment shape and theTO 10tail strands). SiemensLoopSyntax consumes all four sections against its shared loop-frame stack.
- SiemensMcallSyntax
Captures a Siemens
MCALLmodal-call statement whole into aParsing.MCALLsub-object:MCALL CYCLE81(500.,327.9137,0.5,324.564,,,0,1,0)→{ “CycleName”: “CYCLE81”, “Args”: ["500.", …] }; a bareMCALL(modal cancel) →{ “Bare”: true }; a parenthesis-less callee (MCALL L123) keepsCycleNamewithoutArgs. The Logic consumer (SiemensModalCycleSyntax) maps the supportedCYCLE8xfamily 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
MCALLwould otherwise be captured bare-of-context and strand theMCALLLword. 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 bareMSG()clear form) from the unparsed line text into a block-root Msg section, and surfaces the text as aMsg–Displaysystem 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("...")andMSG(). Non-literal arguments (string concatenationMSG("A"<<R1), variable interpolation) are deliberately left whole in UnparsedText for the visibleUnparsedText--Remainingwarning — half-eating them would silently lose content.
- SiemensProcSyntax
Consumes a Siemens
PROCsubprogram 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 (noParsingentry) following the SiemensDefStatementSyntax precedent — a record with no Logic consumer must not land in the UnconsumedCheckSyntax audit tree.Anchored at statement start: Sinumerik requires
PROCto be the first statement of a subprogram file, so a mid-linePROCis 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-concatenationMSG("..."<<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 oneParsing--Unconsumedentry (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
REPEATstatement whole intoParsing.SiemensRepeat:REPEAT LBL1 LBL0→{ “Start”: “LBL1”, “End”: “LBL0” }, with an optional trailing repetition count (P=3orP3). 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 withEndabsent; 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 soREPEAT LBL1 P3reads as start-label + count, not as an end label namedP3.
- SiemensToolCallSyntax
Consumes the Siemens string tool call
T=“name”from the unparsed line text intoParsing.Tas 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 ghostParsing.D/Parsing.Zentries out of the name;(?<=[0-9])and quote→letter\bboundaries 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.