【CSharp Roslyn教程】【其二】语法、语义、工作空间

Overview

这篇讲一些后面代码使用里会遇到的一些基本概念。对应这三篇文章:

  1. https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/work-with-syntax
  2. https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/work-with-semantics
  3. https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/work-with-workspace

语法

Roslyn会生成一种叫做「语法树」的基础数据结构,语法树代表了源代码的词法和句法。

语法树 SyntaxTree

语法树可以理解是关于某份源代码树状的语法描述。

语法树有三个属性:

  1. 语法树一个不落的保存了源代码里所有的语法内容
  2. 从被分析出来的每个语法节点,都可以获取到(还原出)其所在的片段里的源代码内容。这意味着你可以修改某个节点之后重新输出新版本的代码
  3. 语法树在生成之后,它就是一份快照了,其内容不会随着代码的改变而改变,它是immutable(一成不变的)和线程安全的。用户没有办法直接改变语法树的内容,假若用户改变了某个节点,Roslyn中的工厂方法会帮忙生成一个改变后的语法树,不会影响原有的语法树。也就是说即使有多个线程一起在处理同一个语法树,也不会有任何危险。

每棵语法树都是由节点、token和trivia组成的。

语法节点 SyntaxNode

语法节点是语法书中最主要的元素之一。语法节点代表了各种语法结构,比如定义declarations、声明statements、子句clauses、表达式expressions。每种结构所对应的语法节点都继承于基类Microsoft.CodeAnalysis.SyntaxNode。用户不可以往这些节点构成的集合里再添加其他任何自定义的节点(也就是节点也就这么多了)。

任何一个语法节点一定会有一个子节点列表(SyntaxNode.ChildNodes()),以及一个父节点(root的父节点是null)。由于语法树是只读的,所以父节点也是不会变的。我们可以通过SyntaxNode.Parent来访问父节点。

此外,每个语法节点子类通过强类型属性公开所有相同的子级。 例如,BinaryExpressionSyntax 节点类具有三个特定于二元运算符的其他属性:Left、OperatorToken 和 Right。 Right 和 ExpressionSyntax 的类型为 Left,OperatorToken 的类型为 SyntaxToken。

某些语法节点具有可选子级。 例如,IfStatementSyntax 具有可选的 ElseClauseSyntax。 如果没有子级,则该属性返回 null。

语法标记 SyntaxToken

语法标记是语言语法的终端,表示代码的最小语法片段。 它们从不作为其他节点或标记的父级。 语法标记包含关键字、标识符、文本和标点。

语法节点必定有父节点和子节点,语法标记是语法树的终端,相当于叶子。

所有类型的标记都采用同一结构,但包含各种属性,这些属性的意义取决于表示的标记类型。

包含Value属性,这个属性是Object类型的,因为它可能是各种基元类型。

关于语法的其他琐事 SyntaxTrivia

表示对正常理解代码基本上没有意义的源文本部分,例如空格、注释和预处理器指令。

可通过检查标记的 SyntaxToken.LeadingTrivia 或 SyntaxToken.TrailingTrivia 集合来访问琐碎内容。

可使用 SyntaxTrivia.Token 属性访问关联的标记。

范围 Spans

每个节点具有两个 TextSpan 属性:Span 和 FullSpan。

Span 属性表示从节点子树中第一个标记的开头到最后一个标记末尾的文本范围。 此范围不包括任何前导或尾随琐碎内容。

FullSpan 属性表示的文本范围包括节点的正常范围,加上任何前导或尾随琐碎内容的范围。

种类 Kinds

每个节点、标记或琐碎内容都具有 System.Int32 类型的 SyntaxNode.RawKind 属性,标识所表示的确切语法元素。 此值可强制转换为特定语言枚举;每种语言(C# 或 VB)都具有单个 SyntaxKind 枚举(分别为 Microsoft.CodeAnalysis.CSharp.SyntaxKind 和 Microsoft.CodeAnalysis.VisualBasic.SyntaxKind),列出了语法中所有可能的节点、标记和琐碎内容。 可通过访问 CSharpExtensions.Kind 或 VisualBasicExtensions.Kind 扩展方法自动完成此转换。

错误 Errors

即使源文本中包含语法错误,也会公开可与源双向转换的完整语法树。

语义

语法树表示源代码的词法和语法结构。 尽管此信息已足以描述源中的所有声明和逻辑,但不足以识别正在引用的内容。 一个名称可能表示:

  • 一种类型
  • 一个字段
  • 一种方法
  • 一个局部变量

尽管以上每一项都各不相同,但要确定标识符实际上引用哪一项,通常需要深入了解语言规则。

工作空间

Buy Me A Coffee / 捐一杯咖啡的钱
分享这篇文章~
0%
//