mirror of
https://github.com/golang/go
synced 2024-11-22 01:04:40 -07:00
cgo: can look up C identifier kind (type or value) and type
gmp.go:197:4: type mpz_t C type mpz_t gmp.go:205:2: call mpz_init C value func(mpz_ptr) void gmp.go:206:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void gmp.go:221:2: call mpz_init C value func(mpz_ptr) void gmp.go:227:7: call size_t C type size_t gmp.go:228:2: call mpz_export C value func(*void, *size_t, int, size_t, int, size_t, mpz_srcptr) *void gmp.go:235:13: call mpz_sizeinbase C value func(mpz_srcptr, int) size_t gmp.go:241:2: call mpz_set C value func(mpz_ptr, mpz_srcptr) void gmp.go:252:3: call mpz_import C value func(mpz_ptr, size_t, int, size_t, int, size_t, *const void) void gmp.go:261:2: call mpz_set_si C value func(mpz_ptr, long int) void gmp.go:273:5: call mpz_set_str C value func(mpz_ptr, *const char, int) int gmp.go:282:9: call mpz_get_str C value func(*char, int, mpz_srcptr) *char gmp.go:287:3: call mpz_clear C value func(mpz_ptr) void gmp.go:302:2: call mpz_add C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void gmp.go:311:2: call mpz_sub C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void gmp.go:320:2: call mpz_mul C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void gmp.go:329:2: call mpz_tdiv_q C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void gmp.go:339:2: call mpz_tdiv_r C value func(mpz_ptr, mpz_srcptr, mpz_srcptr) void gmp.go:348:2: call mpz_mul_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void gmp.go:356:2: call mpz_div_2exp C value func(mpz_ptr, mpz_srcptr, long unsigned int) void gmp.go:367:3: call mpz_pow_ui C value func(mpz_ptr, mpz_srcptr, long unsigned int) void gmp.go:369:3: call mpz_powm C value func(mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr) void gmp.go:378:2: call mpz_neg C value func(mpz_ptr, mpz_srcptr) void gmp.go:386:2: call mpz_abs C value func(mpz_ptr, mpz_srcptr) void gmp.go:404:9: call mpz_cmp C value func(mpz_srcptr, mpz_srcptr) int gmp.go:413:2: call mpz_tdiv_qr C value func(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void gmp.go:426:2: call mpz_gcdext C value func(mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr) void R=r DELTA=938 (628 added, 308 deleted, 2 changed) OCL=34733 CL=34791
This commit is contained in:
parent
92f773dc77
commit
6a2602de91
@ -6,6 +6,9 @@ include $(GOROOT)/src/Make.$(GOARCH)
|
||||
|
||||
TARG=cgo
|
||||
GOFILES=\
|
||||
cgo.go\
|
||||
ast.go\
|
||||
gcc.go\
|
||||
main.go\
|
||||
util.go\
|
||||
|
||||
include $(GOROOT)/src/Make.cmd
|
||||
|
288
src/cmd/cgo/ast.go
Normal file
288
src/cmd/cgo/ast.go
Normal file
@ -0,0 +1,288 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Parse input AST and prepare Prog structure.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"debug/dwarf";
|
||||
"fmt";
|
||||
"go/ast";
|
||||
"go/doc";
|
||||
"go/parser";
|
||||
"go/scanner";
|
||||
"os";
|
||||
)
|
||||
|
||||
// A Cref refers to an expression of the form C.xxx in the AST.
|
||||
type Cref struct {
|
||||
Name string;
|
||||
Expr *ast.Expr;
|
||||
Context string; // "type", "expr", or "call"
|
||||
TypeName bool; // whether xxx is a C type name
|
||||
DebugType dwarf.Type; // the type of xxx
|
||||
}
|
||||
|
||||
// A Prog collects information about a cgo program.
|
||||
type Prog struct {
|
||||
AST *ast.File; // parsed AST
|
||||
Preamble string; // C preamble (doc comment on import "C")
|
||||
Crefs []*Cref;
|
||||
}
|
||||
|
||||
func openProg(name string) *Prog {
|
||||
p := new(Prog);
|
||||
var err os.Error;
|
||||
p.AST, err = parser.ParsePkgFile("", name, parser.ParseComments);
|
||||
if err != nil {
|
||||
if list, ok := err.(scanner.ErrorList); ok {
|
||||
// If err is a scanner.ErrorList, its String will print just
|
||||
// the first error and then (+n more errors).
|
||||
// Instead, turn it into a new Error that will return
|
||||
// details for all the errors.
|
||||
for _, e := range list {
|
||||
fmt.Fprintln(os.Stderr, e);
|
||||
}
|
||||
os.Exit(2);
|
||||
}
|
||||
fatal("parsing %s: %s", name, err);
|
||||
}
|
||||
|
||||
// Find the import "C" line and get any extra C preamble.
|
||||
found := false;
|
||||
for _, d := range p.AST.Decls {
|
||||
d, ok := d.(*ast.GenDecl);
|
||||
if !ok {
|
||||
continue;
|
||||
}
|
||||
for _, s := range d.Specs {
|
||||
s, ok := s.(*ast.ImportSpec);
|
||||
if !ok {
|
||||
continue;
|
||||
}
|
||||
if len(s.Path) != 1 || string(s.Path[0].Value) != `"C"` {
|
||||
continue;
|
||||
}
|
||||
found = true;
|
||||
if s.Name != nil {
|
||||
error(s.Path[0].Pos(), `cannot rename import "C"`);
|
||||
}
|
||||
if s.Doc != nil {
|
||||
p.Preamble += doc.CommentText(s.Doc) + "\n";
|
||||
}
|
||||
else if len(d.Specs) == 1 && d.Doc != nil {
|
||||
p.Preamble += doc.CommentText(d.Doc) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
error(noPos, `cannot find import "C"`);
|
||||
}
|
||||
|
||||
// Accumulate pointers to uses of C.x.
|
||||
p.Crefs = make([]*Cref, 0, 8);
|
||||
walk(p.AST, p, "prog");
|
||||
return p;
|
||||
}
|
||||
|
||||
func walk(x interface{}, p *Prog, context string) {
|
||||
switch n := x.(type) {
|
||||
case *ast.Expr:
|
||||
if sel, ok := (*n).(*ast.SelectorExpr); ok {
|
||||
// For now, assume that the only instance of capital C is
|
||||
// when used as the imported package identifier.
|
||||
// The parser should take care of scoping in the future,
|
||||
// so that we will be able to distinguish a "top-level C"
|
||||
// from a local C.
|
||||
if l, ok := sel.X.(*ast.Ident); ok && l.Value == "C" {
|
||||
i := len(p.Crefs);
|
||||
if i >= cap(p.Crefs) {
|
||||
new := make([]*Cref, 2*i);
|
||||
for j, v := range p.Crefs {
|
||||
new[j] = v;
|
||||
}
|
||||
p.Crefs = new;
|
||||
}
|
||||
p.Crefs = p.Crefs[0:i+1];
|
||||
p.Crefs[i] = &Cref{
|
||||
Name: sel.Sel.Value,
|
||||
Expr: n,
|
||||
Context: context
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
walk(*n, p, context);
|
||||
|
||||
// everything else just recurs
|
||||
default:
|
||||
error(noPos, "unexpected type %T in walk", x);
|
||||
panic();
|
||||
|
||||
case nil:
|
||||
|
||||
// These are ordered and grouped to match ../../pkg/go/ast/ast.go
|
||||
case *ast.Field:
|
||||
walk(&n.Type, p, "type");
|
||||
case *ast.BadExpr:
|
||||
case *ast.Ident:
|
||||
case *ast.Ellipsis:
|
||||
case *ast.BasicLit:
|
||||
case *ast.StringList:
|
||||
case *ast.FuncLit:
|
||||
walk(n.Type, p, "type");
|
||||
walk(n.Body, p, "stmt");
|
||||
case *ast.CompositeLit:
|
||||
walk(&n.Type, p, "type");
|
||||
walk(n.Elts, p, "expr");
|
||||
case *ast.ParenExpr:
|
||||
walk(&n.X, p, context);
|
||||
case *ast.SelectorExpr:
|
||||
walk(&n.X, p, "selector");
|
||||
case *ast.IndexExpr:
|
||||
walk(&n.X, p, "expr");
|
||||
walk(&n.Index, p, "expr");
|
||||
if n.End != nil {
|
||||
walk(&n.End, p, "expr");
|
||||
}
|
||||
case *ast.TypeAssertExpr:
|
||||
walk(&n.X, p, "expr");
|
||||
walk(&n.Type, p, "type");
|
||||
case *ast.CallExpr:
|
||||
walk(&n.Fun, p, "call");
|
||||
walk(n.Args, p, "expr");
|
||||
case *ast.StarExpr:
|
||||
walk(&n.X, p, context);
|
||||
case *ast.UnaryExpr:
|
||||
walk(&n.X, p, "expr");
|
||||
case *ast.BinaryExpr:
|
||||
walk(&n.X, p, "expr");
|
||||
walk(&n.Y, p, "expr");
|
||||
case *ast.KeyValueExpr:
|
||||
walk(&n.Key, p, "expr");
|
||||
walk(&n.Value, p, "expr");
|
||||
|
||||
case *ast.ArrayType:
|
||||
walk(&n.Len, p, "expr");
|
||||
walk(&n.Elt, p, "type");
|
||||
case *ast.StructType:
|
||||
walk(n.Fields, p, "field");
|
||||
case *ast.FuncType:
|
||||
walk(n.Params, p, "field");
|
||||
walk(n.Results, p, "field");
|
||||
case *ast.InterfaceType:
|
||||
walk(n.Methods, p, "field");
|
||||
case *ast.MapType:
|
||||
walk(&n.Key, p, "type");
|
||||
walk(&n.Value, p, "type");
|
||||
case *ast.ChanType:
|
||||
walk(&n.Value, p, "type");
|
||||
|
||||
case *ast.BadStmt:
|
||||
case *ast.DeclStmt:
|
||||
walk(n.Decl, p, "decl");
|
||||
case *ast.EmptyStmt:
|
||||
case *ast.LabeledStmt:
|
||||
walk(n.Stmt, p, "stmt");
|
||||
case *ast.ExprStmt:
|
||||
walk(&n.X, p, "expr");
|
||||
case *ast.IncDecStmt:
|
||||
walk(&n.X, p, "expr");
|
||||
case *ast.AssignStmt:
|
||||
walk(n.Lhs, p, "expr");
|
||||
walk(n.Rhs, p, "expr");
|
||||
case *ast.GoStmt:
|
||||
walk(&n.Call, p, "expr");
|
||||
case *ast.DeferStmt:
|
||||
walk(&n.Call, p, "expr");
|
||||
case *ast.ReturnStmt:
|
||||
walk(n.Results, p, "expr");
|
||||
case *ast.BranchStmt:
|
||||
case *ast.BlockStmt:
|
||||
walk(n.List, p, "stmt");
|
||||
case *ast.IfStmt:
|
||||
walk(n.Init, p, "stmt");
|
||||
walk(&n.Cond, p, "expr");
|
||||
walk(n.Body, p, "stmt");
|
||||
walk(n.Else, p, "stmt");
|
||||
case *ast.CaseClause:
|
||||
walk(n.Values, p, "expr");
|
||||
walk(n.Body, p, "stmt");
|
||||
case *ast.SwitchStmt:
|
||||
walk(n.Init, p, "stmt");
|
||||
walk(&n.Tag, p, "expr");
|
||||
walk(n.Body, p, "stmt");
|
||||
case *ast.TypeCaseClause:
|
||||
walk(n.Types, p, "type");
|
||||
walk(n.Body, p, "stmt");
|
||||
case *ast.TypeSwitchStmt:
|
||||
walk(n.Init, p, "stmt");
|
||||
walk(n.Assign, p, "stmt");
|
||||
walk(n.Body, p, "stmt");
|
||||
case *ast.CommClause:
|
||||
walk(n.Lhs, p, "expr");
|
||||
walk(n.Rhs, p, "expr");
|
||||
walk(n.Body, p, "stmt");
|
||||
case *ast.SelectStmt:
|
||||
walk(n.Body, p, "stmt");
|
||||
case *ast.ForStmt:
|
||||
walk(n.Init, p, "stmt");
|
||||
walk(&n.Cond, p, "expr");
|
||||
walk(n.Post, p, "stmt");
|
||||
walk(n.Body, p, "stmt");
|
||||
case *ast.RangeStmt:
|
||||
walk(&n.Key, p, "expr");
|
||||
walk(&n.Value, p, "expr");
|
||||
walk(&n.X, p, "expr");
|
||||
walk(n.Body, p, "stmt");
|
||||
|
||||
case *ast.ImportSpec:
|
||||
case *ast.ValueSpec:
|
||||
walk(&n.Type, p, "type");
|
||||
walk(n.Values, p, "expr");
|
||||
case *ast.TypeSpec:
|
||||
walk(&n.Type, p, "type");
|
||||
|
||||
case *ast.BadDecl:
|
||||
case *ast.GenDecl:
|
||||
walk(n.Specs, p, "spec");
|
||||
case *ast.FuncDecl:
|
||||
if n.Recv != nil {
|
||||
walk(n.Recv, p, "field");
|
||||
}
|
||||
walk(n.Type, p, "type");
|
||||
walk(n.Body, p, "stmt");
|
||||
|
||||
case *ast.File:
|
||||
walk(n.Decls, p, "decl");
|
||||
|
||||
case *ast.Package:
|
||||
for _, f := range n.Files {
|
||||
walk(f, p, "file");
|
||||
}
|
||||
|
||||
case []ast.Decl:
|
||||
for _, d := range n {
|
||||
walk(d, p, context);
|
||||
}
|
||||
case []ast.Expr:
|
||||
for i := range n {
|
||||
walk(&n[i], p, context);
|
||||
}
|
||||
case []*ast.Field:
|
||||
for _, f := range n {
|
||||
walk(f, p, context);
|
||||
}
|
||||
case []ast.Stmt:
|
||||
for _, s := range n {
|
||||
walk(s, p, context);
|
||||
}
|
||||
case []ast.Spec:
|
||||
for _, s := range n {
|
||||
walk(s, p, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,308 +0,0 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Cgo; see gmp.go for an overview.
|
||||
|
||||
// TODO(rsc):
|
||||
// Emit correct line number annotations.
|
||||
// Make 6g understand the annotations.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio";
|
||||
"container/vector";
|
||||
"debug/dwarf";
|
||||
"debug/elf";
|
||||
"flag";
|
||||
"fmt";
|
||||
"go/ast";
|
||||
"go/doc";
|
||||
"go/parser";
|
||||
"go/scanner";
|
||||
"go/token";
|
||||
"io";
|
||||
"os";
|
||||
)
|
||||
|
||||
// Map of uses of C.xxx. The key is the pointer
|
||||
// to the use (a pointer so it can be rewritten)
|
||||
// and the value is the context ("call", "expr", "type").
|
||||
type cmap map[*ast.Expr] string
|
||||
|
||||
var noPos token.Position
|
||||
|
||||
func usage() {
|
||||
fmt.Fprint(os.Stderr, "usage: cgo [options] file.cgo\n");
|
||||
flag.PrintDefaults();
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Usage = usage;
|
||||
flag.Parse();
|
||||
|
||||
args := flag.Args();
|
||||
if len(args) != 1 {
|
||||
flag.Usage();
|
||||
}
|
||||
filename := args[0];
|
||||
|
||||
prog, err := parser.ParsePkgFile("", filename, parser.ParseComments);
|
||||
if err != nil {
|
||||
fatal(err);
|
||||
}
|
||||
|
||||
// Find the import "C" line and get any extra C preamble.
|
||||
preamble := "";
|
||||
found := false;
|
||||
for _, d := range prog.Decls {
|
||||
d, ok := d.(*ast.GenDecl);
|
||||
if !ok {
|
||||
continue;
|
||||
}
|
||||
for _, s := range d.Specs {
|
||||
s, ok := s.(*ast.ImportSpec);
|
||||
if !ok {
|
||||
continue;
|
||||
}
|
||||
if len(s.Path) != 1 || string(s.Path[0].Value) != `"C"` {
|
||||
continue;
|
||||
}
|
||||
found = true;
|
||||
if s.Name != nil {
|
||||
error(s.Path[0].Pos(), `cannot rename import "C"`);
|
||||
}
|
||||
if s.Doc != nil {
|
||||
preamble += doc.CommentText(s.Doc) + "\n";
|
||||
}
|
||||
else if len(d.Specs) == 1 && d.Doc != nil {
|
||||
preamble += doc.CommentText(d.Doc) + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
error(noPos, `cannot find import "C"`);
|
||||
}
|
||||
|
||||
// Accumulate pointers to uses of C.x.
|
||||
m := make(cmap);
|
||||
walk(prog, m, "prog");
|
||||
|
||||
fmt.Print(preamble);
|
||||
for p, context := range m {
|
||||
sel := (*p).(*ast.SelectorExpr);
|
||||
fmt.Printf("%s: %s as %s\n", sel.Pos(), sel.Sel.Value, context);
|
||||
}
|
||||
}
|
||||
|
||||
func walk(x interface{}, m cmap, context string) {
|
||||
switch n := x.(type) {
|
||||
case *ast.Expr:
|
||||
if sel, ok := (*n).(*ast.SelectorExpr); ok {
|
||||
// For now, assume that the only instance of capital C is
|
||||
// when used as the imported package identifier.
|
||||
// The parser should take care of scoping in the future,
|
||||
// so that we will be able to distinguish a "top-level C"
|
||||
// from a local C.
|
||||
if l, ok := sel.X.(*ast.Ident); ok && l.Value == "C" {
|
||||
m[n] = context;
|
||||
break;
|
||||
}
|
||||
}
|
||||
walk(*n, m, context);
|
||||
|
||||
// everything else just recurs
|
||||
default:
|
||||
error(noPos, "unexpected type %T in walk", x);
|
||||
panic();
|
||||
|
||||
case nil:
|
||||
|
||||
// These are ordered and grouped to match ../../pkg/go/ast/ast.go
|
||||
case *ast.Field:
|
||||
walk(&n.Type, m, "type");
|
||||
case *ast.BadExpr:
|
||||
case *ast.Ident:
|
||||
case *ast.Ellipsis:
|
||||
case *ast.BasicLit:
|
||||
case *ast.StringList:
|
||||
case *ast.FuncLit:
|
||||
walk(n.Type, m, "type");
|
||||
walk(n.Body, m, "stmt");
|
||||
case *ast.CompositeLit:
|
||||
walk(&n.Type, m, "type");
|
||||
walk(n.Elts, m, "expr");
|
||||
case *ast.ParenExpr:
|
||||
walk(&n.X, m, context);
|
||||
case *ast.SelectorExpr:
|
||||
walk(&n.X, m, "selector");
|
||||
case *ast.IndexExpr:
|
||||
walk(&n.X, m, "expr");
|
||||
walk(&n.Index, m, "expr");
|
||||
if n.End != nil {
|
||||
walk(&n.End, m, "expr");
|
||||
}
|
||||
case *ast.TypeAssertExpr:
|
||||
walk(&n.X, m, "expr");
|
||||
walk(&n.Type, m, "type");
|
||||
case *ast.CallExpr:
|
||||
walk(&n.Fun, m, "call");
|
||||
walk(n.Args, m, "expr");
|
||||
case *ast.StarExpr:
|
||||
walk(&n.X, m, context);
|
||||
case *ast.UnaryExpr:
|
||||
walk(&n.X, m, "expr");
|
||||
case *ast.BinaryExpr:
|
||||
walk(&n.X, m, "expr");
|
||||
walk(&n.Y, m, "expr");
|
||||
case *ast.KeyValueExpr:
|
||||
walk(&n.Key, m, "expr");
|
||||
walk(&n.Value, m, "expr");
|
||||
|
||||
case *ast.ArrayType:
|
||||
walk(&n.Len, m, "expr");
|
||||
walk(&n.Elt, m, "type");
|
||||
case *ast.StructType:
|
||||
walk(n.Fields, m, "field");
|
||||
case *ast.FuncType:
|
||||
walk(n.Params, m, "field");
|
||||
walk(n.Results, m, "field");
|
||||
case *ast.InterfaceType:
|
||||
walk(n.Methods, m, "field");
|
||||
case *ast.MapType:
|
||||
walk(&n.Key, m, "type");
|
||||
walk(&n.Value, m, "type");
|
||||
case *ast.ChanType:
|
||||
walk(&n.Value, m, "type");
|
||||
|
||||
case *ast.BadStmt:
|
||||
case *ast.DeclStmt:
|
||||
walk(n.Decl, m, "decl");
|
||||
case *ast.EmptyStmt:
|
||||
case *ast.LabeledStmt:
|
||||
walk(n.Stmt, m, "stmt");
|
||||
case *ast.ExprStmt:
|
||||
walk(&n.X, m, "expr");
|
||||
case *ast.IncDecStmt:
|
||||
walk(&n.X, m, "expr");
|
||||
case *ast.AssignStmt:
|
||||
walk(n.Lhs, m, "expr");
|
||||
walk(n.Rhs, m, "expr");
|
||||
case *ast.GoStmt:
|
||||
walk(&n.Call, m, "expr");
|
||||
case *ast.DeferStmt:
|
||||
walk(&n.Call, m, "expr");
|
||||
case *ast.ReturnStmt:
|
||||
walk(n.Results, m, "expr");
|
||||
case *ast.BranchStmt:
|
||||
case *ast.BlockStmt:
|
||||
walk(n.List, m, "stmt");
|
||||
case *ast.IfStmt:
|
||||
walk(n.Init, m, "stmt");
|
||||
walk(&n.Cond, m, "expr");
|
||||
walk(n.Body, m, "stmt");
|
||||
walk(n.Else, m, "stmt");
|
||||
case *ast.CaseClause:
|
||||
walk(n.Values, m, "expr");
|
||||
walk(n.Body, m, "stmt");
|
||||
case *ast.SwitchStmt:
|
||||
walk(n.Init, m, "stmt");
|
||||
walk(&n.Tag, m, "expr");
|
||||
walk(n.Body, m, "stmt");
|
||||
case *ast.TypeCaseClause:
|
||||
walk(n.Types, m, "type");
|
||||
walk(n.Body, m, "stmt");
|
||||
case *ast.TypeSwitchStmt:
|
||||
walk(n.Init, m, "stmt");
|
||||
walk(n.Assign, m, "stmt");
|
||||
walk(n.Body, m, "stmt");
|
||||
case *ast.CommClause:
|
||||
walk(n.Lhs, m, "expr");
|
||||
walk(n.Rhs, m, "expr");
|
||||
walk(n.Body, m, "stmt");
|
||||
case *ast.SelectStmt:
|
||||
walk(n.Body, m, "stmt");
|
||||
case *ast.ForStmt:
|
||||
walk(n.Init, m, "stmt");
|
||||
walk(&n.Cond, m, "expr");
|
||||
walk(n.Post, m, "stmt");
|
||||
walk(n.Body, m, "stmt");
|
||||
case *ast.RangeStmt:
|
||||
walk(&n.Key, m, "expr");
|
||||
walk(&n.Value, m, "expr");
|
||||
walk(&n.X, m, "expr");
|
||||
walk(n.Body, m, "stmt");
|
||||
|
||||
case *ast.ImportSpec:
|
||||
case *ast.ValueSpec:
|
||||
walk(&n.Type, m, "type");
|
||||
walk(n.Values, m, "expr");
|
||||
case *ast.TypeSpec:
|
||||
walk(&n.Type, m, "type");
|
||||
|
||||
case *ast.BadDecl:
|
||||
case *ast.GenDecl:
|
||||
walk(n.Specs, m, "spec");
|
||||
case *ast.FuncDecl:
|
||||
if n.Recv != nil {
|
||||
walk(n.Recv, m, "field");
|
||||
}
|
||||
walk(n.Type, m, "type");
|
||||
walk(n.Body, m, "stmt");
|
||||
|
||||
case *ast.File:
|
||||
walk(n.Decls, m, "decl");
|
||||
|
||||
case *ast.Package:
|
||||
for _, f := range n.Files {
|
||||
walk(f, m, "file");
|
||||
}
|
||||
|
||||
case []ast.Decl:
|
||||
for _, d := range n {
|
||||
walk(d, m, context);
|
||||
}
|
||||
case []ast.Expr:
|
||||
for i := range n {
|
||||
walk(&n[i], m, context);
|
||||
}
|
||||
case []*ast.Field:
|
||||
for _, f := range n {
|
||||
walk(f, m, context);
|
||||
}
|
||||
case []ast.Stmt:
|
||||
for _, s := range n {
|
||||
walk(s, m, context);
|
||||
}
|
||||
case []ast.Spec:
|
||||
for _, s := range n {
|
||||
walk(s, m, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fatal(err os.Error) {
|
||||
// If err is a scanner.ErrorList, its String will print just
|
||||
// the first error and then (+n more errors).
|
||||
// Instead, turn it into a new Error that will return
|
||||
// details for all the errors.
|
||||
if list, ok := err.(scanner.ErrorList); ok {
|
||||
for _, e := range list {
|
||||
fmt.Fprintln(os.Stderr, e);
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintln(os.Stderr, err);
|
||||
}
|
||||
os.Exit(2);
|
||||
}
|
||||
|
||||
var nerrors int
|
||||
|
||||
func error(pos token.Position, msg string, args ...) {
|
||||
nerrors++;
|
||||
if pos.IsValid() {
|
||||
fmt.Fprintf(os.Stderr, "%s: ", pos);
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, msg, args);
|
||||
fmt.Fprintf(os.Stderr, "\n");
|
||||
}
|
203
src/cmd/cgo/gcc.go
Normal file
203
src/cmd/cgo/gcc.go
Normal file
@ -0,0 +1,203 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Annotate Crefs in Prog with C types by parsing gcc debug output.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"debug/dwarf";
|
||||
"debug/elf";
|
||||
"debug/macho";
|
||||
"fmt";
|
||||
"os";
|
||||
"strconv";
|
||||
"strings";
|
||||
)
|
||||
|
||||
func (p *Prog) loadDebugInfo() {
|
||||
// Construct a slice of unique names from p.Crefs.
|
||||
m := make(map[string]int);
|
||||
for _, c := range p.Crefs {
|
||||
m[c.Name] = -1;
|
||||
}
|
||||
names := make([]string, 0, len(m));
|
||||
for name, _ := range m {
|
||||
i := len(names);
|
||||
names = names[0:i+1];
|
||||
names[i] = name;
|
||||
m[name] = i;
|
||||
}
|
||||
|
||||
// Coerce gcc into telling us whether each name is
|
||||
// a type, a value, or undeclared. We compile a function
|
||||
// containing the line:
|
||||
// name;
|
||||
// If name is a type, gcc will print:
|
||||
// x.c:2: warning: useless type name in empty declaration
|
||||
// If name is a value, gcc will print
|
||||
// x.c:2: warning: statement with no effect
|
||||
// If name is undeclared, gcc will print
|
||||
// x.c:2: error: 'name' undeclared (first use in this function)
|
||||
// A line number directive causes the line number to
|
||||
// correspond to the index in the names array.
|
||||
var b strings.Buffer;
|
||||
b.WriteString(p.Preamble);
|
||||
b.WriteString("void f(void) {\n");
|
||||
b.WriteString("#line 0 \"cgo-test\"\n");
|
||||
for _, n := range names {
|
||||
b.WriteString(n);
|
||||
b.WriteString(";\n");
|
||||
}
|
||||
b.WriteString("}\n");
|
||||
|
||||
kind := make(map[string]string);
|
||||
_, stderr := gccDebug(b.Bytes());
|
||||
if stderr == "" {
|
||||
fatal("gcc produced no output");
|
||||
}
|
||||
for _, line := range strings.Split(stderr, "\n", 0) {
|
||||
if len(line) < 9 || line[0:9] != "cgo-test:" {
|
||||
continue;
|
||||
}
|
||||
line = line[9:len(line)];
|
||||
colon := strings.Index(line, ":");
|
||||
if colon < 0 {
|
||||
continue;
|
||||
}
|
||||
i, err := strconv.Atoi(line[0:colon]);
|
||||
if err != nil {
|
||||
continue;
|
||||
}
|
||||
what := "";
|
||||
switch {
|
||||
default:
|
||||
continue;
|
||||
case strings.Index(line, "warning: useless type name in empty declaration") >= 0:
|
||||
what = "type";
|
||||
case strings.Index(line, "warning: statement with no effect") >= 0:
|
||||
what = "value";
|
||||
case strings.Index(line, "undeclared") >= 0:
|
||||
what = "error";
|
||||
}
|
||||
if old, ok := kind[names[i]]; ok && old != what {
|
||||
error(noPos, "inconsistent gcc output about C.%s", names[i]);
|
||||
}
|
||||
kind[names[i]] = what;
|
||||
}
|
||||
for _, n := range names {
|
||||
if _, ok := kind[n]; !ok {
|
||||
error(noPos, "could not determine kind of name for C.%s", n);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the types from the DWARF section of an object
|
||||
// from a well-formed C program. Gcc only generates DWARF info
|
||||
// for symbols in the object file, so it is not enough to print the
|
||||
// preamble and hope the symbols we care about will be there.
|
||||
// Instead, emit
|
||||
// typeof(names[i]) *__cgo__i;
|
||||
// for each entry in names and then dereference the type we
|
||||
// learn for __cgo__i.
|
||||
b.Reset();
|
||||
b.WriteString(p.Preamble);
|
||||
for i, n := range names {
|
||||
fmt.Fprintf(&b, "typeof(%s) *__cgo__%d;\n", n, i);
|
||||
}
|
||||
d, stderr := gccDebug(b.Bytes());
|
||||
if d == nil {
|
||||
fatal("gcc failed:\n%s\non input:\n%s", stderr, b.Bytes());
|
||||
}
|
||||
|
||||
// Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
|
||||
types := make([]dwarf.Type, len(names));
|
||||
r := d.Reader();
|
||||
for {
|
||||
e, err := r.Next();
|
||||
if err != nil {
|
||||
fatal("reading DWARF entry: %s", err);
|
||||
}
|
||||
if e == nil {
|
||||
break;
|
||||
}
|
||||
if e.Tag != dwarf.TagVariable {
|
||||
goto Continue;
|
||||
}
|
||||
name, _ := e.Val(dwarf.AttrName).(string);
|
||||
typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset);
|
||||
if name == "" || typOff == 0 {
|
||||
fatal("malformed DWARF TagVariable entry");
|
||||
}
|
||||
if !strings.HasPrefix(name, "__cgo__") {
|
||||
goto Continue;
|
||||
}
|
||||
typ, err := d.Type(typOff);
|
||||
if err != nil {
|
||||
fatal("loading DWARF type: %s", err);
|
||||
}
|
||||
t, ok := typ.(*dwarf.PtrType);
|
||||
if !ok || t == nil {
|
||||
fatal("internal error: %s has non-pointer type", name);
|
||||
}
|
||||
i, err := strconv.Atoi(name[7:len(name)]);
|
||||
if err != nil {
|
||||
fatal("malformed __cgo__ name: %s", name);
|
||||
}
|
||||
types[i] = t.Type;
|
||||
|
||||
Continue:
|
||||
if e.Tag != dwarf.TagCompileUnit {
|
||||
r.SkipChildren();
|
||||
}
|
||||
}
|
||||
|
||||
// Apply types to Crefs.
|
||||
for _, c := range p.Crefs {
|
||||
i := m[c.Name];
|
||||
c.TypeName = kind[c.Name] == "type";
|
||||
c.DebugType = types[i];
|
||||
}
|
||||
}
|
||||
|
||||
// gccDebug runs gcc -gdwarf-2 over the C program stdin and
|
||||
// returns the corresponding DWARF data and any messages
|
||||
// printed to standard error.
|
||||
func gccDebug(stdin []byte) (*dwarf.Data, string) {
|
||||
machine := "-m32";
|
||||
if os.Getenv("GOARCH") == "amd64" {
|
||||
machine = "-m64";
|
||||
}
|
||||
|
||||
tmp := "_cgo_.o";
|
||||
_, stderr, ok := run(stdin, []string{
|
||||
"gcc",
|
||||
machine,
|
||||
"-Wall", // many warnings
|
||||
"-Werror", // warnings are errors
|
||||
"-o"+tmp, // write object to tmp
|
||||
"-gdwarf-2", // generate DWARF v2 debugging symbols
|
||||
"-c", // do not link
|
||||
"-xc", // input language is C
|
||||
"-", // read input from standard input
|
||||
});
|
||||
if !ok {
|
||||
return nil, string(stderr);
|
||||
}
|
||||
|
||||
// Try to parse f as ELF and Mach-O and hope one works.
|
||||
var f interface{DWARF() (*dwarf.Data, os.Error)};
|
||||
var err os.Error;
|
||||
if f, err = elf.Open(tmp); err != nil {
|
||||
if f, err = macho.Open(tmp); err != nil {
|
||||
fatal("cannot parse gcc output %s as ELF or Mach-O object", tmp);
|
||||
}
|
||||
}
|
||||
|
||||
d, err := f.DWARF();
|
||||
if err != nil {
|
||||
fatal("cannot load DWARF debug information from %s: %s", tmp, err);
|
||||
}
|
||||
return d, "";
|
||||
}
|
||||
|
@ -364,7 +364,7 @@ func (z *Int) Exp(x, y, m *Int) *Int {
|
||||
y.doinit();
|
||||
z.doinit();
|
||||
if m == nil {
|
||||
C.mpz_pow(&z.i, &x.i, &y.i);
|
||||
C.mpz_pow_ui(&z.i, &x.i, mpz_get_ui(&y.i));
|
||||
} else {
|
||||
C.mpz_powm(&z.i, &x.i, &y.i, &m.i);
|
||||
}
|
||||
|
46
src/cmd/cgo/main.go
Normal file
46
src/cmd/cgo/main.go
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag";
|
||||
"fmt";
|
||||
"os";
|
||||
"tabwriter";
|
||||
)
|
||||
|
||||
// Cgo; see gmp.go for an overview.
|
||||
|
||||
// TODO(rsc):
|
||||
// Emit correct line number annotations.
|
||||
// Make 6g understand the annotations.
|
||||
|
||||
func usage() {
|
||||
fmt.Fprint(os.Stderr, "usage: cgo file.cgo\n");
|
||||
flag.PrintDefaults();
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Usage = usage;
|
||||
flag.Parse();
|
||||
|
||||
args := flag.Args();
|
||||
if len(args) != 1 {
|
||||
usage();
|
||||
os.Exit(2);
|
||||
}
|
||||
p := openProg(args[0]);
|
||||
p.loadDebugInfo();
|
||||
|
||||
tw := tabwriter.NewWriter(os.Stdout, 1, 1, ' ', 0);
|
||||
for _, cref := range p.Crefs {
|
||||
what := "value";
|
||||
if cref.TypeName {
|
||||
what = "type";
|
||||
}
|
||||
fmt.Fprintf(tw, "%s:\t%s %s\tC %s\t%s\n", (*cref.Expr).Pos(), cref.Context, cref.Name, what, cref.DebugType);
|
||||
}
|
||||
tw.Flush();
|
||||
}
|
96
src/cmd/cgo/util.go
Normal file
96
src/cmd/cgo/util.go
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes";
|
||||
"exec";
|
||||
"fmt";
|
||||
"go/token";
|
||||
"io";
|
||||
"os";
|
||||
)
|
||||
|
||||
// A ByteReaderAt implements io.ReadAt using a slice of bytes.
|
||||
type ByteReaderAt []byte
|
||||
|
||||
func (r ByteReaderAt) ReadAt(p []byte, off int64) (n int, err os.Error) {
|
||||
if off >= int64(len(r)) || off < 0 {
|
||||
return 0, os.EOF;
|
||||
}
|
||||
return bytes.Copy(p, r[off:len(r)]), nil;
|
||||
}
|
||||
|
||||
// run runs the command argv, feeding in stdin on standard input.
|
||||
// It returns the output to standard output and standard error.
|
||||
// ok indicates whether the command exited successfully.
|
||||
func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
|
||||
cmd, err := exec.LookPath(argv[0]);
|
||||
if err != nil {
|
||||
fatal("exec %s: %s", argv[0], err);
|
||||
}
|
||||
r0, w0, err := os.Pipe();
|
||||
if err != nil {
|
||||
fatal("%s", err);
|
||||
}
|
||||
r1, w1, err := os.Pipe();
|
||||
if err != nil {
|
||||
fatal("%s", err);
|
||||
}
|
||||
r2, w2, err := os.Pipe();
|
||||
if err != nil {
|
||||
fatal("%s", err);
|
||||
}
|
||||
pid, err := os.ForkExec(cmd, argv, os.Environ(), "", []*os.File{r0, w1, w2});
|
||||
if err != nil {
|
||||
fatal("%s", err);
|
||||
}
|
||||
r0.Close();
|
||||
w1.Close();
|
||||
w2.Close();
|
||||
c := make(chan bool);
|
||||
go func() {
|
||||
w0.Write(stdin);
|
||||
w0.Close();
|
||||
c <- true;
|
||||
}();
|
||||
var xstdout []byte; // TODO(rsc): delete after 6g can take address of out parameter
|
||||
go func() {
|
||||
xstdout, _ = io.ReadAll(r1);
|
||||
r1.Close();
|
||||
c <- true;
|
||||
}();
|
||||
stderr, _ = io.ReadAll(r2);
|
||||
r2.Close();
|
||||
<-c;
|
||||
<-c;
|
||||
stdout = xstdout;
|
||||
|
||||
w, err := os.Wait(pid, 0);
|
||||
if err != nil {
|
||||
fatal("%s", err);
|
||||
}
|
||||
ok = w.Exited() && w.ExitStatus() == 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Die with an error message.
|
||||
func fatal(msg string, args ...) {
|
||||
fmt.Fprintf(os.Stderr, msg+"\n", args);
|
||||
os.Exit(2);
|
||||
}
|
||||
|
||||
var nerrors int
|
||||
var noPos token.Position
|
||||
|
||||
func error(pos token.Position, msg string, args ...) {
|
||||
nerrors++;
|
||||
if pos.IsValid() {
|
||||
fmt.Fprintf(os.Stderr, "%s: ", pos);
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, msg, args);
|
||||
fmt.Fprintf(os.Stderr, "\n");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user