Files
Interpreter/Doc/compiler/词法.md
T
Admin 4ba44459e2 实现 12.5 递归下降语法:AST + 拒绝清单。
- Parser.h/cpp:POU 外壳(PROGRAM/FUNCTION/FUNCTION_BLOCK)、变量段、语句(赋值/IF/WHILE/FB 调用)、表达式优先级爬升(NOT/AND/OR 短路/比较/算术/函数调用/负号)
- Unit 结构:顶层 VAR_GLOBAL 段(GVL 文件形态)+ POU 列表
- 拒绝:VAR_IN_OUT/REF/CLASS/ANY 等保留名、链式比较、FB 字段赋值、顶层非 GVL 段
- THEN/DO 补入关键字表(12.5 修订,同步 12.1 与词法文档)
- parser_test:98 断言(line1 三文件 AST、FUNCTION 调用、IF/WHILE/TON、9 类负例),ctest 6/6
2026-08-21 11:07:34 +08:00

4.6 KiB
Raw 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 CTU

12.5 修订:THENDO 补入关键字表(IF ... THEN / WHILE ... DO 语法需要), 与 12.1 原表合并,其余不变。

其余单词一律当标识符;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 + 文档