C# AST的树结构

C# AST的树结构,c#,.net,tree,abstract-syntax-tree,C#,.net,Tree,Abstract Syntax Tree,我正试图用C语言编写一个解释器,我正处于解析阶段。我发现此时必须生成抽象语法树,但我不知道如何用C表示它 目前我只是使用列表,但我有一种感觉,我做得不对 非常感谢。有很多技术,从单个节点类型(一个带有类型标记的大字段)到特定类的细粒度层次结构。重要的是要考虑如何使遍历代码简单而健壮,因为您将需要反复遍历此数据结构 然而,退一步来说,口译并不严格要求AST。许多早期的解释器在遇到每一行代码时都会逐行阅读,通过基于堆栈的书籍标记系统动态解析和执行代码,并使用循环等方式实现。我怀疑像bash和cmd.

我正试图用C语言编写一个解释器,我正处于解析阶段。我发现此时必须生成抽象语法树,但我不知道如何用C表示它

目前我只是使用列表,但我有一种感觉,我做得不对


非常感谢。

有很多技术,从单个节点类型(一个带有类型标记的大字段)到特定类的细粒度层次结构。重要的是要考虑如何使遍历代码简单而健壮,因为您将需要反复遍历此数据结构


然而,退一步来说,口译并不严格要求AST。许多早期的解释器在遇到每一行代码时都会逐行阅读,通过基于堆栈的书籍标记系统动态解析和执行代码,并使用循环等方式实现。我怀疑像bash和cmd.exe这样的shell语言今天仍然是这样工作的。

大多数AST节点实现都非常简单

它们是一个结构ok,ok,类,包含一个节点类型,通常是一个整数,子列表是ok;高性能实现具有一组用于统计上常见的第1、第2、第3子级的成员,以及一些附加字段,以携带特定于AST节点实例的值,例如,AST节点整数常量的值5。为了有效地将树从任何节点导航回父节点,通常会有一个返回父节点的特殊引用

更难的是决定应该拥有哪一组AST节点。对于一个大型语法,这是不方便的,因为您必须定义一组几百个语法,并且当您试图修改语法以使其正确时,会出现混乱

一个简单的技巧是只需为每个语法规则定义一个AST节点。这被大多数人称为具体的语法树。但它是无脑的,你不会错过任何东西

我们的方法遵循这个简单的技巧,直接从语法规则生成AST节点类型。它还优化了:树中不存在不带值的叶AST节点,树中不存在一元生成的节点,列表生成的生成具有子节点的列表样式,而其他节点类型具有子节点的固定插槽类型。最终的结果是,不管怎么说,它与抽象语法树非常接近。所有这些都是由DMS的解析器生成器自动构造的,所以您根本不需要思考


DMS还有一个完整的、经过良好测试的C4.0前端。一旦你摆脱了定义AST的麻烦,你就会想从中分析/转换/生成,DMS的其余部分就会突然变得很有价值。

我建议你继续使用列表,直到你清楚地了解这会带来什么限制以及你的需求。或者,因为您正在编写一个LISP解释器,所以创建一个pair类并将其与object一起使用,null相当于':


将您的输入直接解析为S表达式,并让您的解释器直接使用它。毕竟,LISP在ASTs之前就存在了

有没有具体的问题?编写AST并不是一个小问题……看看System.Linq.Expressions.*,它可能会告诉您正确的数据结构是满足您需要的。一旦你有了AST,你打算用它做什么?您预计需要执行什么样的操作?@abatishchev-hi,这个简单的例子可能有助于您理解。它不是一种完整的语言,而是一种表达式计算器;无论如何,它使用了一个扫描器/词法分析器和一个解析器:我明白你的意思。但是在内存中使用AST是非常灵活的:例如,我可以稍后添加JIT。我正在尝试编写一个LISP解释器,如果它matters@Oleg:我当然不推荐即时口译方法。我刚才提到这是一种选择。对于一个固定类型系统,比如Lisp,我会选择基类中带有类型标记的单级层次结构,这样您就可以使用快速切换语句而不是测试类型。还要注意的是,程序和程序中的数据可以用相同的数据结构表示,因为该语言是同源的。Sexps有时被用作AST本身。
public sealed class Pair
{
    public object Car ;
    public object Cdr ;
}