我正在尝试用C#编写一个解释器,我正处于解析阶段。我想我此时必须生成抽象语法树,但我不知道如何在C#中表示它。
目前我只使用List<object>
,但我觉得我做错了。
非常感谢。
答案 0 :(得分:2)
有许多技术,从单个“节点”类型 - 具有“类型”标记的大桶字段 - 到特定类的细粒度层次结构。重要的是要考虑如何使遍历代码简单而健壮,因为您需要反复遍历此数据结构。
然而,退一步,解释并不严格要求AST。许多早期的解释器在他们遇到代码时会完全阅读每行代码,通过基于堆栈的书籍标记系统实现动态解析和执行,循环等。我怀疑像bash和cmd.exe这样的shell语言今天仍然像这样工作。
答案 1 :(得分:2)
我建议您继续使用List<object>
,直到您清楚地了解这种限制以及您的要求是什么。或者,既然您正在编写LISP解释器,请创建一个对类,并将其与object
一起使用,null
等同于'()
:
public sealed class Pair
{
public object Car ;
public object Cdr ;
}
将您的输入直接解析为S表达式,并让您的解释器直接使用它。毕竟,LISP存在于AST之前!
答案 2 :(得分:1)
大多数AST节点实现都非常简单。
它们是一个结构(ok,ok,“class”),包含一个节点类型(通常是一个整数),一个子列表(List是正常的;高性能实现有一组成员用于统计上常见的1st,2nd,第3个子节点,以及一些附加字段,用于携带特定于AST节点实例的值(例如,AST节点的值“5”“整数常量”)。为了实现从任何节点到父节点的树的有效导航,通常会有一个特殊的引用返回到父节点。
决定你应该拥有哪些 AST节点的难度更大。对于一个大的语法,这是不方便的,因为你将不得不定义一组数百个,并且在你尝试正确的时候修改语法会有流失。
一个简单的技巧就是根据语法规则定义一个AST节点。 (大多数人称之为“具体语法树”)。但它没脑子,你不会错过任何东西。
我们DMS Software Reengineering Toolkit遵循这个“简单技巧”的想法,从语法规则中直接生成AST节点类型。它还优化了:树中没有携带值的AST节点不存在于树中,一元产生的节点不存在于树中,而列表形成产生具有子类型的List样式,而其他节点类型具有儿童的固定插槽类型。最终的结果是你无论如何都非常接近“抽象”语法树。所有这些都是由DMS的解析器生成器自动构建的,因此您根本就没有想到。
DMS还有一个完整的,经过良好测试的C#4.0前端。一旦你解决了定义AST的麻烦,你就会想要从中分析/转换/生成,其余的DMS突然变得显而易见。