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

4.7 KiB
Raw Permalink Blame History

词法(12.4

compiler 模块的词法分析。输入:单个 .st 源文件内容;输出:稳定 token 流(带 source_file + 行列)。语法与字段表见 初步计划.md 12.1、12.4。

做 / 不做

  • (* *) 注释、标识符、关键字、整数、TIME 字面量、:=、比较符、括号
  • 关键字与标识符统一折成小写内部形(与 IEC 一致,大小写不敏感)
  • 每个 token 带 source_file + 行列,供以后报错
  • 非法字符 → lex error 硬错误(带行列)

不做(第一版)

  • 字符串字面量、REAL 字面量、十六进制/科学计数
  • 注释嵌套((* 到第一个 *) 结束,未闭合报错)
  • 浮点数、_ 数字分隔符

关键字表(12.1 冻结,只认这些)

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 修订:THENDO 补入关键字表(IF ... THEN / WHILE ... DO 语法需要), 与 12.1 原表合并,其余不变。 12.11 修订:内置 FB 扩为 8 个(TON/TOF/TP/CTU/CTD/CTUD/R_TRIG/F_TRIG)。

其余单词一律当标识符;VAR_IN_OUTREFCLASS 等由语法层(12.5)出明确错误。

Token

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_MAXlex error
  • TIMET#(不敏感)+ 一个或多个 <整数><单位> 段,单位不敏感:ms s m h d,累加为毫秒:
    • T#10ms → 10
    • T#1s250ms → 1250
    • T#2h → 7200000
    • 缺单位 / 未知单位 / 空段 → lex error
  • 负数不是字面量:-5MINUS + 整数,由语法层处理

符号

  • := 优先于 :<> 优先于 </><=/>= 单独匹配

注释

  • (* ... *)不嵌套;未闭合 → lex error
  • 注释内不产 token

错误

稳定前缀 lex error,带文件与行列:

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/*.stlex 成稳定 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_testtests/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 + 文档