如何打印手写的抽象语法树(AST)?

huangapple go评论115阅读模式
英文:

How to print hand-written AST?

问题

我有一组描述网络协议的XML文件,我想要从中生成Go代码,因此我没有任何现有的Go代码可供使用。所有使用go/ast(例如go fmt)的示例都是基于现有代码进行一些AST转换,然后再将其写回。由于我只有XML文件,所以我必须手动编写AST。问题是,我无法让我手写的AST输出。

期望输出:

  1. package foo
  2. type Bar uint32

实际输出:没有任何输出

我该如何让AST输出呢?

英文:

I have a set of XML description of network protocol that I'm trying to generate Go code from, therefore I don't have any existing Go code to work with. All of the examples that make use of go/ast (such as go fmt) take existing code, do some transformation on the AST, then write them back out. Since all I have are XML files, the AST that I'm working with have to be written by hand. The problem is that I cannot get my hand-written AST to output.

Example

  1. package main
  2. import (
  3. "go/ast"
  4. "go/printer"
  5. "go/token"
  6. "os"
  7. )
  8. func main() {
  9. f := ast.File{
  10. Name: ast.NewIdent("foo"),
  11. Decls: []ast.Decl{
  12. &ast.GenDecl{
  13. Tok: token.TYPE,
  14. Specs: []ast.Spec{
  15. &ast.TypeSpec{
  16. Name: ast.NewIdent("Bar"),
  17. Type: ast.NewIdent("uint32"),
  18. },
  19. },
  20. },
  21. },
  22. }
  23. fset := token.NewFileSet()
  24. printer.Fprint(os.Stdout, fset, f)
  25. }

Expected output:

  1. package foo
  2. type Bar uint32

Actual output: nothing

How do I get the AST to print?

答案1

得分: 6

不要忽视错误!

添加:

  1. err := printer.Fprint(os.Stdout, fset, f)
  2. if err != nil {
  3. log.Fatal(err)
  4. }

会得到:"go/printer: 不支持的节点类型 ast.File",这应该足够指引你朝正确的方向前进了。

printer.Fprint 的最后一个参数是 interface{},所以编译器接受任何类型。然而,就像 parser.ParseFile 返回的是 *ast.File(而不是 ast.File),它期望一个节点的指针。

传递一个指针会得到你想要的输出(注意 &ast.File):

  1. package main
  2. import (
  3. "go/ast"
  4. "go/printer"
  5. "go/token"
  6. "log"
  7. "os"
  8. )
  9. func main() {
  10. f := &ast.File{
  11. Name: ast.NewIdent("foo"),
  12. Decls: []ast.Decl{
  13. &ast.GenDecl{
  14. Tok: token.TYPE,
  15. Specs: []ast.Spec{
  16. &ast.TypeSpec{
  17. Name: ast.NewIdent("Bar"),
  18. Type: ast.NewIdent("uint32"),
  19. },
  20. },
  21. },
  22. },
  23. }
  24. fset := token.NewFileSet()
  25. err := printer.Fprint(os.Stdout, fset, f)
  26. if err != nil {
  27. log.Fatal(err)
  28. }
  29. }

<kbd>playground</kbd>

英文:

Don't ignore errors!

Adding:

  1. err := printer.Fprint(os.Stdout, fset, f)
  2. if err != nil {
  3. log.Fatal(err)
  4. }

Gives: "go/printer: unsupported node type ast.File" which should have been enough to point you in the right direction.

printer.Fprint's last argument is interface{} so the compiler accepts anything. However, just as parser.ParseFile returns an *ast.File (rather than ast.File) it expects a pointer to a node.

Passing a pointer gives the output you want (note the &amp;ast.File):

  1. package main
  2. import (
  3. &quot;go/ast&quot;
  4. &quot;go/printer&quot;
  5. &quot;go/token&quot;
  6. &quot;log&quot;
  7. &quot;os&quot;
  8. )
  9. func main() {
  10. f := &amp;ast.File{
  11. Name: ast.NewIdent(&quot;foo&quot;),
  12. Decls: []ast.Decl{
  13. &amp;ast.GenDecl{
  14. Tok: token.TYPE,
  15. Specs: []ast.Spec{
  16. &amp;ast.TypeSpec{
  17. Name: ast.NewIdent(&quot;Bar&quot;),
  18. Type: ast.NewIdent(&quot;uint32&quot;),
  19. },
  20. },
  21. },
  22. },
  23. }
  24. fset := token.NewFileSet()
  25. err := printer.Fprint(os.Stdout, fset, f)
  26. if err != nil {
  27. log.Fatal(err)
  28. }
  29. }

<kbd>playground</kbd>

huangapple
  • 本文由 发表于 2015年2月24日 08:04:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/28685976.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定