Go 学习笔记-Go 词法解析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: Go 学习笔记-Go 词法解析

对于 go 语言源代码可以看做是一个很长的字符串,GO 编译器是如何识别出这个长字符串里边哪些是变量?哪些是赋值语句?哪些是函数?基本解决思路就是使用正则表达式对字符串进行分割,找到对应的标识,可以将这种标识转化为 token,将 go 源代码扫描找出所有 token 的过程称为词法分析。

1.正则表达式举例

对于一个正则表达式 (a|b)*abb,应该如何判断一个字符串对于该正则表达式满足呢?例如:

abb
aabb
babb
aababb
//肉眼可以看出上面字符串是符合上述正则表达式的
a
ab
bb
acabb
//肉眼可以看出上面字符串是不符合上述正则表达式的
abbaabbbaaabbbababaaababb
//对于很长的字符串是否满足上述正则表达式,需要使用程序代码来实现,如何实现一个正则匹配的算法呢?

2.不确定有穷自动机(NFA)

对于一个正则表达式 (a|b)*abb,其对应的 NFA 对应如下:

这个自动机包含 4 个状态,其中 0、1、2 这 3 种状态用一个圈表示中间状态,3 是双圈表示状态机的结束,箭头和字母表示每个状态遇到不同输入迁移到另一个状态,可以用上述例子走一下该自动机,比如字符串 abb,初始状态 0,遇到 a,迁移到 1,状态 1 遇到 b,迁移到 2,状态 2 遇到 b,迁移到 3,状态 3 是结束状态,所以 abb 是满足正则表达式。对于 字符串 ab 最终状态是 2,不是结束状态,不满足正则表达式。但该有穷自动机有一个缺陷,就是状态 0 遇到 a,有可能迁移到状态 1,也有可能迁移到到本身状态 0,所以这里是不确定的有穷自动机,这就导致可能满足表达式的字符串,最终状态并没有到结束状态。

3.确定有穷自动机(DFA)

DFA 和 NFA 不同的是,对于每一个状态遇到的输入都有确定下一个状态,可以使用 re2c 这种工具帮助我们生成正则表达式对应的有穷自动机程序代码。

4.用 re2c 做词法解析

re2c 官网中介绍 go 词法解析的地址是 re2c官网,使用 git 命令可下载 re2c 源码包:

git clone https://github.com/skvadrik/re2c.git
git clone https://git.code.sf.net/p/re2c/code-git

如果是 mac 电脑需要先使用 brew install automake 命令安装 automake, 下载后进入到 re2c 的源码目录下包下执行如下命令就可生成 configure 文件:

进入到 re2c 目录下执行 ./configure && make && make install 命令即可开始编译 re2c :

编译安装完之后,执行 re2c 命令出现如下图所示内容表示安装成功:

提示需要指定源文件,这里编辑一个 t.go 文件,用于判断某个字符是不是二进制数,编辑内容如下:

//go:generate re2go $INPUT -o $OUTPUT -i
package main
func lex(str string) {
    var cursor int
    /*!re2c
      re2c:define:YYCTYPE = char;
      re2c:yyfill:enable = 0;
      end = "\x00";
      bin = '0b'[01]+;
      * { return ERR; }
      bin end { return BIN; }
    */
}
func main() {
    lex("0b1")
}

上面 /*!re2c*/ 之间的内容可以理解为词法解析的正则表达式,这里可以根据自己的需要自己编写正则表达式,re2c 代码库会帮我们生成有限自动机程序代码,然后使用 re2c t.go 命令,可生成与之对应的有限自动机:

生成的与之对应的有限自动机(DFA)程序代码如下:

/* Generated by re2c 2.2 on Thu Oct 21 00:13:40 2021 */
#line 1 "t.go"
//go:generate re2go $INPUT -o $OUTPUT -i
package main
func lex(str string) {
    var cursor int
#line 12 "<stdout>"
{
    char yych;
    yych = *YYCURSOR;
    switch (yych) {
    case '0':    goto yy4;
    default:    goto yy2;
    }
yy2:
    ++YYCURSOR;
yy3:
#line 13 "t.go"
    { return ERR; }
#line 25 "<stdout>"
yy4:
    yych = *(YYMARKER = ++YYCURSOR);
    switch (yych) {
    case 'B':
    case 'b':    goto yy5;
    default:    goto yy3;
    }
yy5:
    yych = *++YYCURSOR;
    if (yych >= 0x01) goto yy8;
yy6:
    YYCURSOR = YYMARKER;
    goto yy3;
yy7:
    yych = *++YYCURSOR;
yy8:
    switch (yych) {
    case 0x00:    goto yy9;
    case '0':
    case '1':    goto yy7;
    default:    goto yy6;
    }
yy9:
    ++YYCURSOR;
#line 14 "t.go"
    { return BIN; }
#line 52 "<stdout>"
}
#line 15 "t.go"
}
func main() {
    lex("0b1")
}

对应的有限自动机图如下图:

5.go 词法解析demo

package main
import (
 "fmt"
 "go/scanner"
 "go/token"
)
func main()  {
 src := []byte("cos(x) + 2i*sin(x) //Euler")
 //初始化 scanner
 var s scanner.Scanner
 fset := token.NewFileSet()
 file := fset.AddFile("",fset.Base(),len(src))
 s.Init(file,src,nil,scanner.ScanComments)
 //扫描
 for  {
  pos,tok,lit := s.Scan()
  if tok == token.EOF{
   break
  }
  fmt.Println("%s\t%s\t%q\n",fset.Position(pos),tok,lit)
 }
}

其中字符串 “cos(x) + 2i*sin(x) //Euler” 可以理解为源代码,输出结果就是将其词法解析,然后 token 化,至此词法解析已经简单实现:

源代码 token 化后,就可进行语法解析,后面将继续介绍语法解析和抽象语法树构建。

目录
打赏
0
0
0
0
1
分享
相关文章
🚀 力扣热题 394:字符串解码(详细解析)(Go语言版)
文章提供了两种解法:栈结构和递归解法。栈解法通过维护数字栈与字符串栈,依次处理 `[` 和 `]`,构造解码结果;递归解法则利用函数调用逐层解析嵌套结构。两者时间复杂度均为 $O(n)$,空间复杂度也为 $O(n)$。栈解法直观易懂,适合初学者;递归解法优雅简洁,适合处理深度嵌套规则。掌握这两种方法,可灵活应对类似问题,提升解题能力。
25 11
探秘员工泄密行为防线:基于Go语言的布隆过滤器算法解析
在信息爆炸时代,员工泄密行为对企业构成重大威胁。本文聚焦布隆过滤器(Bloom Filter)这一高效数据结构,结合Go语言实现算法,帮助企业识别和预防泄密风险。通过构建正常操作“指纹库”,实时监测员工操作,快速筛查可疑行为。示例代码展示了如何利用布隆过滤器检测异常操作,并提出优化建议,如调整参数、结合日志分析系统等,全方位筑牢企业信息安全防线,守护核心竞争力。
基于 Go 语言的公司内网管理软件哈希表算法深度解析与研究
在数字化办公中,公司内网管理软件通过哈希表算法保障信息安全与高效管理。哈希表基于键值对存储和查找,如用户登录验证、设备信息管理和文件权限控制等场景,Go语言实现的哈希表能快速验证用户信息,提升管理效率,确保网络稳定运行。
30 0
|
4月前
|
Go语言中的加解密利器:go-crypto库全解析
在软件开发中,数据安全和隐私保护至关重要。`go-crypto` 是一个专为 Golang 设计的加密解密工具库,支持 AES 和 RSA 等加密算法,帮助开发者轻松实现数据的加密和解密,保障数据传输和存储的安全性。本文将详细介绍 `go-crypto` 的安装、特性及应用实例。
237 0
Go语言中的并发编程模型解析####
在当今的软件开发领域,高效的并发处理能力是提升系统性能的关键。本文深入探讨了Go语言独特的并发编程模型——goroutines和channels,通过实例解析其工作原理、优势及最佳实践,旨在为开发者提供实用的Go语言并发编程指南。 ####
|
4月前
|
Go
Go语言的条件控制语句及循环语句的学习笔记
本文是Go语言的条件控制语句和循环语句的学习笔记,涵盖了if语句、if-else语句、if嵌套语句、switch语句、select语句以及for循环和相关循环控制语句的使用方法。
Go语言的条件控制语句及循环语句的学习笔记
Go: struct 结构体类型和指针【学习笔记记录】
本文是Go语言中struct结构体类型和指针的学习笔记,包括结构体的定义、成员访问、使用匿名字段,以及指针变量的声明使用、指针数组定义使用和函数传参修改值的方法。
Golang学习笔记之方法(method)
原文作者:学生黄哲链接:https://www.jianshu.com/p/6e615b08cfaf來源:简书简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。 ⽅法总是绑定对象实例,并隐式将实例作为第⼀实参 (receiver)。
1430 0
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等