135 lines
6.3 KiB
C++
135 lines
6.3 KiB
C++
/**
|
||
* @file Lexer.h
|
||
* @brief ST 子集词法分析
|
||
* @details 本文件是词法层对外接口:定义 token 类型(Tok)、token 载体
|
||
* (Token)与两个入口(lex / lex_file)。扫描器实现见 Lexer.cpp,
|
||
* 关键字与 token 集见 Doc/compiler/词法.md。
|
||
* @author
|
||
* @date 2026-08-21
|
||
*/
|
||
|
||
#pragma once
|
||
|
||
#include <cstdint>
|
||
#include <string>
|
||
#include <vector>
|
||
|
||
namespace compiler {
|
||
|
||
/**
|
||
* @brief token 类型枚举。
|
||
* @details 关键字与 token 集见 Doc/compiler/词法.md;关键字共 25 个,
|
||
* 与 12.1 冻结表一致(12.5 修订补入 THEN/DO)。顺序冻结后
|
||
* 不得插值改动,只能追加到末尾。
|
||
*/
|
||
enum class Tok {
|
||
// 关键字(25 个,与 12.1 冻结表一致)
|
||
PROGRAM, ///< PROGRAM 声明起始
|
||
FUNCTION, ///< FUNCTION 声明起始
|
||
FUNCTION_BLOCK, ///< FUNCTION_BLOCK 声明起始
|
||
END_PROGRAM, ///< PROGRAM 结束
|
||
END_FUNCTION, ///< FUNCTION 结束
|
||
END_FUNCTION_BLOCK, ///< FUNCTION_BLOCK 结束
|
||
VAR, ///< 局部变量段(VAR)起始
|
||
VAR_INPUT, ///< 输入变量段起始
|
||
VAR_OUTPUT, ///< 输出变量段起始
|
||
VAR_GLOBAL, ///< 全局变量段起始
|
||
VAR_EXTERNAL, ///< 外部变量段起始
|
||
VAR_TEMP, ///< 临时变量段起始(VAR_TEMP)
|
||
END_VAR, ///< 变量段结束
|
||
BOOL, ///< 布尔类型
|
||
BYTE, ///< 位串类型(8 位)
|
||
WORD, ///< 位串类型(16 位)
|
||
DWORD, ///< 位串类型(32 位)
|
||
LWORD, ///< 位串类型(64 位)
|
||
SINT, ///< 有符号整数(8 位)
|
||
INT, ///< 有符号整数(16 位)
|
||
DINT, ///< 有符号整数(32 位)
|
||
LINT, ///< 有符号整数(64 位)
|
||
USINT, ///< 无符号整数(8 位)
|
||
UINT, ///< 无符号整数(16 位)
|
||
UDINT, ///< 无符号整数(32 位)
|
||
ULINT, ///< 无符号整数(64 位)
|
||
TIME, ///< 时间类型(毫秒)
|
||
REAL, ///< 浮点类型(32 位)
|
||
LREAL, ///< 浮点类型(64 位)
|
||
DATE, ///< 日期类型(天数)
|
||
TOD, ///< 时刻类型(当日毫秒)
|
||
DT, ///< 日期时刻类型(64 位)
|
||
IF, ///< IF 关键字
|
||
ELSIF, ///< ELSIF 关键字
|
||
ELSE, ///< ELSE 关键字
|
||
END_IF, ///< IF 结束
|
||
WHILE, ///< WHILE 关键字
|
||
END_WHILE, ///< WHILE 结束
|
||
THEN, ///< IF/ELSIF 分支引导(12.5 修订补入关键字表)
|
||
DO, ///< WHILE 循环体引导(12.5 修订补入关键字表)
|
||
AND, ///< 逻辑与
|
||
OR, ///< 逻辑或
|
||
NOT, ///< 逻辑非(前缀)
|
||
TRUE, ///< 布尔真字面量
|
||
FALSE, ///< 布尔假字面量
|
||
// 字面量
|
||
IDENT, ///< 标识符(text = 小写名;含 FB 类型名,Typecheck 查表)
|
||
INT_LIT, ///< 整数字面量(int_value;含进制 2#/8#/16# 已换算)
|
||
FLOAT_LIT, ///< 浮点字面量(double_value)
|
||
TIME_LIT, ///< 时间字面量(int_value = 毫秒)
|
||
DATE_LIT, ///< 日期字面量(int_value = 天数,1970 纪元)
|
||
TOD_LIT, ///< 时刻字面量(int_value = 当日毫秒)
|
||
DT_LIT, ///< 日期时刻字面量(int64 = date<<32|tod)
|
||
// 符号
|
||
ASSIGN, ///< :=(赋值)
|
||
EQ, ///< =(等于)
|
||
NE, ///< <>(不等)
|
||
LT, ///< <(小于)
|
||
LE, ///< <=(小于等于)
|
||
GT, ///< >(大于)
|
||
GE, ///< >=(大于等于)
|
||
PLUS, ///< +(加)
|
||
MINUS, ///< -(减)
|
||
STAR, ///< *(乘)
|
||
SLASH, ///< /(除)
|
||
LPAREN, ///< ((左括号)
|
||
RPAREN, ///< )(右括号)
|
||
COMMA, ///< ,(逗号)
|
||
SEMI, ///< ;(分号)
|
||
COLON, ///< :(冒号)
|
||
DOT, ///< .(点,FB 字段访问)
|
||
END, ///< 文件结束哨兵
|
||
};
|
||
|
||
/**
|
||
* @brief 单个 token:类型 + 文本/字面量值 + 源位置。
|
||
* @details line/col 从 1 起,记录 token 起始字符的位置。
|
||
*/
|
||
struct Token {
|
||
Tok type; ///< token 类型
|
||
std::string text; ///< 标识符/关键字的小写文本;字面量原文
|
||
int64_t int_value; ///< INT_LIT / TIME_LIT / DATE_LIT / TOD_LIT / DT_LIT 的字面量值
|
||
double double_value; ///< FLOAT_LIT 的字面量值
|
||
std::string source_file; ///< 来源文件名
|
||
uint32_t line; ///< 起始行(从 1 起)
|
||
uint32_t col; ///< 起始列(从 1 起)
|
||
};
|
||
|
||
/**
|
||
* @brief 对源文本做词法分析,产出 token 流(含末尾 END)。
|
||
* @param source_file 源文件名(写入每个 token 的 source_file 并用于报错)
|
||
* @param content 源文本
|
||
* @param out 输出 token 流
|
||
* @param err 错误输出;可为 nullptr(静默)
|
||
* @return true 成功;false 失败(err 前缀 "lex error",带文件与行列)
|
||
*/
|
||
bool lex(const std::string& source_file, const std::string& content,
|
||
std::vector<Token>* out, std::string* err);
|
||
|
||
/**
|
||
* @brief 读取文件后做词法分析。
|
||
* @param path 文件路径
|
||
* @param out 输出 token 流
|
||
* @param err 错误输出;可为 nullptr(静默)
|
||
* @return true 成功;false 失败(文件不存在 / 读取失败也算 lex error)
|
||
*/
|
||
bool lex_file(const std::string& path, std::vector<Token>* out, std::string* err);
|
||
}
|