Namespace Hi.NcParsers.EvaluationSyntaxs
Classes
- FanucSystemControlVariableSyntax
Consumes Fanuc-style system-control variable assignments (
#3000-#3999) — alarm trigger (#3000), millisecond and hour clocks (#3001/#3002), single-block / feed-hold bypass flags (#3003/#3004), pause-with-message (#3006), mirror-image flags (#3007), date / time (#3011/#3012), tool-life data (#3030/#3032), etc.Every id in this range is a controller-side state variable — its authoritative value lives on the real hardware (RTC, alarm bus, override switches, …) and an NC write at most triggers a side effect (clock reset, alarm raise, message-pause prompt). Offline simulation has none of that machinery, so this syntax does not emulate the effect. Instead it:
- records the literal write on the block JSON under
Vars.SystemControl(round-trip and cache-dump visibility); - emits a
FanucSystemControl--UnsupportedUnsupportedMessage(Sentence, string, string, object) so the user knows the assignment was recognised but its controller-side effect is not simulated. Message-severity (not Warning) because these writes are safe no-ops offline — every consumed assignment would emit a Warning per block, which would be noisy without signalling anything the user must act on; - removes the entry from
Parsing.Assignmentsso it does not re-surface as a genericParsing--Unconsumeddiagnostic.
The dictionary carries forward block-by-block (same dict-merge pattern as VolatileVariableReadingSyntax) so a downstream consumer can read the most recent recorded value via
SyntaxPiecelinkage.Only literal numeric RHS values are consumed; non-literal RHS (e.g.
#3002 = #500) is left inParsing.Assignmentsfor VariableEvaluatorSyntax to resolve, mirroring the retained / volatile reading syntaxes.Fanuc-family only — Siemens uses named system variables (
$AC_TIME,$A_DAY, …) and Heidenhain usesFN18: SYSREAD; neither flows throughParsing.Assignments.#nnn.- records the literal write on the block JSON under
- RetainedCommonVariableReadingSyntax
Obtains values for Fanuc-style retained common variables (
#500-#999) by consuming literal numeric assignments fromParsing.Assignments.#nnnand writing them straight to a registered RetainedCommonVariableTable.No SyntaxPiece JSON mirror is created — the table is the single source of truth for retained values, and VariableEvaluatorSyntax reads from the table directly. The hincproj round-trip preserves writes across project sessions.
Only literal numeric RHS values are consumed by this syntax (
#500 = 1.234✓;#600 = #500 + 1✗). Non-literal RHS entries are left untouched inParsing.Assignments; VariableEvaluatorSyntax resolves them and writes the result through the same table. The two syntaxes are decoupled.If no RetainedCommonVariableTable is registered on the runner's
NcDependencyList, this syntax is a no-op.
- SubProgramCallSyntax
Inlines a Fanuc-style subprogram into the source layer when an M98 or M198 host block is reached.
M98 P_ L_reads the matchingO<P>file from InternalFolder;M198 P_reads from ExternalFolder (Fanuc external-storage call — same mechanism as M98, different lookup root). The file is segmented through the host runner's segmenter (SegmenterDependency) and the resulting SyntaxPieces are prepended intolayers[0]via PrependSource(IEnumerable<T>); the rest of the pipeline picks them up through ordinarywalkNode.Nexttraversal as if they had always been part of the host file.Pipeline placement: first child of the Fanuc
EvaluationBundleSyntax. By the time this runs, M98Syntax / M198Syntax (each a ParameterizedFlagSyntax) have written aParsing.M98/Parsing.M198sub-object carrying the capturedP/Lparameters. Note: those sub-objects are this syntax's only trigger —"M98"/"M198"never reachParsing.Flags, because the parameterized match has already consumed the text by the time NumberedFlagSyntax runs.Filename lookup uses a fallback chain:
O{P:D4}.NC,O{P}.NC,O{P:D4},O{P},{P:D4}.NC,{P}.NC— first match wins. Case-insensitive match is delegated to the host filesystem (Windows is, Linux is not).L > 1 inlines the same subprogram
Ltimes in series. Each repetition is a fresh segmentation pass so each block gets its own SyntaxPiece with an independent JSON object — the downstream pipeline mutates JSON in place and would clobber sibling repetitions if instances were shared.Not yet supported:
M99 P{seq}early return inside a subprogram, partial-program calls (M98 P{seq}{prog}split encoding), and arg binding (G65 macro is a separate syntax).
- SubProgramReturnSyntax
Consumes Fanuc-style
M99subprogram-return blocks.In the inline model used by SubProgramCallSyntax, a plain
M99at the end of a subprogram is implicit: the inlined blocks are followed inlayers[0]by the caller's next block, so the natural pipeline traversal already does the "return". This syntax therefore only consumes the M99 flag (so UnconsumedCheckSyntax doesn't warn) and records a SubProgramReturn section for cache-dump visibility.M99 P{seq}(return to caller'sN{seq}sequence number) is captured in P but not yet honoured — the subprogram tail still proceeds straight into the caller's next block. Implementing the jump requires a forward scan of the post-host caller blocks for a matchingN{seq}head index, then dropping the intervening blocks; deferred until the caller-side walk semantics are designed.Pipeline placement: anywhere after Parsing has populated
Parsing.M99. Conventionally placed alongside SubProgramCallSyntax at the head of the Evaluation bundle so call/return live next to each other.Detection is on the
Parsing.M99sub-object written by M99Syntax (a ParameterizedFlagSyntax) — the keyword"M99"never reachesParsing.Flagsbecause the parameterized match has already consumed the text by the time NumberedFlagSyntax runs.
- VariableEvaluatorSyntax
Pure expression normalizer for Custom Macro B syntax. Walks the parser-stage residue on a single block and inlines numeric values wherever a Fanuc-style variable reference or bracket expression appears — but does not write to any specific store. Routing “where the resolved literal lands” stays in the brand-specific reader syntaxes (VolatileVariableReadingSyntax, RetainedCommonVariableTable's reader, FanucSystemControlVariableSyntax, …) which run after this syntax on the same block.
Two passes per block:
-
Assignments normalize —
Parsing.Assignments.#nnnentries whose RHS is non-literal (e.g."#500+1","SQRT[#100]") are evaluated via the VariableEvaluatorSyntax.ChainLookup and the RHS string is replaced with the resolved literal (round-trip-safe"R"-format). The entry stays inParsing.Assignmentsso downstream reader syntaxes consume it as a pure-literal assignment. Iteration follows source order (Parsing.Assignments insertion order). -
Parsing tree substitution — every string-typed value reachable
from
Parsing.<tag>(axis tags, canned-cycle sub-objects) is parsed; on a successful evaluation the string is replaced with a numeric JsonValue. Failures silently leave the original string and rely on downstream GetParsedDouble(JsonObject, string, Sentence, NcDiagnosticProgress) at consumer sites to surfaceVariableExpression--Unevaluatedonly if the tag is actually read.
Lookup chain (first non-null wins, configured per brand preset via RuntimeVariableLookups + IVariableLookup instances on
NcDependencyList):- Current block's own resolved assignments — built-in to
VariableEvaluatorSyntax.ChainLookup; covers same-block forward references in
source order (an earlier
#nnn=literalis visible to a later RHS that mentions#nnn). - Each IRuntimeVariableLookup in
RuntimeVariableLookups, in list order. Typical contents
for a Fanuc-family preset:
LocalVariableLookup (
#1-#33), VolatileVariableLookup (#100-#499), FanucPositionVariableLookup (#5001-#5043). - Each IVariableLookup on the runner's
NcDependencyList, in registration order (RetainedCommonVariableTable, FanucParameterTable, FanucToolOffsetVariableLookup).
Each lookup self-gates its id range; the evaluator stays brand- and range-agnostic. Adding a new variable surface is additive: register an IVariableLookup on a dependency or push an IRuntimeVariableLookup onto the per-preset list.
Same-block forward reference — when an Assignment RHS references a
#nnnthat is also being assigned later in the same block (i.e. listed inParsing.Assignmentsafter the RHS being evaluated), the VariableEvaluatorSyntax.ChainLookup cannot pick up the not-yet-resolved value and falls back to traceback / dependency-table reads — effectively the pre-block value. AVariableEvaluator--SameBlockForwardReferencewarning is emitted per such RHS so the user is told the source-order semantics were not honoured. Practical impact is near-zero for typical CAM-emitted NC (one assignment per line).-
Assignments normalize —
- VolatileVariableReadingSyntax
Obtains values for Fanuc-style non-retained common variables (
#100-#499). Reads literal numeric assignments fromParsing.Assignments.#nnn, dict-merges them with the previous block's volatile state, and writes the resulting per-block dictionary intoVars.Volatile.Lifetime is bounded by
MachiningSession: within one session the dictionary carries forward block-by-block via this syntax; session restart abandons the SyntaxPiece JSON dataflow and starts fresh. Program-end (M02/M30) clearing is handled by ProgramEndCleanSyntax.Only literal numeric RHS values are consumed by this syntax (
#124 = 15.✓;#100 = #1 + 5✗). Non-literal RHS entries are left untouched inParsing.Assignments; VariableEvaluatorSyntax resolves them and writes the result into the same per-block dictionary. The two syntaxes are decoupled — the evaluator's lookup tracebacks viaSyntaxPiecelinkage so it does not depend on having run before or after this syntax.