实现 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
This commit is contained in:
@@ -37,6 +37,8 @@ namespace compiler {
|
||||
END_IF,
|
||||
WHILE,
|
||||
END_WHILE,
|
||||
THEN, // 12.5 修订:IF/WHILE 语法需要,补入关键字表
|
||||
DO, // 同上
|
||||
AND,
|
||||
OR,
|
||||
NOT,
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* @file Parser.h
|
||||
* @brief ST 子集递归下降语法分析(AST 定义 + 入口)
|
||||
* @author
|
||||
* @date 2026-08-21
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace compiler {
|
||||
|
||||
// ---- 类型引用 ----
|
||||
|
||||
enum class TypeKind { Bool, Int, Time, FbBuiltin, FbUser };
|
||||
|
||||
struct TypeRef {
|
||||
TypeKind kind = TypeKind::Bool;
|
||||
std::string name; // FbUser 时为用户 FB 类型名(小写)
|
||||
};
|
||||
|
||||
// ---- 变量段 ----
|
||||
|
||||
struct VarDecl {
|
||||
std::string name;
|
||||
TypeRef type;
|
||||
bool has_init = false; // 可选初值(v1 仅字面量)
|
||||
int64_t init_value = 0; // BOOL 0/1、INT 值、TIME 毫秒
|
||||
uint32_t line = 0;
|
||||
uint32_t col = 0;
|
||||
};
|
||||
|
||||
enum class VarSection { Local, Input, Output, Global, External };
|
||||
|
||||
struct VarBlock {
|
||||
VarSection section = VarSection::Local;
|
||||
std::vector<VarDecl> vars;
|
||||
};
|
||||
|
||||
// ---- 表达式 ----
|
||||
|
||||
enum class ExprKind {
|
||||
LitBool, // int_value 0/1
|
||||
LitInt, // int_value
|
||||
LitTime, // int_value 毫秒
|
||||
VarRef, // name
|
||||
Field, // name.field
|
||||
Not, // operand
|
||||
And, Or, // lhs, rhs(短路语义保留到 12.8)
|
||||
Cmp, Add, Sub, Mul, Div, // lhs, rhs,op
|
||||
Neg, // operand(一元负号)
|
||||
Call, // name + args(函数调用,有返回值)
|
||||
};
|
||||
|
||||
enum class BinOp { Eq, Ne, Lt, Le, Gt, Ge, Add, Sub, Mul, Div };
|
||||
|
||||
struct Expr {
|
||||
ExprKind kind = ExprKind::LitBool;
|
||||
BinOp op = BinOp::Eq; // 二目运算
|
||||
std::string name; // VarRef / Field 对象 / Call 函数名
|
||||
std::string field; // Field 字段名
|
||||
int64_t int_value = 0; // 字面量值
|
||||
std::unique_ptr<Expr> lhs;
|
||||
std::unique_ptr<Expr> rhs;
|
||||
std::unique_ptr<Expr> operand; // Not / Neg
|
||||
std::vector<std::unique_ptr<Expr>> args; // Call 实参
|
||||
};
|
||||
|
||||
// ---- 语句 ----
|
||||
|
||||
enum class StmtKind { Assign, If, While, FbCall };
|
||||
|
||||
struct Stmt; // 前置声明(IfBranch / Stmt 相互引用)
|
||||
|
||||
struct FbArg {
|
||||
std::string name;
|
||||
std::unique_ptr<Expr> value;
|
||||
};
|
||||
|
||||
struct IfBranch {
|
||||
std::unique_ptr<Expr> cond;
|
||||
std::vector<Stmt> body;
|
||||
};
|
||||
|
||||
// 前置声明:Stmt 内部自引用
|
||||
struct Stmt {
|
||||
StmtKind kind = StmtKind::Assign;
|
||||
// Assign
|
||||
std::string target; // 左值标识符
|
||||
bool target_is_field = false; // 左值 fb.field(v1 禁止赋值,语法层拒绝)
|
||||
std::string field;
|
||||
std::unique_ptr<Expr> value;
|
||||
// If / While
|
||||
std::unique_ptr<Expr> cond;
|
||||
std::vector<Stmt> body;
|
||||
std::vector<IfBranch> elsifs;
|
||||
std::vector<Stmt> else_body;
|
||||
// FbCall
|
||||
std::string instance;
|
||||
std::vector<FbArg> args;
|
||||
};
|
||||
|
||||
// ---- POU ----
|
||||
|
||||
enum class PouKind { Program, Function, FunctionBlock };
|
||||
|
||||
struct POU {
|
||||
PouKind kind = PouKind::Program;
|
||||
std::string name;
|
||||
TypeRef result_type; // FUNCTION 才有
|
||||
std::vector<VarBlock> blocks;
|
||||
std::vector<Stmt> body;
|
||||
std::string source_file;
|
||||
};
|
||||
|
||||
// 一个 .st 文件的解析结果:GVL 文件形态(无 POU)时只有 globals 非空
|
||||
struct Unit {
|
||||
std::vector<VarBlock> globals; // 顶层 VAR_GLOBAL 段(仅 GVL 文件)
|
||||
std::vector<POU> pous;
|
||||
};
|
||||
|
||||
// 解析一个 .st 文件的全部内容(顶层 VAR_GLOBAL 段或 POU)。
|
||||
// 失败返回 false,err 前缀 "syntax error",带文件与行列。
|
||||
bool parse_pous(const std::string& source_file, const std::string& content,
|
||||
Unit* out, std::string* err);
|
||||
|
||||
// 读文件后解析
|
||||
bool parse_pous_file(const std::string& path, Unit* out, std::string* err);
|
||||
}
|
||||
Reference in New Issue
Block a user