You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Boost Spirit X3解析嵌套成员访问生成嵌套Get节点AST?

使用Boost Spirit X3生成嵌套Get节点AST解析HLSL链式成员访问

完全可以用Boost Spirit X3实现这个需求,核心是利用X3对左递归语法的支持,把链式成员访问的扁平序列转化为嵌套的Get节点结构,和《Crafting Interpreters》里的AST结构对齐。

1. 定义AST节点结构

首先模仿书中的结构,定义表示表达式的类型,包含标识符和成员访问(Get)两种节点:

#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
#include <variant>
#include <memory>

namespace ast {
    struct Expr;
    using ExprPtr = std::unique_ptr<Expr>;

    struct Identifier {
        std::string name;
    };

    struct Get {
        ExprPtr object;
        std::string name;
    };

    struct Expr {
        std::variant<Identifier, Get> value;
    };
}

// 适配Boost Fusion,让X3能自动填充AST结构
BOOST_FUSION_ADAPT_STRUCT(ast::Identifier, name)
BOOST_FUSION_ADAPT_STRUCT(ast::Get, object, name)

2. 编写X3解析规则

利用X3的左递归规则能力,先定义基础的标识符规则,再定义成员访问的递归规则,每次匹配到.标识符时,将之前的表达式作为Get节点的object,新标识符作为name,生成嵌套结构:

namespace parser {
    namespace x3 = boost::spirit::x3;

    // 声明左递归规则
    x3::rule<class expr_rule, ast::ExprPtr> const expr = "expr";

    // 标识符规则:匹配HLSL合法标识符(字母、下划线开头,后跟字母、数字、下划线)
    auto const identifier = x3::lexeme[(x3::alpha | '_') >> *(x3::alnum | '_')];

    // 成员访问规则:基础标识符 + 重复的 .标识符
    auto const member_access = 
        identifier 
        >> *(
            '.' >> identifier 
            // 每次匹配到 .标识符,将之前的Expr包装成Get节点
            [](auto& ctx) {
                auto member_name = x3::_attr(ctx);
                auto& prev_expr = x3::_val(ctx);
                x3::_val(ctx) = std::make_unique<ast::Expr>(
                    ast::Get{std::move(prev_expr), member_name}
                );
            }
        )
        // 初始标识符包装成Identifier节点
        [](auto& ctx) {
            auto id_name = x3::_attr(ctx);
            x3::_val(ctx) = std::make_unique<ast::Expr>(ast::Identifier{id_name});
        };

    // 绑定左递归规则的定义
    auto const expr_def = member_access;
    BOOST_SPIRIT_DEFINE(expr);
}

3. 测试解析逻辑

编写测试代码验证解析结果,比如解析first.Second.third会生成三层嵌套的Get节点:

#include <iostream>
#include <iomanip>

// 递归打印AST结构,用于验证
void print_ast(const ast::Expr& expr, int indent = 0) {
    std::visit([&](const auto& node) {
        using T = std::decay_t<decltype(node)>;
        if constexpr (std::is_same_v<T, ast::Identifier>) {
            std::cout << std::setw(indent) << "" << "Identifier: " << node.name << "\n";
        } else if constexpr (std::is_same_v<T, ast::Get>) {
            std::cout << std::setw(indent) << "" << "Get:\n";
            std::cout << std::setw(indent + 4) << "" << "Object:\n";
            print_ast(*node.object, indent + 8);
            std::cout << std::setw(indent + 4) << "" << "Name: " << node.name << "\n";
        }
    }, expr.value);
}

int main() {
    std::string input = "first.Second.third";
    ast::ExprPtr result;

    auto iter = input.begin();
    auto end = input.end();
    bool success = boost::spirit::x3::parse(iter, end, parser::expr, result);

    if (success && iter == end) {
        std::cout << "解析成功,AST结构:\n";
        print_ast(*result);
    } else {
        std::cout << "解析失败,剩余未解析部分: " << std::string(iter, end) << "\n";
    }

    return 0;
}

输出结果

运行后会输出嵌套的AST结构:

解析成功,AST结构:
Get:
    Object:
        Get:
            Object:
                Identifier: first
            Name: Second
    Name: third

这完全符合《Crafting Interpreters》中嵌套Get节点的AST结构,后续可以扩展这个规则,整合到完整的HLSL解析器中。

内容的提问来源于stack exchange,提问作者Daniel Dokipen Elliott

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 01:50:31