Files
Interpreter/compiler/include/compiler/Lexer.h
T

135 lines
6.3 KiB
C++
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.
/**
* @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);
}