使用带有返回值的访问者模式实现 AST 的最佳方法是什么?

2024-04-13

我正在尝试使用访问者模式在 C++ 中实现一个简单的抽象语法树(AST)。通常访问者模式不处理返回值。但在我的 AST 中,有一些表达式节点关心其子节点的返回类型和值。例如,我有一个这样的 Node 结构:

class AstNode
{
public:
    virtual void accept(AstNodeVisitor&) = 0;

    void addChild(AstNode* child);
    AstNode* left() { return m_left; }
    AstNode* right() { return m_right; }
...

private:
    AstNode* m_left;
    AstNode* m_right;
};

class CompareNode : public AstNode
{
public:
    virtual void accept(AstNodeVisitor& v)
    {
        v->visitCompareNode(this);
    }

    bool eval(bool lhs, bool rhs) const
    {
        return lhs && rhs;
    }
};

class SumNode : public AstNode
{
public:
    virtual void accept(AstNodeVisitor& v)
    {
        v->visitSumNode(this);
    }

    int eval(int lhs, int rhs) const
    {
        return lhs + rhs;
    }
};

class AstNodeVisitor
{
public:
    ...
    bool visitCompareNode(CompareNode& node)
    {
        // won't work, because accept return void!
        bool lhs = node.left()->accept(*this);
        bool rhs = node.right()->accept(*this);
        return node.eval(lhs, rhs);
    }

    int visitSumNode(Node& node)
    {
        // won't work, because accept return void!
        int lhs = node.left()->accept(*this);
        int rhs = node.right()->accept(*this);
        return node.eval(lhs, rhs);
    }
};

在本例中,CompareNode 和 SumNode 都是二元运算符,但它们依赖于其子级访问的返回类型。

据我所知,要使其发挥作用,只有两种选择:

  1. Accept仍然可以返回void,将返回值保存在传递给每个accept和visit函数的上下文对象中,并在visit函数中使用它们,我知道要使用什么类型。这应该可以工作,但感觉就像是黑客攻击。

  2. 使 AstNode 成为模板,并接受函数 a none virtual,但返回类型取决于模板参数 T。但是如果我这样做,我将不再拥有通用的 AstNode* 类,并且无法在子列表中保存任何 AstNode* 。

例如:

template <typename T`>
class AstNode
{
public:
    T accept(AstNodeVisitor&);
    ...
};

那么有没有更优雅的方法来做到这一点呢?对于实施 AST 行走的人来说,这应该是一个相当常见的问题,所以我想知道最佳实践是什么。

Thanks.


访问者可以拥有可用于存储结果的成员,例如:

class AstNodeVisitor
{
public:
    void visitCompareNode(CompareNode& node)
    {
        node.left()->accept(*this); // modify b
        bool lhs = b;
        node.right()->accept(*this); // modify b
        bool rhs = b;
        b = node.eval(lhs, rhs);
    }

    void visitSumNode(Node& node)
    {
        node.left()->accept(*this); // modify n
        int lhs = n;
        node.right()->accept(*this);  // modify n
        int rhs = n;
        n = node.eval(lhs, rhs);
    }
private:
    bool b;
    int n;
};

您可能还想保存最后结果的类型或使用类似的东西boost::variant.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用带有返回值的访问者模式实现 AST 的最佳方法是什么? 的相关文章

随机推荐

  • 如何向菜单项添加工具提示?

    我正在尝试为菜单栏项添加工具提示 例如 Save 但我无法获取需求菜单项的实例 我可以添加这个工具提示吗 我正在使用 Tkinter 和 python 2 7 def createMenu self menu Menu root root
  • 编写java代码时出现SIGSEGV

    我有一段代码在 HTC Desire HD v2 3 3 上运行得很好 但是在 HTC Desire v2 2 上运行时 关闭蓝牙套接字时会崩溃并出现 SIGSEGV 07 25 16 23 52 462 INFO DEBUG 64 07
  • 如何调用.Net Core需要签名的XML SOAP服务?

    我意识到这个问题指的是旧技术 我正在呼叫供应商系统 并且无法更改服务 我们需要调用 XML SOAP WS 然后签署请求 10 年前 我会使用 Web 服务增强 WSE 3 0 之类的东西 然后继续前进 就像今天一样 我陷入了在 Net C
  • 持久性单元定义冲突

    春季3 1 1 Maven 3 0 4 日本PA Eclipse wtp 靛蓝 你好 我在服务器启动时遇到以下异常 我的项目中只有一个 persistence xml 有任何想法吗 谢谢埃里克 引起原因 java lang IllegalS
  • Node.js 找不到模块“tcp”

    节点在以下行崩溃 var tcp require tcp 错误文本 node js 201 throw e process nextTick error or error event on first tick Error Cannot f
  • 可折叠工具栏布局中的稀松布是什么?

    我在 Android 开发人员上阅读了可折叠工具栏布局 那里使用了一个术语 稀松布 它是什么 Scrim 隐藏或掩盖某事的事物 根据 Android CollapsingToolbarLayout 稀松布内容 当滚动位置达到某个阈值时显示或
  • 使 WooCommerce 结账运送字段可见并删除“运送到不同地址?”复选框

    我想知道是否有办法删除 运送到其他地址 复选框 在 woocommerce 结帐页面中 但保持运输字段可见 我努力了 add filter woocommerce cart needs shipping address return fal
  • Node.js 上通过套接字连接 Redis

    由于共享托管 目标主机上的我的 redis 服务器不在端口上运行 而是在非常特定的套接字上运行 可以通过套接字文件连接到该套接字 只有我的用户可以访问 但是 我还没有找到如何通过套接字指定连接node redis and connect r
  • e2e 测试是否应该将数据保存在真实数据库中?

    我读了很多关于 e2e 测试的文章 但我无法理解的一件事是 e2e 测试应该有多 真实 无论我使用什么工具进行 e2e 测试 我发现大多数时候它们都是在本地 开发或 alpha 环境中使用 如果我的应用程序具有身份验证 我是否应该在数据库中
  • 当具有复杂类型时,KnockoutJs 中的值绑定无法进行选择

    我正在尝试在选择元素上使用值绑定 如本小提琴中所述 http jsfiddle net MikeEast nM6dd 2 http jsfiddle net MikeEast nM6dd 2 但是 我似乎无法设置所选选项 值绑定 我知道我可
  • 为什么我的 XIB 文件无法本地化 (iPhone)?

    情况 我正在启动 XCode 为 iPhone 创建一个新项目 查看应用程序 并将 XIB 文件加载到 IB 中 我操作视图 添加带有字符串 hello 的标签 保存 构建 运行应用程序 一切都很好 现在我正在本地化 XIB 我所做的 右键
  • RttiType.TypeKind 和 RttiType.Name 之间有什么区别?

    以下之间的语义差异是什么 RttiType TypeKind 和 RttiType Name 我问是因为原则上不能从名称推断出 TypeKind 吗 The TypeKind and Name的属性TRttiType是完全不同的事情 Typ
  • 波特词干算法实现问题?

    我正在尝试实现波特词干算法 但我陷入了这一点 Step 1b m gt 0 EED gt EE feed gt feed agreed gt agree v ED gt plastered gt plaster bled gt bled v
  • 无法连接到远程调试 - Web App Azure

    我正在尝试使用 Visual Studio 2017 Professional 远程调试部署为 Azure 应用服务的 Asp Net Core Web 应用程序 使用 Web API 项目 按照记录的说明进行操作here https le
  • 来自本机的 Android O 设备序列号

    在 Android O 上从本机获取序列号而不调用 Java 的正确方法是什么Build getSerial 在 Android string serial read property ro boot serialno string rea
  • 在 openpyxl 中为选项卡着色

    我们有一种情况 我们想要使用 openpyxl 为工作表的选项卡着色 有没有办法在图书馆内做到这一点 或者 有没有人找到一种方法可以在库外部执行此操作 即通过扩展或类似的方式 您可以使用 openpyxl 为sheet properties
  • UIView的transitionWithView丢弃图层设置

    我 viewDidload 我有这样的设置 self layer setCornerRadius 30 0f NSString imgFilepath NSBundle mainBundle pathForResource imageNam
  • IntelliJ IDEA中如何自动分割长字符串?

    我正在编写一个包含很长字符串的测试 我需要拆分这些字符串 private static final String TOO LONG JSON field1 field1 field2 field2 fieldN fieldN 所以他们会变成
  • 在 Azure 上部署后 ChatBot 无法工作 - 内部服务器错误

    我已经使用 LUIS 和 QnA Maker 部署了一个聊天机器人 当我在模拟器上运行它时 它在本地完美运行 它在聊天开始时加载自适应卡 我从 LUIS 那里得到了正确的回复 但是 当我在 Azure 上部署机器人并在 Web 聊天上测试它
  • 使用带有返回值的访问者模式实现 AST 的最佳方法是什么?

    我正在尝试使用访问者模式在 C 中实现一个简单的抽象语法树 AST 通常访问者模式不处理返回值 但在我的 AST 中 有一些表达式节点关心其子节点的返回类型和值 例如 我有一个这样的 Node 结构 class AstNode public