# TSL 词法结构与编译选项

这一篇吸收语法手册里“词法层”和“编译期开关”相关内容：标识符、注释、条件编译和依赖编译选项。

## 本篇职责

<!-- section-id: syntax-15-001 -->

回答“TSL 的词法层规则和编译期开关有哪些”：标识符与大小写、注释形态、保留字清单，以及 `{$...}` 编译开关的书写位置和作用范围。

## 核心规则

<!-- section-id: syntax-15-002 -->

- 标识符大小写无关；下划线可出现在标识符中。
- `//` 是行注释；首行 `#!` 可作为 CGI 风格注释；`{ ... }` 与 `(* ... *)` 是块注释。两种块注释可以交错嵌套，同类块注释不能嵌套。
- 条件编译指令使用 `{$define}`、`{$undef}`、`{$ifdef}`、`{$ifndef}`、`{$else}`、`{$endif}`。
- 条件编译只编译命中的分支；未命中的分支不参与脚本编译。
- `{$explicit+}` 开启后，后续变量必须先用 `var` 声明；`{$explicit-}` 可以在同一源文件里重新关闭这个要求。
- `{$varByRef-}` 与 `{$varByRef+}` 会切换“未修饰形参”的默认传递方式，细节见 [05_functions_and_calls.md](05_functions_and_calls.md)。
- 保留字/关键字大小写无关，不要拿来当普通变量、函数或类名；例如 `params` 是函数参数访问关键字，不适合作为普通变量名。
- `{$i}` / `{$include}` 不作为本页可生成的默认能力。
- `{$dependency ...}` 这类编辑器辅助编译选项不作为本页正文事实。

## 保留字/关键字速查

<!-- section-id: syntax-15-003 -->

<!-- tags: 关键字列表, 保留字, 哪些名字不能用 -->

TSL 关键字大小写无关；本表统一按文档推荐写法展示。生成代码时不要把这些名称用作普通标识符。

<!-- prettier-ignore-start -->
| 分类 | 关键字 / 保留名 | 生成规则 |
| --- | --- | --- |
| 程序与函数结构 | `program`、`function`、`procedure`、`begin`、`end`、`return`、`exit` | 默认写函数时使用 `function`；`procedure` 只在用户明确要求时使用。 |
| 控制流 | `if`、`then`、`else`、`case`、`of`、`for`、`to`、`downto`、`step`、`while`、`do`、`repeat`、`until`、`break`、`continue`、`goto`、`label` | 具体语句形态见 [07_control_flow.md](07_control_flow.md)。 |
| 异常控制 | `try`、`except`、`finally`、`raise`、`exceptObject` | 异常语法见 [07_control_flow.md](07_control_flow.md)。 |
| 值与容器 | `nil`、`true`、`false`、`nan`、`inf`、`array` | 字面量与数组基础见 [03_values_and_literals.md](03_values_and_literals.md) 和 [11_matrix_and_collections.md](11_matrix_and_collections.md)。 |
| 运算关键字 | `and`、`or`、`not`、`in`、`sqlin`、`like`、`is`、`div`、`mod`、`shl`、`shr`、`rol`、`ror` | 运算符规则见 [06_expressions_and_operators.md](06_expressions_and_operators.md)。 |
| 参数访问 | `params`、`paramCount`、`realParamCount`、`var`、`out`、`const` | 普通参数优先写具名形参；`params` / `paramCount` / `realParamCount` 只用于变参或参数个数判断。 |
| 运行时上下文 | `sysParams`、`system`、`debugReturn`、`debugRunEnv`、`debugRunEnvDo`、`echo`、`global`、`static`、`thisFunction`、`_myMem_`、`_maxMem_`、`__line__`、`__stack_frame` | 运行时系统参数见 [10_runtime_context_and_with.md](10_runtime_context_and_with.md)；调试相关事实见 [14_debug_and_profiler.md](14_debug_and_profiler.md)。 |
| LIKE 精度 | `likeEps`、`likeEpsRate` | 只在需要调整 `like` 数值近似判断阈值时使用。 |
| 类与对象 | `type`、`class`、`new`、`findClass`、`findFunction`、`fackClass`、`property`、`self`、`virtual`、`override`、`overload`、`Inherited`、`protected`、`public`、`private`、`published`、`static` | 类声明、对象创建和成员规则见 [08_objects_and_classes.md](08_objects_and_classes.md)；`Inherited;` / `Inherited MethodName(...)` 是祖先类调用写法，同见该页。 |
| 外部调用约定 | `external`、`cdecl`、`pascal`、`stdcall`、`safecall`、`fastcall`、`register` | 外部调用细节见 [17_external_calls_and_threads.md](17_external_calls_and_threads.md)。 |
| 客户端远程调用与权限 | `rdo`、`rdo2`、`sudo`、`setUid` | `rdo` / `rdo2` 见 [24_client_remote_calls.md](24_client_remote_calls.md)；它们不能建模成普通函数。 |
| TS-SQL 查询 | `select`、`vselect`、`sselect`、`mselect`、`distinct`、`selectOpt`、`dRange`、`as`、`from`、`marketTable`、`infoTable`、`tradeTable`、`sqlTable`、`hugeSqlTable`、`keepNull`、`dateKey`、`of`、`order`、`by`、`where`、`desc`、`asc`、`group`、`having` | 查询语法见 [13_ts_sql.md](13_ts_sql.md)。 |
| TS-SQL 聚合与上下文 | `checksumOf`、`countOf`、`sumOf`、`maxOf`、`stdevOf`、`varOf`、`totalVarOf`、`normOf`、`medianOf`、`aveDevOf`、`geoMeanOf`、`skewOf`、`kurtosisOf`、`skew2Of`、`kurtosis2Of`、`largeOf`、`percentileOf`、`quartileOf`、`trimMeanOf`、`avgOf`、`minOf`、`aggOf`、`stdevpOf`、`varpOf`、`modeOf`、`devSqOf`、`harMeanOf`、`checksum_aggOf`、`smallOf`、`percentRankOf`、`rankOf`、`frequencyOf`、`productOf`、`refOf`、`refsOf`、`aggValue`、`thisGroup`、`thisRow`、`thisRowIndex`、`thisOrder` | 这些名称只在 TS-SQL 语境中生成。 |
| TS-SQL 写入 | `insert`、`insertFields`、`values`、`update`、`set`、`delete`、`deleteOpt`、`fetchFirst`、`fetchNext` | 写回/变更型查询只按 TS-SQL 专题页生成。 |
| 系统保留未使用 | `exports`、`dispInterface`、`library`、`asm`、`record`、`resourceString`、`threadVar`、`constructor`、`destructor`、`inline`、`packed`、`abstract` | 这些名称被系统保留，不作为普通标识符使用，也不作为可写语法模板。 |
<!-- prettier-ignore-end -->

## 可直接照写示例

<!-- section-id: syntax-15-004 -->

### 标识符、注释与条件编译

<!-- section-id: syntax-15-005 -->

<!-- tags: 注释怎么写, 大小写敏感吗, 变量命名, 下划线, 嵌套注释, 块注释 -->

大小写无关与下划线标识符：

代码块身份：可直接照写示例

```tsl
my_var := 7;
writeLn(my_var);
writeLn(MY_VAR);
```

结果说明：

- 依次输出 `7`、`7`
- 说明标识符大小写无关，下划线可以出现在标识符中

代码块身份：输出片段

```text
7
7
```

注释与条件编译：

代码块身份：可直接照写示例

```tsl
#! shebang style comment

a := 1; // line comment
{
    (* nested comment marker *)
}
writeLn(a);
{$define FLAG}
{$ifdef FLAG}
writeLn(10);
{$else}
writeLn(20);
{$endif}
{$undef FLAG}
{$ifndef FLAG}
writeLn(30);
{$else}
writeLn(40);
{$endif}
```

结果说明：

- 依次输出 `1`、`10`、`30`
- 说明首行 `#!`、`//`、`{ ... }`、`(* ... *)` 都属于文档明确注释形态
- 说明外层 `{ ... }` 可以包含 `(* ... *)`；反向交错也可用
- 同类 `{ { ... } }` 或 `(* (* ... *) *)` 不构成嵌套注释，会产生语法错误
- 说明 `define` / `undef` / `ifdef` / `ifndef` / `else` / `endif` 这一组条件编译指令可以正常生效

### 显式变量声明开关

<!-- section-id: syntax-15-006 -->

<!-- tags: 强制声明变量, explicit, 必须先 var -->

`{$explicit+}` 的文档明确形态：

代码块身份：可直接照写示例

```tsl
{$explicit+}
var a;
a := 1;
writeLn(a);
```

结果说明：

- 输出 `1`
- 说明 `{$explicit+}` 开启后，配合 `var` 声明可以正常通过

`{$explicit-}` 可以在同一源文件里关掉显式声明要求：

代码块身份：可直接照写示例

```tsl
{$explicit+}
var a;
a := 1;
{$explicit-}
b := 2;
writeLn(a + b);
```

结果说明：

- 输出 `3`
- 说明 `{$explicit-}` 会从出现位置开始取消“变量必须先声明”的限制

### 条件编译分支边界

<!-- section-id: syntax-15-007 -->

<!-- tags: 条件编译, 未命中分支, ifdef 不编译 -->

条件编译不会去编译未命中的坏代码分支：

代码块身份：可直接照写示例

```tsl
{$undef NEVER}
{$ifdef NEVER}
MissingFunction(
{$else}
writeLn(1);
{$endif}
```

结果说明：

- 输出 `1`
- 说明未命中的条件编译分支不会参与脚本编译

### `{$CompileOption}` 编译选项

<!-- section-id: syntax-15-008 -->

<!-- tags: 编译开关, 编译器选项, 改默认行为 -->

TSL 的编译选项使用 `{$Option+}` / `{$Option-}` 一类指令改变后续源码的编译方式。本页只拥有已经分别验证并有专题规则的选项：

- `{$explicit+}` / `{$explicit-}`：切换变量是否必须预先声明，见上一节
- `{$varByRef+}` / `{$varByRef-}`：切换未修饰形参的默认传递方式，见下一节
- `{$ifdef ...}` 等条件编译指令：控制分支是否参与编译

`optimize`、`buffermode`、`DebugInfo` 等没有在本 skill 中形成可验证语义，不作为正式可生成选项。不要用“脚本仍能输出结果”来证明某个未知编译选项确实生效。

### 参数默认传递开关

<!-- section-id: syntax-15-009 -->

<!-- tags: 全局改传参方式, varByRef 开关, 默认按值还是按引用 -->

`{$varByRef-}` 与 `{$varByRef+}`：

代码块身份：可直接照写示例

```tsl
x := 1;
TouchDefault(x);
writeLn(x);
y := 1;
TouchValue(y);
writeLn(y);
z := 1;
TouchForcedVar(z);
writeLn(z);
r := 1;
TouchRestored(r);
writeLn(r);

function TouchDefault(value);
begin
    value := 9;
end;
{$varByRef-}
function TouchValue(value);
begin
    value := 8;
end;
function TouchForcedVar(var value);
begin
    value := 7;
end;
{$varByRef+}
function TouchRestored(value);
begin
    value := 6;
end;
```

结果说明：

- 依次输出 `9`、`1`、`7`、`6`
- 说明默认模式下，未修饰参数仍会写回调用方
- 说明 `{$varByRef-}` 下，未修饰参数会改成按值传递
- 说明 `var` 形参在 `{$varByRef-}` 下仍保持引用语义
- 也说明 `{$varByRef+}` 可以把默认语义重新切回可写回模式

## 禁止项

<!-- section-id: syntax-15-010 -->

- 不要在 `{$explicit+}` 后继续直接使用未声明变量。
- 不要同类嵌套 `{ ... }` 或 `(* ... *)` 块注释；需要嵌套时交错使用两种定界符。
- 不要生成未在本页形成可验证规则的 `{$CompileOption optimize=...}`、`buffermode` 或 `DebugInfo`。
- 不要把 `{$i ...}` / `{$include ...}` 包含文件写法当成可用能力。
- 不要把 `反例 / 不可照写` 代码块复制进正向示例。

代码块身份：反例 / 不可照写

```text
{$explicit+}
a := 1;
```

上面这种写法不作为可写事实；`{$explicit+}` 后必须先声明再使用变量。

代码块身份：反例 / 不可照写

```text
writeLn(1);

{$i "common.inc"}
```

上面这种包含文件写法不作为本页可生成的默认能力。
