This repository has been archived on 2026-10-11. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
HiNC-2025-win-desktop-Deploy/App/wwwroot/HiAPI-docsite/anatomy/general-setup/controller/machine/program-reading.html
T
2026-09-09 17:35:23 +08:00

534 lines
32 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Program Reading | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Program Reading | HiAPI-C# 2025 ">
<link rel="icon" href="../../../../img/HiAPI.favicon.ico">
<link rel="stylesheet" href="../../../../public/docfx.min.css">
<link rel="stylesheet" href="../../../../public/main.css">
<meta name="docfx:navrel" content="../../../../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../../../../">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../../../../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../../../../index.html">
<img id="logo" class="svg" src="../../../../img/HiAPI.logo.png" alt="">
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="Anatomy-ControllerProgramReading">
<h1 id="program-reading">Program Reading</h1>
<p>Program Reading is the pair of Machine / Controller leaves that change how the runner <em>reads</em> a
program rather than how the machine moves: which block-skip layers are active, and where a
subprogram call goes looking for its file. Both live on the General Setup page at <code>/general-setup</code>,
under the Control-Tree ids <code>equipment/controller/machine/block-skip</code> and
<code>equipment/controller/machine/subprograms</code>. The pair is also unevenly branded — every shipped brand
preset carries the subprogram-folder config, and one of the five carries no block-skip config at
all.</p>
<div class="IMPORTANT">
<h5>Important</h5>
<p>Anatomy makes no claim that any id named here is stable across versions. The migration hop that
keeps an older <code>?tree=</code> value resolving is described in
<a class="xref" href="../../../platform/tree-ids-and-routes.html">Tree Ids and Routes</a>.</p>
</div>
<h2 id="the-asymmetry">The Asymmetry</h2>
<p>Both nodes are grown behind a plain presence probe over the runner's proxy-resolved dependency
list: <code>hasBlockSkip</code> is set when the list holds any
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.IBlockSkipConfig.html">IBlockSkipConfig</a>, <code>hasSubprogramFolders</code> when it holds a
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Generic.SubProgramFolderConfig.html">SubProgramFolderConfig</a>. Neither probe inspects a value.</p>
<table>
<thead>
<tr>
<th>Brand preset</th>
<th>Block-skip config</th>
<th>Subprogram-folder config</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fanuc</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<td>Siemens</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<td>Syntec</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<td>Mazak</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<td>Heidenhain</td>
<td><strong>no</strong></td>
<td>yes</td>
</tr>
</tbody>
</table>
<p><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Generic.GenericBlockSkipConfig.html">GenericBlockSkipConfig</a> is the <strong>only</strong> implementer of the
block-skip interface anywhere in the engine, and the Heidenhain preset's pipeline list is the one of
the five that does not carry it. That single omission is what makes Block Skip / Delete the one node
in the whole Controller branch that exists on four brands and not the fifth; every other gate on
this plane is satisfied either by all five presets or by a Siemens-only table. Which flag each row
answers to is <a class="xref" href="../brand-matrix.html">Brand Matrix</a>.</p>
<p>The config is not the only thing missing there. The block-skip switches gate a parsing syntax,
<a class="xref" href="../../../../api/Hi.NcParsers.ParsingSyntaxs.BlockSkipSyntax.html">BlockSkipSyntax</a>, and that syntax appears in the Fanuc, Siemens,
Syntec and Mazak syntax lists and in no other — the Heidenhain list carries no block-delete parser,
so on that preset the nine switches would have nothing to gate.</p>
<p>The subprogram-folder config runs the other way: all five presets carry one, and five call
statements across three brand families read the same two values. The node's own vocabulary is
Fanuc's, because the storage is, but the setting is not Fanuc-only.</p>
<h2 id="block-skip--delete">Block Skip / Delete</h2>
<p>The panel is a caption over nine checkboxes and nothing else. The caption reads <em>&quot;Enabled layers
skip their <code>/n</code>-prefixed blocks (<code>/</code> alone = layer 1).&quot;</em>, the first box is labelled <em>&quot;Layer 1
(bare /)&quot;</em> and the rest <em>&ldquo;Layer 2&rdquo;</em> through <em>&ldquo;Layer 9&rdquo;</em>.</p>
<h3 id="what-a-layer-does-to-a-block">What a layer does to a block</h3>
<p><a class="xref" href="../../../../api/Hi.NcParsers.ParsingSyntaxs.BlockSkipSyntax.html">BlockSkipSyntax</a> matches a leading <code>/</code> optionally followed by a
single digit <code>1</code>–<code>9</code>; a bare slash is layer 1. It then always writes a
<a class="xref" href="../../../../api/Hi.NcParsers.Keywords.BlockSkip.html">BlockSkip</a> section recording the symbol and the layer, and always
consumes the prefix out of the block's unparsed text — so the <code>/</code> itself never survives as residue
for the downstream unrecognized-text check, whatever the switches say.</p>
<p>What the switch decides is the block's <strong>body</strong>:</p>
<ul>
<li><strong>Layer on</strong> — the remaining text is moved into
<a class="xref" href="../../../../api/Hi.NcParsers.Keywords.BlockSkip.html#Hi_NcParsers_Keywords_BlockSkip_Body">Body</a> and the unparsed text is cleared. Every downstream
parsing syntax then sees nothing, so the block emits no NC act, and the run records
<code>BlockSkip--Skipped</code> at message severity for that block.</li>
<li><strong>Layer off, or no config at all</strong> — the body stays null and the rest of the block parses exactly
as an unprefixed one would. A runner with no block-skip config therefore simulates the whole
program, which is the safe reading of an unknown machine setting.</li>
</ul>
<p>Ordering matters for one thing and is fixed in each brand's list: the comment and NC-embedded
script syntaxes run <strong>before</strong> the block-skip syntax, so a comment on a skipped block — and any
script embedded in it — still takes effect while the motion beside it does not.</p>
<h3 id="one-value-seven-spellings-of-the-same-range">One value, seven spellings of the same range</h3>
<p>Layers 1 through 9 are the whole range, and no shared constant carries it. The bound is written out
separately in the parsing syntax's regular expression, in the config's XML reader and again in its
CSV setter, in its per-layer mutator guard, in the read endpoint that enumerates the layers, in the
write endpoint that loops over them, and in the panel's checkbox repeat. A tenth layer is therefore
seven edits, not one, and a partial change would be silent — a switch the panel offered but the
config refused to store would simply never take.</p>
<h3 id="what-a-fully-cleared-set-does-not-survive">What a fully cleared set does not survive</h3>
<p>A freshly applied preset has layer 1 on and the other eight off. The stored form is a
comma-separated list of the enabled layers, and an empty set serializes as an empty element. The
reader treats a blank list and a missing element identically — both mean <em>layer 1 only</em> — so
clearing every box and then reloading the project brings layer 1 back on. Every other combination
round-trips exactly.</p>
<h3 id="the-write">The write</h3>
<p>Each box commits on the click, and the request is the <strong>whole</strong> enabled set rather than the one
layer that changed: the panel sorts its set and sends it, and the endpoint walks 1 through 9 setting
each layer to whether the payload names it. A failed write restores the previous set and raises a
toast; the shared rules behind that shape are
<a class="xref" href="../editing-contract.html">Editing Contract</a>.</p>
<p>On the brand that carries no config, the read answers <em>not present</em> with an empty layer list and any
write is answered unsuccessfully with <em>&ldquo;No IBlockSkipConfig on the active runner&rdquo;</em> — but the node is
not built there, so neither answer is reachable from the tree.</p>
<h2 id="subprogram-folders">Subprogram Folders</h2>
<p>Two plain text fields, labelled <em>&quot;Internal folder (M98)&quot;</em> and <em>&quot;External folder (M198)&quot;</em>, hinted
<em>&ldquo;Relative to the host NC file's folder; empty = that folder itself&rdquo;</em> and <em>&ldquo;Fanuc external-storage
calls; empty = fall back to the internal folder&rdquo;</em>. They write
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Generic.SubProgramFolderConfig.html#Hi_NcParsers_Dependencys_Generic_SubProgramFolderConfig_InternalFolder">InternalFolder</a> and
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Generic.SubProgramFolderConfig.html#Hi_NcParsers_Dependencys_Generic_SubProgramFolderConfig_ExternalFolder">ExternalFolder</a>; an empty or
whitespace-only box is stored as null rather than as an empty string.</p>
<h3 id="which-call-statements-read-these-two-values">Which call statements read these two values</h3>
<table>
<thead>
<tr>
<th>Preset</th>
<th>Call statement</th>
<th>Field it reads</th>
<th>File-name chain, first match wins</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fanuc, Mazak, Syntec</td>
<td><code>M98 P_ L_</code></td>
<td>Internal</td>
<td><code>O{P:D4}.NC</code>, <code>O{P}.NC</code>, <code>O{P:D4}</code>, <code>O{P}</code>, <code>{P:D4}.NC</code>, <code>{P}.NC</code></td>
</tr>
<tr>
<td>Fanuc, Mazak, Syntec</td>
<td><code>M198 P_</code></td>
<td>External, falling back to Internal when it is null</td>
<td>the same chain</td>
</tr>
<tr>
<td>Fanuc</td>
<td><code>G65</code> / <code>G66</code> macro call</td>
<td>Internal</td>
<td>the same chain</td>
</tr>
<tr>
<td>Siemens</td>
<td>name call (<code>L9810</code>, a named cycle)</td>
<td>Internal</td>
<td><code>{name}.SPF</code>, <code>{name}.MPF</code>, <code>{name}</code></td>
</tr>
<tr>
<td>Heidenhain</td>
<td><code>CALL PGM name</code></td>
<td>Internal</td>
<td><code>{name}.h</code>, <code>{name}.H</code>, <code>{name}</code></td>
</tr>
</tbody>
</table>
<p>Two consequences follow from the table, and both are invisible from the field labels.</p>
<p><strong>The External folder is inert on two brands.</strong> Only the Fanuc-family inliner,
<a class="xref" href="../../../../api/Hi.NcParsers.EvaluationSyntaxs.SubProgramCallSyntax.html">SubProgramCallSyntax</a>, ever reads it — the Siemens and
Heidenhain call syntaxes look up their callee through the Internal folder alone. The field is
offered on every brand because the storage is brand-neutral, and it is honoured on the three that
have an <code>M198</code>.</p>
<p><strong>The Internal folder is read by more than the M98 label says.</strong> On the Fanuc preset it also anchors
both Custom Macro B lookups — <a class="xref" href="../../../../api/Hi.NcParsers.EvaluationSyntaxs.Fanuc.FanucMacroCallSyntax.html">FanucMacroCallSyntax</a> for
the <code>G65</code> one-shot call and <a class="xref" href="../../../../api/Hi.NcParsers.EvaluationSyntaxs.Fanuc.FanucModalMacroSyntax.html">FanucModalMacroSyntax</a> for
the <code>G66</code> modal — and on Siemens and Heidenhain it is the <em>only</em> subprogram root there is. Emptying
it to fix an M98 path therefore moves the macro and named-call lookups with it.</p>
<p>Each brand also brings its own file-name chain, and the chains are per-syntax properties rather than
one shared list — the Fanuc chain is
<a class="xref" href="../../../../api/Hi.NcParsers.EvaluationSyntaxs.MacroFileResolver.html#Hi_NcParsers_EvaluationSyntaxs_MacroFileResolver_FilenamePatterns">FilenamePatterns</a>, a static array every
Fanuc-family caller shares, while
<a class="xref" href="../../../../api/Hi.NcParsers.EvaluationSyntaxs.Siemens.SiemensSubProgramCallSyntax.html#Hi_NcParsers_EvaluationSyntaxs_Siemens_SiemensSubProgramCallSyntax_FilePatterns">FilePatterns</a> and
<a class="xref" href="../../../../api/Hi.NcParsers.EvaluationSyntaxs.Heidenhain.HeidenhainSubProgramCallSyntax.html#Hi_NcParsers_EvaluationSyntaxs_Heidenhain_HeidenhainSubProgramCallSyntax_FilePatterns">FilePatterns</a> are
instance properties of their own call syntaxes and are re-writable from the runner file. Case
matching is delegated to the host file system throughout, which is why the Heidenhain chain carries
both <code>.h</code> and <code>.H</code>.</p>
<h3 id="where-a-relative-folder-is-anchored">Where a relative folder is anchored</h3>
<p>The resolver takes the folder as written. An absolute path is used unchanged. A relative path — and
an empty one, which means <em>the root itself</em> — is combined with the base directory supplied by
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.SystemWired.ProjectFolderDependency.html">ProjectFolderDependency</a>, and the machining session wires
that dependency to the <strong>project's</strong> own root before each play.</p>
<p>So the anchor is the project folder, not the folder the host NC file happens to sit in. A program
played from a subfolder of the project resolves <code>NC</code> against the project root, not against its own
neighbour of that name. The field's hint says otherwise, and so does the API summary on the two
config properties the panel writes; the resolver is what runs.</p>
<p>Two further conditions end the lookup before any pattern is tried: a relative folder with no base
directory resolves to nothing, and so does a folder that does not exist as a directory.</p>
<h3 id="a-missing-file-is-an-error-on-one-family-and-a-warning-on-the-other">A missing file is an error on one family and a warning on the other</h3>
<p>The same empty result is reported at two different severities, and the split follows the call
statement rather than the setting.</p>
<ul>
<li><strong>Fanuc, Mazak, Syntec</strong> — an unresolved <code>M98</code> / <code>M198</code> raises <code>SubProgramCall--FileNotFound</code> at
error severity, quoting the folder that was searched, and the call is consumed.</li>
<li><strong>Siemens, Heidenhain</strong> — an unresolved call raises <code>SiemensCall--Skipped</code> or
<code>HeidenhainCall--Skipped</code> at warning severity and is consumed with no motion effect. That is
deliberate: the common unresolved callee on those controls is an OEM or measuring cycle whose
definition file ships with the machine and never travels with the program, so a hard error would
fire on ordinary, correct programs.</li>
</ul>
<p>A resolved call is inlined: the callee is segmented through the runner's own segmenter and its
blocks are prepended into the program ahead of the host block, each stamped with a record naming the
call it came from. <code>M98</code> with an <code>L</code> count above one inlines the same file that many times in
series, each repetition its own segmentation pass.</p>
<h3 id="the-nesting-ceiling-and-where-there-is-none">The nesting ceiling, and where there is none</h3>
<p>A self- or mutually-recursive callee re-captures its own call statement inside every inlined body,
so a call path needs a rail of its own — no loop watchdog covers it. <strong>That rail is declared twice,
independently, and is missing on the third path.</strong></p>
<table>
<thead>
<tr>
<th>Preset</th>
<th>Ceiling</th>
<th>Where it is declared</th>
<th>Exceeded</th>
</tr>
</thead>
<tbody>
<tr>
<td>Siemens</td>
<td>32 frames</td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.EvaluationSyntaxs.Siemens.SiemensSubProgramCallSyntax.html#Hi_NcParsers_EvaluationSyntaxs_Siemens_SiemensSubProgramCallSyntax_DefaultMaxCallDepth">DefaultMaxCallDepth</a></td>
<td><code>SiemensCall--DepthLimitExceeded</code>, consumed as a safe skip</td>
</tr>
<tr>
<td>Heidenhain</td>
<td>32 frames</td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.EvaluationSyntaxs.Heidenhain.HeidenhainSubProgramCallSyntax.html#Hi_NcParsers_EvaluationSyntaxs_Heidenhain_HeidenhainSubProgramCallSyntax_DefaultMaxCallDepth">DefaultMaxCallDepth</a></td>
<td><code>HeidenhainCall--DepthLimitExceeded</code>, consumed as a safe skip</td>
</tr>
<tr>
<td>Fanuc, Mazak, Syntec</td>
<td>none</td>
<td>—</td>
<td>—</td>
</tr>
</tbody>
</table>
<p>The two constants are separate <code>const int</code> declarations on separate classes that happen to hold the
same number, each surfaced as its own writable <code>MaxCallDepth</code> property and each serialized into the
runner file as its own element. Raising one raises nothing else. Both compare against the depth of
the call stack already stamped on the host block, so the count is frames entered, not files listed.</p>
<p>On the Fanuc-family inliner and on both Custom Macro B calls there is no depth comparison at all.
None of them reads the host block's frame count before inlining, so none carries the recursion rail
the Siemens and Heidenhain syntaxes declare. The depth itself is recorded either way — every inlined
block is stamped with a pushed call-stack frame that the matching return statement pops — so what is
missing is the comparison, not the count.</p>
<p>The Heidenhain call syntax carries a second, unrelated ceiling for its section-repeat form:
<a class="xref" href="../../../../api/Hi.NcParsers.EvaluationSyntaxs.Heidenhain.HeidenhainSubProgramCallSyntax.html#Hi_NcParsers_EvaluationSyntaxs_Heidenhain_HeidenhainSubProgramCallSyntax_MaxRepetitions">MaxRepetitions</a> caps
a <code>REP</code> literal at 65534, since the repeat re-scans the file once per repetition.</p>
<h3 id="what-an-empty-internal-folder-does-not-survive">What an empty Internal folder does not survive</h3>
<p>The config's default internal folder is <code>NC</code> — the layout where the main program sits beside an
<code>NC/</code> directory of subprograms — and that default is applied by the property itself, before the XML
reader runs. The writer omits an element for a null folder, and the reader keeps whatever the
property already holds when the element is absent. Clearing the <strong>Internal folder</strong> box therefore
stores a null, writes no element, and reads back as <code>NC</code> the next time the project is opened.</p>
<p>The <strong>External folder</strong> box has no such default and round-trips cleanly: cleared, it stores null,
writes no element, and reads back null — which is the state the field's own hint describes, falling
back to the internal folder.</p>
<h2 id="editing-and-storage">Editing and Storage</h2>
<p>Both panels open with the branch's two empty layers — the shared <em>&quot;No NC runner — load a project
first.&quot;</em> line first, then the panel's own read reporting <em>&quot;No block-skip config on the active
runner.&quot;</em> or <em>&quot;No subprogram-folder config on the active runner.&quot;</em> The first layer is a live guard
against the snapshot emptying under a panel that is already mounted, which is what closing the
project does. The second is unreachable by navigating: the node's gate and the panel's read probe
the same dependency on the same resolved list, so the leaf exists only where the read is about to
succeed.</p>
<p>Their commit shapes differ, and both are recorded in
<a class="xref" href="../editing-contract.html">Editing Contract</a>: the block-skip boxes commit on the click
and roll back on failure, while the two folder fields commit <strong>as a pair</strong> on blur or Enter of
either one, compared against a saved snapshot of both rather than a per-field captured value — so
editing one folder writes both, and a failure restores both.</p>
<p>Both configs are plain runner-owned entries rather than proxies, so their values serialize with the
runner and follow it. Installing a controller file replaces them outright, and a brand apply assigns
a whole fresh preset, so <strong>an applied brand change returns both to that preset's defaults</strong> — layer 1
alone, and the <code>NC</code> internal folder with no external one. Selecting the brand already in force is not
a route to that reset: the apply stays disabled until the selection differs from the runner's own
brand. Which half of a project each value on this plane lands in is
<a class="xref" href="index.html">Machine and Controller Plane</a>.</p>
<h2 id="layout">Layout</h2>
<ul>
<li><strong>General Setup</strong> Control Tree — the left dock of <code>/general-setup</code>
<ul>
<li><strong>Controller</strong> Node Row
<ul>
<li><strong>Machine / Controller</strong> Group Row
<ul>
<li><strong>Block Skip / Delete</strong> Node Row — <code>equipment/controller/machine/block-skip</code>, grown while
the snapshot reports a block-skip config</li>
<li><strong>Subprogram Folders</strong> Node Row — <code>equipment/controller/machine/subprograms</code>, grown while it
reports a subprogram-folder config</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Editor Row — <strong>Block Skip / Delete</strong> Panel
<ul>
<li>No-Runner Line — <em>&quot;No NC runner — load a project first.&quot;</em>, the branch's shared empty state</li>
<li>No-Config Line — <em>&quot;No block-skip config on the active runner.&quot;</em></li>
<li>Description Caption — <em>&quot;Enabled layers skip their <code>/n</code>-prefixed blocks (<code>/</code> alone = layer 1).&quot;</em></li>
<li>Layer CheckBox Column — nine dense boxes in one column
<ul>
<li><strong>Layer 1 (bare /)</strong> CheckBox</li>
<li><strong>Layer 2</strong> … <strong>Layer 9</strong> CheckBoxes</li>
</ul>
</li>
</ul>
</li>
<li>Editor Row — <strong>Subprogram Folders</strong> Panel
<ul>
<li>No-Runner Line — the same shared empty state</li>
<li>No-Config Line — <em>&quot;No subprogram-folder config on the active runner.&quot;</em></li>
<li><strong>Internal folder (M98)</strong> Field — outlined and dense, hinted <em>&ldquo;Relative to the host NC file's
folder; empty = that folder itself&rdquo;</em> — a hint the resolver contradicts, the anchor being the
project root</li>
<li><strong>External folder (M198)</strong> Field — outlined and dense, hinted <em>&ldquo;Fanuc external-storage calls;
empty = fall back to the internal folder&rdquo;</em></li>
</ul>
</li>
</ul>
<p>Every label above is a translated role string rather than a type name, so a locale change rewrites
what is read without touching an id. Both panels mount against one node and take nothing from it:
each serves a single tree id, so neither reads a role off the node's path.</p>
<h2 id="source-code-path">Source Code Path</h2>
<p>See <a class="xref" href="../../../index.html">HiNC App Anatomy</a> for git repository links.</p>
<h3 id="web-application">Web Application</h3>
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
<ul>
<li><code>wwwroot-src/src/components/controlTree/SoftNcBlockSkipPanel.vue</code> — the block-skip panel: the two
empty layers, the caption with its two code slots, the nine boxes and their layer-one label, and
the whole-set write with its rollback.</li>
<li><code>wwwroot-src/src/components/controlTree/SoftNcSubprogramPanel.vue</code> — the folder panel: the two
outlined fields, the blur and Enter bindings on both, the saved-snapshot guard that skips a
redundant write, and the paired rollback.</li>
<li><code>wwwroot-src/src/components/controlTree/SoftNcEmptyState.vue</code> — the shared no-runner line both
panels open with.</li>
<li><code>wwwroot-src/src/components/controlTree/softNcItemTypes.ts</code> — the two node ids, their labels and
label keys, the snapshot flag each is pushed behind, and the item types that bind them to their
panels.</li>
<li><code>wwwroot-src/src/api/softNcRunner.ts</code> — the two readers and their coercions, the layer-array
writer, the paired folder writer, and the snapshot fields the gates read.</li>
<li><code>wwwroot-src/src/api/http.ts</code> — the envelope reader that turns an unsuccessful body into the error
a panel's toast quotes.</li>
<li><code>wwwroot-src/src/composables/useSoftNcRunner.ts</code> — the shared snapshot both first empty layers
read, and its once-per-session install.</li>
<li><code>wwwroot-src/src/i18n/en/softNc.ts</code> — the two node labels, the block-skip caption and layer
labels, the four folder strings, the two empty-state lines and the error contexts.</li>
<li><code>Mech/SoftNcRunnerController.cs</code> — the REST surface: the two presence probes on the snapshot, the
block-skip read that enumerates the nine layers and the write that sets each one, the folder read
that substitutes an empty string for a null and the write that substitutes a null for a blank, the
brand switch whose remark names both of these among the runner-owned values it resets, and the
shared helper that answers a missing dependency with an unsuccessful body rather than an error
status.</li>
</ul>
<h3 id="hiapi-engine">HiAPI Engine</h3>
<ul>
<li><code>HiMech/NcParsers/Dependencys/IBlockSkipConfig.cs</code> — the block-skip contract: the per-layer query
and mutator, and the stated safe default when the dependency is absent.</li>
<li><code>HiMech/NcParsers/Dependencys/Generic/GenericBlockSkipConfig.cs</code> — the only implementer: the
layer-one default, the comma-separated stored form, the range filter repeated in its reader and
its setter, and the blank-equals-absent rule behind the cleared-set round trip.</li>
<li><code>HiMech/NcParsers/ParsingSyntaxs/BlockSkipSyntax.cs</code> — the prefix parser: the layer regular
expression, the always-recorded section, the body move that silences a block, and the message the
skip reports.</li>
<li><code>HiMech/NcParsers/Keywords/BlockSkip.cs</code> — the recorded section: symbol, layer, and the body that
is null exactly when the skip did not take effect.</li>
<li><code>HiMech/NcParsers/Dependencys/Generic/SubProgramFolderConfig.cs</code> — the two folders, the <code>NC</code>
default applied by the property itself, the null fallbacks, and the writer that omits an element
for a null.</li>
<li><code>HiMech/NcParsers/EvaluationSyntaxs/SubProgramCallSyntax.cs</code> — the Fanuc-family inliner: the
internal-versus-external choice, the repetition loop, the file-not-found error, and the absence of
any call-depth comparison.</li>
<li><code>HiMech/NcParsers/EvaluationSyntaxs/MacroFileResolver.cs</code> — the shared resolver: the Fanuc file
name chain, the absolute-versus-relative anchoring, and the directory-exists precondition.</li>
<li><code>HiMech/NcParsers/EvaluationSyntaxs/Fanuc/FanucMacroCallSyntax.cs</code>,
<code>HiMech/NcParsers/EvaluationSyntaxs/Fanuc/FanucModalMacroSyntax.cs</code> — the other two Fanuc readers
of the internal folder: the <code>G65</code> one-shot macro call, and the <code>G66</code> modal that resolves the same
file again on every motion block it fires on.</li>
<li><code>HiMech/NcParsers/EvaluationSyntaxs/Siemens/SiemensSubProgramCallSyntax.cs</code> — the name-call
inliner: its own file-pattern chain, its own depth constant and property, and the safe-skip that
answers an unresolved OEM cycle.</li>
<li><code>HiMech/NcParsers/EvaluationSyntaxs/Heidenhain/HeidenhainSubProgramCallSyntax.cs</code> — the klartext
call inliner: the <code>CALL PGM</code> lookup through the same internal folder, the second depth constant,
and the separate repeat ceiling.</li>
<li><code>HiMech/NcParsers/Keywords/CallStack.cs</code>,
<code>HiMech/NcParsers/EvaluationSyntaxs/SubProgramReturnSyntax.cs</code> — the frame each inliner stamps on
an inlined block, and the <code>M99</code> return that pops it.</li>
<li><code>HiMech/NcParsers/NcDiagnosticProgress.cs</code> — the category and severity behind each diagnostic id
named above.</li>
<li><code>HiMech/NcParsers/Dependencys/SystemWired/ProjectFolderDependency.cs</code> — the base directory a
relative folder is anchored against, and the host-wired provider behind it.</li>
<li><code>HiMech/MachiningProcs/MachiningSession.cs</code> — where that provider is wired to the project root
before a play.</li>
<li><code>HiMech/NcParsers/SoftNcRunner.cs</code> — the five brand presets, and which of them carries each of
these two dependencies.</li>
<li><code>HiMech/NcParsers/Syntaxs/FanucSyntaxUtil.cs</code>,
<code>HiMech/NcParsers/Syntaxs/SiemensSyntaxUtil.cs</code>,
<code>HiMech/NcParsers/Syntaxs/SyntecSyntaxUtil.cs</code>,
<code>HiMech/NcParsers/Syntaxs/MazakSyntaxUtil.cs</code>,
<code>HiMech/NcParsers/Syntaxs/HeidenhainSyntaxUtil.cs</code> — the four lists that carry the block-skip
parser and the one that does not, and which call syntax each preset runs.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="index.html">Machine and Controller Plane</a> — the plane these two leaves sit on, and the storage split that
decides which of its values a brand apply resets and which it leaves alone</li>
<li><a class="xref" href="../brand-matrix.html">Brand Matrix</a> — the two flags that grow these nodes, what each one probes,
and the brand sets they produce</li>
<li><a class="xref" href="../editing-contract.html">Editing Contract</a> — the commit, rollback and empty-state rules these panels
share with the branch, and the paired-field write recorded as one of its exceptions</li>
</ul>
</article>
<div class="contribution d-print-none">
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
</div>
</div>
</footer>
</body>
</html>