C++ 使用二进制和一元节点处理解析器?

C++ 使用二进制和一元节点处理解析器?,c++,c++11,c++14,c++17,C++,C++11,C++14,C++17,我现在觉得这个标题有点奇怪,但我希望你们能理解我在问什么。几个月前我在Python上做过解释器程序,这有点不错,但是现在我想在C++中实现同样的做法,但是这样做给C++带来了很大的问题。 让我们从我在python程序中所做的事情开始。首先,我创建了一个Lexer,它将所有内容分离为令牌(键值对),并编写了一个解析器,它将算术语法转换为操作节点,如BinaryOpNode、UnaryOpNode和NumberNode。ex-(-2+7)^3将转换为AST作为二进制节点,左节点作为另一个二进制节点,

我现在觉得这个标题有点奇怪,但我希望你们能理解我在问什么。几个月前我在Python上做过解释器程序,这有点不错,但是现在我想在C++中实现同样的做法,但是这样做给C++带来了很大的问题。 让我们从我在python程序中所做的事情开始。首先,我创建了一个Lexer,它将所有内容分离为令牌(键值对),并编写了一个解析器,它将算术语法转换为操作节点,如BinaryOpNode、UnaryOpNode和NumberNode。ex-(-2+7)^3将转换为AST作为二进制节点,左节点作为另一个二进制节点,运算符作为POW(POW),右节点作为3的数字节点。该节点的左节点是二进制节点,其左节点是一元节点(减号和数字节点2),右节点是数字节点7,右节点是加号节点

我通过识别表达式、术语和因子来实现这一点。我在C++中编写了Lexer,但是在解析器中有问题。请帮助我在C++中做同样的事情。 到目前为止我做了什么

我尝试了一些奇怪但有点效果的东西。我创建了一个类BinaryOpNode,其中有两个void*成员用于右节点和左节点,一个枚举成员用于Rt和Lt节点之间的操作。现在两个节点的另外两个布尔成员将有助于确定void*Lt和Rt的类型?它们是UnaryOpNode还是BinaryOpNode(默认值)。这将帮助我将节点类型转换为各自的类型

然而,我对我的结果并不满意,因为它们看起来没有那么优化,而且我也不能以这种方式跟踪NumberNode


请帮帮我。提前感谢

您需要的是多态性。也就是说,程序员编写的代码,并根据其操作的对象类型执行不同的操作

C++支持一系列令人困惑的多态性实现方法

最受支持的类型是基于继承的虚拟多态性。在这种情况下,将创建一个基类:

struct INode {
  virtual ~INode() {}
};
并将常见操作添加到其中,使这些常见操作完全虚拟:

struct INode {
  virtual ~INode() {}
  virtual std::vector<INode*> GetChildren() const = 0;
};
这里使用
std::visit
操作具体类型,而不是
dynamic\u cast
,并且解析树基于值而不是基于指针

当您希望一个节点内部有一个
AnyNode
的向量时,会有一些麻烦


第三种方法是
std::function
类型擦除样式。在这里,您可以编写自己的多态系统,它接受任意类型的对象,并将它们的操作封装在值语义包装器中


第四种选择是CRTP静态多态性。这不适合构建动态解析树,但可以用来帮助实现上面的一些功能


第五个选项是面向方面的
std::function
操作包


第六个选项是手动函数表调整,基本上重新实现C++ VTHT解决方案,就像你在C中,但是在C++中。这可以允许您拥有类似于其他OO语言的特性


第七个选项是编写一个信号槽系统并向对象发送消息


几乎可以肯定还有更多


最简单的解决方法可能是首先学习C++中的继承和虚函数(上面的第一个选项)。我个人可能会在这个时候使用<代码> STD::变体编写一个解析树,但是如果你在这一点上还不知道足够的C++来实际操作。

你所寻找的是多态性。也就是说,程序员编写的代码,并根据其操作的对象类型执行不同的操作

C++支持一系列令人困惑的多态性实现方法

最受支持的类型是基于继承的虚拟多态性。在这种情况下,将创建一个基类:

struct INode {
  virtual ~INode() {}
};
并将常见操作添加到其中,使这些常见操作完全虚拟:

struct INode {
  virtual ~INode() {}
  virtual std::vector<INode*> GetChildren() const = 0;
};
这里使用
std::visit
操作具体类型,而不是
dynamic\u cast
,并且解析树基于值而不是基于指针

当您希望一个节点内部有一个
AnyNode
的向量时,会有一些麻烦


第三种方法是
std::function
类型擦除样式。在这里,您可以编写自己的多态系统,它接受任意类型的对象,并将它们的操作封装在值语义包装器中


第四种选择是CRTP静态多态性。这不适合构建动态解析树,但可以用来帮助实现上面的一些功能


第五个选项是面向方面的
std::function
操作包


第六个选项是手动函数表调整,基本上重新实现C++ VTHT解决方案,就像你在C中,但是在C++中。这可以允许您拥有类似于其他OO语言的特性


第七个选项是编写一个信号槽系统并向对象发送消息


几乎可以肯定还有更多


最简单的解决方法可能是首先学习C++中的继承和虚函数(上面的第一个选项)。我个人可能会在下面使用“代码> STD::变体< /Cuff>”来分析语法树,但是如果你在这一点上还不知道足够的C++来实际操作。

看看它,如果你添加一个示例代码,会很有帮助,因为我不是那个高级C++程序员。@ vector然后做一个简单的例子,实际上,std::variant很容易理解,但我认为我使用继承和动态转换所做的并不令人满意。请在你的答案中添加一个示例代码。如果你添加一个示例代码,这将是非常有用的,因为我不是那个高级C++程序员。@ vector然后做一个简单的例子,继承和虚拟函数和动态的铸造。