diff --git a/StgSharp.Common/HighPerformance/Memory/L4.Exceptions.cs b/StgSharp.Common/HighPerformance/Memory/L4.Exceptions.cs
index fba7b503..11a2430a 100644
--- a/StgSharp.Common/HighPerformance/Memory/L4.Exceptions.cs
+++ b/StgSharp.Common/HighPerformance/Memory/L4.Exceptions.cs
@@ -27,6 +27,8 @@
// -----------------------------------------------------------------------
namespace StgSharp.HighPerformance.Memory
{
+#pragma warning disable CA1032 // Implement standard exception constructors
+
public sealed class L4PredictUnregisteredException : Exception
{
@@ -48,4 +50,5 @@ namespace StgSharp.HighPerformance.Memory
: base($"L4 predictor with id {current} has already registered a cache line with base pointer {basePtr} and policy {policy}.") { }
}
+#pragma warning restore CA1032 // Implement standard exception constructors
}
diff --git a/StgSharp.Mathematics/Numeric/Runtime/MatrixParallelTask.cs b/StgSharp.Mathematics/Numeric/Runtime/MatrixParallelTask.cs
index 4e20d4aa..4986f948 100644
--- a/StgSharp.Mathematics/Numeric/Runtime/MatrixParallelTask.cs
+++ b/StgSharp.Mathematics/Numeric/Runtime/MatrixParallelTask.cs
@@ -26,6 +26,7 @@
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
using StgSharp.HighPerformance.Memory;
+using StgSharp.HighPerformance.ProcessorAbstraction;
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
@@ -43,39 +44,17 @@ namespace StgSharp.Mathematics.Numeric.Runtime
}
- [StructLayout(LayoutKind.Explicit)]
- internal unsafe ref struct MatrixTask
- {
-
- [FieldOffset(0)]public L4.Handle Line;
-
- }
-
- internal unsafe struct MatrixExecutionHandle { }
-
[StructLayout(LayoutKind.Explicit)]
internal unsafe struct MatrixParallelTask
{
- [FieldOffset(0)] public MatrixKernel* Mat1;
- [FieldOffset(8)] public MatrixKernel* Mat2;
- [FieldOffset(16)] public MatrixKernel* Mat3;
- ///
- /// Count of kernels to be calculated in a L4 cache line.
- ///
- [FieldOffset(28)] public int CacheLength;
- [FieldOffset(32)] public int CommonK;
- [FieldOffset(36)] public int CommonX;
- [FieldOffset(40)] public int CommonY;
- [FieldOffset(44)] public int VectorLength;
- [FieldOffset(48)] public MatrixElementType ElementType;
- [FieldOffset(52)] public MatrixIntrinsicHandle ComputeHandle;
- ///
- /// Beginning offset of first kernel in a L4 cache line.
- ///
- [FieldOffset(24)] public nuint Offset;
- [FieldOffset(56)] public nuint Vector;
- [FieldOffset(64)] public ScalarPacket Scalar;
+ [FieldOffset(0)] public L4.Handle Buffer0;
+ [FieldOffset(16)] public L4.Handle Buffer1;
+ [FieldOffset(32)] public L4.Handle Buffer2;
+ [FieldOffset(48)] public L4.Handle Buffer3;
+ [FieldOffset(64)] public M512 Profile;
+ [FieldOffset(120)] public MatrixElementType ElementType;
+ [FieldOffset(124)] public MatrixIntrinsicHandle ComputeHandle;
public MatrixParallelTask()
{
diff --git a/StgSharp.Native/README.md b/StgSharp.Native/README.md
index d9b4555d..d9b10776 100644
--- a/StgSharp.Native/README.md
+++ b/StgSharp.Native/README.md
@@ -1,10 +1,19 @@
-StgSharp.Native layout
+# StgSharp.Native
+
+## COMPILE
+
+Though this project do has a .vcxproj file,
+you can only edit but not compile in visul studio.
+Currently you can only compile this lib via Clang and cmake.
+
+## Code Layout
Conventions:
+
- src/ : project C sources and CMakeLists.txt calling add_library/add_executable
- include/ : public headers (if used)
- external/ : third-party libraries, each library lives in its own folder
- - /
+ - libname/
- head/ : header files for the library
- lib/ : static or shared lib files (or CMake build for that lib)
diff --git a/StgSharp.Native/sn-head/sn_intrinsic.context.x86.h b/StgSharp.Native/sn-head/sn_intrinsic.context.x86.h
index 53378d82..4f685adf 100644
--- a/StgSharp.Native/sn-head/sn_intrinsic.context.x86.h
+++ b/StgSharp.Native/sn-head/sn_intrinsic.context.x86.h
@@ -170,16 +170,32 @@ SN_MK_PROC_DECL_STD(double, 512, , fill);
SN_MK_PROC_DECL_STD(float, sse, , quality);
+SN_MK_PROC_DECL_STD(float, sse, , fma_pack);
+SN_MK_PROC_DECL_STD(float, avx, , fma_pack);
+SN_MK_PROC_DECL_STD(float, 512, , fma_pack);
+
SN_MK_PROC_DECL_STD(float, sse, , fma);
SN_MK_PROC_DECL_STD(float, avx, , fma);
SN_MK_PROC_DECL_STD(float, avx, _fma, fma);
SN_MK_PROC_DECL_STD(float, 512, , fma);
+SN_MK_PROC_DECL_STD(float, sse, , fma_unpack);
+SN_MK_PROC_DECL_STD(float, avx, , fma_unpack);
+SN_MK_PROC_DECL_STD(float, 512, , fma_unpack);
+
+SN_MK_PROC_DECL_STD(double, sse, , fma_pack);
+SN_MK_PROC_DECL_STD(double, avx, , fma_pack);
+SN_MK_PROC_DECL_STD(double, 512, , fma_pack);
+
SN_MK_PROC_DECL_STD(double, sse, , fma);
SN_MK_PROC_DECL_STD(double, avx, , fma);
SN_MK_PROC_DECL_STD(double, avx, _fma, fma);
SN_MK_PROC_DECL_STD(double, 512, , fma);
+SN_MK_PROC_DECL_STD(double, sse, , fma_unpack);
+SN_MK_PROC_DECL_STD(double, avx, , fma_unpack);
+SN_MK_PROC_DECL_STD(double, 512, , fma_unpack);
+
SN_SK_PROC_DECL_STD(float, avx, , add);
SN_SK_PROC_DECL_STD(float, 512, , add);
diff --git a/StgSharp.Native/sn-head/sn_intrinsic.h b/StgSharp.Native/sn-head/sn_intrinsic.h
index dafeb3a2..a9955490 100644
--- a/StgSharp.Native/sn-head/sn_intrinsic.h
+++ b/StgSharp.Native/sn-head/sn_intrinsic.h
@@ -46,9 +46,9 @@
#define zero_vec
#define zero_vec_256
-#define ALIGN(simdVec)
-#define ALIGN256(simdVec)
-#define ALIGN512(simdVec)
+#define ALIGN(simdVec)
+#define ALIGN256(simdVec)
+#define ALIGN512(simdVec)
#endif
@@ -79,6 +79,27 @@ typedef struct sn_L4_cache_head {
uint64_t reverse_mask_2;
} sn_L4_cache_head;
+typedef struct sn_L4_handle {
+ void *ptr;
+ sn_L4_cache_head head;
+} sn_L4_handle;
+
+typedef struct matrix_task_pack {
+ sn_L4_handle buffer_0;
+ sn_L4_handle buffer_1;
+ sn_L4_handle buffer_2;
+ sn_L4_handle buffer_3;
+ uint64_t reverse_0;
+ uint64_t reverse_1;
+ uint64_t reverse_2;
+ uint64_t reverse_3;
+ uint64_t reverse_4;
+ uint64_t reverse_5;
+ uint64_t reverse_6;
+ uint64_t reverse_7;
+
+} matrix_task_pack;
+
typedef struct matrix_task {
void *mat_0;
void *mat_1;
@@ -95,7 +116,7 @@ typedef struct matrix_task {
scalar_pack padding;
} matrix_task;
-#define MAT_TASK(T) matrix_task
+#define MAT_TASK(T) matrix_task_pack
#if defined(__cplusplus)
static_assert(sizeof(matrix_task) == 128, "matrix_parallel_task_package size mismatch");
diff --git a/StgSharp.Native/sn-head/sn_intrinsic.std.h b/StgSharp.Native/sn-head/sn_intrinsic.std.h
index 3dbab2f7..7d5f5ac0 100644
--- a/StgSharp.Native/sn-head/sn_intrinsic.std.h
+++ b/StgSharp.Native/sn-head/sn_intrinsic.std.h
@@ -10,6 +10,7 @@
#define SN_STD_TARGET_ATTR(T_arch, T_feature) SN_STD_TARGET_ATTR_IMPL(T_arch, T_feature)
+#pragma region mk_proc attributes
#define MK_PROC_NAME_STD(T_type, T_arch, T_feature, T_op) \
T_type##_multi_kernel_proc_##T_op##_##T_arch##_##T_feature
#define GET_MK_PROC_STD(T_type, T_arch, T_feature, T_op) \
@@ -18,6 +19,9 @@
#define SN_MK_PROC_DECL_STD(T_type, T_arch, T_feature, T_op) \
INTERNAL NOINLINE SN_STD_TARGET_ATTR(T_arch, T_feature) void SN_DECL MK_PROC_NAME_STD( \
T_type, T_arch, T_feature, T_op)(MAT_TASK(T_type) const *task)
+#pragma endregion
+
+#pragma region sk_proc attributes
#define SK_PROC_NAME_STD(T_type, T_arch, T_feature, T_op) \
T_type##_single_kernel_proc_##T_op##_##T_arch##_##T_feature
#define GET_SK_PROC_STD(T_type, T_arch, T_feature, T_op) \
@@ -27,6 +31,7 @@
T_type, T_arch, T_feature, \
T_op)(MAT_KERNEL(T_type) const *left, MAT_KERNEL(T_type) const *right, \
MAT_KERNEL(T_type) *restrict ans, uint64_t scalar)
+#pragma endregion
#define _SN_STD__PROBE_0 0
#define _SN_STD__PROBE_1 1
@@ -42,27 +47,27 @@
#define _SN_MATPROC_ANS_SCALAR 1
#define _SN_MK_EXPAND_RIGHT_ANS \
- SN_MAT_KERNEL_LOCAL const *right = (SN_MAT_KERNEL_LOCAL const *)task->mat_1; \
- SN_MAT_KERNEL_LOCAL *restrict ans = (SN_MAT_KERNEL_LOCAL *)task->mat_2;
+ SN_MAT_KERNEL_LOCAL const *right = (SN_MAT_KERNEL_LOCAL const *)task->buffer_1.ptr; \
+ SN_MAT_KERNEL_LOCAL *restrict ans = (SN_MAT_KERNEL_LOCAL *)task->buffer_2.ptr;
#define _SN_MK_EXPAND_LEFT_RIGHT_ANS \
- SN_MAT_KERNEL_LOCAL const *left = (SN_MAT_KERNEL_LOCAL const *)task->mat_0; \
- SN_MAT_KERNEL_LOCAL const *right = (SN_MAT_KERNEL_LOCAL const *)task->mat_1; \
- SN_MAT_KERNEL_LOCAL *restrict ans = (SN_MAT_KERNEL_LOCAL *)task->mat_2;
+ SN_MAT_KERNEL_LOCAL const *left = (SN_MAT_KERNEL_LOCAL const *)task->buffer_0.ptr; \
+ SN_MAT_KERNEL_LOCAL const *right = (SN_MAT_KERNEL_LOCAL const *)task->buffer_1.ptr; \
+ SN_MAT_KERNEL_LOCAL *restrict ans = (SN_MAT_KERNEL_LOCAL *)task->buffer_2.ptr;
#define _SN_MK_EXPAND_RIGHT_ANS_SCALAR \
- SN_MAT_KERNEL_LOCAL const *right = (SN_MAT_KERNEL_LOCAL const *)task->mat_1; \
- SN_MAT_KERNEL_LOCAL *restrict ans = (SN_MAT_KERNEL_LOCAL *)task->mat_2; \
+ SN_MAT_KERNEL_LOCAL const *right = (SN_MAT_KERNEL_LOCAL const *)task->buffer_1.ptr; \
+ SN_MAT_KERNEL_LOCAL *restrict ans = (SN_MAT_KERNEL_LOCAL *)task->buffer_2.ptr; \
scalar_pack *restrict scalar = (scalar_pack *restrict)task->scalar;
#define _SN_MK_EXPAND_LEFT_RIGHT_ANS_SCALAR \
- SN_MAT_KERNEL_LOCAL const *left = (SN_MAT_KERNEL_LOCAL const *)task->mat_0; \
- SN_MAT_KERNEL_LOCAL const *right = (SN_MAT_KERNEL_LOCAL const *)task->mat_1; \
- SN_MAT_KERNEL_LOCAL *restrict ans = (SN_MAT_KERNEL_LOCAL *)task->mat_2; \
+ SN_MAT_KERNEL_LOCAL const *left = (SN_MAT_KERNEL_LOCAL const *)task->buffer_0.ptr; \
+ SN_MAT_KERNEL_LOCAL const *right = (SN_MAT_KERNEL_LOCAL const *)task->buffer_1.ptr; \
+ SN_MAT_KERNEL_LOCAL *restrict ans = (SN_MAT_KERNEL_LOCAL *)task->buffer_2.ptr; \
scalar_pack *restrict scalar = (scalar_pack *restrict)task->scalar;
#define _SN_MK_EXPAND_ANS_SCALAR \
- SN_MAT_KERNEL_LOCAL *restrict ans = (SN_MAT_KERNEL_LOCAL *)task->mat_2; \
+ SN_MAT_KERNEL_LOCAL *restrict ans = (SN_MAT_KERNEL_LOCAL *)task->buffer_2.ptr; \
scalar_pack *restrict scalar = (scalar_pack *restrict)&(task->padding);
#define _SN_PARAM_STYLE(T) _SN_MATPROC_##T
@@ -90,6 +95,7 @@
size_t common_x = UNSAFE_AS(size_t, task->common_x); \
size_t common_y = UNSAFE_AS(size_t, task->common_y); \
size_t common_z = UNSAFE_AS(size_t, task->common_z);
+
#define _MK_MKPROC_EXPAND_INDEX_TILE \
size_t x = UNSAFE_AS(size_t, task->x); \
size_t y = UNSAFE_AS(size_t, task->y); \
@@ -104,7 +110,7 @@
#define __mk_param_std(mem, param, T) \
typedef MAT_KERNEL(T) SN_MAT_KERNEL_LOCAL; \
- matrix_task const *_ = (_SN_PARAM_STYLE(param), (_SN_MEM_LAYOUT(mem)), task); \
+ matrix_task_pack const *_ = (_SN_PARAM_STYLE(param), (_SN_MEM_LAYOUT(mem)), task); \
_SN_MK_EXPAND_PARAM(param); \
_SN_MK_EXPAND_MEM(mem)
diff --git a/StgSharp.Native/sn-src/mk.fma.x86.c b/StgSharp.Native/sn-src/mk.fma.x86.c
index f399e746..fd8a88f6 100644
--- a/StgSharp.Native/sn-src/mk.fma.x86.c
+++ b/StgSharp.Native/sn-src/mk.fma.x86.c
@@ -7,12 +7,35 @@
#include "sn_intrinsic.std.h"
#include "sn_intrinsic.context.x86.h"
+#include
+
#define _FMA_SELECT(i) _MM_SHUFFLE(i, i, i, i)
#define GET_INDEX(col_len, x, y) (col_len * x + y)
// float
+SN_MK_PROC_DECL_STD(float, sse, , fma_pack)
+{
+ __mk_param_std(TILE, RIGHT_ANS, float);
+
+ memcpy(ans, right, sizeof(MAT_KERNEL(float)) * common_y * common_z);
+}
+
+SN_MK_PROC_DECL_STD(float, avx, , fma_pack)
+{
+ __mk_param_std(TILE, RIGHT_ANS, float);
+
+ memcpy(ans, right, sizeof(MAT_KERNEL(float)) * common_y * common_z);
+}
+
+SN_MK_PROC_DECL_STD(float, 512, , fma_pack)
+{
+ __mk_param_std(TILE, RIGHT_ANS, float);
+
+ memcpy(ans, right, sizeof(MAT_KERNEL(float)) * common_y * common_z);
+}
+
SN_MK_PROC_DECL_STD(float, sse, , fma)
{
__mk_param_std(TILE, LEFT_RIGHT_ANS, float);
diff --git a/future/ngra-as-language.md b/future/ngra-as-language.md
new file mode 100644
index 00000000..a77f4c9d
--- /dev/null
+++ b/future/ngra-as-language.md
@@ -0,0 +1,182 @@
+# NGRA 作为计算语言:设计讨论笔记(草案)
+
+> 本文是一次理论讨论的结论沉淀,**不是规范**。
+> 主业仍是「通用序列模式分析器」(用于解释/编译器前端、日志分析)。
+> 「把 NGRA 扩展成通用语言」是副产品,优先级靠后。
+> 但其中若干结论会**反过来影响主业的语法设计**,已在文末标出。
+
+---
+
+## 0. 一句话总览
+
+NGRA 在理论上可以是图灵完备的通用语言,但它的最优生态位不是通用语言,
+而是**可嵌入宿主的、面向任意可分类线性序列的改写/分析处理器**(awk 之于文本,NGRA 之于任意序列)。
+作为语言时,它是**胶水语言 / 教学语言**,不适合做大型通用系统。
+
+---
+
+## 1. 计算能力:图灵完备,但靠「写回反馈回路」而非随机访问
+
+- 「正则 + 序列改写」这条路在理论上图灵完备(参照 Markov 算法、Thue、sed、XSLT)。
+- 决定生死的不是「能不能随机读写」,而是**有没有「写回 → 重新匹配」的反馈回路**:
+ - 单向「输入序列 → 输出序列」= 有界转换器(transducer),不图灵完备。对应 `scanning`。
+ - 存在「工作序列可读可写、写完再进入下一轮匹配直到不动点」= Markov/Post 改写系统,图灵完备。对应 `stepping` + `Feed/Step/Flush`。
+- 「不能随机读写」**不影响图灵完备性**(图灵机本身只有单向带),只影响**渐进复杂度与人体工程学**:模拟随机访问/堆是 O(n) 扫描重写,写算法反人类。
+- 结论:NGRA 的弱点不是「能不能算」,而是「算法类、随机访问类负载写起来难受」。
+
+---
+
+## 2. 计算模型:reduction(收敛),不是 evaluation(求值)
+
+- 数学/逻辑是**标准库问题**,不是语言核心问题:给基本型提供 `Add` 等方法 + 算符重载即可。
+- 算符重载 = 一条改写规则;`return` = **把匹配到的 redex 就地替换成结果**。
+ - 局部运算(`a+b`、向量相加)写起来很干净:消费 N 个元素 → 吐回 1 个元素。
+- 别扭之处不在单步,而在**嵌套与组合**:
+ 1. 中间结果是「显式存在于序列里的真实元素」,会污染序列,需打 tag/island 隔离;
+ 2. 求值顺序要靠规则匹配优先级 + 边界自己控制(等于手写优先级/结合性);
+ 3. 没有「可反复引用的变量」——值在序列里只有一份,用一次即被消耗,复用需显式拷贝(线性/一次性,类似 linear logic)。
+- 一句话:**NGRA 的「算」是 reduce to normal form,不是 evaluate。**
+ - 能自然表达成「局部模式 → 局部替换 → 整体收敛」的计算,写起来甚至比命令式干净。
+ - 依赖「可变变量多次读写 / 深层嵌套 / 随机寻址结构」的计算会持续别扭,且是结构性的。
+
+---
+
+## 3. 双空间模型(**影响主业**)
+
+NGRA 有两个语义空间,必须分开:
+
+| 空间 | 单元 | 受谁影响 | 用途 |
+| --- | --- | --- | --- |
+| **类型/布局空间** | 恒为**字节** | 与 `#input` 无关 | 类型声明、字段偏移、size |
+| **算术/解析空间** | 由 `#input` 决定(string/byte/bit/event…) | `#input` | 提取函数、表达式计算 |
+
+- `<_:12>` 中的 12 永远是**字节**。
+- `#input` 只管算术/解析空间可用哪些内联函数,**不影响类型定义**。
+- 代价:**位域(sub-byte 字段)不在类型声明层**,只能在解析层用 `#input bit` + `Bit(n)` 处理。
+
+---
+
+## 4. 类型系统:定长闭包 + 被动布局
+
+### 4.1 类型声明 = `reinterpret_cast`,不是匹配
+- 类型声明**不匹配/不判定**任何东西,它只贡献两样:`size(T)` 和「字段 → 偏移」表。
+- 「读一段字节并视作 T」永远成立(零成本重解释),成员访问 = `base + 常量偏移` 读一个寄存器基本型。
+- 推论:**裸 union 在类型空间没有「消歧」问题**——读哪个视图由访问方决定,无 tag、纯偏移(与 C union 同)。
+
+### 4.2 struct = 乘积类型(天作之合)
+- 顺序拼接 `` 在序列上就是连接 = 乘积,**本身就是 struct**。
+- 优势:字节布局显式无歧义(默认 packed,无隐式 padding);ABI padding 需显式写 `<_:N>`;字节序需显式声明。
+- bitfield:在类型空间表达不了(见 §3),归解析层。
+
+### 4.3 union / overlay = 和类型(`|`)
+- 类型空间的 `|`:作用域 = 当前 `()` 层,向前向后直到 `|` 或 `(`/`)`;中间连续字段按 struct 排列。
+- 规则要点:
+ - `|` 是 **flat n-ary sum**(可交换、可结合,扁平候选集);
+ - **禁止空分支**(尾随 `|` 静默变可选是隐形 bug);
+ - 分支不等长时:**`size = max(分支)`,开头对齐**(同 C union),短分支尾部隐含 padding;
+ - **读 union 时游标恒前进 `max` 字节**(由类型 size 决定,不由匹配到的分支决定)——这是静态偏移得以保住的关键。
+- **赠品:overlay / FieldOffset = `|`(同基址重叠)+ `<_:N>`(精确偏移)**,不需要负游标或绝对偏移锚点:
+
+```ngra
+define Overlay =
+ # x@0, y@4
+ | <_:4> ; # z@4,与 y 同址重叠
+```
+
+- 「裸 union 读消歧」在类型空间是**伪问题**:`|` 默认产出**多视图和类型(multi-view sum)**,所有成立视图同时有效;需要「排他单一分支」时用**判别字段(tagged)**,判定逻辑属于**使用方/规则空间**,不进类型声明。
+
+### 4.4 `<_:N>` 与 `int[0]`(一对对偶)
+- `<_:N>`:**匿名、占 N 字节、不产字段**的纯偏移推进(padding)。只前进,保持游标单调。
+ - 单位:字节(见 §3);读 = skip 不校验;写 = 填零;参与 span/diagnostics 但不进 AST(复用 `` 哲学)。
+- `int[0]`:**具名、占 0 字节、产一个零元素字段**的偏移锚点。
+ - 其「值」= 长度 0 的空序列视图(**不是 null、不是 0**,避免与缺失字段 / 具体 0 值撞语义);
+ - 与 `int[n]` 在 n=0 处语义连续;越界访问(`buf[0]`)= **诊断错误**(不学 C 的 UB)。
+
+### 4.5 定长闭包是地基(**影响主业**)
+- 类型**必须**声明为确定性长度:允许 `int[0]`,**禁止 `int[]`**。
+- `int[]` 的毒性是**传染**:一个变长字段令外层 size 与后续偏移全部变运行期值,沿嵌套向外塌方。
+- 禁 `int[]` = **斩断传染链,保住整棵类型树的定长闭包**。
+- 「全定长」是 §3、§4 一切结论(静态偏移、reinterpret、overlay 的 `max` 常量)的**公共前提/地基**,不是「模仿 C99」。
+- **变长被驱逐到规则/解析空间**(`{@count=$len}` 这类带求值的顺序读取),**绝不回流进 `define`**。两个空间之间这道墙就是靠「禁 `int[]`」砌起来的。
+
+---
+
+## 5. 变长数据 / 字符串:靠 slice(fat pointer)
+
+- 「定长不兼容字符串」不是缺陷,是缺了 C 早有的间接层:**`char* + len` = fat pointer / slice**。
+- 解法**不是放松定长闭包**,而是新增一个**定长的序列引用类型**:
+
+```ngra
+define Slice = ; # 自身定长!只存「从哪开始、多长」
+```
+
+- slice 把变长内容留在纸带 / 规则空间,类型空间只持有定长把手 → **地基不动,字符串进来**。
+- slice 就是**正则捕获组的推广**(捕获组 = 输入串上的 (start,len),slice = 纸带上的 (ptr,len))。
+- `ptr` 就是**纸带指针**本身(现成的),**不引入 arena / trust domain**(见 §7)。
+
+---
+
+## 6. 函数与调用约定(通用语言化部分,**可挂起**)
+
+工作在纸带上的语言不能用传统 `return`,模型如下:
+
+1. **默认 = 纯 reducer**:调用点 `p` 记下,函数跑完游标复位回 `p`,结果落在终止时游标位置;调用区间 `` 被结果**替换**(消费 redex,不堆垃圾)。
+2. **不复位模式 = consumer / 流推进**:游标停在 `p'`,返回锚点 = 终止时游标位置(复位与否只决定该游标在哪)。
+3. **insert vs overwrite 是正交轴**:
+ - overwrite 不改长度,O(1),不漂移偏移(对静态布局友好);
+ - insert 撑开纸带,O(尾部长度),且令后续**纸带绝对位置**漂移;
+ - reduction 真正要的是「**替换 redex**」(insert/overwrite 的统一)。
+4. **静态偏移在 insert 下存活的前提**:偏移常量只在**类型对象内部**成立;**纸带绝对位置是易失的、不可长期持有**(只能持有「相对游标」或「对象基址内偏移」)。
+5. **双纸带**:公共纸带 + 函数私有纸带(随函数销毁)= 双带图灵机 = 天然栈帧,配复位 → 干净递归。
+6. **`emit` = 序列语言版 return**:把私有纸带上的值**显式拷贝**到公共纸带的返回锚点;可多次调用 → **能返回整个序列**(比传统 return 强);定长返回类型下 `emit` 累计须正好凑满 `size(T)`。
+7. **传参双通道**:
+ - 标量 / 捕获 `$name` / `@count` 走**上下文通道**(VM 绑定,不占纸带寻址);
+ - 序列 / 大对象 copy 到**私有纸带** `0x00` 起,函数读完游标前移。
+8. **悬垂引用对策**:slice **只能指向公共纸带**,私有纸带数据要外传**必须 `emit` 拷贝**。
+ → 「匹配字符串后要序列拷贝」是**显式、必然、无悬垂**的操作(诚实,且与「越界判错」的安全取向一致)。
+
+---
+
+## 7. 内存模型与自我定位
+
+- **不引入 arena / trust domain**:这是唯一不背离「源自正则」的选择。
+ - 正则捕获组从无「所有权 / 回收」概念;arena 会引入正则世界里**不存在**的问题。
+- 由此,NGRA 只有两种内存:**纸带(线性、易失)** 与 **类型对象(定长、内联)**。
+- 缺的是第三种:**生命周期独立于控制流的、可长期持有的动态堆对象**。
+ - 准确说法:NGRA **没有「独立生命周期堆对象」这个概念本身**(而非「有但不安全」)。
+ - 这让它**结构上是流处理器,而非系统构建器** → 注定是胶水 / 教学语言。
+- 生态位(体面且有独占性,与 awk/jq/sed/XSLT 同列,但更泛化):
+ > **可嵌入宿主语言的、面向任意可分类线性序列的改写/分析处理器生成框架。**
+- 「教学语言」是真资产:NGRA 把**纸带、栈帧、fat pointer、求值收敛、内存布局**全暴露成第一类语法——
+ 「不适合生产」与「适合教学」是同一个原因:**没有隐藏的魔法**。
+
+---
+
+## 8. 对主业(序列分析器)的直接影响 —— 现在就要认的三条
+
+1. **双空间分离(§3)**:定义 `.ngra` 类型语法前,先认「类型空间字节寻址 / 算术空间随 `#input`」这条线。
+2. **定长闭包 + 变长隔离进规则空间(§4.5)**:直接决定 `define` 与规则体的语法边界,是主业地基。
+3. **`{...}` 记号超载问题**:当前 `{...}` 同时承担
+ - 属性谓词 `{value="if"}`、
+ - 泛型参数 `Array{T:int}`、
+ - 计数约束 `{?=8}`。
+ 三者挤在同一对花括号里,词法上几乎无法区分。**建议早定方案**,例如:
+ - 计数沿用 `@count`:`{@count=8}`;
+ - 泛型改用尖/方括号:`Array` 或 `Array[T:int]`。
+
+其余偏计算的(§6 的 `emit`、双纸带、reduction、算符重载、数学库)属于语言化,**可等主业稳定后再展开**。
+
+---
+
+## 9. 主业 vs 语言化:清单
+
+**属于主业、现在就该落地:**
+- token/序列提取(`Regex`/`Byte`/`Bit`/`Char` + `Regex(expr, group)` 消费但不产出)
+- `<...>` 规则调用、`` 胶水、捕获 `(?:...)` / `$name`
+- 岛屿分层压缩 + `scanning`/`stepping` 双模式
+- 定长类型声明(struct / overlay-union / `<_:N>` / `int[0]`)——二进制日志、协议解析刚需
+- slice 作为「匹配结果的引用」——捕获组的自然形态
+
+**属于语言化、可挂起:**
+- 函数 / `emit` / 双纸带调用约定 / reduction 求值
+- 算符重载、数学标准库、写回反馈回路