本文基于Go 1.17
写作
在我们写Go程序时,不需要手动的在行末输入分号,编译器会自动帮你完成这件事,在行末添加分号,那么Go是如何帮你在行末添加分号的呢?
cmd/compile/internal/syntax/parser.go
中有这样一个结构体:
type parser struct {
...
scanner
...
}
parser
是执行语法分析的主体,今天我们的主角是词法分析器,也就是parser
肚子里这个匿名字段:scanner
。
scanner
结构体里存储着我们源代码的原始信息,比如每个源代码字符。同时也储存着词法分析的相关数据,比如当前分析到哪一行,哪一列,当前正在分析的Token是什么。
type scanner struct {
source // 源代码信息存储在这个结构体里
// 当前处理到的Token等
line, col uint
blank bool // line is blank up to col
tok token
lit string // valid if tok is _Name, _Literal, or _Semi ("semicolon", "newline", or "EOF"); may be malformed if bad is true
...
}
scanner
有一系列的方法,其中next
方法使scanner
来读取下一个Token:
func (s *scanner) next() {
...
// 跳过空格
for s.ch == ' ' || s.ch == 't' || s.ch == 'n' && !nlsemi || s.ch == 'r' {
//处理下一个字符
s.nextch()
}
// 处理字母
if isLetter(s.ch) || s.ch >= utf8.RuneSelf && s.atIdentChar(true) {
s.nextch()
s.ident()
return
}
// 处理符号和数字
// 如果当前字符是:
switch s.ch {
// 文件结尾
case -1:
if nlsemi {
s.lit = "EOF"
s.tok = _Semi
break
}
s.tok = _EOF
// 换行符
case 'n':
s.nextch()
s.lit = "newline"
// 设置当前Token为分号
s.tok = _Semi
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
s.number(false)
...
}
如果当前字符是n
(换行符),就设置当前的Token为分号,然后继续处理后面的字符。
在词法分析的过程中,会不断调用next
方法来解析源码中的下一个Token,就像这样:
这是我之前写《自制编程语言》[1]时做的动图,展示了词法分析的过程。
没用的小知识增加了
参考资料
自制编程语言-词法分析: https://mp.weixin.qq.com/s/yLRNbQb0eWc9LhpwfJOJpQ
原文始发于微信公众号(梦真日记):Go编译器小知识:1-Go是如何为行末添加分号的
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/167843.html