C# 如何设计抽象语法树的各个部分?

C# 如何设计抽象语法树的各个部分?,c#,syntax,tree,abstract,C#,Syntax,Tree,Abstract,为了获得学习经验,我正在从头开始编写C#口译员,到目前为止,一切都进展顺利。我有一个功能齐全的C#lexer,可以向解析器输出各种标记。我知道如何解析标记,但我不确定应该如何构造AST(抽象语法树) 例如,如果我有一个简单的代码片段: using System.Xml; 解析树时,树是什么样子的 像这样 UsingDirective Identifier(System) Identifier(Xml) 还是像这样 UsingDirective Identifier(S

为了获得学习经验,我正在从头开始编写C#口译员,到目前为止,一切都进展顺利。我有一个功能齐全的C#lexer,可以向解析器输出各种标记。我知道如何解析标记,但我不确定应该如何构造AST(抽象语法树)

例如,如果我有一个简单的代码片段:

using System.Xml;
解析树时,树是什么样子的

像这样

UsingDirective
   Identifier(System)
      Identifier(Xml)
还是像这样

UsingDirective
   Identifier(System)
   Identifier(Xml)

如果我能得到一些建议和/或示例,比如如何构造带有点的标识符、If/else If/else语句、组合在一条语句中的变量声明/赋值(int I=0;)以及函数定义等,那将非常有用。我只需要更好地了解如何构建这棵树,然后我就能自己解决其余的问题。谢谢。

你可以看看微软是如何与Roslyn合作的。你可以在那里看到他们是如何为C#(和VB.NET)声明语法树的,也许你甚至可以在编写它们之前使用它来代替解释器的部分

具体来说,使用指令的
的Roslyn语法树如下所示:

UsingDirective
    UsingKeyword
    QualifiedName
        IdentifierName (System)
        DotToken
        IdentifierName (Xml)
    SemicolonToken
UsingDirective
   IdentifierList
     Identifier (LeftNode) (System)
     Identifier (RightNode) (Xml)
因此,与您的第二个版本类似,但更详细


我认为你的第一个版本没有多大意义
Xml
在语法层面上不是
System
的子类(即使以后在语义层面上可能会有“父名称空间”的概念)。

我过去写过几个解析器,我通常会这样做:

UsingDirective
    UsingKeyword
    QualifiedName
        IdentifierName (System)
        DotToken
        IdentifierName (Xml)
    SemicolonToken
UsingDirective
   IdentifierList
     Identifier (LeftNode) (System)
     Identifier (RightNode) (Xml)
在这种情况下,
使用System.Collections.Generic

UsingDirective
   IdentifierList
       IdentifierList (LeftNode)
           Identifier (LeftNode) (System)
           Identifier (RightNode) (Collections)
       Identifier (RightNode) (Generic)
与Roslyn不同,我更喜欢通过不包括分号、使用
关键字的
等标记来保持ASTs的轻量级,因为编译器不需要它们


我专门为IDE编写的解析器看起来不一样——它们携带了所有这些额外的东西以及更多的信息,如行号和列号。

如果你想实现所有的C:-,这将是一个漫长的学习经历)好吧,我将省略大部分类库。我基本上只是实现基本类/函数定义、变量创建/使用和函数调用需要实现的内容。但这不是一个抽象语法树,而是一个具体的语法树,因为它包括部分源代码,如点和分号。是的,你是对的。但我认为你可以以此为基础来建立你的AST。你为什么要把你的
身份识别列表
设为只有两个孩子?为什么不让一个
标识列表
包含尽可能多的孩子呢?是的,我认为一个包含无限孩子的标识列表会更好。无论如何,谢谢你的回答,我相信这也行。我个人发现,以这种方式(递归地)遍历它比仅仅是一个标识列表更容易。我将设置一个函数
traverIdentList
如果(identlist.leftnode是identlistnode){traverseIdentList(leftnode);}否则{traverseident(leftnode);}traverseident(rightnode)好的观点。稍后,我将对数学运算符使用递归方法。我无法决定接受哪个答案。它们都是有用的XD。