以 Golang 为例详解 AST 抽象语法树

这篇具有很好参考价值的文章主要介绍了以 Golang 为例详解 AST 抽象语法树。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

各位同行有没有想过一件事,一个程序文件,比如 hello.go 是如何被编译器理解的,平常在编写程序时,IDE 又是如何提供代码提示的。在这奥妙无穷的背后, AST(Abstract Syntax Tree)抽象语法树功不可没,他站在每一行程序的身后,默默无闻的工作,为繁荣的互联网世界立下了汗马功劳。

AST 抽象语法树

AST 使用树状结构来表达编程语言的结构,树中的每一个节点都表示源码中的一个结构。听到这或许你的心里会咯噔一下,其实说通俗一点,在源代码解析后会得到一串数据,这个数据自然的呈现树状结构,它被称之为 CST(Concrete Syntax Tree) 具体语法树,在 CST 的基础上保留核心结构。忽略一些不重要的结构,比如标点符号,空白符,括号等,就得到了 AST。

如何生成 AST 

生成 AST 大概需要两个步骤,词法分析lexical analysis和语法分析syntactic analysis 。

词法分析 lexical analysis

lexical analysis 简称 lexer ,它表示字符串序列,也就是我们的源代码转化为 token 的过程,进行词法分析的工具叫做词法分析器(lexical analyzer,简称lexer),也叫扫描器(scanner)。Go 语言的 go/scanner 包提供词法分析。 

func ScannerDemo() {
	// 源代码
	src := []byte(`
func demo() {
	fmt.Println("When you are old and gray and full of sleep")
}
`)

	// 初始化标记
	var s scanner.Scanner
	fset := token.NewFileSet()
	file := fset.AddFile("", fset.Base(), len(src))
	s.Init(file, src, nil, scanner.ScanComments)

	// Scan 进行扫码并打印出结果
	for {
		pos, tok, lit := s.Scan()
		if tok == token.EOF {
			break
		}
		fmt.Printf("%s\t%s\t%q\n", fset.Position(pos), tok, lit)
	}
}

打印的结果我们接着往下看。

标记 token

标记(token)  是词法分析后留下的产物,是构成源代码的最小单位,但是这些 token 之间没有任何逻辑关系。以上述代码为例:

func demo() {
	fmt.Println("When you are old and gray and full of sleep")
}

经过词法分析后,会得到:

token literal(字面量,以string表示)
func "func"
IDENT "demo"
( ""
) ""
{ ""
IDENT "fmt"
. ""
IDENT "Println"
( ""
STRING "\"When you are old and gray and full of sleep\""
) ""
; "\n"
} ""
; "\n"

在 Go 语言中,如果 token 类型就是一个字面量,例如整型,字符串类型等,那么它的值就是相对应的值,比如上表的 STRING;如果 token 是 Go 的关键词,那么它的值就是关键词,比如上表的 fun;对于分号,它的值则是换行符;其他 token 类要么是不合法的,如果是合法的,则值为空字符串,比如上表的 {

语法分析 syntactic analysis

不具备逻辑关系的 token 经过语法分析(syntactic analysis,也叫 parsing)就可以得到具有逻辑关系的 CST 具体语法树,然后对 CST 进行分析提炼即可得到 AST 抽象语法树。完成语法分析的工具叫做语法分析器(parser)。Go 语言的 go/parser 提供语法分析。

func ParserDemo() {
	src := `
package main
`
	fset := token.NewFileSet()
	// 如果 src 为 nil,则使用第二个参数,它可以是一个 .go 文件地址
	f, err := parser.ParseFile(fset, "", src, 0)
	if err != nil {
		panic(err)
	}

	ast.Print(fset, f)
}

打印出来的 AST:

 0  *ast.File {
 1  .  Package: 2:1
 2  .  Name: *ast.Ident {
 3  .  .  NamePos: 2:9
 4  .  .  Name: "main"
 5  .  }
 6  .  FileStart: 1:1
 7  .  FileEnd: 2:14
 8  .  Scope: *ast.Scope {
 9  .  .  Objects: map[string]*ast.Object (len = 0) {}
10  .  }
11  }

它包含了源代码的结构信息,看起来像一个 JSON。

总结

源代码经过词法分析后得到 token(标记),token 经过语法分析得到 CST 具体语法树,在 CST 上创建 AST 抽象语法树。 来个图图或许更直观:

Go 的抽象语法树

这里我们以一个具体的例子来看:从 go 代码中提取所有结构体的名称。文章来源地址https://www.toymoban.com/news/detail-794567.html

// 源码
type A struct{}
type B struct{}
type C struct{}
func ExampleGetStructName() {
	fileSet := token.NewFileSet()
	node, err := parser.ParseFile(fileSet, "demo.go", nil, parser.ParseComments)
	if err != nil {
		return
	}

	ast.Inspect(node, func(n ast.Node) bool {
		if v, ok := n.(*ast.TypeSpec); ok {
			fmt.Println(v.Name.Name)
		}
		return true
	})
	// Output:
	// A
	// B
	// C
}

到了这里,关于以 Golang 为例详解 AST 抽象语法树的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 《golang设计模式》第一部分·创建型模式-04-抽象工厂模式(Abstract Factory)

    在不具体指定产品类的情况下,为相互关联的产品簇或产品集提供创建接口,并向客户隐藏具体产品创建的细节或表示的对象。 AbstractFactory(抽象工厂):它声明了一组用于创建产品的方法,每一个方法对应一种产品。 ConcreteFactory(具体工厂):它实现了在抽象工厂中声明

    2024年02月14日
    浏览(43)
  • 【Golang】一文学完 Golang 基本语法

    安装包链接:https://share.weiyun.com/InsZoHHu IDE 下载:https://www.jetbrains.com/go/ 每个可执行代码都必须包含 Package、import 以及 function 这三个要素。 主函数文件: package1 包的文件: 注意:golang是 以首字母大小写 来区分对包外是否可见。 所以 Fun() 函数,Str,想要在 main 文件被访问,

    2024年02月13日
    浏览(40)
  • 【GoLang】基础语法(上)

    注释主要的功能就是为了增强代码的可读性,不参与程序的一切功能 ,G0语言的注释主要分成两类: 单行注释 多行注释 写注释是一个十分良好的习惯,我们都应该按照要求给自己代码写好注释,为了自己,也为了他人。很多大公司里也是对注释有严格要求的。 搞清楚注释之

    2024年02月15日
    浏览(37)
  • Golang基本语法(上)

    1. 变量与常量 Golang 中的标识符与 标识符 Go语言中标识符由字母数字和 _ (下划线)组成,并且只能以字母和 _ 开头。 举几个例子: abc , _ , _123 , a123 。 和保留字都不建议用作变量名: Go语言中有 25 个 。 此外,还有 37 个 保留字 。 Golang 中的变量

    2024年02月12日
    浏览(33)
  • 细说golang语法糖

    Go语言(通常称为Golang)以其简洁性和高效性而闻名,这部分得益于其语言设计中包含的“语法糖”。语法糖(syntactic sugar)是指在编程语言中添加的某些语法特性,它们使得代码更易读和编写,而不改变程序的实际执行逻辑。以下是Go语言中的一些语法糖: 类型推断 : Go语

    2024年04月10日
    浏览(61)
  • Golang常用语法糖

    语法糖(Syntactic sugar)的概念是由英国计算机科学家彼得·兰丁提出的,用于表示编程语言中的某种类型的语法,这些语法不会影响功能,但使用起来却很方便。 语法糖,也称糖语法,这些语法不仅不会影响功能, 编译后的结果跟不使用语法糖也一样。 语法糖,有可能让代

    2024年02月04日
    浏览(24)
  • LL(1)语法分析设计原理与实现——以赋值语句为例

    一、实验目的 语法分析的设计方法和实现原理;LL(1)分析表的构造;LL(1)分析过程;LL(1)分析器 的构造; 二、实验内容 实现 LL(1)分析中控制程序(表驱动程序);完成以下描述赋值语句的 LL(1) 文法的 LL(1)分析过程。 G[S]:S→V=E E→TE′ E′→ATE′|ε T→FT′ T′→MFT′|ε F→

    2024年02月03日
    浏览(49)
  • Golang之路---02 基础语法——字典

    字典(Map 类型),是由若干个 key:value 这样的键值对映射组合在一起的数据结构。 key 不能是切片,不能是字典,不能是函数。 字典初始化 方式:map[KEY_TYPE]VALUE_TYPE 字典的相关操作 嵌套字典 判断key是否存在 当key不存在,会返回value-type的零值 ,所以你不能通过返回的结果是

    2024年02月15日
    浏览(54)
  • 【LeetCode题目详解】1281题 整数的各位积和之差 面试题 01.01. 判定字符是否唯一 python题解(作业一二)

    问题描述: 1281. 整数的各位积和之差 给你一个整数 n,请你帮忙计算并返回该整数「各位数字之积」与「各位数字之和」的差。 示例 1: 输入:n = 234 输出:15 解释: 各位数之积 = 2 * 3 * 4 = 24 各位数之和 = 2 + 3 + 4 = 9 结果 = 24 - 9 = 15 示例 2: 输入:n = 4421 输出:21 解释:

    2024年02月10日
    浏览(48)
  • 【c语言】详解c语言#预处理期过程 | 宏定义前言

    c语言系列专栏: c语言之路重点知识整合   创作不易,本篇文章如果帮助到了你,还请点赞支持一下♡𖥦)!!  主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步! 给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ 代码编译到执

    2024年02月01日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包