Namespace Hi.NcParsers.EvaluationSyntaxs.Heidenhain
Classes
- HeidenhainExpressionParser
Recursive-descent parser for Heidenhain klartext FN value expressions. Produces the same NcExpr AST as the Fanuc NcExpressionParser so NcExpressionEvaluator is reused unchanged. Pure: no variable lookup, no evaluation.
Grammar (lowest precedence at top):
expr := add-expr add-expr := term (('+' | '-') term)* term := factor (('*' | '/' | 'DIV') factor)* factor := ('+' | '-')? primary primary := number | '(' expr ')' | 'Q' digits | 'QR' digits | 'QL' digits | 'QS' digits | func primary → prefix form "SQRT 4" (FN 5) | func '(' arglist ')' → paren form "SQRT(Q2)"Dialect notes: Q-family tokens are canonicalised to uppercase (
q1→Q1) soParsing.Assignmentskeys, table lookups and same-block references agree. (Caveat shared with the Siemens R canonicalisation: a lowercase-captured Assignments key keeps its raw spelling in the evaluator's same-block dictionary, so a later same-block reference resolves to the pre-block value instead — klartext posts emit uppercase, corpus-zero.)DIVis the FN 4 division spelling (FN 4: Q4 = +8 DIV +Q2) and maps onto the shared divide operator. Function names are limited to the klartext math vocabulary (SQRT SIN COS TAN ASIN ACOS ATAN ABS INT FRAC SGN NEG LN LOG EXP);INTnormalises to the evaluator'sFIX(truncate toward zero), names the shared evaluator lacks (FRAC/SGN/NEG/LOG) parse fine and fail soft at evaluation. Any other identifier is a parse error — klartext has no named variables, and rejecting bare words keeps the evaluator's Parsing-tree pass from touching non-expression strings (MM,MAX, tool-axis letters). Comparison/logical operators are deliberately absent: FN 9–12 jump conditions are pre-normalised by the control-flow syntaxes (P5), not parsed here.
- HeidenhainQParameterReadingSyntax
Obtains values for Heidenhain Q parameters by consuming literal numeric assignments from
Parsing.Assignments.Qn/QRnand routing them by id range — one reader for the singleQkey shape, range routing inside (the Heidenhain analogue of the Fanuc range-routed reader trio):Q0-Q99→ HeidenhainQParameterTable free range (hincproj-persisted; the table is the single source of truth — no JSON mirror).QRn→ the same table's permanent QR store.Q100-Q199→ controller-written system parameters: the write is consumed but not applied, with aHeidenhainQ--SystemReadOnlywarning (no fabricated values).Q200+→ volatile range: dict-merged intoVars.Volatilewith canonicalQ+id keys, carried block-to-block like the Fanuc VolatileVariableReadingSyntax; cleared at program end by ProgramEndCleanSyntax.
The carry of the previous block's
Vars.Volatilehappens on every block regardless of assignments, so the single-step traceback contract of HeidenhainVolatileQLookup holds.Only literal numeric RHS values are consumed (
Q1 = 5000✓;Q1 = Q1*.75✗). Non-literal RHS entries are left untouched inParsing.Assignments; VariableEvaluatorSyntax resolves them to literals earlier on the same block, so by the time this syntax runs, every evaluable RHS is literal. The two syntaxes are decoupled.
- HeidenhainVolatileQLookup
Reads Heidenhain volatile Q parameters (
Q200+, the cycle/user range that resets at program start) fromVars.Volatile. Self-gates the id range so the evaluator's RuntimeVariableLookups chain can fall through for other keys (Q0-Q99/QRnresolve on the HeidenhainQParameterTable further down the chain;Q100-Q199stay vacant by design). Sibling of the Fanuc VolatileVariableLookup with the same single-step traceback contract: HeidenhainQParameterReadingSyntax dict-merges every block'sVars.Volatileinto the next block, so the entry — if it exists — is on the current block or the immediately previous one.Keys are stored canonically as
Q+ id by the reader; this lookup re-canonicalises the incoming key the same way, so lowercase raw captures still resolve. Stateless and dependency-free.