152 lines
5.7 KiB
Markdown
152 lines
5.7 KiB
Markdown
# STCompiler 使用说明
|
||
|
||
把 ST 工程(`project.toml` + 若干 `.st`)编译成单一映像 `.stb`。执行由 `BytecodeExecutor`(12.9/12.10 实现)负责。
|
||
|
||
## 构建
|
||
|
||
```bash
|
||
cmake --preset gcc-debug # 配置
|
||
cmake --build --preset gcc-debug # 编译
|
||
ctest --test-dir build/gcc-debug # 测试(当前 9 个用例)
|
||
```
|
||
|
||
可执行文件:`build/gcc-debug/compiler/STCompiler`
|
||
|
||
## 用法
|
||
|
||
```text
|
||
STCompiler <project.toml> [-o <name>.stb]
|
||
STCompiler <name>.stb --disasm
|
||
```
|
||
|
||
| 参数 | 作用 |
|
||
|---|---|
|
||
| `<project.toml>` | 工程文件(必填) |
|
||
| `-o <name>.stb` | 编译并写出映像文件;**缺省时只打印文件集合与工程哈希**(12.3 阶段行为) |
|
||
| `<name>.stb --disasm` | **反汇编一个已编译的映像**(不重新编译,见下) |
|
||
| `--help` | 打印帮助 |
|
||
|
||
退出码:`0` 成功;`1` 编译失败(错误信息打到 stderr)。
|
||
|
||
## 反汇编(--disasm)
|
||
|
||
对已编译的 `.stb` 逐段查看:段摘要、函数表逐条指令(文件绝对偏移)、常量表、数据段 hex。
|
||
|
||
```bash
|
||
$ STCompiler line1.stb --disasm
|
||
image: line1.stb (184 bytes, 2 functions, 4 globals, entry fn 1)
|
||
dt_ms=10 cycle_limit=100000 hash=0xc3fe4ae74ad45900
|
||
functions:
|
||
fn 0: nregs=8, offset=0, len=1
|
||
0x0060 RET
|
||
fn 1: nregs=13, offset=4, len=17
|
||
0x0064 LOAD_I r8, 1
|
||
0x0068 STORE_GLOBAL r8, 8
|
||
0x006c LOAD_GLOBAL r9, 2
|
||
...
|
||
data (16 bytes):
|
||
0x0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||
```
|
||
|
||
说明:
|
||
|
||
- 指令偏移是**文件绝对字节偏移**,可直接对照 `xxd line1.stb`
|
||
- 映像里**没有符号名**(函数表只有 fn_id,数据段无名字映射),因此按 `fn 0` / `fn 1`、槽号显示
|
||
- 文件损坏或打不开 → `error: ...` 退出码 1
|
||
|
||
## 示例(line1)
|
||
|
||
```bash
|
||
$ STCompiler examples/line1/project.toml
|
||
project: line1
|
||
files:
|
||
globals.st
|
||
motor.st
|
||
main.st
|
||
hash: 0xc3fe4ae74ad45900
|
||
|
||
$ STCompiler examples/line1/project.toml -o line1.stb
|
||
compiled: line1.stb (184 bytes, 2 functions, 4 globals)
|
||
```
|
||
|
||
产物 `line1.stb`:魔数 `STSC` + 版本 1 的单一映像(指令见 `Doc/isa/指令与映像.md`)。
|
||
|
||
## 工程文件(project.toml)
|
||
|
||
只做三件事:**列出源文件、指定唯一 GVL、可选地把已声明全局接到硬件**。不声明变量。
|
||
|
||
| 字段 | 必填 | 说明 |
|
||
|---|---|---|
|
||
| `project.name` | 是 | 工程名 |
|
||
| `project.entry` | 是 | 第一版必须 `"program MAIN"` |
|
||
| `project.cycle_limit` | 是 | 每周期指令上限(>0) |
|
||
| `project.dt_ms` | 是 | 本周期 Δt 毫秒(>0),给 TON/TOF/CTU |
|
||
| `files.st` | 是 | 源文件列表(非空数组) |
|
||
| `gvl.file` | 否 | 唯一允许 `VAR_GLOBAL` 的文件;已在 `files.st` 则不重复收录 |
|
||
| `[[io.input]]` / `[[io.output]]` | 否 | `var` + `channel` + `bit`;`var` 必须已在 GVL 声明 |
|
||
|
||
```toml
|
||
[project]
|
||
name = "line1"
|
||
entry = "program MAIN"
|
||
cycle_limit = 100000
|
||
dt_ms = 10
|
||
|
||
[files]
|
||
st = ["globals.st", "motor.st", "main.st"]
|
||
|
||
[gvl]
|
||
file = "globals.st"
|
||
|
||
[[io.input]]
|
||
var = "EmergencyStop"
|
||
channel = 0
|
||
bit = 2
|
||
```
|
||
|
||
## ST 子集(第一版)
|
||
|
||
**POU**:`PROGRAM` / `FUNCTION` / `FUNCTION_BLOCK`(含对应 `END_*`)。
|
||
|
||
**变量段**:`VAR` / `VAR_INPUT` / `VAR_OUTPUT` / `VAR_GLOBAL`(仅 `gvl.file` 顶层)/ `VAR_EXTERNAL`。
|
||
|
||
**类型**:`BOOL` / `INT` / `TIME`;内建 FB 类型 `TON` / `TOF` / `CTU`(关键字,不可作变量名)。
|
||
|
||
**语句**:赋值 `:=`、`IF / ELSIF / ELSE / END_IF`、`WHILE / END_WHILE`、FB 调用 `fb(in := ..., ...);`、字段读 `fb.Q`。
|
||
|
||
**表达式**:字面量(`TRUE`/`FALSE`、整数、`T#10ms` 式 TIME)、`NOT`、`AND`/`OR`(**短路**)、比较 `= <> < <= > >=`(不连锁)、算术 `+ - * /`、一元负号、函数调用 `Add(3, 4)`。
|
||
|
||
**函数**:结果 = 函数名赋值(`Add := a + b;`);返回类型 `FUNCTION Add : INT`;调用约定:结果 r0、参数 r1..r7(最多 7 个输入,函数内只读)、变量与临时从 r8 起(见 `Doc/compiler/寄存器码.md`)。
|
||
|
||
**限制(v1 明确不做)**:指针 / `REF` / `CLASS` / `ANY` / `VAR_IN_OUT`(语法层直接拒绝)、链式比较、FB 字段赋值、`REAL`、字符串、用户类型套娃、隐式类型转换、函数循环调用(链接层拒绝)、`FUNCTION` 写全局(类型检查层拒绝,含经 `VAR_EXTERNAL`)。
|
||
|
||
## 编译管线与错误类别
|
||
|
||
```
|
||
project.toml + .st
|
||
→ 词法(lex error)→ 语法(syntax error)→ 链接(link error)
|
||
→ 类型检查(type error)→ 寄存器码(codegen error)→ .stb
|
||
```
|
||
|
||
错误消息前缀即阶段:`lex error` / `syntax error` / `link error` / `type error` / `codegen error`,均带文件与行列(`type error` 仅带文件)。
|
||
|
||
| 类别 | 示例 |
|
||
|---|---|
|
||
| `lex error` | 非法字符、未闭合注释、坏 `T#` 字面量 |
|
||
| `syntax error` | 缺 `END_*`、`VAR_IN_OUT` 等保留名、链式比较 |
|
||
| `link error` | 非 GVL 文件写 `VAR_GLOBAL`、同名全局、io.var 未在 GVL、未声明实例、循环调用 |
|
||
| `type error` | `FUNCTION` 写全局、AND 吃 INT、赋值类型不匹配、FB 输入类型不匹配 |
|
||
| `codegen error` | 寄存器溢出、写 io.input、写函数输入 |
|
||
|
||
## 样例与测试
|
||
|
||
- `examples/line1/`:最小闭环(MAIN + MotorStarter FB + I/O + 全局),给人看
|
||
- `tests/cases/01~20/`:20 个用例(每份 `project.toml` + `.st` + `EXPECTED.md`),编译结果按表
|
||
- `tests/`:CTest(`isa_roundtrip` / `compiler_toml` / `lexer_tokens` / `parser_syntax` / `linker_links` / `typecheck_types` / `codegen_slice1`)
|
||
|
||
## 当前状态
|
||
|
||
- ✅ 可编译:14 个正例用例全部产出 `.stb`;6 个负例按期望拒绝
|
||
- ⏳ 执行:`BytecodeExecutor`(加载 `.stb` 跑扫描周期)在 12.9/12.10
|
||
- ⏳ sidecar(`<name>.runtime.toml`,I/O 绑定)在 12.10 随执行器一起接线
|