教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 修改Go语言(golang)编译器源代码让它支持UTF-8 BOM

修改Go语言(golang)编译器源代码让它支持UTF-8 BOM

发布时间:2022-02-04   编辑:jiaochengji.com
教程集为您提供修改Go语言(golang)编译器源代码让它支持UTF-8 BOM等资源,欢迎您收藏本站,我们将为您提供最新的修改Go语言(golang)编译器源代码让它支持UTF-8 BOM资源

  Go语言(golang)第一个正式版Go1发布了,但是这个新兴的编程语言还是非常不完善。这不,我(Liigo)又发现它的编译器竟然不支持编译带BOM的UTF-8编码的.go源文件。这就很奇怪,该语言明明要求源代码文件.go必须是UTF-8编码,但有不允许带UTF-8 BOM。要知道,这个世界上带BOM的文件太多了,很多文本编辑器/代码编辑器/IDE都会默认生成带有BOM的UTF-8文件。如果仅仅因为源代码文件多了BOM,编译器将不能编译这个文件,我觉得它太低能了。

Go语言编译器(gc)不支持带有BOM的UTF-8源文件
Golang's compiler (gc) don't accept the .go files with UTF-8 BOM: 

<pre><code>E:\liigo\golang\src>go run hello.go package : hello.go:1:1: illegal character U FEFF E:\liigo\golang\src>go run hello.go # command-line-arguments .\hello.go:9: illegal UTF-8 sequence ce d2</code></pre>

  好在Go语言是开源项目,我(Liigo)来贡献代码,让它支持编译带UTF-8 BOM的.go源代码文件。经过分析后发现,Go语言编译器(gc)源代码中有两处地方涉及从磁盘文件中读取.go文件:一个是C语言写的词法分析器(src/cmd/gc/lex.c),一个是Go语言写的.go文件解析器(src/pkg/go/parser/interface.go)。解决思路也很简单,就是从磁盘读取文件内容后,判断前三个字节,与UTF-8 BOM的三个字节(0xef, 0xbb, 0xbf)核对,如果一致则忽略这三个字节,从第四个字节算作文件的真正内容,然后再交给词法分析器和解析器处理,后面就一切正常了。

  Go语言的词法分析器是用C语言手工编写的,其中用到了lib9/libbio库,是一个磁盘文件读写缓冲区,逐字节读取该缓冲区时,它可以做到“反读取”最近的4个字节,就是说,假设我刚刚读取了abcd是个字节,现在我“反读取”后两个字节,实际上就相当于我刚刚读取了ab还没有读取cd。利用它的这个“凡读取”机制,恰恰可以很容易的忽略掉UTF-8文件最前面的BOM:首先读出前三个字节,如果这三个字节正好是UTF-8 BOM的三个字节(0xef, 0xbb, 0xbf),那么直接把刚刚读出的三个字节扔掉就完事了,后面词法分析器处理时正好从BOM后面的字节开始读取;如果已经读出的三个字节不是UTF-8 BOM呢,需要“反读取”,即把他们再放回去,就当作我没有读取过它们。修改后的代码如下:

<pre><code>// src/cmd/gc/lex.c : </code></pre><pre><code> 319 // Try to read and ignore UTF-8 BOM 320 c1 = Bgetc(curio.bin); 321 c2 = Bgetc(curio.bin); 322 c3 = Bgetc(curio.bin); 323 if(c1 != 0xef || c2 != 0xbb || c3 != 0xbf) { 324 // If not UTF-8 BOM, restore the bytes. 325 // Bungetsize > 3, so we can safely call Bungetc() 3 times. 326 Bungetc(curio.bin); 327 Bungetc(curio.bin); 328 Bungetc(curio.bin); 329 }</code></pre>

  Go语言的源代码解析器(pkg/go/parser)是用Go语言自己编写的,其功能是解析.go源代码文件为语法树。Go语言官方提供的go build命令用pkg/go/parser分析处理编译前的库依赖项。go build命令(pkg/go/parser)是把.go文件整个读入内存后再解析的。我要做的工作就是,在pkg/go/parser开始正式解析前,把前面可能存在的UTF-8 BOM删除掉即可,这个工作仅仅涉及Go语言中byte slice的基本操作,是很轻量级的廉价操作。

<pre><code>// src/pkg/go/parser/interface.go : </code></pre><pre><code> // The data read from .go files maybe start with the UTF-8 BOM(byte order mark), // we ignore the bytes here to make sure that the parser parses properly. // func ignoreUTF8BOM(data []byte) []byte { if data == nil { return nil } if len(data) >= 3 && data[0] == 0xef && data[1] == 0xbb && data[2] == 0xbf { return data[3:] } return data } // If src != nil, readSource converts src to a []byte if possible; // otherwise it returns an error. If src == nil, readSource returns // the result of reading the file specified by filename. @@ -27,22 40,23 @@ case string: return []byte(s), nil case []byte: - return s, nil return ignoreUTF8BOM(s), nil case *bytes.Buffer: // is io.Reader, but src is already available in []byte form if s != nil { - return s.Bytes(), nil return ignoreUTF8BOM(s.Bytes()), nil } case io.Reader: var buf bytes.Buffer if _, err := io.Copy(&buf, s); err != nil { return nil, err } - return buf.Bytes(), nil return ignoreUTF8BOM(buf.Bytes()), nil } return nil, errors.New("invalid source") } - return ioutil.ReadFile(filename) fileData, err := ioutil.ReadFile(filename) return ignoreUTF8BOM(fileData), err }</code></pre>


  我把上面修改的代码提交到Go语言官方源码库,代码审查页面地址是: http://codereview.appspot.com/6036054/, 或 http://codereview.appsp0t.com/6036054/。

  但是Go语言的作者/官方开发者拒绝这一改进。Go开发组老大Rob Pike亲自回复给出就拒绝的理由:

<pre><code>Strictly speaking, a BOM is legal in UTF-8 but only as a marker for the type of the data stream, a magic number if you will. Since Go source code is required to be UTF-8, a BOM is never necessary and arguably erroneous. We've come this far without accepting BOMS and I'd like to keep it that way.</code></pre>

  在我看来,理由非常勉强,在逻辑上甚至都不成立。哦,既然规定了.go必须使用UTF-8编码,所以就一定不能加UTF-8 BOM了?加了BOM就拒不接收了?前面已经说过了,很多文本编辑器都会自动添加UTF-8 BOM的,怎么到你这里就不合法了。一个很现实的例子是,Windows XP / Windows 7系统内置的“记事本”程序(notepad.exe)在保存UTF-8文件时是一定会自动添加UTF-8 BOM的。也就是说,你想用记事本保存的.go源代码是一定不能编译通过的。但就是这么严重的问题,Go作者们就是不当一回事;这么容易就可以改进的问题,他们就是拒绝改进。生生的为用户使用go语言又凭空制造一道阻力。要说是面临技术方案的妥协选择折中还可以理解,偏偏要在无关紧要的地方坚持己见宁死不去考虑方便用户。我只能说他们是死脑筋。类似的情况我遇到也不止一次了,总结下来就是:<span style="color: rgb(255, 0, 0);">技术大牛挂帅做产品害人害己</span>;闭门造车的代价是死都不知道咋死的。(这样的总结也为我们做易语言产品敲响了警钟:绝对不能单纯以技术人员的心态做产品。)


---------------------------------------------------------------------------------------------------


2013-7-15 Liigo 补记

<span style="color: rgb(255, 0, 0);">2013年5月13日发布的 golang 1.1 终于支持带UTF-8 BOM的源代码文件了</span>:

<pre><code>"The Unicode byte order mark U FEFF, encoded in UTF-8, is now permitted as the first character of a Go source file."</code></pre>

http://golang.org/doc/go1.1#unicode

这一日,距离Go语言开发组老大Rob Pike拒绝UTF-8 BOM那番话发表(2012-4-17,内容见上文),已过去了一年多,可能他已经忘记了自己说过什么。

而且他们对源代码的修改思路也是跟我一致的(都修改了lex.c同一处;我虽然没有直接修改scanner,但通过修改parser也间接达到了目的):

<span style="color: rgb(0, 0, 0); font-size: 13px;">cc2bca9c03ef by Rob Pike, 2012-9-10: </span><span style="font-size: 14px;">gc: initial BOM is legal</span>

3d58333e8e2a<span style="font-size: 13px;"> by Russ Cox, 2012-10-7: </span><span style="font-size: 14px;">cmd/gc: skip over reported BOMs</span>

<span style="color: rgb(0, 0, 0); font-size: 13px;"><span style="color: rgb(0, 0, 0);">4245c8cdc599 by <span style="font-size: 14px;">Robert Griesemer, 2012-9-7: </span></span></span><span style="font-size: 14px;">go/scanner: skip first character if it's a BOM</span>

<span style="color: rgb(0, 0, 0); font-size: 13px;"><span style="color: rgb(0, 0, 0); font-size: 13px;">30444b809a9e by <span style="font-size: 14px;">Robert Griesemer, 2013-4-12: <span style="font-size: 14px;">go/scanner: reject BOMs that are not at the beginning</span>
</span></span></span>

看到没!三个作者(包括两位老大)先后修改提交了至少4次,前后跨度7个月,才总算达到了我一次性修改提交源代码的效果。



---------------------------------------------------------------------------------------------------


2014-3-18 Liigo 补记

<span style="color: rgb(255, 0, 0);">历史总是惊人的相似,时隔两年之后,我(Liigo)又修改了Rust编程语言编译器的源代码,为其增加了支持UTF-8 BOM的功能。与Go语言官方开发组形成鲜明对比的是,Rust官方开发人员很爽快的采纳了我这个Pull Request#12976:libsyntax: librustdoc: ignore utf-8 BOM in .rs files。</span>

到此这篇关于“修改Go语言(golang)编译器源代码让它支持UTF-8 BOM”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
修改Go语言(golang)编译器源代码让它支持UTF-8 BOM
Windows平台下GO语言编译器(GO-windows)
有关 UTF-8 BOM 导致样式错乱的解决方法
Golang 学习笔记:环境变量及代理
关于Golang的介绍
Go语言发展历史、核心、特性及学习路线
go语言入门-安装-编写-运行(一)
Go 语言到底适合干什么?
你好,Go语言
Go语言学习3----Go语言特色

[关闭]
~ ~