Files
Interpreter/Doc/compiler/词法.md
T
Admin 26256a36b9 扩充内置功能块为 8 个:TON/TOF/TP/CTU/CTD/CTUD/R_TRIG/F_TRIG。
- isa:CAL_* 操作码连续占 24..31(CALL/RET 后移为 32/33,kOpCount=34);disasm 支持 5 个新操作码
- 词法/语法/链接:新 8 个关键字与冻结布局(TP=in/pt/q/et、CTD=cd/ld/pv/q/cv、
  CTUD=cu/cd/r/lu/pv/qu/qd/cv、R_TRIG/F_TRIG=clk/q)
- VM:do_cal 全 8 个语义(TP 脉冲、CTD 递减、CTUD 双向+装载、R_TRIG 上升沿、F_TRIG 下降沿);
  edge_prev_ 每槽 2 字节存边沿上次输入;exec_one 分发补 5 个新操作码
- 验证:TP 30ms 脉冲 2 周期、CTD 装载+递减到 q=1、CTUD cu/cd 双向、R/F_TRIG 交替;
  ctest 11/11 全绿
- 文档:指令与映像/词法/初步计划/符号表与链接/指令执行/扫描周期/使用说明 同步
2026-08-21 20:38:27 +08:00

132 lines
4.7 KiB
Markdown
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.
# 词法(12.4
compiler 模块的词法分析。输入:单个 `.st` 源文件内容;输出:稳定 token 流(带 `source_file` + 行列)。语法与字段表见 [`初步计划.md`](../初步计划.md) 12.1、12.4。
## 做 / 不做
**做**
- `(* *)` 注释、标识符、关键字、整数、`TIME` 字面量、`:=`、比较符、括号
- 关键字与标识符统一折成**小写**内部形(与 IEC 一致,大小写不敏感)
- 每个 token 带 `source_file` + 行列,供以后报错
- 非法字符 → `lex error` 硬错误(带行列)
**不做(第一版)**
- 字符串字面量、`REAL` 字面量、十六进制/科学计数
- 注释嵌套(`(*` 到第一个 `*)` 结束,未闭合报错)
- 浮点数、`_` 数字分隔符
## 关键字表(12.1 冻结,只认这些)
```text
PROGRAM FUNCTION FUNCTION_BLOCK END_PROGRAM END_FUNCTION END_FUNCTION_BLOCK
VAR VAR_INPUT VAR_OUTPUT VAR_GLOBAL VAR_EXTERNAL END_VAR
BOOL INT TIME
IF ELSIF ELSE END_IF WHILE END_WHILE
AND OR NOT
TRUE FALSE
TON TOF TP CTU CTD CTUD R_TRIG F_TRIG
```
> 12.5 修订:`THEN`、`DO` 补入关键字表(`IF ... THEN` / `WHILE ... DO` 语法需要),
> 与 12.1 原表合并,其余不变。
> 12.11 修订:内置 FB 扩为 8 个(TON/TOF/TP/CTU/CTD/CTUD/R_TRIG/F_TRIG)。
其余单词一律当标识符;`VAR_IN_OUT``REF``CLASS` 等由语法层(12.5)出明确错误。
## Token
```cpp
enum class Tok {
// 关键字(25 个,逐一对应上表)
...
// 字面量
IDENT, // text = 小写名
INT_LIT, // int_value
TIME_LIT, // int_value = 毫秒
// 符号
ASSIGN, // :=
EQ, NE, LT, LE, GT, GE, // = <> < <= > >=
PLUS, MINUS, STAR, SLASH, // + - * /
LPAREN, RPAREN, COMMA, SEMI, // ( ) , ;
COLON, DOT, // : .
END, // 文件结束
};
struct Token {
Tok type;
std::string text; // 标识符/关键字的小写文本;字面量原文
int64_t int_value; // INT_LIT / TIME_LIT(毫秒)
std::string source_file;
uint32_t line; // 从 1 起
uint32_t col; // 从 1 起
};
```
## 规则
### 大小写
- 关键字匹配**大小写不敏感**`program` / `PROGRAM` / `Program` 同义)
- 标识符统一折小写存入 `text`(内部形);原始大小写不保留(v1 无字符串字面量,报错靠行列定位)
### 字面量
- 整数:`[0-9]+``int64_t` 存储;超 `INT64_MAX``lex error`
- `TIME``T#`(不敏感)+ 一个或多个 `<整数><单位>` 段,单位不敏感:`ms s m h d`,累加为毫秒:
- `T#10ms` → 10
- `T#1s250ms` → 1250
- `T#2h` → 7200000
- 缺单位 / 未知单位 / 空段 → `lex error`
- 负数不是字面量:`-5``MINUS` + 整数,由语法层处理
### 符号
- `:=` 优先于 `:``<>` 优先于 `<`/`>``<=`/`>=` 单独匹配
### 注释
- `(* ... *)`**不嵌套**;未闭合 → `lex error`
- 注释内不产 token
## 错误
稳定前缀 `lex error`,带文件与行列:
```text
lex error: illegal character '@' (motor.st, line 3, col 7)
lex error: unterminated comment (main.st, line 1, col 1)
lex error: bad time literal 'T#3q' (main.st, line 4, col 10)
```
## 完成标准
1. 第 11 节三个文件(`examples/line1/*.st`lex 成稳定 token 流;`lexer_test` 断言数量、类型、小写化、行列、`END` 收尾
2. 非法字符 / 未闭合注释 / 坏 TIME 字面量 → `lex error` 负例过
3. 全部构建 + `ctest` 无回归
---
## 执行计划(单步确认)
1. **`Lexer.h`(新建 `compiler/include/compiler/Lexer.h`**
- `Tok` 枚举:25 关键字 + `IDENT`/`INT_LIT`/`TIME_LIT` + 符号(`:= = <> < <= > >= + - * / ( ) , ; : .`+ `END`
- `Token { type, text, int_value, source_file, line, col }`(行列从 1 起)
- `bool lex_file(path, out, err)` / `bool lex(source_file, content, out, err)`
2. **`Lexer.cpp`(重写占位)**
- 25 关键字小写映射表,大小写不敏感,标识符统一折小写
- `(* *)` 注释不嵌套、未闭合报错;非法字符报错
- 整数 `[0-9]+`(超 `INT64_MAX` 报错);`T#<int><单位>` 段式解析累加毫秒(`ms s m h d`
- `:=` / `<>` / `<=` / `>=` 最长匹配优先
- 错误前缀 `lex error`,带 file/line/col
3. **`lexer_test``tests/src/lexer_test.cpp` + CMake,链 `compiler` 库)**
- line1 三文件:token 数量 / 类型序列 / 小写化 / 行列 / `END` 收尾断言
- 负例:`@` 非法字符、未闭合注释、`T#3q` 坏字面量、超大整数 → `lex error` 类别
4. **验证**`cmake --build` + `ctest`(新增 `lexer_test` 后 5/5 全绿)
5. **提交**`Lexer.h/cpp` + `lexer_test` + 文档