├── add ├── ld │ ├── z.go │ └── util.go ├── new6l │ └── z.go ├── obj │ ├── i386 │ │ └── util.go │ ├── x86 │ │ └── util.go │ ├── ppc64 │ │ └── util.go │ ├── arm │ │ └── util.go │ ├── textflag.go │ ├── fmt.go │ ├── flag.go │ └── util.go ├── new5g │ └── util.go ├── new6g │ └── util.go ├── new8g │ └── util.go ├── new9g │ └── util.go └── gc │ └── util.go ├── cc ├── doc.go ├── stmt.go ├── print_test.go ├── parse.go ├── stdhdr.go ├── type.go ├── expr.go ├── print.go ├── lex.go └── typecheck.go ├── README.md ├── LICENSE ├── main.go ├── run.ld ├── export.go ├── array.go ├── run ├── rename.go ├── output.go ├── config.go ├── qsort.go ├── printf.go ├── syntax.go └── printer.go /add/ld/z.go: -------------------------------------------------------------------------------- 1 | package ld 2 | -------------------------------------------------------------------------------- /add/new6l/z.go: -------------------------------------------------------------------------------- 1 | package main 2 | -------------------------------------------------------------------------------- /cc/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package cc implements parsing, type checking, and printing of C programs. 6 | package cc // import "rsc.io/c2go/cc" 7 | -------------------------------------------------------------------------------- /add/obj/i386/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package i386 6 | 7 | func bool2int(b bool) int { 8 | if b { 9 | return 1 10 | } 11 | return 0 12 | } 13 | -------------------------------------------------------------------------------- /add/obj/x86/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package x86 6 | 7 | func bool2int(b bool) int { 8 | if b { 9 | return 1 10 | } 11 | return 0 12 | } 13 | -------------------------------------------------------------------------------- /add/obj/ppc64/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ppc64 6 | 7 | func bool2int(b bool) int { 8 | if b { 9 | return 1 10 | } 11 | return 0 12 | } 13 | -------------------------------------------------------------------------------- /add/obj/arm/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build ignore 6 | 7 | package arm 8 | 9 | func bool2int(b bool) int { 10 | if b { 11 | return 1 12 | } 13 | return 0 14 | } 15 | -------------------------------------------------------------------------------- /add/new5g/util.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | // Copyright 2015 The Go Authors. All rights reserved. 4 | // Use of this source code is governed by a BSD-style 5 | // license that can be found in the LICENSE file. 6 | 7 | package main 8 | 9 | import ( 10 | "cmd/internal/obj" 11 | "strconv" 12 | ) 13 | 14 | func bool2int(b bool) int { 15 | if b { 16 | return 1 17 | } 18 | return 0 19 | } 20 | -------------------------------------------------------------------------------- /add/new6g/util.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | // Copyright 2015 The Go Authors. All rights reserved. 4 | // Use of this source code is governed by a BSD-style 5 | // license that can be found in the LICENSE file. 6 | 7 | package main 8 | 9 | import ( 10 | "cmd/internal/obj" 11 | "strconv" 12 | ) 13 | 14 | func bool2int(b bool) int { 15 | if b { 16 | return 1 17 | } 18 | return 0 19 | } 20 | -------------------------------------------------------------------------------- /add/new8g/util.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | // Copyright 2015 The Go Authors. All rights reserved. 4 | // Use of this source code is governed by a BSD-style 5 | // license that can be found in the LICENSE file. 6 | 7 | package main 8 | 9 | import ( 10 | "cmd/internal/obj" 11 | "strconv" 12 | ) 13 | 14 | func bool2int(b bool) int { 15 | if b { 16 | return 1 17 | } 18 | return 0 19 | } 20 | -------------------------------------------------------------------------------- /add/new9g/util.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | // Copyright 2015 The Go Authors. All rights reserved. 4 | // Use of this source code is governed by a BSD-style 5 | // license that can be found in the LICENSE file. 6 | 7 | package main 8 | 9 | import ( 10 | "cmd/internal/obj" 11 | "strconv" 12 | ) 13 | 14 | func bool2int(b bool) int { 15 | if b { 16 | return 1 17 | } 18 | return 0 19 | } 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C->Go translator 2 | 3 | **UNMAINTAINED**. See [elliotchance/c2go](https://github.com/elliotchance/c2go) for a general purpose tool. 4 | 5 | This program was used to convert much of the Go runtime, compiler, and linker from C to Go. 6 | It's now here only for historical value and reference. It is not maintained in any way. 7 | 8 | go get rsc.io/c2go 9 | 10 | http://godoc.org/rsc.io/c2go 11 | -------------------------------------------------------------------------------- /cc/stmt.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package cc 6 | 7 | type Stmt struct { 8 | SyntaxInfo 9 | Op StmtOp 10 | Pre *Expr 11 | Expr *Expr 12 | Post *Expr 13 | Decl *Decl 14 | Body *Stmt 15 | Else *Stmt 16 | Block []*Stmt 17 | Labels []*Label 18 | Text string 19 | Type *Type 20 | } 21 | 22 | type StmtOp int 23 | 24 | const ( 25 | _ StmtOp = iota 26 | StmtDecl 27 | StmtExpr 28 | Empty 29 | Block 30 | ARGBEGIN 31 | Break 32 | Continue 33 | Do 34 | For 35 | If 36 | Goto 37 | Return 38 | Switch 39 | While 40 | ) 41 | 42 | type Label struct { 43 | SyntaxInfo 44 | Op LabelOp 45 | Expr *Expr 46 | Name string 47 | } 48 | 49 | type LabelOp int 50 | 51 | const ( 52 | _ LabelOp = iota 53 | Case 54 | Default 55 | LabelName 56 | ) 57 | -------------------------------------------------------------------------------- /add/obj/textflag.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file defines flags attached to various functions 6 | // and data objects. The compilers, assemblers, and linker must 7 | // all agree on these values. 8 | 9 | package obj 10 | 11 | const ( 12 | // Don't profile the marked routine. This flag is deprecated. 13 | NOPROF = 1 14 | 15 | // It is ok for the linker to get multiple of these symbols. It will 16 | // pick one of the duplicates to use. 17 | DUPOK = 2 18 | 19 | // Don't insert stack check preamble. 20 | NOSPLIT = 4 21 | 22 | // Put this data in a read-only section. 23 | RODATA = 8 24 | 25 | // This data contains no pointers. 26 | NOPTR = 16 27 | 28 | // This is a wrapper function and should not count as disabling 'recover'. 29 | WRAPPER = 32 30 | 31 | // This function uses its incoming context register. 32 | NEEDCTXT = 64 33 | ) 34 | -------------------------------------------------------------------------------- /add/obj/fmt.go: -------------------------------------------------------------------------------- 1 | /* 2 | * The authors of this software are Rob Pike and Ken Thompson. 3 | * Copyright (c) 2002 by Lucent Technologies. 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose without fee is hereby granted, provided that this entire notice 6 | * is included in all copies of any software which is or includes a copy 7 | * or modification of this software and in all copies of the supporting 8 | * documentation for such software. 9 | * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED 10 | * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY 11 | * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY 12 | * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 13 | */ 14 | 15 | package obj 16 | 17 | const ( 18 | FmtWidth = 1 19 | FmtLeft = FmtWidth << 1 20 | FmtPrec = FmtLeft << 1 21 | FmtSharp = FmtPrec << 1 22 | FmtSpace = FmtSharp << 1 23 | FmtSign = FmtSpace << 1 24 | FmtApost = FmtSign << 1 25 | FmtZero = FmtApost << 1 26 | FmtUnsigned = FmtZero << 1 27 | FmtShort = FmtUnsigned << 1 28 | FmtLong = FmtShort << 1 29 | FmtVLong = FmtLong << 1 30 | FmtComma = FmtVLong << 1 31 | FmtByte = FmtComma << 1 32 | FmtLDouble = FmtByte << 1 33 | FmtFlag = FmtLDouble << 1 34 | ) 35 | -------------------------------------------------------------------------------- /cc/print_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package cc 6 | 7 | import "testing" 8 | 9 | var exprTests = []string{ 10 | "x", 11 | "123", 12 | "1.4", 13 | "'z'", 14 | `"abc" "def"`, 15 | "x + y", 16 | "x * y", 17 | "x / y", 18 | "x % y", 19 | "x << y", 20 | "x >> y", 21 | "x < y", 22 | "x > y", 23 | "x <= y", 24 | "x >= y", 25 | "x == y", 26 | "x != y", 27 | "x & y", 28 | "x ^ y", 29 | "x | y", 30 | "x && y", 31 | "x || y", 32 | "x ? y : z", 33 | "x = y", 34 | "x += y", 35 | "x -= y", 36 | "x *= y", 37 | "x /= y", 38 | "x %= y", 39 | "x <<= y", 40 | "x >>= y", 41 | "x &= y", 42 | "x ^= y", 43 | "x |= y", 44 | "*x", 45 | "&x", 46 | "+x", 47 | "-x", 48 | "!x", 49 | "~x", 50 | "++x", 51 | "--x", 52 | "sizeof x", 53 | "sizeof(int)", 54 | "offsetof(int, x)", 55 | "(int)x", 56 | "(int){}", 57 | "(int){x}", 58 | "(x, y, z)", 59 | "x, y, z", 60 | "f(x, y, z)", 61 | "x[y]", 62 | "x++", 63 | "x--", 64 | "va_arg(x, int)", 65 | } 66 | 67 | func TestPrintExpr(t *testing.T) { 68 | for _, str := range exprTests { 69 | x, err := ParseExpr(str) 70 | if err != nil { 71 | t.Errorf("%v", err) 72 | continue 73 | } 74 | out := x.String() 75 | if out != str { 76 | t.Errorf("ParseExpr(%#q).String() = %#q, want original input", str, out) 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // C2go converts C programs to Go. 6 | // It is a custom tool written to support the migration of the Go toolchain from C to Go. 7 | // An earlier variant of it helped with the conversion of Go's package runtime. 8 | // 9 | // Warning Warning Warning 10 | // 11 | // C2go is not a magic wand, nor even a general purpose tool. 12 | // There is no documentation, and it will not convert your C program. 13 | // If you have a large code base to convert, you might find c2go a 14 | // good starting point, but you will certainly need to understand and 15 | // modify the source code. 16 | // 17 | package main // import "rsc.io/c2go" 18 | 19 | import ( 20 | "flag" 21 | "fmt" 22 | "io" 23 | "log" 24 | "os" 25 | 26 | "rsc.io/c2go/cc" 27 | ) 28 | 29 | var ( 30 | cfgFile = flag.String("c", "", "config file") 31 | inc = flag.String("I", "", "include directory") 32 | ) 33 | 34 | func main() { 35 | log.SetFlags(0) 36 | flag.Parse() 37 | flag.Usage = func() { 38 | fmt.Fprintf(os.Stderr, "usage: c2go [options] *.c\n") 39 | flag.PrintDefaults() 40 | os.Exit(2) 41 | } 42 | 43 | if *inc != "" { 44 | cc.AddInclude(*inc) 45 | } 46 | 47 | args := flag.Args() 48 | if len(args) == 0 { 49 | flag.Usage() 50 | } 51 | 52 | var r []io.Reader 53 | files := args 54 | for _, file := range files { 55 | f, err := os.Open(file) 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | r = append(r, f) 60 | defer f.Close() 61 | } 62 | prog, err := cc.ReadMany(files, r) 63 | if err != nil { 64 | log.Fatal(err) 65 | } 66 | cfg := new(Config) 67 | if *cfgFile != "" { 68 | cfg.read(*cfgFile) 69 | } 70 | rewriteTypes(cfg, prog) 71 | rewriteSyntax(cfg, prog) 72 | rewriteLen(cfg, prog) 73 | fixGoTypes(cfg, prog) 74 | simplifyBool(cfg, prog) 75 | renameDecls(cfg, prog) 76 | exportDecls(cfg, prog) 77 | writeGoFiles(cfg, prog) 78 | 79 | for _, d := range cfg.diffs { 80 | if d.used == 0 { 81 | fmt.Fprintf(os.Stderr, "%s: unused diff\n", d.line) 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /run.ld: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | eval $(go env) 5 | export GOROOT 6 | go install 7 | rm -f c2go 8 | dst=$GOROOT # !!! 9 | rm -rf $dst/src/cmd/internal/ld* $dst/src/cmd/new?l 10 | 11 | for i in 6 5 8 9 12 | do 13 | rm -rf $dst/src/cmd/internal/ld 14 | c2go -c c2go.ld.cfg -dst $dst -I $GOROOT/include -I $GOROOT/src/cmd/ld -I $GOROOT/src/cmd/${i}l $GOROOT/src/liblink/*.c $GOROOT/src/cmd/ld/*.c $GOROOT/src/cmd/${i}l/*.c 15 | mv $dst/src/cmd/internal/ld $dst/src/cmd/internal/ld.$i 16 | done 17 | 18 | mv $dst/src/cmd/internal/ld.6 $dst/src/cmd/internal/ld 19 | rm -rf $dst/src/cmd/internal/ld.? 20 | 21 | for i in add/new6l/*.go; do 22 | base=$(echo $i | sed 's;add/;;') 23 | cat $i | grep -v 'build ignore' >$dst/src/cmd/$base 24 | done 25 | for i in add/ld/*.go; do 26 | base=$(echo $i | sed 's;.*/;;') 27 | cat $i | grep -v 'build ignore' >$dst/src/cmd/internal/ld/$base 28 | done 29 | 30 | gofmt -w $dst/src/cmd/internal/ld $dst/src/cmd/new?l # check for syntax errors, mainly 31 | rm -rf /tmp/c2gomain 32 | mv $dst/src/main /tmp/c2gomain 33 | export GOPATH="" 34 | rm $dst/src/cmd/internal/ld/bio.go 35 | echo 'X ,s/main\./obj./g 36 | X ,s/obj\.Argv0/os.Args[0]/g 37 | X ,s/obj\.Exits\(".+"\)/Exit(2)/g 38 | X ,s/gc\.Zconv/Zconv/g 39 | X ,s/BGETC/Bgetc/g 40 | X ,s/\*Endian/binary.ByteOrder/g 41 | X ,s/\&le([^a-zA-Z0-9_]|\n)/binary.LittleEndian\1/g 42 | X ,s/\&be([^a-zA-Z0-9_]|\n)/binary.BigEndian\1/g 43 | X ,s/ be\./ binary.BigEndian./g 44 | X ,s/ le\./ binary.LittleEndian./g 45 | X ,s/\.e64/.Uint64/g 46 | X ,s/\.e32/.Uint32/g 47 | X ,s/\.e16/.Uint16/g 48 | X ,s/obj\.Werrstr/err = fmt.Errorf/g 49 | X ,s/(err = fmt.Errorf.*)\n( +)return -1\n/\1\n\2return err\n/g 50 | X ,s/argv\[argc\] = (.*)\n +argc\+\+\n/argv = append(argv, \1)\n/g 51 | X/'"'"'/w 52 | q' | sam -d $(find $dst/src/cmd/{internal/ld,new?l} -type f -a -name '*.go') 53 | goimports -w $dst/src/cmd/new?l $dst/src/cmd/internal/ld 54 | wc $(find $dst/src/cmd/{internal/ld,new?l} -type f -a -name '*.go') 55 | go install -gcflags -e cmd/internal/ld cmd/new{5,6,8,9}l 56 | 57 | go tool 6g ~/hellocgo.go 58 | go tool new6l helloworld.6 59 | ./6.out 60 | 61 | for i in 5l 6l 8l 9l 62 | do 63 | cp $(which new$i) $(toolstash -n $i) 64 | done 65 | exit 0 66 | -------------------------------------------------------------------------------- /add/gc/util.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | package gc 4 | 5 | import ( 6 | "cmd/internal/obj" 7 | "os" 8 | "runtime/pprof" 9 | "strconv" 10 | "strings" 11 | ) 12 | 13 | func bool2int(b bool) int { 14 | if b { 15 | return 1 16 | } 17 | return 0 18 | } 19 | 20 | func (n *Node) Line() string { 21 | return obj.Linklinefmt(Ctxt, int(n.Lineno), false, false) 22 | } 23 | 24 | func atoi(s string) int { 25 | // NOTE: Not strconv.Atoi, accepts hex and octal prefixes. 26 | n, _ := strconv.ParseInt(s, 0, 0) 27 | return int(n) 28 | } 29 | 30 | func isalnum(c int) bool { 31 | return isalpha(c) || isdigit(c) 32 | } 33 | 34 | func isalpha(c int) bool { 35 | return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' 36 | } 37 | 38 | func isdigit(c int) bool { 39 | return '0' <= c && c <= '9' 40 | } 41 | 42 | func plan9quote(s string) string { 43 | if s == "" { 44 | goto needquote 45 | } 46 | for i := 0; i < len(s); i++ { 47 | if s[i] <= ' ' || s[i] == '\'' { 48 | goto needquote 49 | } 50 | } 51 | return s 52 | 53 | needquote: 54 | return "'" + strings.Replace(s, "'", "''", -1) + "'" 55 | } 56 | 57 | // simulation of int(*s++) in C 58 | func intstarstringplusplus(s string) (int, string) { 59 | if s == "" { 60 | return 0, "" 61 | } 62 | return int(s[0]), s[1:] 63 | } 64 | 65 | // strings.Compare, introduced in Go 1.5. 66 | func stringsCompare(a, b string) int { 67 | if a == b { 68 | return 0 69 | } 70 | if a < b { 71 | return -1 72 | } 73 | return +1 74 | } 75 | 76 | var atExitFuncs []func() 77 | 78 | func AtExit(f func()) { 79 | atExitFuncs = append(atExitFuncs, f) 80 | } 81 | 82 | func Exit(code int) { 83 | for i := len(atExitFuncs) - 1; i >= 0; i-- { 84 | f := atExitFuncs[i] 85 | atExitFuncs = atExitFuncs[:i] 86 | f() 87 | } 88 | os.Exit(code) 89 | } 90 | 91 | var cpuprofile string 92 | var memprofile string 93 | 94 | func startProfile() { 95 | if cpuprofile != "" { 96 | f, err := os.Create(cpuprofile) 97 | if err != nil { 98 | Fatal("%v", err) 99 | } 100 | if err := pprof.StartCPUProfile(f); err != nil { 101 | Fatal("%v", err) 102 | } 103 | AtExit(pprof.StopCPUProfile) 104 | } 105 | if memprofile != "" { 106 | f, err := os.Create(memprofile) 107 | if err != nil { 108 | Fatal("%v", err) 109 | } 110 | AtExit(func() { 111 | if err := pprof.WriteHeapProfile(f); err != nil { 112 | Fatal("%v", err) 113 | } 114 | }) 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /export.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "strings" 9 | "unicode/utf8" 10 | 11 | "rsc.io/c2go/cc" 12 | ) 13 | 14 | func exportDecls(cfg *Config, prog *cc.Prog) { 15 | for _, d := range cfg.topDecls { 16 | if shouldExport(cfg, d.Name) { 17 | exportDecl(d) 18 | } 19 | pkg := d.GoPackage 20 | if pkg == "" { 21 | continue 22 | } 23 | cc.Preorder(d, func(x cc.Syntax) { 24 | switch x := x.(type) { 25 | case *cc.Expr: 26 | if x.Op == cc.Name && x.XDecl != nil && x.XDecl.GoPackage != "" && x.XDecl.GoPackage != pkg { 27 | exportDecl(x.XDecl) 28 | } 29 | case *cc.Type: 30 | if x.Kind == cc.TypedefType && x.TypeDecl != nil && x.TypeDecl.GoPackage != "" && x.TypeDecl.GoPackage != pkg { 31 | exportDecl(x.TypeDecl) 32 | x.Name = x.TypeDecl.Name 33 | } 34 | } 35 | }) 36 | } 37 | 38 | for _, d := range cfg.topDecls { 39 | renameDecl(cfg, d) 40 | } 41 | } 42 | 43 | func shouldExport(cfg *Config, name string) bool { 44 | for _, s := range cfg.exports { 45 | if s == name { 46 | return true 47 | } 48 | } 49 | return false 50 | } 51 | 52 | func exportDecl(d *cc.Decl) { 53 | d.Name = exportName(d.Name) 54 | if d.Storage&cc.Typedef != 0 && d.Type.Kind == cc.Struct { 55 | for _, dd := range d.Type.Decls { 56 | exportDecl(dd) 57 | // type became type_, became Type_. Drop underscore now that it's not needed. 58 | if strings.HasSuffix(dd.Name, "_") && goKeyword[strings.ToLower(dd.Name[:len(dd.Name)-1])] { 59 | dd.Name = dd.Name[:len(dd.Name)-1] 60 | } 61 | if dd.Name == "U" { 62 | for _, dd := range dd.Type.Decls { 63 | exportDecl(dd) 64 | } 65 | } 66 | } 67 | } 68 | } 69 | 70 | func exportName(name string) string { 71 | _, size := utf8.DecodeRuneInString(name) 72 | return strings.ToUpper(name[:size]) + name[size:] 73 | } 74 | 75 | func renameDecl(cfg *Config, d *cc.Decl) { 76 | key := declKey(d) 77 | if cfg.rename[key] != "" { 78 | d.Name = cfg.rename[key] 79 | } 80 | if d.Storage&cc.Typedef != 0 && d.Type.Kind == cc.Struct { 81 | for _, dd := range d.Type.Decls { 82 | renameDecl(cfg, dd) 83 | if dd.Name == "U" { 84 | for _, dd := range dd.Type.Decls { 85 | renameDecl(cfg, dd) 86 | } 87 | } 88 | } 89 | } 90 | 91 | if d.Type != nil && d.Type.Kind == cc.Func && d.Body != nil { 92 | for _, s := range d.Body.Block { 93 | if s.Op == cc.StmtDecl && s.Decl.Storage&cc.Static != 0 { 94 | renameDecl(cfg, s.Decl) 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /add/obj/flag.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package obj 6 | 7 | import ( 8 | "flag" 9 | "fmt" 10 | ) 11 | 12 | func Flagfn2(string, string, func(string, string)) {panic("flag")} 13 | 14 | func Flagcount(name, usage string, val *int) { 15 | flag.Var((*count)(val), name, usage) 16 | } 17 | 18 | func Flagint32(name, usage string, val *int32) { 19 | flag.Var((*int32Value)(val), name, usage) 20 | } 21 | 22 | func Flagint64(name, usage string, val *int64) { 23 | flag.Int64Var(val, name, *val, usage) 24 | } 25 | 26 | func Flagstr(name, usage string, val *string) { 27 | flag.StringVar(val, name, *val, usage) 28 | } 29 | 30 | func Flagfn0(name, usage string, f func()) { 31 | flag.Var(fn0(f), name, usage) 32 | } 33 | 34 | func Flagfn1(name, usage string, f func(string)) { 35 | flag.Var(fn1(f), name, usage) 36 | } 37 | 38 | func Flagprint(fd int) { 39 | if fd == 1 { 40 | flag.CommandLine.SetOutput(os.Stdout) 41 | } 42 | flag.PrintDefaults() 43 | } 44 | 45 | func Flagparse(usage func()) { 46 | flag.Usage = usage 47 | flag.Parse() 48 | } 49 | 50 | // count is a flag.Value that is like a flag.Bool and a flag.Int. 51 | // If used as -name, it increments the count, but -name=x sets the count. 52 | // Used for verbose flag -v. 53 | type count int 54 | 55 | func (c *count) String() string { 56 | return fmt.Sprint(int(*c)) 57 | } 58 | 59 | func (c *count) Set(s string) error { 60 | switch s { 61 | case "true": 62 | *c++ 63 | case "false": 64 | *c = 0 65 | default: 66 | n, err := strconv.Atoi(s) 67 | if err != nil { 68 | return fmt.Errorf("invalid count %q", s) 69 | } 70 | *c = count(n) 71 | } 72 | return nil 73 | } 74 | 75 | func (c *count) IsBoolFlag() bool { 76 | return true 77 | } 78 | 79 | type int32Value int32 80 | 81 | func newIntValue(val int32, p *int32) *int32Value { 82 | *p = val 83 | return (*int32Value)(p) 84 | } 85 | 86 | func (i *int32Value) Set(s string) error { 87 | v, err := strconv.ParseInt(s, 0, 64) 88 | *i = int32Value(v) 89 | return err 90 | } 91 | 92 | func (i *int32Value) Get() interface{} { return int32(*i) } 93 | 94 | func (i *int32Value) String() string { return fmt.Sprintf("%v", *i) } 95 | 96 | type fn0 func() 97 | 98 | func (f fn0) Set(s string) error { 99 | f() 100 | return nil 101 | } 102 | 103 | func (f fn0) Get() interface{} { return nil } 104 | 105 | func (f fn0) String() string { return "" } 106 | 107 | func (f fn0) IsBoolFlag() bool { 108 | return true 109 | } 110 | 111 | type fn1 func(string) 112 | 113 | func (f fn1) Set(s string) error { 114 | f(s) 115 | return nil 116 | } 117 | 118 | func (f fn1) String() string { return "" } 119 | -------------------------------------------------------------------------------- /cc/parse.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package cc 6 | 7 | import ( 8 | "fmt" 9 | "io" 10 | "io/ioutil" 11 | "strings" 12 | ) 13 | 14 | func Read(name string, r io.Reader) (*Prog, error) { 15 | return ReadMany([]string{name}, []io.Reader{r}) 16 | } 17 | 18 | func ReadMany(names []string, readers []io.Reader) (*Prog, error) { 19 | lx := &lexer{} 20 | var prog *Prog 21 | for i, name := range names { 22 | if lx.includeSeen[name] != nil { 23 | continue 24 | } 25 | r := readers[i] 26 | data, err := ioutil.ReadAll(r) 27 | if err != nil { 28 | return nil, err 29 | } 30 | data = append(data, '\n') 31 | lx.start = startProg 32 | lx.lexInput = lexInput{ 33 | input: string(data), 34 | file: name, 35 | lineno: 1, 36 | } 37 | lx.parse() 38 | if lx.errors != nil { 39 | return nil, fmt.Errorf("%v", lx.errors[0]) 40 | } 41 | if prog == nil { 42 | prog = lx.prog 43 | } else { 44 | prog.Span.End = lx.prog.Span.End 45 | prog.Decls = append(prog.Decls, lx.prog.Decls...) 46 | } 47 | lx.prog = nil 48 | for sc := lx.scope; sc != nil; sc = sc.Next { 49 | for name, decl := range sc.Decl { 50 | if decl.Storage&Static != 0 || (decl.Storage&Typedef != 0 && strings.HasSuffix(decl.Span.Start.File, ".c")) { 51 | delete(sc.Decl, name) 52 | } 53 | } 54 | for name, typ := range sc.Tag { 55 | if strings.HasSuffix(typ.Span.Start.File, ".c") { 56 | delete(sc.Tag, name) 57 | } 58 | } 59 | } 60 | } 61 | lx.prog = prog 62 | lx.assignComments() 63 | lx.typecheck(lx.prog) 64 | if lx.errors != nil { 65 | return nil, fmt.Errorf("%v", strings.Join(lx.errors, "\n")) 66 | } 67 | 68 | removeDuplicates(lx.prog) 69 | 70 | return lx.prog, nil 71 | } 72 | 73 | func ParseExpr(str string) (*Expr, error) { 74 | lx := &lexer{ 75 | start: startExpr, 76 | lexInput: lexInput{ 77 | input: str + "\n", 78 | file: "", 79 | lineno: 1, 80 | }, 81 | } 82 | lx.parse() 83 | if lx.errors != nil { 84 | return nil, fmt.Errorf("parsing expression %#q: %v", str, lx.errors[0]) 85 | } 86 | return lx.expr, nil 87 | } 88 | 89 | type Prog struct { 90 | SyntaxInfo 91 | Decls []*Decl 92 | } 93 | 94 | // removeDuplicates drops the duplicated declarations 95 | // caused by forward decls from prog. 96 | // It keeps the _last_ of each given declaration, 97 | // assuming that's the complete one. 98 | // This heuristic tends to preserve something like 99 | // source order. 100 | // It would be defeated by someone writing a "forward" 101 | // declaration following the real definition. 102 | func removeDuplicates(prog *Prog) { 103 | count := map[*Decl]int{} 104 | for _, d := range prog.Decls { 105 | count[d]++ 106 | } 107 | var out []*Decl 108 | for _, d := range prog.Decls { 109 | count[d]-- 110 | if count[d] == 0 { 111 | out = append(out, d) 112 | } 113 | } 114 | prog.Decls = out 115 | } 116 | -------------------------------------------------------------------------------- /array.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import "rsc.io/c2go/cc" 8 | 9 | // fixArrays rewrites uses of the untyped "Array" container defined in cmd/gc 10 | // to use native Go slices. 11 | // It has nothing to do with standard C arrays. 12 | func fixArray(fn *cc.Decl, x *cc.Expr) { 13 | // arraynew(n, sizeof(T)) becomes Go make([]T, 0, n). 14 | if isCall(x, "arraynew") { 15 | if len(x.List) != 2 { 16 | fprintf(x.Span, "wrong number of arguments to arraynew") 17 | return 18 | } 19 | if x.List[1].Op != cc.SizeofType { 20 | fprintf(x.Span, "second argument to arraynew must be sizeof(T)") 21 | return 22 | } 23 | x.Left.Text = "make" 24 | x.Left.XDecl = nil 25 | typ := &cc.Type{Kind: Slice, Base: x.List[1].Type} 26 | x.XType = typ 27 | x.List = append(x.List, x.List[0]) 28 | x.List[1] = &cc.Expr{Op: cc.Number, Text: "0"} 29 | x.List[0] = &cc.Expr{Op: ExprType, Type: typ} 30 | return 31 | } 32 | 33 | // arraylength(x) becomes len(x) 34 | if isCall(x, "arraylength") { 35 | x.Left.Text = "len" 36 | x.Left.XDecl = nil 37 | return 38 | } 39 | 40 | // arrayset is unused in practice! 41 | 42 | // arrayadd(x, &elem) becomes x = append(x, elem). 43 | // Strictly speaking, this is not a complete translation, 44 | // because in the C code x might be a pointer taken from 45 | // another place, and arrayadd changes the len at that 46 | // other place too. In cmd/gc this does not happen. 47 | if isCall(x, "arrayadd") { 48 | if len(x.List) != 2 { 49 | fprintf(x.Span, "wrong number of arguments to arrayadd") 50 | return 51 | } 52 | if x.List[1].Op != cc.Addr { 53 | fprintf(x.Span, "second argument to arrayadd must be &x, have %v", x.List[1]) 54 | return 55 | } 56 | append := copyExpr(x) 57 | append.Left.Text = "append" 58 | append.Left.XDecl = nil 59 | x.Op = cc.Eq 60 | x.Left = append.List[0] 61 | x.Right = append 62 | append.List[1] = append.List[1].Left 63 | return 64 | } 65 | 66 | // *(T**)(arrayget(x, i)) turns into x[i]. 67 | // Record that x should have translated type T*. 68 | if x.Op == cc.Indir && x.Left.Op == cc.Cast && x.Left.Type.Kind == cc.Ptr && x.Left.Type.Base.Kind == cc.Ptr && isCall(x.Left.Left, "arrayget") { 69 | call := x.Left.Left 70 | x.Op = cc.Index 71 | x.XType = x.Left.Type.Base 72 | x.Left = call.List[0] 73 | x.Right = call.List[1] 74 | saveSliceType(x.Left, x.XType) 75 | return 76 | } 77 | 78 | // TODO: arraysort 79 | } 80 | 81 | func fixArrayStmt(fn *cc.Decl, x *cc.Stmt) { 82 | // Turn call to arrayfree into empty statement. 83 | // This is the only statment-level operation. 84 | // All other rewrites are done at the expression level 85 | // (or pseudo-expression, since assignments count as 86 | // expressions in our representation). 87 | if x.Op == cc.StmtExpr && isCall(x.Expr, "arrayfree") { 88 | x.Op = cc.Empty 89 | x.Expr = nil 90 | } 91 | } 92 | 93 | func isCall(x *cc.Expr, name string) bool { 94 | return x != nil && x.Op == cc.Call && x.Left.Op == cc.Name && x.Left.Text == name 95 | } 96 | 97 | func saveSliceType(x *cc.Expr, elem *cc.Type) { 98 | switch x.Op { 99 | case cc.Name, cc.Arrow, cc.Dot: 100 | if x.XDecl != nil { 101 | x.XDecl.Type = &cc.Type{Kind: Slice, Base: elem} 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo DONE WITH THIS 4 | exit 0 5 | 6 | set -e 7 | eval $(go env) 8 | export GOROOT 9 | go install 10 | rm -f c2go 11 | rm -f $GOROOT/src/liblink/sched9.c # implement 'build ignore' comment 12 | rm -f $GOROOT/src/cmd/gc/mkbuiltin1.c $GOROOT/src/cmd/gc/y.tab.c # implement 'build ignore' comment 13 | dst=$GOROOT # !!! 14 | cp $dst/src/cmd/internal/obj/zbootstrap.go /tmp 15 | trap "mkdir -p $dst/src/cmd/internal/obj && cp /tmp/zbootstrap.go $dst/src/cmd/internal/obj && cd $dst/src/cmd/gc && git checkout HEAD mkbuiltin1.c y.tab.c" 0 16 | rm -rf $dst/src/cmd/internal/obj $dst/src/cmd/internal/gc* $dst/src/cmd/new?g ## $dst/src/cmd/internal/ld* $dst/src/cmd/new?l 17 | 18 | for i in 6 5 8 9 19 | do 20 | ## rm -rf $dst/src/cmd/internal/obj $dst/src/cmd/internal/ld 21 | ## c2go -c c2go.cfg -dst $dst -I $GOROOT/include -I $GOROOT/src/cmd/${i}g $GOROOT/src/liblink/*.c $GOROOT/src/cmd/ld/*.c $GOROOT/src/cmd/${i}l/*.c 22 | ## mv $dst/src/cmd/internal/ld $dst/src/cmd/internal/ld.$i 23 | 24 | rm -rf $dst/src/cmd/internal/obj $dst/src/cmd/internal/gc 25 | c2go -c c2go.cfg -dst $dst -I $GOROOT/include -I $GOROOT/src/cmd/${i}g $GOROOT/src/liblink/*.c $GOROOT/src/cmd/gc/*.c $GOROOT/src/cmd/${i}g/*.c 26 | mv $dst/src/cmd/internal/gc $dst/src/cmd/internal/gc.$i 27 | done 28 | 29 | mv $dst/src/cmd/internal/gc.6 $dst/src/cmd/internal/gc 30 | ## mv $dst/src/cmd/internal/ld.6 $dst/src/cmd/internal/ld 31 | rm -rf $dst/src/cmd/internal/gc.? ## $dst/src/cmd/internal/ld.? 32 | cp /tmp/zbootstrap.go $dst/src/cmd/internal/obj 33 | for i in add/obj/*.go; do 34 | base=$(echo $i | sed 's;.*/;;') 35 | cat $i | grep -v 'build ignore' >$dst/src/cmd/internal/obj/$base 36 | done 37 | for i in add/obj/*/*.go; do 38 | base=$(echo $i | sed 's;add/obj/;;') 39 | cat $i | grep -v 'build ignore' >$dst/src/cmd/internal/obj/$base 40 | done 41 | for i in add/gc/*.*; do 42 | base=$(echo $i | sed 's;.*/;;') 43 | cat $i | grep -v 'build ignore' >$dst/src/cmd/internal/gc/$base 44 | done 45 | for i in add/new{5,6,8,9}g/*.go; do 46 | base=$(echo $i | sed 's;add/;;') 47 | cat $i | grep -v 'build ignore' >$dst/src/cmd/$base 48 | done 49 | ##for i in add/new6{g,l}/*.go; do 50 | ## base=$(echo $i | sed 's;add/;;') 51 | ## cat $i | grep -v 'build ignore' >$dst/src/cmd/$base 52 | ##done 53 | ##for i in add/ld/*.go; do 54 | ## base=$(echo $i | sed 's;.*/;;') 55 | ## cat $i | grep -v 'build ignore' >$dst/src/cmd/internal/ld/$base 56 | ##done 57 | 58 | rm $dst/src/cmd/internal/gc/{yerr.go,y.tab.go} 59 | (cd $dst/src/cmd/internal/gc && go tool yacc go.y) 60 | rm $dst/src/cmd/internal/obj/bio.go 61 | gofmt -w $dst/src/cmd/internal/obj # check for syntax errors, mainly 62 | rm -rf /tmp/c2gomain 63 | mv $dst/src/main /tmp/c2gomain 64 | export GOPATH="" 65 | goimports -w $dst/src/cmd/new* $dst/src/cmd/internal 66 | wc $(find $dst/src/cmd/{internal/obj,internal/gc,new?g,new?l} -type f -a -name '*.go') 67 | go install -gcflags -e cmd/internal/obj... cmd/objwriter cmd/internal/gc cmd/new{5,6,8,9}{a,g} ## cmd/new{5,6,8,9}{a,g,l} 68 | 69 | go tool new6g ~/g/go/test/helloworld.go 70 | go tool 6l helloworld.6 71 | ./6.out 72 | GOARCH=386 go tool new8g ~/g/go/test/helloworld.go 73 | GOARCH=386 go tool 8l helloworld.8 74 | ./8.out 75 | 76 | for i in 5g 6g 8g 9g 77 | do 78 | cp $(which new$i) $(toolstash -n $i) 79 | done 80 | 81 | exit 0 82 | 83 | GOOBJ=2 go tool 6g ~/g/go/test/helloworld.go 84 | GOOBJ=2 go build -work -a strings 85 | go tool dist install cmd/{5,6,8,9}{a,g,l} 86 | for arch in ppc64 ppc64le 386 amd64 amd64p32 arm 87 | do 88 | os=linux 89 | if [ "$arch" = "amd64p32" ]; then 90 | os=nacl 91 | fi 92 | echo $os/$arch 93 | GOOS=$os GOARCH=$arch go tool dist install runtime 94 | GOOBJ=2 GOOS=$os GOARCH=$arch go build -a std 95 | done 96 | 97 | # Edit ,s/(if\(.*\))\n(.*;)\n( *)else\n(.*;)/\1 {\n\2\n\3} else {\n\4\n\3}/g 98 | # Edit ,s/( *)(if\(.*\))\n(.*;)\n/\1\2 {\n\3\n\1}\n/g 99 | # Edit ,s/'\\0'/'\\x00'/g 100 | -------------------------------------------------------------------------------- /cc/stdhdr.go: -------------------------------------------------------------------------------- 1 | package cc 2 | 3 | var hdr_u_h = ` 4 | typedef signed char schar; 5 | typedef unsigned char uchar; 6 | typedef unsigned short ushort; 7 | typedef unsigned int uint; 8 | typedef unsigned long ulong; 9 | typedef long long vlong; 10 | typedef unsigned long long uvlong; 11 | 12 | typedef schar int8; 13 | typedef uchar uint8; 14 | typedef short int16; 15 | typedef ushort uint16; 16 | typedef long int32; 17 | typedef ulong uint32; 18 | typedef vlong int64; 19 | typedef uvlong uint64; 20 | typedef float float32; 21 | typedef double float64; 22 | typedef unsigned long uintptr; 23 | 24 | typedef schar s8int; 25 | typedef uchar u8int; 26 | typedef short s16int; 27 | typedef ushort u16int; 28 | typedef long s32int; 29 | typedef ulong u32int; 30 | typedef vlong s64int; 31 | typedef uvlong u64int; 32 | 33 | void *nil; 34 | 35 | typedef struct va_list *va_list; 36 | ` 37 | 38 | var hdr_libc_h = ` 39 | #include 40 | 41 | extern char *argv0; 42 | 43 | int nelem(void*); 44 | 45 | int memcmp(void*, void*, long); 46 | void *memset(void*, int, long); 47 | int strcmp(char*, char*); 48 | int strncmp(char*, char*, int); 49 | char *strcpy(char*, char*); 50 | char *smprint(char*, ...); 51 | void strcat(char*, char*); 52 | 53 | vlong seek(int, vlong, int); 54 | int write(int, void*, long); 55 | void atexit(void (*)(void)); 56 | void strncpy(char*, char*, int); 57 | int tokenize(char*, char**, int); 58 | 59 | int atoi(char*); 60 | ulong strtoul(char*, char**, int); 61 | long strtol(char*, char**, int); 62 | vlong strtoll(char*, char**, int); 63 | int isspace(int); 64 | int close(int); 65 | int read(int, void*, int); 66 | double atof(char*); 67 | int create(char*, int, int); 68 | int open(char*, int); 69 | uvlong strtoull(char*, char**, int); 70 | char *getenv(char*); 71 | int getwd(char*, int); 72 | double cputime(void); 73 | 74 | enum 75 | { 76 | AEXIST = 0, 77 | }; 78 | 79 | int errstr(char*, uint); 80 | void werrstr(char*, ...); 81 | 82 | void exits(char*); 83 | void sysfatal(char*, ...); 84 | char *strstr(char*, char*); 85 | int strlen(char*); 86 | void memmove(void*, void*, int); 87 | char *strdup(char*); 88 | void *malloc(int); 89 | void *calloc(int, int); 90 | void *realloc(void*, int); 91 | void free(void*); 92 | 93 | void va_start(va_list, void*); 94 | void va_end(va_list); 95 | void qsort(void *base, int nmemb, int size, int (*compar)(const void *, const void *)); 96 | char *GOEXPERIMENT; 97 | void setfcr(int); 98 | void notify(void*); 99 | void signal(int, void*); 100 | uintptr getcallerpc(void*); 101 | 102 | enum 103 | { 104 | OREAD, 105 | OWRITE, 106 | ORDWR, 107 | SIGBUS, 108 | SIGSEGV, 109 | NDFLT, 110 | FPPDBL, 111 | FPRNR, 112 | HEADER_IO, 113 | BOM = 0xFEFF, 114 | }; 115 | 116 | extern void flagcount(char*, char*, int*); 117 | extern void flagint32(char*, char*, int32*); 118 | extern void flagint64(char*, char*, int64*); 119 | extern void flagstr(char*, char*, char**); 120 | extern void flagparse(int*, char***, void (*usage)(void)); 121 | extern void flagfn0(char*, char*, void(*fn)(void)); 122 | extern void flagfn1(char*, char*, void(*fn)(char*)); 123 | extern void flagfn2(char*, char*, void(*fn)(char*, char*)); 124 | extern void flagprint(int); 125 | extern char* strecpy(char*, char*, char*); 126 | extern void abort(void); 127 | extern int remove(const char*); 128 | extern char* getgoos(void); 129 | extern char* getgoarch(void); 130 | extern char* getgoroot(void); 131 | extern char* getgoversion(void); 132 | extern char* getgoarm(void); 133 | extern char* getgo386(void); 134 | extern char* getgoextlinkenabled(void); 135 | extern char* getgohostos(void); 136 | extern char* getgohostarch(void); 137 | extern int runcmd(char**); 138 | extern char* strchr(char*, int); 139 | extern char* strrchr(char*, int); 140 | extern double floor(double); 141 | extern double ldexp(double, int); 142 | extern double frexp(double, int*); 143 | extern double pow(double, double); 144 | 145 | extern int access(char*, int); 146 | extern int isdigit(int); 147 | extern int isalpha(int); 148 | extern int isalnum(int); 149 | extern int getfields(char*, char**, int, int, char*); 150 | extern char* cleanname(char*); 151 | extern int noted(int); 152 | 153 | ` 154 | 155 | var hdr_extra_go_h = ` 156 | extern Node *N; 157 | extern Sym *S; 158 | extern Type *T; 159 | extern Label *L; 160 | //extern Case *C; 161 | extern Prog *P; 162 | 163 | enum 164 | { 165 | BITS = 5, 166 | NVAR = BITS*4*8, 167 | }; 168 | ` 169 | 170 | var hdr_sys_stat_h = ` 171 | struct stat { 172 | int st_mode; 173 | }; 174 | 175 | int lstat(char*, struct stat*); 176 | int S_ISREG(int); 177 | ` 178 | -------------------------------------------------------------------------------- /rename.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "path/filepath" 10 | "strings" 11 | 12 | "rsc.io/c2go/cc" 13 | ) 14 | 15 | var goKeyword = map[string]bool{ 16 | "chan": true, 17 | "defer": true, 18 | "fallthrough": true, 19 | "func": true, 20 | "go": true, 21 | "import": true, 22 | "interface": true, 23 | "iota": true, 24 | "map": true, 25 | "package": true, 26 | "range": true, 27 | "select": true, 28 | "type": true, 29 | "var": true, 30 | 31 | // not keywords but still need renaming 32 | "fmt": true, 33 | "path": true, 34 | "rune": true, 35 | "true": true, 36 | "false": true, 37 | } 38 | 39 | // renameDecls renames file-local declarations to make them 40 | // unique across the whole set of files being considered. 41 | // For now, it appends the file base name to the declared name. 42 | // Eventually it could be smarter and not do that when not necessary. 43 | // It also renames names like 'type' and 'func' to avoid Go keywords. 44 | func renameDecls(cfg *Config, prog *cc.Prog) { 45 | // Rewrite C identifiers to avoid important Go words (keywords, iota, etc). 46 | cc.Preorder(prog, func(x cc.Syntax) { 47 | switch x := x.(type) { 48 | case *cc.Decl: 49 | if goKeyword[x.Name] { 50 | // NOTE: Must put _ last so that name can be upper-cased for export. 51 | x.Name += "_" 52 | } 53 | 54 | case *cc.Stmt: 55 | for _, lab := range x.Labels { 56 | if goKeyword[lab.Name] { 57 | lab.Name += "_" 58 | } 59 | } 60 | switch x.Op { 61 | case cc.Goto: 62 | if goKeyword[x.Text] { 63 | x.Text += "_" 64 | } 65 | } 66 | } 67 | }) 68 | 69 | // Assign to packages (needed below but also in writeGoFiles). 70 | for _, d := range prog.Decls { 71 | if d.Body != nil && d.Body.Span.Start.File != "" { 72 | d.Span = d.Body.Span 73 | } 74 | d.GoPackage = cfg.filePackage(d.Span.Start.File) 75 | } 76 | 77 | // Build list of declared top-level names. 78 | // Not just prog.Decls because of enums and struct definitions. 79 | typedefs := map[*cc.Type]bool{} 80 | for _, d := range prog.Decls { 81 | if d.Storage&cc.Typedef != 0 { 82 | typedefs[d.Type] = true 83 | } 84 | } 85 | 86 | var decls []*cc.Decl 87 | for _, d := range prog.Decls { 88 | if d.Name == "" { 89 | if typedefs[d.Type] { 90 | continue 91 | } 92 | switch d.Type.Kind { 93 | case cc.Struct: 94 | if d.Type.Tag != "" { 95 | decls = append(decls, d) 96 | d.Name = d.Type.Tag 97 | d.Storage = cc.Typedef 98 | } 99 | if d.Type.TypeDecl == nil { 100 | d.Type.TypeDecl = d 101 | } 102 | case cc.Enum: 103 | d.Type.Tag = "" // enum tags are worthless 104 | for _, dd := range d.Type.Decls { 105 | decls = append(decls, dd) 106 | } 107 | } 108 | continue 109 | } 110 | decls = append(decls, d) 111 | if d.Storage&cc.Typedef != 0 && d.Type != nil && d.Type.TypeDecl == nil { 112 | d.Type.TypeDecl = d 113 | } 114 | } 115 | 116 | // Assign declarations to packages and identify conflicts. 117 | count := make(map[string]int) 118 | src := make(map[string]string) 119 | for _, d := range decls { 120 | // TODO(rsc): I don't understand why this is necessary given the above. 121 | if d.Body != nil && d.Body.Span.Start.File != "" { 122 | d.Span = d.Body.Span 123 | } 124 | d.GoPackage = cfg.filePackage(d.Span.Start.File) 125 | key := d.GoPackage + "." + d.Name 126 | if count[key]++; count[key] > 1 { 127 | if d.Span.String() == src[key] { 128 | // Assume this is a nested header and ignore duplicates. 129 | count[key] = 1 130 | continue 131 | } 132 | fprintf(d.Span, "conflicting name %s in %s (last at %s)", d.Name, d.GoPackage, src[key]) 133 | continue 134 | } 135 | src[key] = fmt.Sprintf("%s:%d", d.Span.Start.File, d.Span.Start.Line) 136 | } 137 | 138 | // Rename static, conflicting names. 139 | for _, d := range decls { 140 | key := d.GoPackage + "." + d.Name 141 | if count[key] > 1 { 142 | file := filepath.Base(d.Span.Start.File) 143 | if i := strings.Index(file, "."); i >= 0 { 144 | file = file[:i] 145 | } 146 | d.Name += "_" + file 147 | } 148 | 149 | if d.Type.Kind == cc.Func { 150 | if d.Body != nil { 151 | for _, s := range d.Body.Block { 152 | if s.Op == cc.StmtDecl && s.Decl.Storage&cc.Static != 0 { 153 | // Add function name as prefix. 154 | // Will print at top level. 155 | dd := s.Decl 156 | dd.Name = d.Name + "_" + dd.Name 157 | } 158 | } 159 | } 160 | } 161 | } 162 | 163 | cfg.topDecls = decls 164 | } 165 | -------------------------------------------------------------------------------- /add/obj/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build ignore 6 | 7 | package obj 8 | 9 | import ( 10 | "bufio" 11 | "fmt" 12 | "io" 13 | "log" 14 | "os" 15 | "strconv" 16 | "time" 17 | ) 18 | 19 | var start time.Time 20 | 21 | func Cputime() float64 { 22 | if start.IsZero() { 23 | start = time.Now() 24 | } 25 | return time.Since(start).Seconds() 26 | } 27 | 28 | type Biobuf struct { 29 | unget [2]int 30 | numUnget int 31 | f *os.File 32 | r *bufio.Reader 33 | w *bufio.Writer 34 | linelen int 35 | } 36 | 37 | func Bopenw(name string) (*Biobuf, error) { 38 | f, err := os.Create(name) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil 43 | } 44 | 45 | func Bopenr(name string) (*Biobuf, error) { 46 | f, err := os.Open(name) 47 | if err != nil { 48 | return nil, err 49 | } 50 | return &Biobuf{f: f, r: bufio.NewReader(f)}, nil 51 | } 52 | 53 | func Binitw(w io.Writer) *Biobuf { 54 | return &Biobuf{w: bufio.NewWriter(w)} 55 | } 56 | 57 | func (b *Biobuf) Write(p []byte) (int, error) { 58 | return b.w.Write(p) 59 | } 60 | 61 | func Bwritestring(b *Biobuf, p string) (int, error) { 62 | return b.w.WriteString(p) 63 | } 64 | 65 | func Bseek(b *Biobuf, offset int64, whence int) int64 { 66 | if b.w != nil { 67 | if err := b.w.Flush(); err != nil { 68 | log.Fatal("writing output: %v", err) 69 | } 70 | } else if b.r != nil { 71 | if whence == 1 { 72 | offset -= int64(b.r.Buffered()) 73 | } 74 | } 75 | off, err := b.f.Seek(offset, whence) 76 | if err != nil { 77 | log.Fatal("seeking in output: %v", err) 78 | } 79 | if b.r != nil { 80 | b.r.Reset(b.f) 81 | } 82 | return off 83 | } 84 | 85 | func Boffset(b *Biobuf) int64 { 86 | if err := b.w.Flush(); err != nil { 87 | log.Fatal("writing output: %v", err) 88 | } 89 | off, err := b.f.Seek(0, 1) 90 | if err != nil { 91 | log.Fatal("seeking in output: %v", err) 92 | } 93 | return off 94 | } 95 | 96 | func (b *Biobuf) Flush() error { 97 | return b.w.Flush() 98 | } 99 | 100 | func Bwrite(b *Biobuf, p []byte) (int, error) { 101 | return b.w.Write(p) 102 | } 103 | 104 | func Bputc(b *Biobuf, c byte) { 105 | b.w.WriteByte(c) 106 | } 107 | 108 | const Beof = -1 109 | 110 | func Bread(b *Biobuf, p []byte) int { 111 | n, err := io.ReadFull(b.r, p) 112 | if n == 0 { 113 | if err != nil && err != io.EOF { 114 | n = -1 115 | } 116 | } 117 | return n 118 | } 119 | 120 | func Bgetc(b *Biobuf) int { 121 | if b.numUnget > 0 { 122 | b.numUnget-- 123 | return int(b.unget[b.numUnget]) 124 | } 125 | c, err := b.r.ReadByte() 126 | r := int(c) 127 | if err != nil { 128 | r = -1 129 | } 130 | b.unget[1] = b.unget[0] 131 | b.unget[0] = r 132 | return r 133 | } 134 | 135 | func Bgetrune(b *Biobuf) int { 136 | r, _, err := b.r.ReadRune() 137 | if err != nil { 138 | return -1 139 | } 140 | return int(r) 141 | } 142 | 143 | func Bungetrune(b *Biobuf) { 144 | b.r.UnreadRune() 145 | } 146 | 147 | func (b *Biobuf) Read(p []byte) (int, error) { 148 | return b.r.Read(p) 149 | } 150 | 151 | func Brdline(b *Biobuf, delim int) string { 152 | s, err := b.r.ReadBytes(byte(delim)) 153 | if err != nil { 154 | log.Fatalf("reading input: %v", err) 155 | } 156 | b.linelen = len(s) 157 | return string(s) 158 | } 159 | 160 | func Brdstr(b *Biobuf, delim int, cut int) string { 161 | s, err := b.r.ReadString(byte(delim)) 162 | if err != nil { 163 | log.Fatalf("reading input: %v", err) 164 | } 165 | if len(s) > 0 && cut > 0 { 166 | s = s[:len(s)-1] 167 | } 168 | return s 169 | } 170 | 171 | func Access(name string, mode int) int { 172 | if mode != 0 { 173 | panic("bad access") 174 | } 175 | _, err := os.Stat(name) 176 | if err != nil { 177 | return -1 178 | } 179 | return 0 180 | } 181 | 182 | func Blinelen(b *Biobuf) int { 183 | return b.linelen 184 | } 185 | 186 | func Bungetc(b *Biobuf) { 187 | b.numUnget++ 188 | } 189 | 190 | func Bflush(b *Biobuf) error { 191 | return b.w.Flush() 192 | } 193 | 194 | func Bterm(b *Biobuf) error { 195 | var err error 196 | if b.w != nil { 197 | err = b.w.Flush() 198 | } 199 | err1 := b.f.Close() 200 | if err == nil { 201 | err = err1 202 | } 203 | return err 204 | } 205 | 206 | func envOr(key, value string) string { 207 | if x := os.Getenv(key); x != "" { 208 | return x 209 | } 210 | return value 211 | } 212 | 213 | func Getgoroot() string { 214 | return envOr("GOROOT", defaultGOROOT) 215 | } 216 | 217 | func Getgoarch() string { 218 | return envOr("GOARCH", defaultGOARCH) 219 | } 220 | 221 | func Getgoos() string { 222 | return envOr("GOOS", defaultGOOS) 223 | } 224 | 225 | func Getgoarm() string { 226 | return envOr("GOARM", defaultGOARM) 227 | } 228 | 229 | func Getgo386() string { 230 | return envOr("GO386", defaultGO386) 231 | } 232 | 233 | func Getgoversion() string { 234 | return version 235 | } 236 | 237 | func Atoi(s string) int { 238 | i, _ := strconv.Atoi(s) 239 | return i 240 | } 241 | 242 | func (p *Prog) Line() string { 243 | return Linklinefmt(p.Ctxt, int(p.Lineno), false, false) 244 | } 245 | 246 | func (p *Prog) String() string { 247 | if p.Ctxt == nil { 248 | return fmt.Sprintf("") 249 | } 250 | return p.Ctxt.Arch.Pconv(p) 251 | } 252 | 253 | func (ctxt *Link) NewProg() *Prog { 254 | p := new(Prog) // should be the only call to this; all others should use ctxt.NewProg 255 | p.Ctxt = ctxt 256 | return p 257 | } 258 | 259 | func (ctxt *Link) Line(n int) string { 260 | return Linklinefmt(ctxt, n, false, false) 261 | } 262 | 263 | func (ctxt *Link) Dconv(a *Addr) string { 264 | return ctxt.Arch.Dconv(nil, 0, a) 265 | } 266 | 267 | func (ctxt *Link) Rconv(reg int) string { 268 | return ctxt.Arch.Rconv(reg) 269 | } 270 | 271 | func Getcallerpc(interface{}) uintptr { 272 | return 1 273 | } 274 | -------------------------------------------------------------------------------- /output.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bytes" 9 | "flag" 10 | "go/format" 11 | "io/ioutil" 12 | "log" 13 | "os" 14 | "path" 15 | "path/filepath" 16 | "strings" 17 | 18 | "rsc.io/c2go/cc" 19 | ) 20 | 21 | var dst = flag.String("dst", "/tmp/c2go", "GOPATH root of destination") 22 | 23 | // writeGoFiles writes prog to Go source files in a tree of packages. 24 | func writeGoFiles(cfg *Config, prog *cc.Prog) { 25 | printers := map[string]*Printer{} 26 | cfiles := map[string]string{} 27 | for _, decl := range prog.Decls { 28 | if decl.GoPackage == "" { 29 | decl.GoPackage = "other" 30 | } 31 | cfile := decl.Span.Start.File 32 | gofile := strings.TrimSuffix(strings.TrimSuffix(cfile, ".c"), ".h") + ".go" 33 | gofile = decl.GoPackage + "/" + filepath.Base(gofile) 34 | cfiles[gofile] = cfile 35 | p := printers[gofile] 36 | if p == nil { 37 | p = new(Printer) 38 | p.Package = decl.GoPackage 39 | pkg := path.Base(p.Package) 40 | if strings.Count(p.Package, "/") == 1 && strings.HasPrefix(p.Package, "cmd/") { 41 | pkg = "main" 42 | } 43 | p.Print("package ", pkg, "\n\n") 44 | switch p.Package { 45 | case "cmd/new5g", "cmd/new6g", "cmd/new8g", "cmd/new9g": 46 | p.Print(`import "cmd/internal/obj"`, "\n") 47 | p.Print(`import "cmd/internal/gc"`, "\n") 48 | 49 | case "cmd/new5l", "cmd/new6l", "cmd/new8l", "cmd/new9l": 50 | p.Print(`import "cmd/internal/obj"`, "\n") 51 | p.Print(`import "cmd/internal/ld"`, "\n") 52 | 53 | case "cmd/internal/gc", "cmd/internal/ld", "cmd/internal/obj/arm", "cmd/internal/obj/ppc64", "cmd/internal/obj/x86", "cmd/internal/obj/amd64": 54 | p.Print(`import "cmd/internal/obj"`, "\n") 55 | } 56 | 57 | printers[gofile] = p 58 | } 59 | 60 | off := len(p.Bytes()) 61 | repl, ok := cfg.replace[decl.Name] 62 | if !ok { 63 | repl, ok = cfg.replace[strings.ToLower(decl.Name)] 64 | } 65 | if cfg.delete[decl.Name] || cfg.delete[strings.ToLower(decl.Name)] { 66 | repl, ok = "", true 67 | } 68 | if ok { 69 | // Use replacement text from config but keep surrounding comments. 70 | p.Print(decl.Comments.Before) 71 | p.Print(repl) 72 | p.Print(decl.Comments.Suffix, decl.Comments.After) 73 | } else { 74 | p.Print(decl) 75 | } 76 | if len(p.Bytes()) > off { 77 | p.Print(Newline) 78 | p.Print(Newline) 79 | } 80 | } 81 | 82 | for gofile, p := range printers { 83 | dstfile := filepath.Join(*dst+"/src", gofile) 84 | os.MkdirAll(filepath.Dir(dstfile), 0777) 85 | buf := p.Bytes() 86 | 87 | // Not entirely sure why these lines get broken. 88 | buf = bytes.Replace(buf, []byte("\n,"), []byte(","), -1) 89 | buf = bytes.Replace(buf, []byte("\n {"), []byte(" {"), -1) 90 | 91 | buf1, err := format.Source(buf) 92 | if err != nil { 93 | // Scream because it invalidates diffs. 94 | log.Printf("ERROR formatting %s: %v", gofile, err) 95 | } 96 | if err == nil { 97 | buf = buf1 98 | } 99 | 100 | // Not sure where these blank lines come from. 101 | buf = bytes.Replace(buf, []byte("{\n\n"), []byte("{\n"), -1) 102 | 103 | buf = fixCopyright(gofile, cfiles[gofile], buf) 104 | 105 | for i, d := range cfg.diffs { 106 | if bytes.Contains(buf, d.before) { 107 | buf = bytes.Replace(buf, d.before, d.after, -1) 108 | cfg.diffs[i].used++ 109 | } 110 | } 111 | 112 | if err := ioutil.WriteFile(dstfile, buf, 0666); err != nil { 113 | log.Print(err) 114 | } 115 | } 116 | } 117 | 118 | var copyrightPrefixes = []string{ 119 | "// Copyright", 120 | "// Inferno", 121 | "// Derived", 122 | "// cmd/", 123 | "/*\n * The authors of this software", 124 | "/*\nhttp://code.google.com", 125 | } 126 | 127 | // fixCopyright hoists the copyright notice to the top of the file. 128 | // The package statement has been printed above it. 129 | // If fixCopyright cannot find a notice, it calls copyCopyright to copy it 130 | // from the original C file. 131 | func fixCopyright(gofile, cfile string, buf []byte) []byte { 132 | i := -1 133 | for _, prefix := range copyrightPrefixes { 134 | if j := bytes.Index(buf, []byte(prefix)); j >= 0 && (i < 0 || j < i) { 135 | i = j 136 | } 137 | } 138 | if i < 0 { 139 | //log.Printf("%s: cannot find copyright notice", gofile) 140 | return copyCopyright(gofile, cfile, buf) 141 | } 142 | 143 | k := bytes.Index(buf[i:], []byte("\n\n")) 144 | if k < 0 { 145 | log.Printf("%s: cannot find end of copyright notice", gofile) 146 | return buf 147 | } 148 | k += i 149 | for l := k - 1; l >= 0; l-- { 150 | if buf[l] == '\n' { 151 | if buf[l+1] != '/' || buf[l+2] != '/' { 152 | log.Printf("%s: copyright notice not followed by blank line", gofile) 153 | return buf 154 | } 155 | break 156 | } 157 | } 158 | 159 | var out []byte 160 | out = append(out, buf[i:k+2]...) 161 | out = append(out, buf[:i]...) 162 | out = append(out, buf[k+1:]...) // k+1 to include an extra \n 163 | return out 164 | } 165 | 166 | // copyCopyright inserts the copyright from cfile at the beginning of buf 167 | // and returns the result. 168 | func copyCopyright(gofile, cfile string, buf []byte) []byte { 169 | if strings.HasPrefix(cfile, "internal/") { 170 | return buf 171 | } 172 | data, err := ioutil.ReadFile(cfile) 173 | if err != nil { 174 | log.Printf("%s: reading copyright from C: %v", gofile, err) 175 | return buf 176 | } 177 | 178 | i := -1 179 | for _, prefix := range copyrightPrefixes { 180 | if j := bytes.Index(data, []byte(prefix)); j >= 0 && (i < 0 || j < i) { 181 | i = j 182 | } 183 | } 184 | if i < 0 { 185 | log.Printf("%s: cannot find copyright notice in C file %s", gofile, cfile) 186 | return buf 187 | } 188 | 189 | j := bytes.Index(data[i:], []byte("\n\n")) 190 | if j < 0 { 191 | log.Printf("%s: cannot find end of copyright notice in C file %s", gofile, cfile) 192 | } 193 | j += i 194 | return append(data[i:j+2], buf...) 195 | } 196 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "io/ioutil" 11 | "log" 12 | "path" 13 | "path/filepath" 14 | "runtime" 15 | "strings" 16 | 17 | "rsc.io/c2go/cc" 18 | ) 19 | 20 | type Config struct { 21 | pkgRules []pkgRule 22 | exports []string 23 | replace map[string]string 24 | delete map[string]bool 25 | diffs []diff 26 | slice map[string]bool 27 | len map[string]string 28 | cap map[string]string 29 | typeMap map[string]string 30 | bool map[string]bool 31 | ptr map[string]bool 32 | rename map[string]string 33 | 34 | // derived during analysis 35 | topDecls []*cc.Decl 36 | } 37 | 38 | type pkgRule struct { 39 | pattern string 40 | pkg string 41 | } 42 | 43 | type diff struct { 44 | line string 45 | before []byte 46 | after []byte 47 | used int 48 | } 49 | 50 | func (cfg *Config) filePackage(file string) (pkg string) { 51 | file = filepath.ToSlash(strings.TrimPrefix(file, runtime.GOROOT()+string(filepath.Separator))) 52 | pkg = "main" 53 | for _, rule := range cfg.pkgRules { 54 | matched, err := path.Match(rule.pattern, file) 55 | if err != nil { 56 | log.Printf("invalid pattern: %v", err) 57 | continue 58 | } 59 | if matched { 60 | pkg = rule.pkg 61 | } 62 | } 63 | return pkg 64 | } 65 | 66 | func (cfg *Config) read(file string) { 67 | data, err := ioutil.ReadFile(file) 68 | if err != nil { 69 | log.Fatal(err) 70 | } 71 | lineno := 0 72 | lines := strings.Split(string(data), "\n") 73 | cfg.replace = make(map[string]string) 74 | cfg.delete = make(map[string]bool) 75 | cfg.slice = make(map[string]bool) 76 | cfg.len = make(map[string]string) 77 | cfg.cap = make(map[string]string) 78 | cfg.typeMap = make(map[string]string) 79 | cfg.bool = make(map[string]bool) 80 | cfg.ptr = make(map[string]bool) 81 | cfg.rename = make(map[string]string) 82 | 83 | for len(lines) > 0 { 84 | line := lines[0] 85 | lines = lines[1:] 86 | lineno++ 87 | line = strings.TrimSpace(line) 88 | if strings.HasPrefix(line, "#") { 89 | continue 90 | } 91 | f := strings.Fields(line) 92 | if len(f) == 0 { 93 | continue 94 | } 95 | switch f[0] { 96 | case "package": 97 | pkg := f[len(f)-1] 98 | for i := 1; i < len(f)-1; i++ { 99 | cfg.pkgRules = append(cfg.pkgRules, pkgRule{f[i], pkg}) 100 | } 101 | 102 | case "export": 103 | cfg.exports = append(cfg.exports, f[1:]...) 104 | 105 | case "delete": 106 | for _, name := range f[1:] { 107 | cfg.delete[name] = true 108 | } 109 | 110 | case "bool": 111 | for _, name := range f[1:] { 112 | cfg.bool[name] = true 113 | } 114 | 115 | case "ptr": 116 | for _, name := range f[1:] { 117 | cfg.ptr[name] = true 118 | } 119 | 120 | case "string": 121 | if len(f) >= 3 { 122 | cfg.len[f[2]] = f[1] 123 | } 124 | 125 | case "slice": 126 | if len(f) >= 2 { 127 | cfg.slice[f[1]] = true 128 | } 129 | if len(f) >= 3 { 130 | cfg.len[f[2]] = f[1] 131 | } 132 | if len(f) >= 4 { 133 | cfg.cap[f[3]] = f[1] 134 | } 135 | if len(f) >= 5 { 136 | log.Printf("%s:%d: extra arguments for slice", file, lineno) 137 | } 138 | 139 | case "func", "type": 140 | if len(f) < 2 { 141 | log.Printf("%s:%d: short func/type declaration", file, lineno) 142 | } 143 | var buf bytes.Buffer 144 | buf.WriteString(line + "\n") 145 | if strings.HasSuffix(line, "{") { 146 | for { 147 | lineno++ 148 | if len(lines) == 0 { 149 | log.Fatalf("%s:%d: unexpected EOF reading func/type body", file, lineno) 150 | } 151 | line = lines[0] 152 | lines = lines[1:] 153 | buf.WriteString(line + "\n") 154 | if line == "}" { 155 | break 156 | } 157 | } 158 | } 159 | name := f[1] 160 | if i := strings.Index(name, "("); i >= 0 { 161 | name = name[:i] 162 | } 163 | cfg.replace[name] = buf.String() 164 | 165 | case "diff": 166 | if line != "diff {" { 167 | log.Printf("%s:%d: invalid diff opening", file, lineno) 168 | break 169 | } 170 | 171 | var old, new bytes.Buffer 172 | fileline := fmt.Sprintf("%s:%d", file, lineno) 173 | for { 174 | lineno++ 175 | if len(lines) == 0 { 176 | log.Fatalf("%s:%d: unexpected EOF reading diff", file, lineno) 177 | } 178 | line = lines[0] 179 | lines = lines[1:] 180 | if line == "}" { 181 | break 182 | } 183 | switch { 184 | case strings.HasPrefix(line, "+"): 185 | line = strings.TrimPrefix(line[1:], " ") 186 | new.WriteString(line + "\n") 187 | 188 | case strings.HasPrefix(line, "-"): 189 | line = strings.TrimPrefix(line[1:], " ") 190 | old.WriteString(line + "\n") 191 | 192 | default: 193 | line = strings.TrimPrefix(strings.TrimPrefix(line, " "), " ") 194 | old.WriteString(line + "\n") 195 | new.WriteString(line + "\n") 196 | } 197 | } 198 | cfg.diffs = append(cfg.diffs, diff{ 199 | line: fileline, 200 | before: old.Bytes(), 201 | after: new.Bytes(), 202 | }) 203 | 204 | case "typemap": 205 | if len(f) != 3 { 206 | log.Printf("%s:%d: invalid typemap directive", file, lineno) 207 | continue 208 | } 209 | cfg.typeMap[f[1]] = f[2] 210 | 211 | case "rename": 212 | if len(f) != 3 { 213 | log.Printf("%s:%d: invalid rename directive", file, lineno) 214 | continue 215 | } 216 | cfg.rename[f[1]] = f[2] 217 | 218 | default: 219 | log.Printf("%s:%d: unknown verb %s", file, lineno, f[0]) 220 | } 221 | } 222 | } 223 | 224 | func declKey(d *cc.Decl) string { 225 | key := d.Name 226 | if t := d.OuterType; t != nil { 227 | name := t.Name 228 | if name == "" { 229 | name = t.Tag 230 | } 231 | if name == "" { 232 | name = t.String() 233 | } 234 | key = name + "." + key 235 | } 236 | if d.CurFn != nil { 237 | key = declKey(d.CurFn) + "." + key 238 | } 239 | return key 240 | } 241 | -------------------------------------------------------------------------------- /qsort.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "rsc.io/c2go/cc" 9 | ) 10 | 11 | func fixQsort(prog *cc.Prog, x *cc.Expr) { 12 | if len(x.List) != 4 { 13 | fprintf(x.Span, "unsupported %v - wrong arg count", x) 14 | return 15 | } 16 | if x.List[2].Op != cc.SizeofExpr || unparen(x.List[2].Left).String() != unparen(x.List[0]).String()+"[0]" { 17 | fprintf(x.Span, "unsupported %v - wrong elem size %v vs %v", x, unparen(x.List[2].Left).String(), unparen(x.List[0]).String()+"[0]") 18 | return 19 | } 20 | if x.List[3].Op != cc.Name || x.List[3].XDecl == nil { 21 | fprintf(x.Span, "unsupported %v - unknown comparison function", x) 22 | return 23 | } 24 | cmp := x.List[3].XDecl.Name 25 | decl := x.List[3].XDecl 26 | 27 | typ, newDecl := fixQsortCmp(decl) 28 | if typ == nil { 29 | return 30 | } 31 | 32 | x.Left.Text = "sort.Sort" 33 | x.Left.XDecl = nil 34 | x.List = []*cc.Expr{ 35 | &cc.Expr{ 36 | Op: cc.Call, 37 | Left: &cc.Expr{Op: cc.Name, Text: cmp}, 38 | List: []*cc.Expr{ 39 | { 40 | Op: ExprSlice, 41 | List: []*cc.Expr{ 42 | x.List[0], 43 | nil, 44 | x.List[1], 45 | }, 46 | }, 47 | }, 48 | }, 49 | } 50 | 51 | typeDecl := &cc.Decl{ 52 | GoPackage: decl.GoPackage, 53 | SyntaxInfo: cc.SyntaxInfo{Span: decl.Span}, 54 | Name: cmp, 55 | Storage: cc.Typedef, 56 | Type: &cc.Type{ 57 | Kind: Slice, 58 | Base: typ, 59 | }, 60 | } 61 | 62 | lenFunc := &cc.Decl{ 63 | GoPackage: decl.GoPackage, 64 | SyntaxInfo: cc.SyntaxInfo{Span: decl.Span}, 65 | Name: "(x " + cmp + ") Len", 66 | Type: &cc.Type{ 67 | Kind: cc.Func, 68 | Base: intType, 69 | }, 70 | Body: &cc.Stmt{ 71 | Op: cc.Block, 72 | Block: []*cc.Stmt{ 73 | { 74 | Op: cc.Return, 75 | Expr: &cc.Expr{ 76 | Op: cc.Name, 77 | Text: "len(x)", 78 | }, 79 | }, 80 | }, 81 | }, 82 | } 83 | 84 | swapFunc := &cc.Decl{ 85 | GoPackage: decl.GoPackage, 86 | SyntaxInfo: cc.SyntaxInfo{Span: decl.Span}, 87 | Name: "(x " + cmp + ") Swap", 88 | Type: &cc.Type{ 89 | Kind: cc.Func, 90 | Base: &cc.Type{Kind: cc.Void}, 91 | Decls: []*cc.Decl{ 92 | {Name: "i", Type: &cc.Type{Kind: cc.TypedefType}}, 93 | {Name: "j", Type: intType}, 94 | }, 95 | }, 96 | Body: &cc.Stmt{ 97 | Op: cc.Block, 98 | Block: []*cc.Stmt{ 99 | { 100 | Op: cc.StmtExpr, 101 | Expr: &cc.Expr{ 102 | Op: cc.Name, 103 | Text: "x[i], x[j] = x[j], x[i]", 104 | }, 105 | }, 106 | }, 107 | }, 108 | } 109 | 110 | for i, d := range prog.Decls { 111 | if d == decl { 112 | prog.Decls = append(append(prog.Decls[:i:i], typeDecl, lenFunc, swapFunc, newDecl), prog.Decls[i+1:]...) 113 | return 114 | } 115 | } 116 | prog.Decls = append(prog.Decls[:len(prog.Decls):len(prog.Decls)], typeDecl, lenFunc, swapFunc, newDecl) 117 | } 118 | 119 | // isGoVoidPtr reports whether t is a void* or the Go translation of a void* (*struct{}). 120 | func isGoVoidPtr(t *cc.Type) bool { 121 | if t == nil || t.Kind != cc.Ptr { 122 | return false 123 | } 124 | t = t.Base 125 | return t.Kind == cc.Void || t.Kind == cc.Struct && len(t.Decls) == 0 126 | } 127 | 128 | func fixQsortCmp(decl *cc.Decl) (*cc.Type, *cc.Decl) { 129 | ftyp := decl.Type 130 | if ftyp.Kind != cc.Func || len(ftyp.Decls) != 2 || !isEmptyInterface(ftyp.Decls[0].Type) || !isEmptyInterface(ftyp.Decls[1].Type) { 131 | fprintf(decl.Span, "invalid qsort cmp function %v - wrong args", GoString(ftyp)) 132 | return nil, nil 133 | } 134 | 135 | a1, a2 := ftyp.Decls[0], ftyp.Decls[1] 136 | var eq1, eq2, p1, p2 *cc.Expr 137 | var indir1, indir2 bool 138 | 139 | cc.Preorder(decl.Body, func(x cc.Syntax) { 140 | switch x := x.(type) { 141 | case *cc.Expr: 142 | if x.Op != cc.Eq { 143 | return 144 | } 145 | r := x.Right 146 | if r.Op == cc.Indir { 147 | r = r.Left 148 | } 149 | if (r.Op == TypeAssert || r.Op == cc.Cast) && r.Left.Op == cc.Name { 150 | if r.Left.XDecl == a1 && p1 == nil { 151 | p1 = x.Left 152 | eq1 = x 153 | indir1 = r != x.Right 154 | } 155 | if r.Left.XDecl == a2 && p2 == nil { 156 | p2 = x.Left 157 | eq2 = x 158 | indir2 = r != x.Right 159 | } 160 | } 161 | } 162 | }) 163 | 164 | if p1 == nil || p2 == nil { 165 | fprintf(decl.Span, "invalid qsort cmp function - cannot find arg extraction") 166 | return nil, nil 167 | } 168 | 169 | if !sameType(p1.XType, p2.XType) { 170 | fprintf(decl.Span, "invalid qsort cmp function - different arg types %v and %v", GoString(p1.XType), GoString(p2.XType)) 171 | return nil, nil 172 | } 173 | if indir1 != indir2 { 174 | fprintf(decl.Span, "invalid qsort cmp function - different arg indirection") 175 | return nil, nil 176 | } 177 | 178 | typ := p1.XType 179 | if !indir1 { 180 | if typ.Def().Kind != cc.Ptr { 181 | fprintf(decl.Span, "invalid qsort cmp function - arg ptr cast to non-ptr %v", GoString(typ)) 182 | return nil, nil 183 | } 184 | typ = typ.Def().Base 185 | } 186 | 187 | // Have all the information. Committed. 188 | // Rewrite to take x, i, j, use x[i] for p1, x[j] for p2, 189 | // take address of x[i], x[j] if there was no indirect, 190 | // replace all return z with return z < 0. 191 | newDecl := *decl 192 | decl.Body = nil 193 | decl = &newDecl 194 | cmp := decl.Name 195 | decl.Name = "(x " + cmp + ") Less" 196 | decl.Type = &cc.Type{ 197 | Kind: cc.Func, 198 | Base: boolType, 199 | Decls: []*cc.Decl{ 200 | {Name: "i", Type: &cc.Type{Kind: cc.TypedefType}}, 201 | {Name: "j", Type: intType}, 202 | }, 203 | } 204 | 205 | prefix := "" 206 | if !indir1 { 207 | prefix = "&" 208 | } 209 | eq1.Right = &cc.Expr{Op: cc.Name, Text: prefix + "x[i]", XType: p1.XType} 210 | eq2.Right = &cc.Expr{Op: cc.Name, Text: prefix + "x[j]", XType: p1.XType} 211 | 212 | cc.Preorder(decl.Body, func(x cc.Syntax) { 213 | switch x := x.(type) { 214 | case *cc.Stmt: 215 | if x.Op == cc.Return && x.Expr != nil { 216 | ret := x.Expr 217 | // Pick off 0, -1, +1. 218 | // Otherwise rewrite ret to ret < 0. 219 | switch ret.Op { 220 | case cc.Minus, cc.Plus: 221 | if ret.Left.Op == cc.Number && ret.Left.Text == "1" { 222 | if ret.Op == cc.Plus { 223 | ret.Text = "false" 224 | } else { 225 | ret.Text = "true" 226 | } 227 | ret.Op = cc.Name 228 | ret.Left = nil 229 | ret.XType = boolType 230 | return 231 | } 232 | case cc.Number: 233 | if ret.Text == "0" { 234 | ret.Op = cc.Name 235 | ret.Text = "false" 236 | ret.XType = boolType 237 | return 238 | } 239 | } 240 | x.Expr = &cc.Expr{Op: cc.Lt, Left: ret, Right: &cc.Expr{Op: cc.Number, Text: "0"}, XType: boolType} 241 | return 242 | } 243 | } 244 | }) 245 | 246 | return typ, decl 247 | } 248 | -------------------------------------------------------------------------------- /cc/type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package cc 6 | 7 | import ( 8 | "fmt" 9 | "strings" 10 | ) 11 | 12 | var printf = fmt.Printf 13 | 14 | type Type struct { 15 | SyntaxInfo 16 | Kind TypeKind 17 | Qual TypeQual 18 | Base *Type 19 | Tag string 20 | Decls []*Decl 21 | Width *Expr 22 | Name string 23 | TypeDecl *Decl 24 | } 25 | 26 | type TypeKind int 27 | 28 | const ( 29 | _ TypeKind = iota 30 | Void 31 | Char 32 | Uchar 33 | Short 34 | Ushort 35 | Int 36 | Uint 37 | Long 38 | Ulong 39 | Longlong 40 | Ulonglong 41 | Float 42 | Double 43 | Enum 44 | Ptr 45 | Struct 46 | Union 47 | Array 48 | Func 49 | TypedefType 50 | ) 51 | 52 | var typeKindString = []string{ 53 | Void: "void", 54 | Char: "char", 55 | Uchar: "uchar", 56 | Short: "short", 57 | Ushort: "ushort", 58 | Int: "int", 59 | Uint: "uint", 60 | Long: "long", 61 | Ulong: "ulong", 62 | Longlong: "longlong", 63 | Ulonglong: "ulonglong", 64 | Float: "float", 65 | Double: "double", 66 | Ptr: "pointer", 67 | Struct: "struct", 68 | Union: "union", 69 | Enum: "enum", 70 | Array: "array", 71 | Func: "func", 72 | TypedefType: "", 73 | } 74 | 75 | func (k TypeKind) String() string { 76 | if 0 <= int(k) && int(k) <= len(typeKindString) && typeKindString[k] != "" { 77 | return typeKindString[k] 78 | } 79 | return fmt.Sprintf("TypeKind(%d)", k) 80 | } 81 | 82 | type TypeQual int 83 | 84 | const ( 85 | Const TypeQual = 1 << iota 86 | Volatile 87 | ) 88 | 89 | func (q TypeQual) String() string { 90 | s := "" 91 | if q&Const != 0 { 92 | s += "const " 93 | } 94 | if q&Volatile != 0 { 95 | s += "volatile " 96 | } 97 | if s == "" { 98 | return "" 99 | } 100 | return s[:len(s)-1] 101 | } 102 | 103 | type Storage int 104 | 105 | const ( 106 | Auto Storage = 1 << iota 107 | Static 108 | Extern 109 | Typedef 110 | Register 111 | Inline 112 | ) 113 | 114 | func (c Storage) String() string { 115 | s := "" 116 | if c&Auto != 0 { 117 | s += "auto " 118 | } 119 | if c&Static != 0 { 120 | s += "static " 121 | } 122 | if c&Extern != 0 { 123 | s += "extern " 124 | } 125 | if c&Typedef != 0 { 126 | s += "typedef " 127 | } 128 | if c&Register != 0 { 129 | s += "register " 130 | } 131 | if c&Inline != 0 { 132 | s += "inline " 133 | } 134 | if s == "" { 135 | return "" 136 | } 137 | return s[:len(s)-1] 138 | } 139 | 140 | var ( 141 | CharType = newType(Char) 142 | UcharType = newType(Uchar) 143 | ShortType = newType(Short) 144 | UshortType = newType(Ushort) 145 | IntType = newType(Int) 146 | UintType = newType(Uint) 147 | LongType = newType(Long) 148 | UlongType = newType(Ulong) 149 | LonglongType = newType(Longlong) 150 | UlonglongType = newType(Ulonglong) 151 | FloatType = newType(Float) 152 | DoubleType = newType(Double) 153 | VoidType = newType(Void) 154 | BoolType = &Type{Kind: TypedefType, Name: "bool", Base: IntType} 155 | ) 156 | 157 | type typeOp int 158 | 159 | const ( 160 | tChar typeOp = 1 << iota 161 | tShort 162 | tInt 163 | tLong 164 | tSigned 165 | tUnsigned 166 | tFloat 167 | tDouble 168 | tVoid 169 | tLonglong 170 | ) 171 | 172 | var builtinTypes = map[typeOp]*Type{ 173 | tChar: CharType, 174 | tChar | tSigned: CharType, 175 | tChar | tUnsigned: UcharType, 176 | tShort: ShortType, 177 | tShort | tSigned: ShortType, 178 | tShort | tUnsigned: UshortType, 179 | tShort | tInt: ShortType, 180 | tShort | tSigned | tInt: ShortType, 181 | tShort | tUnsigned | tInt: UshortType, 182 | tInt: IntType, 183 | tInt | tSigned: IntType, 184 | tInt | tUnsigned: UintType, 185 | tLong: LongType, 186 | tLong | tSigned: LongType, 187 | tLong | tUnsigned: UlongType, 188 | tLong | tInt: LongType, 189 | tLong | tSigned | tInt: LongType, 190 | tLong | tUnsigned | tInt: UlongType, 191 | tLonglong: LonglongType, 192 | tLonglong | tSigned: LonglongType, 193 | tLonglong | tUnsigned: UlonglongType, 194 | tLonglong | tInt: LonglongType, 195 | tLonglong | tSigned | tInt: LonglongType, 196 | tLonglong | tUnsigned | tInt: UlonglongType, 197 | tFloat: FloatType, 198 | tDouble: DoubleType, 199 | tVoid: VoidType, 200 | } 201 | 202 | func splitTypeWords(ws []string) (c Storage, q TypeQual, ty *Type) { 203 | // Could check for doubled words in general, 204 | // like const const, but no one cares. 205 | var t typeOp 206 | var ts []string 207 | for _, w := range ws { 208 | switch w { 209 | case "const": 210 | q |= Const 211 | case "volatile": 212 | q |= Volatile 213 | case "auto": 214 | c |= Auto 215 | case "static": 216 | c |= Static 217 | case "extern": 218 | c |= Extern 219 | case "typedef": 220 | c |= Typedef 221 | case "register": 222 | c |= Register 223 | case "inline": 224 | c |= Inline 225 | case "char": 226 | t |= tChar 227 | ts = append(ts, w) 228 | case "short": 229 | t |= tShort 230 | ts = append(ts, w) 231 | case "int": 232 | t |= tInt 233 | ts = append(ts, w) 234 | case "long": 235 | if t&tLong != 0 { 236 | t ^= tLonglong | tLong 237 | } else { 238 | t |= tLong 239 | } 240 | ts = append(ts, w) 241 | case "signed": 242 | t |= tSigned 243 | ts = append(ts, w) 244 | case "unsigned": 245 | t |= tUnsigned 246 | ts = append(ts, w) 247 | case "float": 248 | t |= tFloat 249 | ts = append(ts, w) 250 | case "double": 251 | t |= tDouble 252 | ts = append(ts, w) 253 | case "void": 254 | t |= tVoid 255 | ts = append(ts, w) 256 | } 257 | } 258 | 259 | if t == 0 { 260 | t |= tInt 261 | } 262 | 263 | ty = builtinTypes[t] 264 | if ty == nil { 265 | fmt.Printf("unsupported type %q\n", strings.Join(ts, " ")) 266 | } 267 | 268 | return c, q, builtinTypes[t] 269 | } 270 | 271 | func newType(k TypeKind) *Type { 272 | return &Type{Kind: k} 273 | } 274 | 275 | func (t *Type) String() string { 276 | if t == nil { 277 | return "" 278 | } 279 | switch t.Kind { 280 | default: 281 | return t.Kind.String() 282 | case TypedefType: 283 | if t.Name == "" { 284 | return "missing_typedef_name" 285 | } 286 | return t.Name 287 | case Ptr: 288 | return t.Base.String() + "*" 289 | case Struct, Union, Enum: 290 | if t.Tag == "" { 291 | return t.Kind.String() 292 | } 293 | return t.Kind.String() + " " + t.Tag 294 | case Array: 295 | return t.Base.String() + "[]" 296 | case Func: 297 | s := "func(" 298 | for i, d := range t.Decls { 299 | if i > 0 { 300 | s += ", " 301 | } 302 | s += d.Name + " " + d.Type.String() 303 | } 304 | if t.Base == t { 305 | s += ") SELF" 306 | } else { 307 | s += ") " + t.Base.String() 308 | } 309 | return s 310 | } 311 | } 312 | 313 | type Decl struct { 314 | SyntaxInfo 315 | Name string 316 | Type *Type 317 | Storage Storage 318 | Init *Init 319 | Body *Stmt 320 | 321 | XOuter *Decl 322 | CurFn *Decl 323 | OuterType *Type 324 | GoPackage string 325 | } 326 | 327 | func (d *Decl) String() string { 328 | if d == nil { 329 | return "nil Decl" 330 | } 331 | return fmt.Sprintf("Decl{%s, %s}", d.Name, d.Type) 332 | } 333 | -------------------------------------------------------------------------------- /add/ld/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ld 6 | 7 | import ( 8 | "bufio" 9 | "bytes" 10 | "encoding/binary" 11 | "io" 12 | "log" 13 | "os" 14 | "runtime/pprof" 15 | "strings" 16 | "time" 17 | ) 18 | 19 | func cstring(x []byte) string { 20 | i := bytes.IndexByte(x, '\x00') 21 | if i >= 0 { 22 | x = x[:i] 23 | } 24 | return string(x) 25 | } 26 | 27 | func plan9quote(s string) string { 28 | if s == "" { 29 | goto needquote 30 | } 31 | for i := 0; i < len(s); i++ { 32 | if s[i] <= ' ' || s[i] == '\'' { 33 | goto needquote 34 | } 35 | } 36 | return s 37 | 38 | needquote: 39 | return "'" + strings.Replace(s, "'", "''", -1) + "'" 40 | } 41 | 42 | func tokenize(s string) []string { 43 | var f []string 44 | for { 45 | s = strings.TrimLeft(s, " \t\r\n") 46 | if s == "" { 47 | break 48 | } 49 | quote := false 50 | i := 0 51 | for ; i < len(s); i++ { 52 | if s[i] == '\'' { 53 | if quote && i+1 < len(s) && s[i+1] == '\'' { 54 | i++ 55 | continue 56 | } 57 | quote = !quote 58 | } 59 | if !quote && (s[i] == ' ' || s[i] == '\t' || s[i] == '\r' || s[i] == '\n') { 60 | break 61 | } 62 | } 63 | next := s[:i] 64 | s = s[i:] 65 | if strings.Contains(next, "'") { 66 | var buf []byte 67 | quote := false 68 | for i := 0; i < len(next); i++ { 69 | if next[i] == '\'' { 70 | if quote && i+1 < len(next) && next[i+1] == '\'' { 71 | i++ 72 | buf = append(buf, '\'') 73 | } 74 | quote = !quote 75 | continue 76 | } 77 | buf = append(buf, next[i]) 78 | } 79 | next = string(buf) 80 | } 81 | f = append(f, next) 82 | } 83 | return f 84 | } 85 | 86 | func cutStringAtNUL(s string) string { 87 | if i := strings.Index(s, "\x00"); i >= 0 { 88 | s = s[:i] 89 | } 90 | return s 91 | } 92 | 93 | type Biobuf struct { 94 | unget [2]int 95 | numUnget int 96 | f *os.File 97 | r *bufio.Reader 98 | w *bufio.Writer 99 | linelen int 100 | } 101 | 102 | func Bopenw(name string) (*Biobuf, error) { 103 | f, err := os.Create(name) 104 | if err != nil { 105 | return nil, err 106 | } 107 | return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil 108 | } 109 | 110 | func Bopenr(name string) (*Biobuf, error) { 111 | f, err := os.Open(name) 112 | if err != nil { 113 | return nil, err 114 | } 115 | return &Biobuf{f: f, r: bufio.NewReader(f)}, nil 116 | } 117 | 118 | func Binitw(w *os.File) *Biobuf { 119 | return &Biobuf{w: bufio.NewWriter(w), f: w} 120 | } 121 | 122 | func (b *Biobuf) Write(p []byte) (int, error) { 123 | return b.w.Write(p) 124 | } 125 | 126 | func Bwritestring(b *Biobuf, p string) (int, error) { 127 | return b.w.WriteString(p) 128 | } 129 | 130 | func Bseek(b *Biobuf, offset int64, whence int) int64 { 131 | if b.w != nil { 132 | if err := b.w.Flush(); err != nil { 133 | log.Fatalf("writing output: %v", err) 134 | } 135 | } else if b.r != nil { 136 | if whence == 1 { 137 | offset -= int64(b.r.Buffered()) 138 | } 139 | } 140 | off, err := b.f.Seek(offset, whence) 141 | if err != nil { 142 | log.Panicf("seeking in output [%d %d %p]: %v", offset, whence, b.f, err) 143 | } 144 | if b.r != nil { 145 | b.r.Reset(b.f) 146 | } 147 | return off 148 | } 149 | 150 | func Boffset(b *Biobuf) int64 { 151 | if b.w != nil { 152 | if err := b.w.Flush(); err != nil { 153 | log.Fatalf("writing output: %v", err) 154 | } 155 | } 156 | off, err := b.f.Seek(0, 1) 157 | if err != nil { 158 | log.Fatalf("seeking in output [0, 1]: %v", err) 159 | } 160 | if b.r != nil { 161 | off -= int64(b.r.Buffered()) 162 | } 163 | return off 164 | } 165 | 166 | func (b *Biobuf) Flush() error { 167 | return b.w.Flush() 168 | } 169 | 170 | func Bwrite(b *Biobuf, p []byte) (int, error) { 171 | return b.w.Write(p) 172 | } 173 | 174 | func Bputc(b *Biobuf, c byte) { 175 | b.w.WriteByte(c) 176 | } 177 | 178 | const Beof = -1 179 | 180 | func Bread(b *Biobuf, p []byte) int { 181 | if b.numUnget > 0 { 182 | Bseek(b, -int64(b.numUnget), 1) 183 | b.numUnget = 0 184 | } 185 | n, err := io.ReadFull(b.r, p) 186 | if n == 0 { 187 | if err != nil && err != io.EOF { 188 | n = -1 189 | } 190 | } 191 | return n 192 | } 193 | 194 | func Bgetc(b *Biobuf) int { 195 | if b.numUnget > 0 { 196 | b.numUnget-- 197 | return int(b.unget[b.numUnget]) 198 | } 199 | c, err := b.r.ReadByte() 200 | r := int(c) 201 | if err != nil { 202 | r = -1 203 | } 204 | b.unget[1] = b.unget[0] 205 | b.unget[0] = r 206 | return r 207 | } 208 | 209 | func Bgetrune(b *Biobuf) int { 210 | if b.numUnget > 0 { 211 | Bseek(b, -int64(b.numUnget), 1) 212 | b.numUnget = 0 213 | } 214 | r, _, err := b.r.ReadRune() 215 | if err != nil { 216 | return -1 217 | } 218 | return int(r) 219 | } 220 | 221 | func Bungetrune(b *Biobuf) { 222 | b.r.UnreadRune() 223 | } 224 | 225 | func (b *Biobuf) Read(p []byte) (int, error) { 226 | return b.r.Read(p) 227 | } 228 | 229 | func Brdline(b *Biobuf, delim int) string { 230 | if b.numUnget > 0 { 231 | Bseek(b, -int64(b.numUnget), 1) 232 | b.numUnget = 0 233 | } 234 | s, err := b.r.ReadBytes(byte(delim)) 235 | if err != nil { 236 | log.Fatalf("reading input: %v", err) 237 | } 238 | b.linelen = len(s) 239 | return string(s) 240 | } 241 | 242 | func Brdstr(b *Biobuf, delim int, cut int) string { 243 | if b.numUnget > 0 { 244 | Bseek(b, -int64(b.numUnget), 1) 245 | b.numUnget = 0 246 | } 247 | s, err := b.r.ReadString(byte(delim)) 248 | if err != nil { 249 | log.Fatalf("reading input: %v", err) 250 | } 251 | if len(s) > 0 && cut > 0 { 252 | s = s[:len(s)-1] 253 | } 254 | return s 255 | } 256 | 257 | func Access(name string, mode int) int { 258 | if mode != 0 { 259 | panic("bad access") 260 | } 261 | _, err := os.Stat(name) 262 | if err != nil { 263 | return -1 264 | } 265 | return 0 266 | } 267 | 268 | func Blinelen(b *Biobuf) int { 269 | return b.linelen 270 | } 271 | 272 | func Bungetc(b *Biobuf) { 273 | b.numUnget++ 274 | } 275 | 276 | func Bflush(b *Biobuf) error { 277 | return b.w.Flush() 278 | } 279 | 280 | func Bterm(b *Biobuf) error { 281 | var err error 282 | if b.w != nil { 283 | err = b.w.Flush() 284 | } 285 | err1 := b.f.Close() 286 | if err == nil { 287 | err = err1 288 | } 289 | return err 290 | } 291 | 292 | // strings.Compare, introduced in Go 1.5. 293 | func stringsCompare(a, b string) int { 294 | if a == b { 295 | return 0 296 | } 297 | if a < b { 298 | return -1 299 | } 300 | return +1 301 | } 302 | 303 | var atExitFuncs []func() 304 | 305 | func AtExit(f func()) { 306 | atExitFuncs = append(atExitFuncs, f) 307 | } 308 | 309 | func Exit(code int) { 310 | for i := len(atExitFuncs) - 1; i >= 0; i-- { 311 | f := atExitFuncs[i] 312 | atExitFuncs = atExitFuncs[:i] 313 | f() 314 | } 315 | os.Exit(code) 316 | } 317 | 318 | var cpuprofile string 319 | var memprofile string 320 | 321 | func startProfile() { 322 | if cpuprofile != "" { 323 | f, err := os.Create(cpuprofile) 324 | if err != nil { 325 | log.Fatalf("%v", err) 326 | } 327 | if err := pprof.StartCPUProfile(f); err != nil { 328 | log.Fatalf("%v", err) 329 | } 330 | AtExit(pprof.StopCPUProfile) 331 | } 332 | if memprofile != "" { 333 | f, err := os.Create(memprofile) 334 | if err != nil { 335 | log.Fatalf("%v", err) 336 | } 337 | AtExit(func() { 338 | if err := pprof.WriteHeapProfile(f); err != nil { 339 | log.Fatalf("%v", err) 340 | } 341 | }) 342 | } 343 | } 344 | 345 | func artrim(x []byte) string { 346 | i := 0 347 | j := len(x) 348 | for i < len(x) && x[i] == ' ' { 349 | i++ 350 | } 351 | for j > i && x[j-1] == ' ' { 352 | j-- 353 | } 354 | return string(x[i:j]) 355 | } 356 | 357 | func stringtouint32(x []uint32, s string) { 358 | for i := 0; len(s) > 0; i++ { 359 | var buf [4]byte 360 | s = s[copy(buf[:], s):] 361 | x[i] = binary.LittleEndian.Uint32(buf[:]) 362 | } 363 | } 364 | 365 | var start = time.Now() 366 | 367 | func elapsed() float64 { 368 | return time.Since(start).Seconds() 369 | } 370 | -------------------------------------------------------------------------------- /cc/expr.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package cc 6 | 7 | import "fmt" 8 | 9 | // An Expr is a parsed C expression. 10 | type Expr struct { 11 | SyntaxInfo 12 | Op ExprOp // operator 13 | Left *Expr // left (or only) operand 14 | Right *Expr // right operand 15 | List []*Expr // operand list, for Comma, Cond, Call 16 | Text string // name or literal, for Name, Number, Goto, Arrow, Dot 17 | Texts []string // list of literals, for String 18 | Type *Type // type operand, for SizeofType, Offsetof, Cast, CastInit, VaArg 19 | Init *Init // initializer, for CastInit 20 | Block []*Stmt // for c2go 21 | 22 | // derived information 23 | XDecl *Decl 24 | XType *Type // expression type, derived 25 | } 26 | 27 | func (x *Expr) String() string { 28 | var p Printer 29 | p.hideComments = true 30 | p.printExpr(x, precLow) 31 | return p.String() 32 | } 33 | 34 | type ExprOp int 35 | 36 | const ( 37 | _ ExprOp = iota 38 | Add // Left + Right 39 | AddEq // Left += Right 40 | Addr // &Left 41 | And // Left & Right 42 | AndAnd // Left && Right 43 | AndEq // Left &= Right 44 | Arrow // Left->Text 45 | Call // Left(List) 46 | Cast // (Type)Left 47 | CastInit // (Type){Init} 48 | Comma // x, y, z; List = {x, y, z} 49 | Cond // x ? y : z; List = {x, y, z} 50 | Div // Left / Right 51 | DivEq // Left /= Right 52 | Dot // Left.Name 53 | Eq // Left = Right 54 | EqEq // Left == Right 55 | Gt // Left > Right 56 | GtEq // Left >= Right 57 | Index // Left[Right] 58 | Indir // *Left 59 | Lsh // Left << Right 60 | LshEq // Left <<= Right 61 | Lt // Left < Right 62 | LtEq // Left <= Right 63 | Minus // -Left 64 | Mod // Left % Right 65 | ModEq // Left %= Right 66 | Mul // Left * Right 67 | MulEq // Left *= Right 68 | Name // Text (function, variable, or enum name) 69 | Not // !Left 70 | NotEq // Left != Right 71 | Number // Text (numeric or chraracter constant) 72 | Offsetof // offsetof(Type, Left) 73 | Or // Left | Right 74 | OrEq // Left |= Right 75 | OrOr // Left || Right 76 | Paren // (Left) 77 | Plus // +Left 78 | PostDec // Left-- 79 | PostInc // Left++ 80 | PreDec // --Left 81 | PreInc // ++Left 82 | Rsh // Left >> Right 83 | RshEq // Left >>= Right 84 | SizeofExpr // sizeof(Left) 85 | SizeofType // sizeof(Type) 86 | String // Text (quoted string literal) 87 | Sub // Left - Right 88 | SubEq // Left -= Right 89 | Twid // ~Left 90 | VaArg // va_arg(Left, Type) 91 | Xor // Left ^ Right 92 | XorEq // Left ^= Right 93 | ) 94 | 95 | var exprOpString = []string{ 96 | Add: "Add", 97 | AddEq: "AddEq", 98 | Addr: "Addr", 99 | And: "And", 100 | AndAnd: "AndAnd", 101 | AndEq: "AndEq", 102 | Arrow: "Arrow", 103 | Call: "Call", 104 | Cast: "Cast", 105 | CastInit: "CastInit", 106 | Comma: "Comma", 107 | Cond: "Cond", 108 | Div: "Div", 109 | DivEq: "DivEq", 110 | Dot: "Dot", 111 | Eq: "Eq", 112 | EqEq: "EqEq", 113 | Gt: "Gt", 114 | GtEq: "GtEq", 115 | Index: "Index", 116 | Indir: "Indir", 117 | Lsh: "Lsh", 118 | LshEq: "LshEq", 119 | Lt: "Lt", 120 | LtEq: "LtEq", 121 | Minus: "Minus", 122 | Mod: "Mod", 123 | ModEq: "ModEq", 124 | Mul: "Mul", 125 | MulEq: "MulEq", 126 | Name: "Name", 127 | Not: "Not", 128 | NotEq: "NotEq", 129 | Number: "Number", 130 | Offsetof: "Offsetof", 131 | Or: "Or", 132 | OrEq: "OrEq", 133 | OrOr: "OrOr", 134 | Paren: "Paren", 135 | Plus: "Plus", 136 | PostDec: "PostDec", 137 | PostInc: "PostInc", 138 | PreDec: "PreDec", 139 | PreInc: "PreInc", 140 | Rsh: "Rsh", 141 | RshEq: "RshEq", 142 | SizeofExpr: "SizeofExpr", 143 | SizeofType: "SizeofType", 144 | String: "String", 145 | Sub: "Sub", 146 | SubEq: "SubEq", 147 | Twid: "Twid", 148 | VaArg: "VaArg", 149 | Xor: "Xor", 150 | XorEq: "XorEq", 151 | } 152 | 153 | func (op ExprOp) String() string { 154 | if 0 <= int(op) && int(op) <= len(exprOpString) { 155 | return exprOpString[op] 156 | } 157 | return fmt.Sprintf("ExprOp(%d)", op) 158 | } 159 | 160 | // Prefix is an initializer prefix. 161 | type Prefix struct { 162 | Span Span 163 | Dot string // .Dot = 164 | XDecl *Decl // for .Dot 165 | Index *Expr // [Index] = 166 | } 167 | 168 | // Init is an initializer expression. 169 | type Init struct { 170 | SyntaxInfo 171 | Prefix []*Prefix // list of prefixes 172 | Expr *Expr // Expr 173 | Braced []*Init // {Braced} 174 | 175 | XType *Type // derived type 176 | } 177 | 178 | // Walk traverses the syntax x, calling before and after on entry to and exit from 179 | // each Syntax encountered during the traversal. In case of cross-linked input, 180 | // the traversal never visits a given Syntax more than once. 181 | func Walk(x Syntax, before, after func(Syntax)) { 182 | seen := map[Syntax]bool{ 183 | nil: true, 184 | (*Decl)(nil): true, 185 | (*Init)(nil): true, 186 | (*Type)(nil): true, 187 | (*Expr)(nil): true, 188 | (*Stmt)(nil): true, 189 | (*Label)(nil): true, 190 | } 191 | walk(x, before, after, seen) 192 | } 193 | 194 | func walk(x Syntax, before, after func(Syntax), seen map[Syntax]bool) { 195 | if seen[x] { 196 | return 197 | } 198 | seen[x] = true 199 | before(x) 200 | switch x := x.(type) { 201 | default: 202 | panic(fmt.Sprintf("walk: unexpected type %T", x)) 203 | 204 | case *Prog: 205 | for _, d := range x.Decls { 206 | walk(d, before, after, seen) 207 | } 208 | 209 | case *Decl: 210 | walk(x.Type, before, after, seen) 211 | walk(x.Init, before, after, seen) 212 | walk(x.Body, before, after, seen) 213 | 214 | case *Init: 215 | for _, b := range x.Braced { 216 | walk(b, before, after, seen) 217 | } 218 | walk(x.Expr, before, after, seen) 219 | 220 | case *Type: 221 | walk(x.Base, before, after, seen) 222 | for _, d := range x.Decls { 223 | walk(d, before, after, seen) 224 | } 225 | walk(x.Width, before, after, seen) 226 | 227 | case *Expr: 228 | walk(x.Left, before, after, seen) 229 | walk(x.Right, before, after, seen) 230 | for _, y := range x.List { 231 | walk(y, before, after, seen) 232 | } 233 | walk(x.Type, before, after, seen) 234 | walk(x.Init, before, after, seen) 235 | for _, y := range x.Block { 236 | walk(y, before, after, seen) 237 | } 238 | 239 | case *Stmt: 240 | walk(x.Pre, before, after, seen) 241 | walk(x.Expr, before, after, seen) 242 | walk(x.Post, before, after, seen) 243 | walk(x.Decl, before, after, seen) 244 | walk(x.Body, before, after, seen) 245 | walk(x.Else, before, after, seen) 246 | for _, y := range x.Block { 247 | walk(y, before, after, seen) 248 | } 249 | for _, y := range x.Labels { 250 | walk(y, before, after, seen) 251 | } 252 | 253 | case *Label: 254 | walk(x.Expr, before, after, seen) 255 | } 256 | after(x) 257 | } 258 | 259 | // Preorder calls f for each piece of syntax of x in a preorder traversal. 260 | func Preorder(x Syntax, f func(Syntax)) { 261 | Walk(x, f, func(Syntax) {}) 262 | } 263 | 264 | // Preorder calls f for each piece of syntax of x in a postorder traversal. 265 | func Postorder(x Syntax, f func(Syntax)) { 266 | Walk(x, func(Syntax) {}, f) 267 | } 268 | -------------------------------------------------------------------------------- /cc/print.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package cc 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "strings" 11 | ) 12 | 13 | type special int 14 | 15 | const ( 16 | indent special = iota 17 | unindent 18 | untab 19 | newline 20 | ) 21 | 22 | type Printer struct { 23 | buf bytes.Buffer 24 | indent int 25 | html bool 26 | suffix []Comment // suffix comments to print at next newline 27 | hideComments bool 28 | } 29 | 30 | func (p *Printer) StartHTML() { 31 | p.buf.WriteString("
")
 32 | 	p.html = true
 33 | }
 34 | 
 35 | func (p *Printer) EndHTML() {
 36 | 	p.buf.WriteString("
") 37 | } 38 | 39 | func (p *Printer) Bytes() []byte { 40 | return p.buf.Bytes() 41 | } 42 | 43 | func (p *Printer) String() string { 44 | return p.buf.String() 45 | } 46 | 47 | type exprPrec struct { 48 | expr *Expr 49 | prec int 50 | } 51 | 52 | type nestBlock struct { 53 | stmt *Stmt 54 | more bool 55 | } 56 | 57 | type TypedName struct { 58 | Type *Type 59 | Name string 60 | } 61 | 62 | var htmlEscaper = strings.NewReplacer("<", "<", ">", ">", "&", "&") 63 | 64 | func (p *Printer) Print(args ...interface{}) { 65 | for _, arg := range args { 66 | switch arg := arg.(type) { 67 | default: 68 | fmt.Fprintf(&p.buf, "(?%T)", arg) 69 | case string: 70 | if p.html { 71 | htmlEscaper.WriteString(&p.buf, arg) 72 | } else { 73 | p.buf.WriteString(arg) 74 | } 75 | case exprPrec: 76 | p.printExpr(arg.expr, arg.prec) 77 | case *Expr: 78 | p.printExpr(arg, precLow) 79 | case *Prefix: 80 | p.printPrefix(arg) 81 | case *Init: 82 | p.printInit(arg) 83 | case *Prog: 84 | p.printProg(arg) 85 | case *Stmt: 86 | p.printStmt(arg) 87 | case *Type: 88 | p.printType(arg, "") 89 | case *Decl: 90 | p.printDecl(arg) 91 | case TypedName: 92 | p.printType(arg.Type, arg.Name) 93 | case Storage: 94 | p.Print(arg.String()) 95 | case []Comment: 96 | for _, com := range arg { 97 | p.Print(com) 98 | } 99 | case Comment: 100 | if p.hideComments { 101 | break 102 | } 103 | com := arg 104 | if com.Suffix { 105 | p.suffix = append(p.suffix, com) 106 | } else { 107 | for _, line := range strings.Split(com.Text, "\n") { 108 | p.Print(line, newline) 109 | } 110 | } 111 | case nestBlock: 112 | if arg.stmt.Op == Block { 113 | p.Print(" ", arg.stmt) 114 | } else { 115 | p.Print(indent, newline, arg.stmt, unindent) 116 | if arg.more { 117 | p.Print(newline) 118 | } 119 | } 120 | case special: 121 | switch arg { 122 | default: 123 | fmt.Fprintf(&p.buf, "(?special:%d)", arg) 124 | case indent: 125 | p.indent++ 126 | case unindent: 127 | p.indent-- 128 | case untab: 129 | b := p.buf.Bytes() 130 | if len(b) > 0 && b[len(b)-1] == '\t' { 131 | p.buf.Truncate(len(b) - 1) 132 | } 133 | case newline: 134 | for _, com := range p.suffix { 135 | p.Print(" ", com.Text) 136 | } 137 | p.suffix = p.suffix[:0] 138 | p.buf.WriteString("\n") 139 | for i := 0; i < p.indent; i++ { 140 | p.buf.WriteByte('\t') 141 | } 142 | } 143 | } 144 | } 145 | } 146 | 147 | const ( 148 | precNone = iota 149 | precArrow 150 | precAddr 151 | precMul 152 | precAdd 153 | precLsh 154 | precLt 155 | precEqEq 156 | precAnd 157 | precXor 158 | precOr 159 | precAndAnd 160 | precOrOr 161 | precCond 162 | precEq 163 | precComma 164 | precLow 165 | ) 166 | 167 | var opPrec = []int{ 168 | Add: precAdd, 169 | AddEq: precEq, 170 | Addr: precAddr, 171 | And: precAnd, 172 | AndAnd: precAndAnd, 173 | AndEq: precEq, 174 | Arrow: precArrow, 175 | Call: precArrow, 176 | Cast: precAddr, 177 | CastInit: precAddr, 178 | Comma: precComma, 179 | Cond: precCond, 180 | Div: precMul, 181 | DivEq: precEq, 182 | Dot: precArrow, 183 | Eq: precEq, 184 | EqEq: precEqEq, 185 | Gt: precLt, 186 | GtEq: precLt, 187 | Index: precArrow, 188 | Indir: precAddr, 189 | Lsh: precLsh, 190 | LshEq: precEq, 191 | Lt: precLt, 192 | LtEq: precLt, 193 | Minus: precAddr, 194 | Mod: precMul, 195 | ModEq: precEq, 196 | Mul: precMul, 197 | MulEq: precEq, 198 | Name: precNone, 199 | Not: precAddr, 200 | NotEq: precEqEq, 201 | Number: precNone, 202 | Offsetof: precAddr, 203 | Or: precOr, 204 | OrEq: precEq, 205 | OrOr: precOrOr, 206 | Paren: precLow, 207 | Plus: precAddr, 208 | PostDec: precAddr, 209 | PostInc: precAddr, 210 | PreDec: precAddr, 211 | PreInc: precAddr, 212 | Rsh: precLsh, 213 | RshEq: precEq, 214 | SizeofExpr: precAddr, 215 | SizeofType: precAddr, 216 | String: precNone, 217 | Sub: precAdd, 218 | SubEq: precEq, 219 | Twid: precAddr, 220 | VaArg: precAddr, 221 | Xor: precXor, 222 | XorEq: precEq, 223 | } 224 | 225 | var opStr = []string{ 226 | Add: "+", 227 | AddEq: "+=", 228 | Addr: "&", 229 | And: "&", 230 | AndAnd: "&&", 231 | AndEq: "&=", 232 | Div: "/", 233 | DivEq: "/=", 234 | Eq: "=", 235 | EqEq: "==", 236 | Gt: ">", 237 | GtEq: ">=", 238 | Indir: "*", 239 | Lsh: "<<", 240 | LshEq: "<<=", 241 | Lt: "<", 242 | LtEq: "<=", 243 | Minus: "-", 244 | Mod: "%", 245 | ModEq: "%=", 246 | Mul: "*", 247 | MulEq: "*=", 248 | Not: "!", 249 | NotEq: "!=", 250 | Or: "|", 251 | OrEq: "|=", 252 | OrOr: "||", 253 | Plus: "+", 254 | PreDec: "--", 255 | PreInc: "++", 256 | Rsh: ">>", 257 | RshEq: ">>=", 258 | Sub: "-", 259 | SubEq: "-=", 260 | Twid: "~", 261 | Xor: "^", 262 | XorEq: "^=", 263 | SizeofExpr: "sizeof ", 264 | } 265 | 266 | func (p *Printer) printExpr(x *Expr, prec int) { 267 | if x == nil { 268 | return 269 | } 270 | if p.html { 271 | fmt.Fprintf(&p.buf, "", x.Op, x.XType) 272 | defer fmt.Fprintf(&p.buf, "") 273 | } 274 | 275 | p.Print(x.Comments.Before) 276 | defer p.Print(x.Comments.Suffix, x.Comments.After) 277 | 278 | var newPrec int 279 | if 0 <= int(x.Op) && int(x.Op) < len(opPrec) { 280 | newPrec = opPrec[x.Op] 281 | } 282 | if prec < newPrec { 283 | p.Print("(") 284 | defer p.Print(")") 285 | } 286 | prec = newPrec 287 | 288 | var str string 289 | if 0 <= int(x.Op) && int(x.Op) < len(opStr) { 290 | str = opStr[x.Op] 291 | } 292 | if str != "" { 293 | if x.Right != nil { 294 | // binary operator 295 | if prec == precEq { 296 | // right associative 297 | p.Print(exprPrec{x.Left, prec - 1}, " ", str, " ", exprPrec{x.Right, prec}) 298 | } else { 299 | // left associative 300 | p.Print(exprPrec{x.Left, prec}, " ", str, " ", exprPrec{x.Right, prec - 1}) 301 | } 302 | } else { 303 | // unary operator 304 | if (x.Op == Plus || x.Op == Minus || x.Op == Addr) && x.Left.Op == x.Op || 305 | x.Op == Plus && x.Left.Op == PreInc || 306 | x.Op == Minus && x.Left.Op == PreDec { 307 | prec-- // force parenthesization +(+x) not ++x 308 | } 309 | p.Print(str, exprPrec{x.Left, prec}) 310 | } 311 | return 312 | } 313 | 314 | // special cases 315 | switch x.Op { 316 | default: 317 | p.Print(fmt.Sprintf("Expr(Op=%d)", x.Op)) 318 | 319 | case Arrow: 320 | p.Print(exprPrec{x.Left, prec}, "->", x.Text) 321 | 322 | case Call: 323 | p.Print(exprPrec{x.Left, precAddr}, "(") 324 | for i, y := range x.List { 325 | if i > 0 { 326 | p.Print(", ") 327 | } 328 | p.printExpr(y, precComma) 329 | } 330 | p.Print(")") 331 | 332 | case Cast: 333 | p.Print("(", x.Type, ")", exprPrec{x.Left, prec}) 334 | 335 | case CastInit: 336 | p.Print("(", x.Type, ")", x.Init) 337 | 338 | case Comma: 339 | for i, y := range x.List { 340 | if i > 0 { 341 | p.Print(", ") 342 | } 343 | p.printExpr(y, prec-1) 344 | } 345 | 346 | case Cond: 347 | p.Print(exprPrec{x.List[0], prec - 1}, " ? ", exprPrec{x.List[1], prec}, " : ", exprPrec{x.List[2], prec}) 348 | 349 | case Dot: 350 | p.Print(exprPrec{x.Left, prec}, ".", x.Text) 351 | 352 | case Index: 353 | p.Print(exprPrec{x.Left, prec}, "[", exprPrec{x.Right, precLow}, "]") 354 | 355 | case Name, Number: 356 | p.Print(x.Text) 357 | 358 | case String: 359 | for i, str := range x.Texts { 360 | if i > 0 { 361 | p.Print(" ") 362 | } 363 | p.Print(str) 364 | } 365 | 366 | case Offsetof: 367 | p.Print("offsetof(", x.Type, ", ", exprPrec{x.Left, precComma}, ")") 368 | 369 | case Paren: 370 | p.Print("(", exprPrec{x.Left, prec}, ")") 371 | 372 | case PostDec: 373 | p.Print(exprPrec{x.Left, prec}, "--") 374 | 375 | case PostInc: 376 | p.Print(exprPrec{x.Left, prec}, "++") 377 | 378 | case SizeofType: 379 | p.Print("sizeof(", x.Type, ")") 380 | 381 | case VaArg: 382 | p.Print("va_arg(", exprPrec{x.Left, precComma}, ", ", x.Type, ")") 383 | } 384 | } 385 | 386 | func (p *Printer) printPrefix(x *Prefix) { 387 | if x.Dot != "" { 388 | p.Print(".", x.Dot) 389 | } else { 390 | p.Print("[", x.Index, "]") 391 | } 392 | } 393 | 394 | func (p *Printer) printInit(x *Init) { 395 | p.Print(x.Comments.Before) 396 | defer p.Print(x.Comments.Suffix, x.Comments.After) 397 | 398 | if len(x.Prefix) > 0 { 399 | for _, pre := range x.Prefix { 400 | p.Print(pre) 401 | } 402 | p.Print(" = ") 403 | } 404 | if x.Expr != nil { 405 | p.printExpr(x.Expr, precComma) 406 | } else { 407 | nl := len(x.Braced) > 0 && x.Braced[0].Span.Start.Line != x.Braced[len(x.Braced)-1].Span.End.Line 408 | p.Print("{") 409 | if nl { 410 | p.Print(indent) 411 | } 412 | for i, y := range x.Braced { 413 | if i > 0 { 414 | p.Print(",") 415 | } 416 | if nl { 417 | p.Print(newline) 418 | } else if i > 0 { 419 | p.Print(" ") 420 | } 421 | p.Print(y) 422 | } 423 | if nl { 424 | p.Print(unindent, newline) 425 | } 426 | p.Print("}") 427 | } 428 | 429 | for _, com := range x.Comments.After { 430 | p.Print(com) 431 | } 432 | } 433 | 434 | func (p *Printer) printProg(x *Prog) { 435 | p.Print(x.Comments.Before) 436 | defer p.Print(x.Comments.Suffix, x.Comments.After) 437 | 438 | for _, decl := range x.Decls { 439 | p.Print(decl, newline) 440 | } 441 | } 442 | 443 | func (p *Printer) printStmt(x *Stmt) { 444 | if len(x.Labels) > 0 { 445 | p.Print(untab, unindent, x.Comments.Before, indent, "\t") 446 | for _, lab := range x.Labels { 447 | p.Print(untab, unindent, lab.Comments.Before, indent, "\t") 448 | p.Print(untab) 449 | switch { 450 | case lab.Name != "": 451 | p.Print(lab.Name) 452 | case lab.Expr != nil: 453 | p.Print("case ", lab.Expr) 454 | default: 455 | p.Print("default") 456 | } 457 | p.Print(":", lab.Comments.Suffix, newline) 458 | } 459 | } else { 460 | p.Print(x.Comments.Before) 461 | } 462 | defer p.Print(x.Comments.Suffix, x.Comments.After) 463 | 464 | switch x.Op { 465 | case ARGBEGIN: 466 | p.Print("ARGBEGIN{", indent, newline, x.Body, unindent, newline, "}ARGEND") 467 | 468 | case Block: 469 | p.Print("{", indent) 470 | for _, b := range x.Block { 471 | p.Print(newline, b) 472 | } 473 | p.Print(unindent, newline, "}") 474 | 475 | case Break: 476 | p.Print("break;") 477 | 478 | case Continue: 479 | p.Print("continue;") 480 | 481 | case Do: 482 | p.Print("do", nestBlock{x.Body, true}, " while(", x.Expr, ");") 483 | 484 | case Empty: 485 | p.Print(";") 486 | 487 | case For: 488 | p.Print("for(", x.Pre, ";") 489 | if x.Expr != nil { 490 | p.Print(" ") 491 | } 492 | p.Print(x.Expr, ";") 493 | if x.Post != nil { 494 | p.Print(" ") 495 | } 496 | p.Print(x.Post, ")", nestBlock{x.Body, false}) 497 | 498 | case If: 499 | p.Print("if(", x.Expr, ")", nestBlock{x.Body, x.Else != nil}) 500 | if x.Else != nil { 501 | if x.Body.Op == Block { 502 | p.Print(" ") 503 | } 504 | p.Print("else", nestBlock{x.Else, false}) 505 | } 506 | 507 | case Goto: 508 | p.Print("goto ", x.Text, ";") 509 | 510 | case Return: 511 | if x.Expr == nil { 512 | p.Print("return;") 513 | } else { 514 | p.Print("return ", x.Expr, ";") 515 | } 516 | 517 | case StmtDecl: 518 | p.Print(x.Decl, ";") 519 | 520 | case StmtExpr: 521 | p.Print(x.Expr, ";") 522 | 523 | case Switch: 524 | p.Print("switch(", x.Expr, ")", nestBlock{x.Body, false}) 525 | 526 | case While: 527 | p.Print("while(", x.Expr, ")", nestBlock{x.Body, false}) 528 | } 529 | } 530 | 531 | func (p *Printer) printType(x *Type, name string) { 532 | // Shouldn't happen but handle in case it does. 533 | p.Print(x.Comments.Before) 534 | defer p.Print(x.Comments.Suffix, x.Comments.After) 535 | 536 | switch x.Kind { 537 | case Ptr: 538 | p.printType(x.Base, "*"+name) 539 | case Array: 540 | if strings.HasPrefix(name, "*") { 541 | name = "(" + name + ")" 542 | } 543 | if x.Width == nil { 544 | p.printType(x.Base, name+"[]") 545 | } else { 546 | p.printType(x.Base, name+"["+x.Width.String()+"]") 547 | } 548 | case Func: 549 | var pp Printer 550 | if strings.HasPrefix(name, "*") { 551 | name = "(" + name + ")" 552 | } 553 | pp.Print(name, "(") 554 | for i, decl := range x.Decls { 555 | if i > 0 { 556 | pp.Print(", ") 557 | } 558 | pp.Print(decl) 559 | } 560 | pp.Print(")") 561 | p.printType(x.Base, pp.String()) 562 | 563 | default: 564 | p.Print(x.String()) 565 | i := 0 566 | for i < len(name) && name[i] == '*' { 567 | i++ 568 | } 569 | if i < len(name) && name[i] != '\n' { 570 | p.Print(" ") 571 | } 572 | p.Print(name) 573 | } 574 | } 575 | 576 | func (p *Printer) printDecl(x *Decl) { 577 | p.Print(x.Comments.Before) 578 | defer p.Print(x.Comments.Suffix, x.Comments.After) 579 | 580 | if x.Storage != 0 { 581 | p.Print(x.Storage, " ") 582 | } 583 | if x.Type == nil { 584 | p.Print(x.Name) 585 | } else { 586 | name := x.Name 587 | if x.Type.Kind == Func && x.Body != nil { 588 | name = "\n" + name 589 | } 590 | p.Print(TypedName{x.Type, name}) 591 | if x.Name == "" { 592 | switch x.Type.Kind { 593 | case Struct, Union, Enum: 594 | p.Print(" {", indent) 595 | for _, decl := range x.Type.Decls { 596 | p.Print(newline, decl) 597 | } 598 | p.Print(unindent, newline, "}") 599 | } 600 | } 601 | } 602 | if x.Init != nil { 603 | p.Print(" = ", x.Init) 604 | } 605 | if x.Body != nil { 606 | p.Print(newline, x.Body) 607 | } 608 | } 609 | -------------------------------------------------------------------------------- /printf.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "strconv" 11 | "strings" 12 | 13 | "rsc.io/c2go/cc" 14 | ) 15 | 16 | func tryPrintf(curfn *cc.Decl, x *cc.Expr, name string, fmtpos int, newName string) bool { 17 | if (x.Left.Text == name || (strings.Contains(name, ".") || strings.Contains(name, "->")) && x.Left.String() == name) && len(x.List) >= fmtpos+1 && x.List[fmtpos].Op == cc.String { 18 | x.List = append(x.List[:fmtpos+1], fixPrintFormat(curfn, x.List[fmtpos], x.List[fmtpos+1:])...) 19 | if newName != "" { 20 | x.Left.Text = newName 21 | x.Left.XDecl = nil 22 | } 23 | return true 24 | } 25 | return false 26 | } 27 | 28 | func fixPrintf(curfn *cc.Decl, x *cc.Expr) bool { 29 | if x.Op != cc.Call { 30 | return false 31 | } 32 | if tryPrintf(curfn, x, "sprint", 1, "fmt.Sprintf") { 33 | targ := x.List[0] 34 | x.List = x.List[1:] 35 | x.Right = copyExpr(x) 36 | x.List = nil 37 | x.Left = targ 38 | x.Op = cc.Eq 39 | 40 | // sprint(strchr(s, 0), "hello") => s += "hello" 41 | if targ.Op == cc.Call && len(targ.List) == 2 && targ.Left.Text == "strchr" && targ.List[1].Text == "0" { 42 | x.Left = targ.List[0] 43 | x.Op = cc.AddEq 44 | } else if targ.Op == cc.Add && targ.Right.Op == cc.Call && targ.Right.Left.Text == "strlen" && len(targ.Right.List) == 1 && GoString(targ.Left) == GoString(targ.Right.List[0]) { 45 | x.Left = targ.Left 46 | x.Op = cc.AddEq 47 | } 48 | return true 49 | } 50 | if tryPrintf(curfn, x, "snprint", 2, "fmt.Sprintf") { 51 | targ := x.List[0] 52 | x.List = x.List[2:] 53 | x.Right = copyExpr(x) 54 | x.List = nil 55 | x.Left = targ 56 | x.Op = cc.Eq 57 | return true 58 | } 59 | if tryPrintf(curfn, x, "fmtprint", 1, "fmt.Sprintf") { 60 | targ := x.List[0] 61 | x.List = x.List[1:] 62 | x.Right = copyExpr(x) 63 | x.List = nil 64 | x.Left = targ 65 | x.Op = cc.AddEq 66 | if x.Left.Op == cc.Addr { 67 | x.Left = x.Left.Left 68 | } 69 | return true 70 | } 71 | if tryPrintf(curfn, x, "smprint", 0, "fmt.Sprintf") { 72 | x.XType = stringType 73 | return true 74 | } 75 | if tryPrintf(curfn, x, "print", 0, "fmt.Printf") { 76 | return true 77 | } 78 | if tryPrintf(curfn, x, "fprint", 1, "fmt.Fprintf") { 79 | if x.List[0].String() == "2" { 80 | x.List[0] = &cc.Expr{Op: cc.Name, Text: "os.Stderr"} 81 | } 82 | return true 83 | } 84 | if tryPrintf(curfn, x, "sysfatal", 0, "log.Fatalf") { 85 | return true 86 | } 87 | if tryPrintf(curfn, x, "fatal", 0, "") { 88 | return true 89 | } 90 | if tryPrintf(curfn, x, "ctxt->diag", 0, "") { 91 | return true 92 | } 93 | if tryPrintf(curfn, x, "diag", 0, "") { 94 | return true 95 | } 96 | if tryPrintf(curfn, x, "werrstr", 0, "") { 97 | return true 98 | } 99 | if tryPrintf(curfn, x, "yyerror", 0, "") { 100 | return true 101 | } 102 | if tryPrintf(curfn, x, "yyerrorl", 1, "") { 103 | forceConvert(curfn, x.List[0], x.List[0].XType, intType) 104 | return true 105 | } 106 | if tryPrintf(curfn, x, "onearg", 1, "") { 107 | return true 108 | } 109 | if tryPrintf(curfn, x, "warn", 0, "") { 110 | return true 111 | } 112 | if tryPrintf(curfn, x, "warnl", 1, "") { 113 | forceConvert(curfn, x.List[0], x.List[0].XType, intType) 114 | return true 115 | } 116 | if tryPrintf(curfn, x, "Bprint", 1, "fmt.Fprintf") { 117 | return true 118 | } 119 | 120 | if isCall(x, "exprfmt") && len(x.List) == 3 { 121 | // exprfmt(fp, x, y) becomes fp += exprfmt(x, y) 122 | x.Op = cc.AddEq 123 | x.Right = &cc.Expr{Op: cc.Call, Left: x.Left, List: x.List[1:]} 124 | x.Left = x.List[0] 125 | x.List = nil 126 | x.XType = stringType 127 | return true 128 | } 129 | 130 | if isCall(x, "fmtstrinit") && len(x.List) == 1 && x.List[0].Op == cc.Addr { 131 | x.Op = cc.Eq 132 | x.Left = x.List[0].Left 133 | x.List = nil 134 | x.Right = &cc.Expr{Op: cc.Name, Text: `""`} 135 | } 136 | 137 | if isCall(x, "fmtstrflush") && len(x.List) == 1 && x.List[0].Op == cc.Addr { 138 | x.Op = cc.Paren 139 | x.Left = x.List[0].Left 140 | x.List = nil 141 | } 142 | 143 | return false 144 | } 145 | 146 | func fixPrintFormat(curfn *cc.Decl, fx *cc.Expr, args []*cc.Expr) []*cc.Expr { 147 | for _, arg := range args { 148 | fixGoTypesExpr(curfn, arg, nil) 149 | cc.Preorder(arg, func(x cc.Syntax) { 150 | if x, ok := x.(*cc.Expr); ok && x.Op == cc.Name && strings.HasPrefix(x.Text, "bigP") { 151 | x.Text = "p" 152 | x.XDecl = nil 153 | } 154 | }) 155 | } 156 | 157 | isGC := strings.Contains(fx.Span.Start.File, "cmd/gc") 158 | isCompiler := isGC || strings.Contains(fx.Span.Start.File, "cmd/6g") || strings.Contains(fx.Span.Start.File, "cmd/8g") || strings.Contains(fx.Span.Start.File, "cmd/5g") || strings.Contains(fx.Span.Start.File, "cmd/9g") 159 | 160 | narg := 0 161 | for j, text := range fx.Texts { 162 | format, err := strconv.Unquote(text) 163 | if err != nil { 164 | fprintf(fx.Span, "cannot parse quoted string: %v", err) 165 | return args 166 | } 167 | 168 | suffix := "" 169 | 170 | var buf bytes.Buffer 171 | start := 0 172 | for i := 0; i < len(format); i++ { 173 | if format[i] != '%' { 174 | continue 175 | } 176 | buf.WriteString(format[start:i]) 177 | start = i 178 | i++ 179 | if i < len(format) && format[i] == '%' { 180 | buf.WriteByte('%') 181 | buf.WriteByte('%') 182 | start = i + 1 183 | continue 184 | } 185 | for i < len(format) { 186 | c := format[i] 187 | switch c { 188 | case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '#', '-', '.', ',', ' ', 'h', 'l', 'u', '*': 189 | i++ 190 | continue 191 | } 192 | break 193 | } 194 | if i >= len(format) { 195 | fprintf(fx.Span, "print format ends mid-verb") 196 | return args 197 | } 198 | flags, verb := format[start:i], format[i] 199 | start = i + 1 200 | 201 | allFlags := flags 202 | _ = allFlags 203 | 204 | flags = strings.Replace(flags, "h", "", -1) 205 | flags = strings.Replace(flags, "l", "", -1) 206 | flags = strings.Replace(flags, "u", "", -1) 207 | 208 | if j := strings.Index(flags, "#0"); j >= 0 && verb == 'x' { 209 | k := j + 2 210 | for k < len(flags) && '0' <= flags[k] && flags[k] <= '9' { 211 | k++ 212 | } 213 | n, _ := strconv.Atoi(flags[j+2 : k]) 214 | flags = flags[:j+2] + fmt.Sprint(n-2) + flags[k:] 215 | } 216 | 217 | narg += strings.Count(allFlags, "*") 218 | 219 | convert := "" 220 | switch verb { 221 | default: 222 | fprintf(fx.Span, "unrecognized format %s%c", flags, verb) 223 | buf.WriteString("%") 224 | buf.WriteString(flags) 225 | buf.WriteString(string(verb)) 226 | 227 | case 'f', 'e', 'g', 's', 'c', 'p': 228 | // usual meanings 229 | buf.WriteString(flags) 230 | buf.WriteString(string(verb)) 231 | 232 | case 'x', 'X', 'o', 'd', 'b': 233 | // usual meanings, but force unsigned if u is given 234 | buf.WriteString(flags) 235 | buf.WriteString(string(verb)) 236 | if narg >= len(args) || !strings.Contains(allFlags, "u") { 237 | break 238 | } 239 | arg := args[narg] 240 | if t := arg.XType.Def(); t != nil { 241 | switch t.Kind { 242 | case Int8: 243 | convert = "uint8" 244 | case Int16: 245 | convert = "uint16" 246 | case Int32: 247 | convert = "uint32" 248 | case Int64: 249 | convert = "uint64" 250 | case Int: 251 | convert = "uint" 252 | } 253 | } 254 | 255 | case 'C': // rune 256 | buf.WriteString(flags) 257 | buf.WriteString("c") 258 | 259 | case 'q': // plan 9 rc(1) quoted string 260 | buf.WriteString(flags) 261 | buf.WriteString("v") 262 | convert = "plan9quote" 263 | 264 | case 'A': // asm opcode 265 | if allFlags != "%" { 266 | fprintf(fx.Span, "format %s%c", allFlags, verb) 267 | } 268 | buf.WriteString("%v") 269 | if narg < len(args) { 270 | forceConvert(nil, args[narg], args[narg].XType, intType) 271 | } 272 | convert = "Aconv" + suffix 273 | if isCompiler { 274 | switch { 275 | case strings.Contains(fx.Span.Start.File, "cmd/6g"): 276 | convert = "amd64." + convert 277 | case strings.Contains(fx.Span.Start.File, "cmd/8g"): 278 | convert = "i386." + convert 279 | case strings.Contains(fx.Span.Start.File, "cmd/5g"): 280 | convert = "arm." + convert 281 | case strings.Contains(fx.Span.Start.File, "cmd/9g"): 282 | convert = "ppc64." + convert 283 | } 284 | } 285 | 286 | case 'L': 287 | if allFlags != "%" { 288 | fprintf(fx.Span, "format %s%c", allFlags, verb) 289 | } 290 | buf.WriteString("%v") 291 | if narg >= len(args) { 292 | break 293 | } 294 | arg := args[narg] 295 | if (arg.Op == cc.Dot || arg.Op == cc.Arrow) && arg.Text == "lineno" { 296 | arg.Text = "Line" 297 | arg.XDecl = nil 298 | args[narg] = &cc.Expr{Op: cc.Call, Left: arg, XType: stringType} 299 | break 300 | } 301 | convert = "ctxt.Line" 302 | if isCompiler { 303 | if isGC { 304 | convert = "Ctxt.Line" 305 | } else { 306 | convert = "gc.Ctxt.Line" 307 | } 308 | forceConvert(curfn, arg, arg.XType, intType) 309 | } 310 | 311 | case '@': 312 | if allFlags != "%" { 313 | fprintf(fx.Span, "format %s%c", allFlags, verb) 314 | } 315 | buf.WriteString("%v") 316 | convert = "RAconv" + suffix 317 | 318 | case '^': 319 | if allFlags != "%" { 320 | fprintf(fx.Span, "format %s%c", allFlags, verb) 321 | } 322 | buf.WriteString("%v") 323 | convert = "DRconv" + suffix 324 | 325 | case 'D': 326 | if allFlags != "%" && allFlags != "%l" { 327 | fprintf(fx.Span, "format %s%c", allFlags, verb) 328 | } 329 | buf.WriteString("%v") 330 | if narg >= len(args) { 331 | break 332 | } 333 | flag := &cc.Expr{Op: cc.Name, Text: "0"} 334 | if strings.Contains(allFlags, "l") { 335 | flag.Text = "obj.FmtLong" 336 | } 337 | arg := args[narg] 338 | args[narg] = &cc.Expr{ 339 | Op: cc.Call, 340 | Left: &cc.Expr{Op: cc.Name, Text: "Dconv" + suffix}, 341 | List: []*cc.Expr{ 342 | &cc.Expr{Op: cc.Name, Text: "p"}, 343 | flag, 344 | arg, 345 | }, 346 | XType: stringType, 347 | } 348 | if isCompiler { 349 | args[narg].List = args[narg].List[2:] 350 | args[narg].Left.Text = "Ctxt.Dconv" 351 | if !isGC { 352 | args[narg].Left.Text = "gc.Ctxt.Dconv" 353 | } 354 | } 355 | 356 | case 'M': 357 | if allFlags != "%" { 358 | fprintf(fx.Span, "format %s%c", allFlags, verb) 359 | } 360 | buf.WriteString("%v") 361 | convert = "Mconv" + suffix 362 | 363 | case 'R': 364 | if allFlags != "%" { 365 | fprintf(fx.Span, "format %s%c", allFlags, verb) 366 | } 367 | buf.WriteString("%v") 368 | forceConvert(curfn, args[narg], args[narg].XType, intType) 369 | convert = "Rconv" + suffix 370 | if isCompiler { 371 | convert = "Ctxt." + convert 372 | if !isGC { 373 | convert = "gc." + convert 374 | } 375 | } 376 | 377 | case '$': 378 | if allFlags != "%" { 379 | fprintf(fx.Span, "format %s%c", allFlags, verb) 380 | } 381 | buf.WriteString("%q") 382 | 383 | case 'P': 384 | if allFlags != "%" { 385 | fprintf(fx.Span, "format %s%c", allFlags, verb) 386 | } 387 | buf.WriteString("%v") 388 | 389 | case 'r': // plan 9 errstr 390 | buf.WriteString("%v") 391 | if narg > len(args) { 392 | break 393 | } 394 | args = append(append(args[:narg:narg], &cc.Expr{Op: cc.Name, Text: "err"}), args[narg:]...) 395 | 396 | case 'B', 'E', 'F', 'H', 'J', 'N', 'O', 'Q', 'S', 'T', 'V', 'Z': 397 | switch verb { 398 | case 'E', 'O': 399 | convert = "int" 400 | } 401 | f := allFlags 402 | mod := "0" 403 | if strings.Contains(f, "-") { 404 | mod += "|obj.FmtLeft" 405 | f = strings.Replace(f, "-", "", 1) 406 | } 407 | if strings.Contains(f, "h") { 408 | mod += "|obj.FmtShort" 409 | f = strings.Replace(f, "h", "", 1) 410 | if strings.Contains(f, "h") { 411 | mod += "|obj.FmtByte" 412 | f = strings.Replace(f, "h", "", 1) 413 | } 414 | } 415 | if strings.Contains(f, "#") { 416 | mod += "|obj.FmtSharp" 417 | f = strings.Replace(f, "#", "", 1) 418 | } 419 | if strings.Contains(f, "l") { 420 | mod += "|obj.FmtLong" 421 | f = strings.Replace(f, "l", "", 1) 422 | } 423 | if strings.Contains(f, ",") { 424 | mod += "|obj.FmtComma" 425 | f = strings.Replace(f, ",", "", 1) 426 | } 427 | if strings.Contains(f, "+") { 428 | mod += "|obj.FmtSign" 429 | f = strings.Replace(f, "+", "", 1) 430 | } 431 | if strings.Contains(f, "u") { 432 | mod += "|obj.FmtUnsigned" 433 | f = strings.Replace(f, "u", "", 1) 434 | } 435 | if f != "%" { 436 | fprintf(fx.Span, "format %s%c", allFlags, verb) 437 | } 438 | buf.WriteString("%v") 439 | if narg >= len(args) { 440 | break 441 | } 442 | if mod != "0" { 443 | mod = mod[2:] 444 | } 445 | if !isCompiler { 446 | mod = strings.Replace(mod, "obj.", "", -1) 447 | } 448 | flag := &cc.Expr{Op: cc.Name, Text: mod} 449 | if convert != "" { 450 | args[narg] = &cc.Expr{Op: cc.Call, Left: &cc.Expr{Op: cc.Name, Text: convert}, List: []*cc.Expr{args[narg]}, XType: stringType} 451 | convert = "" 452 | } 453 | arg := args[narg] 454 | args[narg] = &cc.Expr{ 455 | Op: cc.Call, 456 | Left: &cc.Expr{Op: cc.Name, Text: string(verb) + "conv"}, 457 | List: []*cc.Expr{ 458 | arg, 459 | flag, 460 | }, 461 | XType: stringType, 462 | } 463 | if !isGC { 464 | args[narg].Left.Text = "gc." + args[narg].Left.Text 465 | } 466 | } 467 | 468 | if convert != "" && narg < len(args) { 469 | arg := args[narg] 470 | args[narg] = &cc.Expr{Op: cc.Call, Left: &cc.Expr{Op: cc.Name, Text: convert}, List: []*cc.Expr{arg}, XType: stringType} 471 | } 472 | 473 | narg++ 474 | } 475 | buf.WriteString(format[start:]) 476 | fx.Texts[j] = strconv.Quote(buf.String()) 477 | } 478 | 479 | return args 480 | } 481 | 482 | func fixFormatter(fn *cc.Decl) { 483 | // Find va_arg assignment. 484 | var arg *cc.Expr 485 | var argType *cc.Type 486 | var ps []*cc.Expr 487 | cc.Preorder(fn.Body, func(x cc.Syntax) { 488 | switch x := x.(type) { 489 | case *cc.Expr: 490 | if x.Op == cc.Name && strings.HasPrefix(x.Text, "bigP") { 491 | ps = append(ps, x) 492 | } 493 | case *cc.Stmt: 494 | stmt := x 495 | if stmt.Op != cc.StmtExpr { 496 | return 497 | } 498 | expr := stmt.Expr 499 | if expr.Op != cc.Eq { 500 | return 501 | } 502 | if expr.Left.Op == cc.Name && strings.HasPrefix(expr.Left.Text, "bigP") { 503 | stmt.Op = cc.Empty 504 | stmt.Expr = nil 505 | return 506 | } 507 | if expr.Op != cc.Eq || expr.Right.Op != cc.VaArg { 508 | return 509 | } 510 | if arg != nil { 511 | fprintf(fn.Span, "multiple va_arg in formatter") 512 | } 513 | arg = expr.Left 514 | argType = expr.Right.Type 515 | stmt.Op = cc.Empty 516 | } 517 | }) 518 | 519 | fp := fn.Type.Decls[0] 520 | fp.Type = stringType 521 | fn.Type.Base = stringType 522 | if arg != nil { 523 | fn.Type.Decls[0] = arg.XDecl 524 | } else { 525 | if len(fn.Type.Decls) == 1 { 526 | fprintf(fn.Span, "missing va_arg in formatter") 527 | return 528 | } 529 | fn.Type.Decls = fn.Type.Decls[1:] 530 | decl := &cc.Stmt{ 531 | Op: cc.StmtDecl, 532 | Decl: fp, 533 | } 534 | fn.Body.Block = append([]*cc.Stmt{decl}, fn.Body.Block...) 535 | } 536 | 537 | if strings.HasPrefix(fn.Name, "Dconv") && len(ps) > 0 { 538 | pd := &cc.Decl{Name: "p", Type: ps[0].XDecl.Type} 539 | fd := &cc.Decl{Name: "flag", Type: intType} 540 | for _, p := range ps { 541 | p.XDecl = pd 542 | } 543 | fn.Type.Decls = []*cc.Decl{ 544 | pd, 545 | fd, 546 | arg.XDecl, 547 | } 548 | } 549 | if len(fn.Name) == 5 && strings.HasSuffix(fn.Name, "conv") { 550 | switch fn.Name[0] { 551 | case 'B', 'E', 'F', 'H', 'J', 'N', 'O', 'Q', 'S', 'T', 'V', 'Z': 552 | fn.Type.Decls = append(fn.Type.Decls, &cc.Decl{ 553 | Name: "flag", 554 | Type: intType, 555 | }) 556 | } 557 | } 558 | 559 | cc.Preorder(fn.Body, func(x cc.Syntax) { 560 | switch x := x.(type) { 561 | case *cc.Stmt: 562 | if arg != nil && x.Op == cc.StmtDecl && x.Decl == arg.XDecl { 563 | x.Decl = fp 564 | } 565 | 566 | if x.Op == cc.Return && x.Expr != nil && x.Expr.Text == "0" { 567 | x.Expr = &cc.Expr{Op: cc.Name, Text: fp.Name, XDecl: fp} 568 | } 569 | 570 | case *cc.Expr: 571 | if x.Op == cc.Arrow && x.Text == "flags" { 572 | x.Op = cc.Name 573 | x.Text = "flag" 574 | x.XDecl = nil 575 | x.Left = nil 576 | } 577 | } 578 | }) 579 | 580 | } 581 | 582 | func fixFormatStmt(fn *cc.Decl, x *cc.Stmt) { 583 | if x.Op == cc.StmtDecl && GoString(x.Decl.Type) == "Fmt" { 584 | x.Decl.Type = stringType 585 | return 586 | } 587 | } 588 | -------------------------------------------------------------------------------- /syntax.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | 10 | "rsc.io/c2go/cc" 11 | ) 12 | 13 | var numRewrite int 14 | 15 | // Rewrite from C constructs to Go constructs. 16 | func rewriteSyntax(cfg *Config, prog *cc.Prog) { 17 | numRewrite++ 18 | cc.Preorder(prog, func(x cc.Syntax) { 19 | switch x := x.(type) { 20 | case *cc.Stmt: 21 | rewriteStmt(x) 22 | 23 | case *cc.Expr: 24 | switch x.Op { 25 | case cc.Name: 26 | switch x.Text { 27 | case "nil": 28 | x.XDecl = nil // just nil, not main.Nil 29 | case "nelem": 30 | x.Text = "len" 31 | x.XDecl = nil 32 | } 33 | case cc.Number: 34 | // Rewrite char literal. 35 | // In general we'd need to rewrite all string and char literals 36 | // but these are the only forms that comes up. 37 | switch x.Text { 38 | case `'\0'`: 39 | x.Text = `'\x00'` 40 | case `'\"'`: 41 | x.Text = `'"'` 42 | } 43 | 44 | case cc.Paren: 45 | switch x.Left.Op { 46 | case cc.Number, cc.Name: 47 | fixMerge(x, x.Left) 48 | } 49 | 50 | case cc.OrEq, cc.AndEq, cc.Or, cc.Eq, cc.EqEq, cc.NotEq, cc.LtEq, cc.GtEq, cc.Lt, cc.Gt: 51 | cutParen(x, cc.Or, cc.And, cc.Lsh, cc.Rsh) 52 | } 53 | 54 | case *cc.Type: 55 | // Rewrite int f(void) to int f(). 56 | if x.Kind == cc.Func && len(x.Decls) == 1 && x.Decls[0].Name == "" && x.Decls[0].Type.Is(cc.Void) { 57 | x.Decls = nil 58 | } 59 | } 60 | }) 61 | 62 | // Apply changed struct tags to typedefs. 63 | // Excise dead pieces. 64 | cc.Postorder(prog, func(x cc.Syntax) { 65 | switch x := x.(type) { 66 | case *cc.Type: 67 | if x.Kind == cc.TypedefType && x.Base != nil && x.Base.Tag != "" { 68 | x.Name = x.Base.Tag 69 | } 70 | 71 | case *cc.Stmt: 72 | if x.Op == cc.StmtExpr && x.Expr.Op == cc.Comma && len(x.Expr.List) == 0 { 73 | x.Op = cc.Empty 74 | } 75 | x.Block = filterBlock(x.Block) 76 | 77 | case *cc.Expr: 78 | if x.Op == ExprBlock { 79 | x.Block = filterBlock(x.Block) 80 | } 81 | 82 | switch x.Op { 83 | case cc.Add, cc.Sub: 84 | // Turn p + y - z, which is really (p + y) - z, into p + (y - z), 85 | // so that there is only one pointer addition (which will turn into 86 | // a slice operation using y-z as the index). 87 | if x.XType != nil && x.XType.Kind == cc.Ptr { 88 | switch x.Left.Op { 89 | case cc.Add, cc.Sub: 90 | if x.Left.XType != nil && x.Left.XType.Kind == cc.Ptr { 91 | p, op1, y, op2, z := x.Left.Left, x.Left.Op, x.Left.Right, x.Op, x.Right 92 | if op1 == cc.Sub { 93 | y = &cc.Expr{Op: cc.Minus, Left: y, XType: y.XType} 94 | } 95 | x.Op = cc.Add 96 | x.Left = p 97 | x.Right = &cc.Expr{Op: op2, Left: y, Right: z, XType: x.XType} 98 | } 99 | } 100 | } 101 | } 102 | 103 | // Turn c + p - q, which is really (c + p) - q, into c + (p - q), 104 | // so that there is no int + ptr addition, only a ptr - ptr subtraction. 105 | if x.Op == cc.Sub && x.Left.Op == cc.Add && !isPtrOrArray(x.XType) && isPtrOrArray(x.Left.XType) && !isPtrOrArray(x.Left.Left.XType) { 106 | c, p, q := x.Left.Left, x.Left.Right, x.Right 107 | expr := x.Left 108 | expr.Left = p 109 | expr.Right = q 110 | expr.Op = cc.Sub 111 | x.Op = cc.Add 112 | x.Left = c 113 | x.Right = expr 114 | expr.XType = x.XType 115 | } 116 | } 117 | }) 118 | } 119 | 120 | func cutParen(x *cc.Expr, ops ...cc.ExprOp) { 121 | if x.Left != nil && x.Left.Op == cc.Paren { 122 | for _, op := range ops { 123 | if x.Left.Left.Op == op { 124 | fixMerge(x.Left, x.Left.Left) 125 | break 126 | } 127 | } 128 | } 129 | if x.Right != nil && x.Right.Op == cc.Paren { 130 | for _, op := range ops { 131 | if x.Right.Left.Op == op { 132 | fixMerge(x.Right, x.Right.Left) 133 | break 134 | } 135 | } 136 | } 137 | } 138 | 139 | func isPtrOrArray(t *cc.Type) bool { 140 | return t != nil && (t.Kind == cc.Ptr || t.Kind == cc.Array) 141 | } 142 | 143 | func filterBlock(x []*cc.Stmt) []*cc.Stmt { 144 | all := x[:0] 145 | for _, stmt := range x { 146 | if stmt.Op != cc.Empty || len(stmt.Comments.Before)+len(stmt.Comments.After)+len(stmt.Labels) > 0 { 147 | all = append(all, stmt) 148 | } 149 | } 150 | return all 151 | } 152 | 153 | func rewriteStmt(stmt *cc.Stmt) { 154 | // TODO: Double-check stmt.Labels 155 | 156 | switch stmt.Op { 157 | case cc.ARGBEGIN: 158 | panic(fmt.Sprintf("unexpected ARGBEGIN")) 159 | 160 | case cc.Do: 161 | // Rewrite do { ... } while(x) 162 | // to for(;;) { ... if(!x) break } 163 | // Since rewriteStmt is called in a preorder traversal, 164 | // the recursion into the children will clean up x 165 | // in the if condition as needed. 166 | stmt.Op = cc.For 167 | x := stmt.Expr 168 | stmt.Expr = nil 169 | stmt.Body = forceBlock(stmt.Body) 170 | stmt.Body.Block = append(stmt.Body.Block, &cc.Stmt{ 171 | Op: cc.If, 172 | Expr: &cc.Expr{Op: cc.Not, Left: x}, 173 | Body: &cc.Stmt{Op: cc.Break}, 174 | }) 175 | 176 | case cc.While: 177 | stmt.Op = cc.For 178 | fallthrough 179 | 180 | case cc.For: 181 | before1, _ := extractSideEffects(stmt.Pre, sideStmt|sideNoAfter) 182 | before2, _ := extractSideEffects(stmt.Expr, sideNoAfter) 183 | if len(before2) > 0 { 184 | x := stmt.Expr 185 | stmt.Expr = nil 186 | stmt.Body = forceBlock(stmt.Body) 187 | top := &cc.Stmt{ 188 | Op: cc.If, 189 | Expr: &cc.Expr{Op: cc.Not, Left: x}, 190 | Body: &cc.Stmt{Op: cc.Break}, 191 | } 192 | stmt.Body.Block = append(append(before2, top), stmt.Body.Block...) 193 | } 194 | if len(before1) > 0 { 195 | old := copyStmt(stmt) 196 | stmt.Pre = nil 197 | stmt.Expr = nil 198 | stmt.Post = nil 199 | stmt.Body = nil 200 | stmt.Op = BlockNoBrace 201 | stmt.Block = append(before1, old) 202 | } 203 | before, after := extractSideEffects(stmt.Post, sideStmt) 204 | if len(before)+len(after) > 0 { 205 | all := append(append(before, &cc.Stmt{Op: cc.StmtExpr, Expr: stmt.Post}), after...) 206 | stmt.Post = &cc.Expr{Op: ExprBlock, Block: all} 207 | } 208 | 209 | case cc.If, cc.Return: 210 | if stmt.Op == cc.If && stmt.Else == nil { 211 | fixAndAndAssign(stmt) 212 | } 213 | before, _ := extractSideEffects(stmt.Expr, sideNoAfter) 214 | if len(before) > 0 { 215 | old := copyStmt(stmt) 216 | stmt.Expr = nil 217 | stmt.Body = nil 218 | stmt.Else = nil 219 | stmt.Op = BlockNoBrace 220 | stmt.Block = append(before, old) 221 | } 222 | 223 | case cc.StmtExpr: 224 | before, after := extractSideEffects(stmt.Expr, sideStmt) 225 | if len(before)+len(after) > 0 { 226 | old := copyStmt(stmt) 227 | stmt.Expr = nil 228 | stmt.Op = BlockNoBrace 229 | stmt.Block = append(append(before, old), after...) 230 | } 231 | 232 | case cc.Goto: 233 | // TODO: Figure out where the goto goes and maybe rewrite 234 | // to labeled break/continue. 235 | // Otherwise move code or something. 236 | 237 | case cc.Switch: 238 | // TODO: Change default fallthrough to default break. 239 | before, _ := extractSideEffects(stmt.Expr, sideNoAfter) 240 | if len(before) > 0 { 241 | old := copyStmt(stmt) 242 | stmt.Expr = nil 243 | stmt.Body = nil 244 | stmt.Else = nil 245 | stmt.Op = BlockNoBrace 246 | stmt.Block = append(before, old) 247 | break // recursion will rewrite new inner switch 248 | } 249 | rewriteSwitch(stmt) 250 | } 251 | } 252 | 253 | // fixAndAndAssign rewrites if(x && (y = z) ...) ... to if(x) { y = z; if(...) ... } 254 | func fixAndAndAssign(stmt *cc.Stmt) { 255 | changed := false 256 | clauses := splitExpr(stmt.Expr, cc.AndAnd) 257 | for i := len(clauses) - 1; i > 0; i-- { 258 | before, _ := extractSideEffects(clauses[i], sideNoAfter) 259 | if len(before) == 0 { 260 | continue 261 | } 262 | changed = true 263 | stmt.Body = &cc.Stmt{ 264 | Op: BlockNoBrace, 265 | Block: append(before, &cc.Stmt{ 266 | Op: cc.If, 267 | Expr: joinExpr(clauses[i:], cc.AndAnd), 268 | Body: stmt.Body, 269 | }), 270 | } 271 | clauses = clauses[:i] 272 | } 273 | if changed { 274 | stmt.Expr = joinExpr(clauses, cc.AndAnd) 275 | } 276 | } 277 | 278 | func splitExpr(x *cc.Expr, op cc.ExprOp) []*cc.Expr { 279 | if x == nil { 280 | return nil 281 | } 282 | var list []*cc.Expr 283 | for x.Op == op { 284 | list = append(list, x.Right) 285 | x = x.Left 286 | } 287 | list = append(list, x) 288 | for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 { 289 | list[i], list[j] = list[j], list[i] 290 | } 291 | return list 292 | } 293 | 294 | func joinExpr(list []*cc.Expr, op cc.ExprOp) *cc.Expr { 295 | if len(list) == 0 { 296 | return nil 297 | } 298 | x := list[0] 299 | for _, y := range list[1:] { 300 | x = &cc.Expr{Op: op, Left: x, Right: y} 301 | } 302 | return x 303 | } 304 | 305 | func rewriteSwitch(swt *cc.Stmt) { 306 | if numRewrite != 1 { 307 | return 308 | } 309 | var out []*cc.Stmt 310 | for _, stmt := range swt.Body.Block { 311 | // Put names after cases, so that they go to the same place. 312 | var names, cases []*cc.Label 313 | var def *cc.Label 314 | for _, lab := range stmt.Labels { 315 | if lab.Op == cc.LabelName { 316 | names = append(names, lab) 317 | } else if lab.Op == cc.Default { 318 | def = lab 319 | } else { 320 | cases = append(cases, lab) 321 | } 322 | } 323 | if def != nil { 324 | cases = append(cases, def) // put default last for printing 325 | } 326 | if len(cases) > 0 && len(names) > 0 { 327 | stmt.Labels = append(cases, names...) 328 | } 329 | if len(cases) > 0 { 330 | // Remove break or add fallthrough if needed. 331 | if len(out) > 0 { 332 | last := out[len(out)-1] 333 | if last.Op == cc.Break && len(last.Labels) == 0 { 334 | last.Op = cc.Empty 335 | } else if fallsThrough(last) { 336 | out = append(out, &cc.Stmt{Op: cc.StmtExpr, Expr: &cc.Expr{Op: cc.Name, Text: "fallthrough"}}) 337 | } 338 | } 339 | } 340 | out = append(out, stmt) 341 | } 342 | // Remove final break. 343 | if len(out) > 0 { 344 | last := out[len(out)-1] 345 | if last.Op == cc.Break && len(last.Labels) == 0 { 346 | last.Op = cc.Empty 347 | } 348 | } 349 | 350 | swt.Body.Block = out 351 | } 352 | 353 | func fallsThrough(x *cc.Stmt) bool { 354 | switch x.Op { 355 | case cc.Break, cc.Continue, cc.Return, cc.Goto: 356 | return false 357 | case cc.StmtExpr: 358 | if x.Expr.Op == cc.Call && x.Expr.Left.Op == cc.Name && (x.Expr.Left.Text == "sysfatal" || x.Expr.Left.Text == "fatal") { 359 | return false 360 | } 361 | if x.Expr.Op == cc.Name && x.Expr.Text == "fallthrough" { 362 | return false 363 | } 364 | } 365 | return true 366 | } 367 | 368 | func forceBlock(x *cc.Stmt) *cc.Stmt { 369 | if x.Op != cc.Block { 370 | x = &cc.Stmt{Op: cc.Block, Block: []*cc.Stmt{x}} 371 | } 372 | return x 373 | } 374 | 375 | const ( 376 | sideStmt = 1 << iota 377 | sideNoAfter 378 | ) 379 | 380 | func extractSideEffects(x *cc.Expr, mode int) (before, after []*cc.Stmt) { 381 | doSideEffects(x, &before, &after, mode) 382 | return 383 | } 384 | 385 | var tmpGen = make(chan int) 386 | 387 | func init() { 388 | go func() { 389 | for i := 1; ; i++ { 390 | tmpGen <- i 391 | } 392 | }() 393 | } 394 | 395 | func doSideEffects(x *cc.Expr, before, after *[]*cc.Stmt, mode int) { 396 | if x == nil { 397 | return 398 | } 399 | 400 | // Cannot hoist side effects from conditionally evaluated expressions 401 | // into unconditionally evaluated statement lists. 402 | // For now, detect but do not handle. 403 | switch x.Op { 404 | case cc.Cond: 405 | doSideEffects(x.List[0], before, after, mode&^sideStmt|sideNoAfter) 406 | checkNoSideEffects(x.List[1], 0) 407 | checkNoSideEffects(x.List[2], 0) 408 | 409 | case cc.AndAnd, cc.OrOr: 410 | doSideEffects(x.Left, before, after, mode&^sideStmt|sideNoAfter) 411 | checkNoSideEffects(x.Right, 0) 412 | 413 | case cc.Comma: 414 | var leftover []*cc.Expr 415 | for i, y := range x.List { 416 | m := mode | sideNoAfter 417 | if i+1 < len(x.List) { 418 | m |= sideStmt 419 | } 420 | doSideEffects(y, before, after, m) 421 | switch y.Op { 422 | case cc.PostInc, cc.PostDec, cc.Eq, cc.AddEq, cc.SubEq, cc.MulEq, cc.DivEq, cc.ModEq, cc.XorEq, cc.OrEq, cc.AndEq, cc.LshEq, cc.RshEq: 423 | *before = append(*before, &cc.Stmt{Op: cc.StmtExpr, Expr: y}) 424 | default: 425 | leftover = append(leftover, y) 426 | } 427 | } 428 | x.List = leftover 429 | 430 | default: 431 | doSideEffects(x.Left, before, after, mode&^sideStmt) 432 | doSideEffects(x.Right, before, after, mode&^sideStmt) 433 | for _, y := range x.List { 434 | doSideEffects(y, before, after, mode&^sideStmt) 435 | } 436 | } 437 | 438 | if mode&sideStmt != 0 { 439 | // Expression as statement. 440 | // Can leave x++ alone, can rewrite ++x to x++, can leave x [op]= y alone. 441 | switch x.Op { 442 | case cc.PreInc: 443 | x.Op = cc.PostInc 444 | return 445 | case cc.PreDec: 446 | x.Op = cc.PostDec 447 | return 448 | case cc.PostInc, cc.PostDec: 449 | return 450 | case cc.Eq, cc.AddEq, cc.SubEq, cc.MulEq, cc.DivEq, cc.ModEq, cc.XorEq, cc.OrEq, cc.AndEq, cc.LshEq, cc.RshEq: 451 | return 452 | case cc.Call: 453 | return 454 | } 455 | } 456 | 457 | switch x.Op { 458 | case cc.Eq, cc.AddEq, cc.SubEq, cc.MulEq, cc.DivEq, cc.ModEq, cc.XorEq, cc.OrEq, cc.AndEq, cc.LshEq, cc.RshEq: 459 | x.Left = forceCheap(before, x.Left) 460 | old := copyExpr(x) 461 | *before = append(*before, &cc.Stmt{Op: cc.StmtExpr, Expr: old}) 462 | fixMerge(x, x.Left) 463 | 464 | case cc.PreInc, cc.PreDec: 465 | x.Left = forceCheap(before, x.Left) 466 | old := copyExpr(x) 467 | old.SyntaxInfo = cc.SyntaxInfo{} 468 | if old.Op == cc.PreInc { 469 | old.Op = cc.PostInc 470 | } else { 471 | old.Op = cc.PostDec 472 | } 473 | *before = append(*before, &cc.Stmt{Op: cc.StmtExpr, Expr: old}) 474 | fixMerge(x, x.Left) 475 | 476 | case cc.PostInc, cc.PostDec: 477 | x.Left = forceCheap(before, x.Left) 478 | if mode&sideNoAfter != 0 { 479 | // Not allowed to generate fixups afterward. 480 | d := &cc.Decl{ 481 | Name: fmt.Sprintf("tmp%d", <-tmpGen), 482 | Type: x.Left.XType, 483 | } 484 | eq := &cc.Expr{ 485 | Op: ColonEq, 486 | Left: &cc.Expr{Op: cc.Name, Text: d.Name, XDecl: d}, 487 | Right: x.Left, 488 | } 489 | old := copyExpr(x.Left) 490 | old.SyntaxInfo = cc.SyntaxInfo{} 491 | *before = append(*before, 492 | &cc.Stmt{Op: cc.StmtExpr, Expr: eq}, 493 | &cc.Stmt{Op: cc.StmtExpr, Expr: &cc.Expr{Op: x.Op, Left: old}}, 494 | ) 495 | x.Op = cc.Name 496 | x.Text = d.Name 497 | x.XDecl = d 498 | x.Left = nil 499 | break 500 | } 501 | old := copyExpr(x) 502 | old.SyntaxInfo = cc.SyntaxInfo{} 503 | *after = append(*after, &cc.Stmt{Op: cc.StmtExpr, Expr: old}) 504 | fixMerge(x, x.Left) 505 | 506 | case cc.Cond: 507 | // Rewrite c ? y : z into tmp with initialization: 508 | // var tmp typeof(c?y:z) 509 | // if c { 510 | // tmp = y 511 | // } else { 512 | // tmp = z 513 | // } 514 | d := &cc.Decl{ 515 | Name: "tmp", 516 | Type: x.XType, 517 | } 518 | *before = append(*before, 519 | &cc.Stmt{Op: cc.StmtDecl, Decl: d}, 520 | &cc.Stmt{Op: cc.If, Expr: x.List[0], 521 | Body: &cc.Stmt{ 522 | Op: cc.StmtExpr, 523 | Expr: &cc.Expr{ 524 | Op: cc.Eq, 525 | Left: &cc.Expr{Op: cc.Name, Text: d.Name, XDecl: d}, 526 | Right: x.List[1], 527 | }, 528 | }, 529 | Else: &cc.Stmt{ 530 | Op: cc.StmtExpr, 531 | Expr: &cc.Expr{ 532 | Op: cc.Eq, 533 | Left: &cc.Expr{Op: cc.Name, Text: d.Name, XDecl: d}, 534 | Right: x.List[2], 535 | }, 536 | }, 537 | }, 538 | ) 539 | x.Op = cc.Name 540 | x.Text = d.Name 541 | x.XDecl = d 542 | x.List = nil 543 | 544 | case cc.Call: 545 | if x.Left.Text == "fmtstrcpy" || x.Left.Text == "fmtprint" { 546 | old := copyExpr(x) 547 | old.SyntaxInfo = cc.SyntaxInfo{} 548 | *before = append(*before, &cc.Stmt{Op: cc.StmtExpr, Expr: old}) 549 | x.Op = cc.Number 550 | x.Text = "0" 551 | x.XDecl = nil 552 | x.Left = nil 553 | x.List = nil 554 | } 555 | } 556 | } 557 | 558 | func copyExpr(x *cc.Expr) *cc.Expr { 559 | old := *x 560 | old.SyntaxInfo = cc.SyntaxInfo{} 561 | return &old 562 | } 563 | 564 | func copyStmt(x *cc.Stmt) *cc.Stmt { 565 | old := *x 566 | old.SyntaxInfo = cc.SyntaxInfo{} 567 | old.Labels = nil 568 | return &old 569 | } 570 | 571 | func forceCheap(before *[]*cc.Stmt, x *cc.Expr) *cc.Expr { 572 | // TODO 573 | return x 574 | } 575 | 576 | func fixMerge(dst, src *cc.Expr) { 577 | syn := dst.SyntaxInfo 578 | syn.Comments.Before = append(syn.Comments.Before, src.Comments.Before...) 579 | syn.Comments.After = append(syn.Comments.After, src.Comments.After...) 580 | syn.Comments.Suffix = append(syn.Comments.Suffix, src.Comments.Suffix...) 581 | *dst = *src 582 | dst.SyntaxInfo = syn 583 | } 584 | 585 | func checkNoSideEffects(x *cc.Expr, mode int) { 586 | var before, after []*cc.Stmt 587 | old := x.String() 588 | doSideEffects(x, &before, &after, mode) 589 | if len(before)+len(after) > 0 { 590 | fprintf(x.Span, "cannot handle side effects in %s", old) 591 | } 592 | } 593 | 594 | // Apply DeMorgan's law and invert comparisons 595 | // to simplify negation of boolean expressions. 596 | func simplifyBool(cfg *Config, prog *cc.Prog) { 597 | cc.Preorder(prog, func(x cc.Syntax) { 598 | switch x := x.(type) { 599 | case *cc.Expr: 600 | switch x.Op { 601 | case cc.Not: 602 | y := x.Left 603 | for y.Op == cc.Paren { 604 | y = y.Left 605 | } 606 | switch y.Op { 607 | case cc.AndAnd: 608 | *x = *y 609 | x.Left = &cc.Expr{Op: cc.Not, Left: x.Left} 610 | x.Right = &cc.Expr{Op: cc.Not, Left: x.Right} 611 | x.Op = cc.OrOr 612 | 613 | case cc.OrOr: 614 | *x = *y 615 | x.Left = &cc.Expr{Op: cc.Not, Left: x.Left} 616 | x.Right = &cc.Expr{Op: cc.Not, Left: x.Right} 617 | x.Op = cc.AndAnd 618 | 619 | case cc.EqEq: 620 | if isfloat(x.Left.XType) { 621 | break 622 | } 623 | *x = *y 624 | x.Op = cc.NotEq 625 | 626 | case cc.NotEq: 627 | if isfloat(x.Left.XType) { 628 | break 629 | } 630 | *x = *y 631 | x.Op = cc.EqEq 632 | 633 | case cc.Lt: 634 | if isfloat(x.Left.XType) { 635 | break 636 | } 637 | *x = *y 638 | x.Op = cc.GtEq 639 | 640 | case cc.LtEq: 641 | if isfloat(x.Left.XType) { 642 | break 643 | } 644 | *x = *y 645 | x.Op = cc.Gt 646 | 647 | case cc.Gt: 648 | if isfloat(x.Left.XType) { 649 | break 650 | } 651 | *x = *y 652 | x.Op = cc.LtEq 653 | 654 | case cc.GtEq: 655 | if isfloat(x.Left.XType) { 656 | break 657 | } 658 | *x = *y 659 | x.Op = cc.Lt 660 | } 661 | } 662 | } 663 | }) 664 | } 665 | 666 | func isfloat(t *cc.Type) bool { 667 | return t != nil && (t.Kind == Float32 || t.Kind == Float64) 668 | } 669 | -------------------------------------------------------------------------------- /cc/lex.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:generate go tool yacc cc.y 6 | 7 | package cc 8 | 9 | import ( 10 | "fmt" 11 | "io/ioutil" 12 | "os" 13 | "path/filepath" 14 | "sort" 15 | "strings" 16 | ) 17 | 18 | // A Syntax represents any syntax element. 19 | type Syntax interface { 20 | // GetSpan returns the start and end position of the syntax, 21 | // excluding leading or trailing comments. 22 | // The use of a Get prefix is non-standard but avoids a conflict 23 | // with the field named Span in most implementations. 24 | GetSpan() Span 25 | 26 | // GetComments returns the comments attached to the syntax. 27 | // This method would normally be named 'Comments' but that 28 | // would interfere with embedding a type of the same name. 29 | // The use of a Get prefix is non-standard but avoids a conflict 30 | // with the field named Comments in most implementations. 31 | GetComments() *Comments 32 | } 33 | 34 | // SyntaxInfo contains metadata about a piece of syntax. 35 | type SyntaxInfo struct { 36 | Span Span // location of syntax in input 37 | Comments Comments 38 | } 39 | 40 | func (s *SyntaxInfo) GetSpan() Span { 41 | return s.Span 42 | } 43 | 44 | func (s *SyntaxInfo) GetComments() *Comments { 45 | return &s.Comments 46 | } 47 | 48 | // Comments collects the comments associated with a syntax element. 49 | type Comments struct { 50 | Before []Comment // whole-line comments before this syntax 51 | Suffix []Comment // end-of-line comments after this syntax 52 | 53 | // For top-level syntax elements only, After lists whole-line 54 | // comments following the syntax. 55 | After []Comment 56 | } 57 | 58 | type lexer struct { 59 | // input 60 | start int 61 | byte int 62 | lexInput 63 | pushed []lexInput 64 | forcePos Pos 65 | c2goComment bool // inside /*c2go ... */ comment 66 | comments []Comment 67 | 68 | // comment assignment 69 | pre []Syntax 70 | post []Syntax 71 | enumSeen map[interface{}]bool 72 | 73 | // type checking state 74 | scope *Scope 75 | includeSeen map[string]*Header 76 | 77 | // output 78 | errors []string 79 | prog *Prog 80 | expr *Expr 81 | } 82 | 83 | type Header struct { 84 | decls []*Decl 85 | types []*Type 86 | } 87 | 88 | func (lx *lexer) parse() { 89 | if lx.includeSeen == nil { 90 | lx.includeSeen = make(map[string]*Header) 91 | } 92 | if lx.wholeInput == "" { 93 | lx.wholeInput = lx.input 94 | } 95 | lx.scope = &Scope{} 96 | yyParse(lx) 97 | } 98 | 99 | type lexInput struct { 100 | wholeInput string 101 | input string 102 | tok string 103 | lastsym string 104 | file string 105 | lineno int 106 | declSave *Header 107 | } 108 | 109 | func (lx *lexer) pushInclude(includeLine string) { 110 | s := strings.TrimSpace(strings.TrimPrefix(includeLine, "#include")) 111 | if !strings.HasPrefix(s, "<") && !strings.HasPrefix(s, "\"") { 112 | lx.Errorf("malformed #include") 113 | return 114 | } 115 | sep := ">" 116 | if s[0] == '"' { 117 | sep = "\"" 118 | } 119 | i := strings.Index(s[1:], sep) 120 | if i < 0 { 121 | lx.Errorf("malformed #include") 122 | return 123 | } 124 | i++ 125 | 126 | file := s[1:i] 127 | origFile := file 128 | 129 | file, data, err := lx.findInclude(file, s[0] == '<') 130 | if err != nil { 131 | lx.Errorf("#include %s: %v", s[:i+1], err) 132 | return 133 | } 134 | 135 | if hdr := lx.includeSeen[file]; hdr != nil { 136 | for _, decl := range hdr.decls { 137 | // fmt.Printf("%s: replay %s\n", file, decl.Name) 138 | lx.pushDecl(decl) 139 | } 140 | for _, typ := range hdr.types { 141 | lx.pushType(typ) 142 | } 143 | return 144 | } 145 | 146 | hdr := lx.declSave 147 | if hdr == nil { 148 | hdr = new(Header) 149 | lx.includeSeen[file] = hdr 150 | } else { 151 | fmt.Printf("%s: warning nested %s\n", lx.span(), includeLine) 152 | } 153 | 154 | if extraMap[origFile] != "" { 155 | str := extraMap[origFile] + "\n" 156 | lx.pushed = append(lx.pushed, lx.lexInput) 157 | lx.lexInput = lexInput{ 158 | input: str, 159 | wholeInput: str, 160 | file: "internal/" + origFile, 161 | lineno: 1, 162 | declSave: hdr, 163 | } 164 | } 165 | 166 | if data == nil { 167 | return 168 | } 169 | 170 | lx.pushed = append(lx.pushed, lx.lexInput) 171 | str := string(append(data, '\n')) 172 | lx.lexInput = lexInput{ 173 | input: str, 174 | wholeInput: str, 175 | file: file, 176 | lineno: 1, 177 | declSave: hdr, 178 | } 179 | } 180 | 181 | var stdMap = map[string]string{ 182 | "u.h": hdr_u_h, 183 | "libc.h": hdr_libc_h, 184 | "stdarg.h": "", 185 | "signal.h": "", 186 | "sys/stat.h": hdr_sys_stat_h, 187 | } 188 | 189 | var extraMap = map[string]string{ 190 | "go.h": hdr_extra_go_h, 191 | } 192 | 193 | var includes []string 194 | 195 | func AddInclude(dir string) { 196 | includes = append(includes, dir) 197 | } 198 | 199 | func (lx *lexer) findInclude(name string, std bool) (string, []byte, error) { 200 | if std { 201 | if redir, ok := stdMap[name]; ok { 202 | if redir == "" { 203 | return "", nil, nil 204 | } 205 | return "internal/" + name, []byte(redir), nil 206 | } 207 | name = "/Users/rsc/g/go/include/" + name 208 | } 209 | if !filepath.IsAbs(name) { 210 | name1 := filepath.Join(filepath.Dir(lx.file), name) 211 | if _, err := os.Stat(name1); err != nil { 212 | for _, dir := range includes { 213 | name2 := filepath.Join(dir, name) 214 | if _, err := os.Stat(name2); err == nil { 215 | name1 = name2 216 | break 217 | } 218 | } 219 | } 220 | name = name1 221 | } 222 | data, err := ioutil.ReadFile(name) 223 | if err != nil { 224 | return "", nil, err 225 | } 226 | return name, data, nil 227 | } 228 | 229 | func (lx *lexer) pop() bool { 230 | if len(lx.pushed) == 0 { 231 | return false 232 | } 233 | lx.lexInput = lx.pushed[len(lx.pushed)-1] 234 | lx.pushed = lx.pushed[:len(lx.pushed)-1] 235 | return true 236 | } 237 | 238 | func (lx *lexer) pos() Pos { 239 | if lx.forcePos.Line != 0 { 240 | return lx.forcePos 241 | } 242 | return Pos{lx.file, lx.lineno, lx.byte} 243 | } 244 | func (lx *lexer) span() Span { 245 | p := lx.pos() 246 | return Span{p, p} 247 | } 248 | 249 | func (lx *lexer) setSpan(s Span) { 250 | lx.forcePos = s.Start 251 | } 252 | 253 | func span(l1, l2 Span) Span { 254 | if l1.Start.Line == 0 { 255 | return l2 256 | } 257 | if l2.Start.Line == 0 { 258 | return l1 259 | } 260 | return Span{l1.Start, l2.End} 261 | } 262 | 263 | func (lx *lexer) skip(i int) { 264 | lx.lineno += strings.Count(lx.input[:i], "\n") 265 | lx.input = lx.input[i:] 266 | lx.byte += i 267 | } 268 | 269 | func (lx *lexer) token(i int) { 270 | lx.tok = lx.input[:i] 271 | lx.skip(i) 272 | } 273 | 274 | func (lx *lexer) sym(i int) { 275 | lx.token(i) 276 | lx.lastsym = lx.tok 277 | } 278 | 279 | func (lx *lexer) comment(i int) { 280 | var c Comment 281 | c.Span.Start = lx.pos() 282 | c.Text = lx.input[:i] 283 | j := len(lx.wholeInput) - len(lx.input) 284 | for j > 0 && (lx.wholeInput[j-1] == ' ' || lx.wholeInput[j-1] == '\t') { 285 | j-- 286 | } 287 | if j > 0 && lx.wholeInput[j-1] != '\n' { 288 | c.Suffix = true 289 | } 290 | prefix := lx.wholeInput[j : len(lx.wholeInput)-len(lx.input)] 291 | lines := strings.Split(c.Text, "\n") 292 | for i, line := range lines { 293 | if strings.HasPrefix(line, prefix) { 294 | lines[i] = line[len(prefix):] 295 | } 296 | } 297 | c.Text = strings.Join(lines, "\n") 298 | 299 | lx.skip(i) 300 | c.Span.End = lx.pos() 301 | lx.comments = append(lx.comments, c) 302 | } 303 | 304 | func isalpha(c byte) bool { 305 | return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '_' || c >= 0x80 || '0' <= c && c <= '9' 306 | } 307 | 308 | func isspace(c byte) bool { 309 | return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f' 310 | } 311 | 312 | func (lx *lexer) setEnd(yy *yySymType) { 313 | yy.span.End = lx.pos() 314 | } 315 | 316 | func (lx *lexer) Lex(yy *yySymType) (yyt int) { 317 | //defer func() { println("tok", yy.str, yyt) }() 318 | if lx.start != 0 { 319 | tok := lx.start 320 | lx.start = 0 321 | return tok 322 | } 323 | *yy = yySymType{} 324 | defer lx.setEnd(yy) 325 | Restart: 326 | yy.span.Start = lx.pos() 327 | in := lx.input 328 | if len(in) == 0 { 329 | if lx.pop() { 330 | goto Restart 331 | } 332 | return tokEOF 333 | } 334 | c := in[0] 335 | if isspace(c) { 336 | i := 1 337 | for i < len(in) && isspace(in[i]) { 338 | i++ 339 | } 340 | lx.skip(i) 341 | goto Restart 342 | } 343 | 344 | i := 0 345 | switch c { 346 | case '#': 347 | i++ 348 | for in[i] != '\n' { 349 | if in[i] == '\\' && in[i+1] == '\n' && i+2 < len(in) { 350 | i++ 351 | } 352 | i++ 353 | } 354 | str := in[:i] 355 | lx.skip(i) 356 | if strings.HasPrefix(str, "#include") { 357 | lx.pushInclude(str) 358 | } 359 | goto Restart 360 | 361 | case 'L': 362 | if in[1] != '\'' && in[1] != '"' { 363 | break // goes to alpha case after switch 364 | } 365 | i = 1 366 | fallthrough 367 | 368 | case '"', '\'': 369 | q := in[i] 370 | i++ // for the quote 371 | for ; in[i] != q; i++ { 372 | if in[i] == '\n' { 373 | what := "string" 374 | if q == '\'' { 375 | what = "character" 376 | } 377 | lx.Errorf("unterminated %s constant", what) 378 | } 379 | if in[i] == '\\' { 380 | i++ 381 | } 382 | } 383 | i++ // for the quote 384 | lx.sym(i) 385 | yy.str = lx.tok 386 | if q == '"' { 387 | return tokString 388 | } else { 389 | return tokLitChar 390 | } 391 | 392 | case '.': 393 | if in[1] < '0' || '9' < in[1] { 394 | if in[1] == '.' && in[2] == '.' { 395 | lx.token(3) 396 | return tokDotDotDot 397 | } 398 | lx.token(1) 399 | return int(c) 400 | } 401 | fallthrough 402 | 403 | case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': 404 | for '0' <= in[i] && in[i] <= '9' || in[i] == '.' || 'A' <= in[i] && in[i] <= 'Z' || 'a' <= in[i] && in[i] <= 'z' { 405 | i++ 406 | } 407 | lx.sym(i) 408 | yy.str = lx.tok 409 | return tokNumber 410 | 411 | case '/': 412 | switch in[1] { 413 | case '*': 414 | if strings.HasPrefix(in, "/*c2go") { 415 | lx.skip(6) 416 | lx.c2goComment = true 417 | goto Restart 418 | } 419 | i := 2 420 | for ; ; i++ { 421 | if i+2 <= len(in) && in[i] == '*' && in[i+1] == '/' { 422 | i += 2 423 | break 424 | } 425 | if i >= len(in) { 426 | lx.Errorf("unterminated /* comment") 427 | return tokError 428 | } 429 | } 430 | lx.comment(i) 431 | goto Restart 432 | 433 | case '/': 434 | for in[i] != '\n' { 435 | i++ 436 | } 437 | lx.comment(i) 438 | if len(lx.input) >= 2 && lx.input[0] == '\n' && lx.input[1] == '\n' { 439 | lx.skip(1) 440 | lx.comment(0) 441 | } 442 | goto Restart 443 | } 444 | fallthrough 445 | 446 | case '~', '*', '(', ')', '[', ']', '{', '}', '?', ':', ';', ',', '%', '^', '!', '=', '<', '>', '+', '-', '&', '|': 447 | if lx.c2goComment && in[0] == '*' && in[1] == '/' { 448 | lx.c2goComment = false 449 | lx.skip(2) 450 | goto Restart 451 | } 452 | if c == '-' && in[1] == '>' { 453 | lx.token(2) 454 | return tokArrow 455 | } 456 | if in[1] == '=' && tokEq[c] != 0 { 457 | lx.token(2) 458 | return int(tokEq[c]) 459 | } 460 | if in[1] == c && tokTok[c] != 0 { 461 | if in[2] == '=' && tokTokEq[c] != 0 { 462 | lx.token(3) 463 | return int(tokTokEq[c]) 464 | } 465 | lx.token(2) 466 | return int(tokTok[c]) 467 | } 468 | lx.token(1) 469 | return int(c) 470 | } 471 | 472 | if isalpha(c) { 473 | for isalpha(in[i]) { 474 | i++ 475 | } 476 | lx.sym(i) 477 | switch lx.tok { 478 | case "Adr": 479 | lx.tok = "Addr" 480 | case "union": 481 | lx.tok = "struct" 482 | } 483 | yy.str = lx.tok 484 | if t := tokId[lx.tok]; t != 0 { 485 | return int(t) 486 | } 487 | yy.decl = lx.lookupDecl(lx.tok) 488 | if yy.decl != nil && yy.decl.Storage&Typedef != 0 { 489 | t := yy.decl.Type 490 | for t.Kind == TypedefType && t.Base != nil { 491 | t = t.Base 492 | } 493 | yy.typ = &Type{Kind: TypedefType, Name: yy.str, Base: t, TypeDecl: yy.decl} 494 | return tokTypeName 495 | } 496 | if lx.tok == "EXTERN" { 497 | goto Restart 498 | } 499 | return tokName 500 | } 501 | 502 | lx.Errorf("unexpected input byte %#02x (%c)", c, c) 503 | return tokError 504 | } 505 | 506 | func (lx *lexer) Error(s string) { 507 | lx.Errorf("%s near %s", s, lx.lastsym) 508 | } 509 | 510 | func (lx *lexer) Errorf(format string, args ...interface{}) { 511 | lx.errors = append(lx.errors, fmt.Sprintf("%s: %s", lx.span(), fmt.Sprintf(format, args...))) 512 | } 513 | 514 | type Pos struct { 515 | File string 516 | Line int 517 | Byte int 518 | } 519 | 520 | type Span struct { 521 | Start Pos 522 | End Pos 523 | } 524 | 525 | func (l Span) String() string { 526 | return fmt.Sprintf("%s:%d", l.Start.File, l.Start.Line) 527 | } 528 | 529 | type Comment struct { 530 | Span 531 | Text string 532 | Suffix bool 533 | } 534 | 535 | func (c Comment) GetSpan() Span { 536 | return c.Span 537 | } 538 | 539 | var tokEq = [256]int32{ 540 | '*': tokMulEq, 541 | '/': tokDivEq, 542 | '+': tokAddEq, 543 | '-': tokSubEq, 544 | '%': tokModEq, 545 | '^': tokXorEq, 546 | '!': tokNotEq, 547 | '=': tokEqEq, 548 | '<': tokLtEq, 549 | '>': tokGtEq, 550 | '&': tokAndEq, 551 | '|': tokOrEq, 552 | } 553 | 554 | var tokTok = [256]int32{ 555 | '<': tokLsh, 556 | '>': tokRsh, 557 | '=': tokEqEq, 558 | '+': tokInc, 559 | '-': tokDec, 560 | '&': tokAndAnd, 561 | '|': tokOrOr, 562 | } 563 | 564 | var tokTokEq = [256]int32{ 565 | '<': tokLshEq, 566 | '>': tokRshEq, 567 | } 568 | 569 | var tokId = map[string]int32{ 570 | "auto": tokAuto, 571 | "break": tokBreak, 572 | "case": tokCase, 573 | "char": tokChar, 574 | "const": tokConst, 575 | "continue": tokContinue, 576 | "default": tokDefault, 577 | "do": tokDo, 578 | "double": tokDouble, 579 | "else": tokElse, 580 | "enum": tokEnum, 581 | "extern": tokExtern, 582 | "float": tokFloat, 583 | "for": tokFor, 584 | "goto": tokGoto, 585 | "if": tokIf, 586 | "inline": tokInline, 587 | "int": tokInt, 588 | "long": tokLong, 589 | "offsetof": tokOffsetof, 590 | "register": tokRegister, 591 | "return": tokReturn, 592 | "short": tokShort, 593 | "signed": tokSigned, 594 | "sizeof": tokSizeof, 595 | "static": tokStatic, 596 | "struct": tokStruct, 597 | "switch": tokSwitch, 598 | "typedef": tokTypedef, 599 | "union": tokUnion, 600 | "unsigned": tokUnsigned, 601 | "va_arg": tokVaArg, 602 | "void": tokVoid, 603 | "volatile": tokVolatile, 604 | "while": tokWhile, 605 | 606 | "ARGBEGIN": tokARGBEGIN, 607 | "ARGEND": tokARGEND, 608 | "AUTOLIB": tokAUTOLIB, 609 | "USED": tokUSED, 610 | "SET": tokSET, 611 | } 612 | 613 | // Comment assignment. 614 | // We build two lists of all subexpressions, preorder and postorder. 615 | // The preorder list is ordered by start location, with outer expressions first. 616 | // The postorder list is ordered by end location, with outer expressions last. 617 | // We use the preorder list to assign each whole-line comment to the syntax 618 | // immediately following it, and we use the postorder list to assign each 619 | // end-of-line comment to the syntax immediately preceding it. 620 | 621 | // enum walks the expression adding it and its subexpressions to the pre list. 622 | // The order may not reflect the order in the input. 623 | func (lx *lexer) enum(x Syntax) { 624 | switch x := x.(type) { 625 | default: 626 | panic(fmt.Errorf("order: unexpected type %T", x)) 627 | case nil: 628 | return 629 | case *Expr: 630 | if x == nil { 631 | return 632 | } 633 | lx.enum(x.Left) 634 | lx.enum(x.Right) 635 | for _, y := range x.List { 636 | lx.enum(y) 637 | } 638 | case *Init: 639 | if x == nil { 640 | return 641 | } 642 | lx.enum(x.Expr) 643 | for _, y := range x.Braced { 644 | lx.enum(y) 645 | } 646 | case *Prog: 647 | if x == nil { 648 | return 649 | } 650 | for _, y := range x.Decls { 651 | lx.enum(y) 652 | } 653 | case *Stmt: 654 | if x == nil { 655 | return 656 | } 657 | for _, y := range x.Labels { 658 | lx.enum(y) 659 | } 660 | lx.enum(x.Pre) 661 | lx.enum(x.Expr) 662 | lx.enum(x.Post) 663 | lx.enum(x.Body) 664 | lx.enum(x.Else) 665 | for _, y := range x.Block { 666 | lx.enum(y) 667 | } 668 | case *Label: 669 | // ok 670 | case *Decl: 671 | if x == nil { 672 | return 673 | } 674 | if lx.enumSeen[x] { 675 | return 676 | } 677 | lx.enumSeen[x] = true 678 | lx.enum(x.Type) 679 | lx.enum(x.Init) 680 | lx.enum(x.Body) 681 | case *Type: 682 | if x == nil { 683 | return 684 | } 685 | lx.enum(x.Base) 686 | for _, y := range x.Decls { 687 | lx.enum(y) 688 | } 689 | return // do not record type itself, just inner decls 690 | } 691 | lx.pre = append(lx.pre, x) 692 | } 693 | 694 | func (lx *lexer) order(prog *Prog) { 695 | lx.enumSeen = make(map[interface{}]bool) 696 | lx.enum(prog) 697 | sort.Sort(byStart(lx.pre)) 698 | lx.post = make([]Syntax, len(lx.pre)) 699 | copy(lx.post, lx.pre) 700 | sort.Sort(byEnd(lx.post)) 701 | } 702 | 703 | type byStart []Syntax 704 | 705 | func (x byStart) Len() int { return len(x) } 706 | func (x byStart) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 707 | func (x byStart) Less(i, j int) bool { 708 | pi := x[i].GetSpan() 709 | pj := x[j].GetSpan() 710 | // Order by start byte, leftmost first, 711 | // and break ties by choosing outer before inner. 712 | if pi.Start.Byte != pj.Start.Byte { 713 | return pi.Start.Byte < pj.Start.Byte 714 | } 715 | return pi.End.Byte > pj.End.Byte 716 | } 717 | 718 | type byEnd []Syntax 719 | 720 | func (x byEnd) Len() int { return len(x) } 721 | func (x byEnd) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 722 | func (x byEnd) Less(i, j int) bool { 723 | pi := x[i].GetSpan() 724 | pj := x[j].GetSpan() 725 | // Order by end byte, leftmost first, 726 | // and break ties by choosing inner before outer. 727 | if pi.End.Byte != pj.End.Byte { 728 | return pi.End.Byte < pj.End.Byte 729 | } 730 | return pi.Start.Byte > pj.Start.Byte 731 | } 732 | 733 | // assignComments attaches comments to nearby syntax. 734 | func (lx *lexer) assignComments() { 735 | // Generate preorder and postorder lists. 736 | lx.order(lx.prog) 737 | 738 | // Split into whole-line comments and suffix comments. 739 | var line, suffix []Comment 740 | for _, com := range lx.comments { 741 | if com.Suffix { 742 | suffix = append(suffix, com) 743 | } else { 744 | line = append(line, com) 745 | } 746 | } 747 | 748 | // Assign line comments to syntax immediately following. 749 | for _, x := range lx.pre { 750 | start := x.GetSpan().Start 751 | xcom := x.GetComments() 752 | for len(line) > 0 && start.Byte >= line[0].Start.Byte { 753 | xcom.Before = append(xcom.Before, line[0]) 754 | line = line[1:] 755 | } 756 | } 757 | 758 | // Remaining line comments go at end of file. 759 | lx.prog.Comments.After = append(lx.prog.Comments.After, line...) 760 | 761 | // Assign suffix comments to syntax immediately before. 762 | for i := len(lx.post) - 1; i >= 0; i-- { 763 | x := lx.post[i] 764 | 765 | // Do not assign suffix comments to call, list, end-of-list, or whole file. 766 | // Instead assign them to the last argument, element, or rule. 767 | /* 768 | switch x.(type) { 769 | case *CallExpr, *ListExpr, *End, *File: 770 | continue 771 | } 772 | */ 773 | 774 | // Do not assign suffix comments to something that starts 775 | // on an earlier line, so that in 776 | // 777 | // tags = [ "a", 778 | // "b" ], # comment 779 | // 780 | // we assign the comment to "b" and not to tags = [ ... ]. 781 | span := x.GetSpan() 782 | start, end := span.Start, span.End 783 | if start.Line != end.Line { 784 | continue 785 | } 786 | xcom := x.GetComments() 787 | for len(suffix) > 0 && end.Byte <= suffix[len(suffix)-1].Start.Byte { 788 | xcom.Suffix = append(xcom.Suffix, suffix[len(suffix)-1]) 789 | suffix = suffix[:len(suffix)-1] 790 | } 791 | } 792 | 793 | // We assigned suffix comments in reverse. 794 | // If multiple suffix comments were appended to the same 795 | // expression node, they are now in reverse. Fix that. 796 | for _, x := range lx.post { 797 | reverseComments(x.GetComments().Suffix) 798 | } 799 | 800 | // Remaining suffix comments go at beginning of file. 801 | lx.prog.Comments.Before = append(lx.prog.Comments.Before, suffix...) 802 | } 803 | 804 | // reverseComments reverses the []Comment list. 805 | func reverseComments(list []Comment) { 806 | for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 { 807 | list[i], list[j] = list[j], list[i] 808 | } 809 | } 810 | -------------------------------------------------------------------------------- /printer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "os" 11 | "path" 12 | "strings" 13 | 14 | "rsc.io/c2go/cc" 15 | ) 16 | 17 | type PrintSpecial int 18 | 19 | const ( 20 | Indent PrintSpecial = iota 21 | Unindent 22 | Untab 23 | Newline 24 | ) 25 | 26 | // print an error; fprintf is a bad name but helps go vet. 27 | func fprintf(span cc.Span, format string, args ...interface{}) { 28 | msg := fmt.Sprintf(format, args...) 29 | fmt.Fprintf(os.Stderr, "%s:%d: %s\n", span.Start.File, span.Start.Line, msg) 30 | } 31 | 32 | type Printer struct { 33 | Package string 34 | buf bytes.Buffer 35 | indent int 36 | html bool 37 | lastline int 38 | 39 | printed map[interface{}]bool 40 | suffix []cc.Comment // suffix comments to print at next newline 41 | } 42 | 43 | func (p *Printer) dup(x interface{}) bool { 44 | if p.printed[x] { 45 | return true 46 | } 47 | if p.printed == nil { 48 | p.printed = make(map[interface{}]bool) 49 | } 50 | p.printed[x] = true 51 | return false 52 | } 53 | 54 | func (p *Printer) StartHTML() { 55 | p.buf.WriteString("
")
  56 | 	p.html = true
  57 | }
  58 | 
  59 | func (p *Printer) EndHTML() {
  60 | 	p.buf.WriteString("
") 61 | } 62 | 63 | func (p *Printer) Bytes() []byte { 64 | return p.buf.Bytes() 65 | } 66 | 67 | func (p *Printer) String() string { 68 | return p.buf.String() 69 | } 70 | 71 | type exprPrec struct { 72 | expr *cc.Expr 73 | prec int 74 | } 75 | 76 | type nestBlock struct { 77 | stmt *cc.Stmt 78 | more bool 79 | } 80 | 81 | type unnestBlock struct { 82 | stmt *cc.Stmt 83 | } 84 | 85 | type typedInit struct { 86 | typ *cc.Type 87 | init *cc.Init 88 | } 89 | 90 | var htmlEscaper = strings.NewReplacer("<", "<", ">", ">", "&", "&") 91 | 92 | func GoString(args ...interface{}) string { 93 | var p Printer 94 | p.Print(args...) 95 | return p.buf.String() 96 | } 97 | 98 | type spanner interface { 99 | GetSpan() cc.Span 100 | } 101 | 102 | func (p *Printer) spacing(arg spanner) { 103 | span := arg.GetSpan() 104 | if p.lastline+1 < span.Start.Line { 105 | p.buf.WriteString("\n") 106 | } 107 | if span.End.Line > 0 { 108 | p.lastline = span.End.Line 109 | } 110 | } 111 | 112 | func (p *Printer) Print(args ...interface{}) { 113 | for _, arg := range args { 114 | switch arg := arg.(type) { 115 | default: 116 | fmt.Fprintf(&p.buf, "(?%T)", arg) 117 | case string: 118 | if p.html { 119 | htmlEscaper.WriteString(&p.buf, arg) 120 | } else { 121 | p.buf.WriteString(arg) 122 | } 123 | case exprPrec: 124 | p.printExpr(arg.expr, arg.prec) 125 | case *cc.Expr: 126 | p.printExpr(arg, precLow) 127 | case *cc.Prefix: 128 | p.printPrefix(arg) 129 | case *cc.Init: 130 | p.printInit(nil, arg) 131 | case typedInit: 132 | p.printInit(arg.typ, arg.init) 133 | case *cc.Prog: 134 | p.spacing(arg) 135 | p.printProg(arg) 136 | case *cc.Stmt: 137 | if arg.Op != cc.Block { 138 | p.spacing(arg) 139 | } 140 | p.printStmt(arg) 141 | case *cc.Type: 142 | p.printType(arg) 143 | case *cc.Decl: 144 | p.spacing(arg) 145 | p.printDecl(arg) 146 | case cc.Storage: 147 | p.Print(arg.String()) 148 | case []cc.Comment: 149 | for _, com := range arg { 150 | p.Print(com) 151 | } 152 | case cc.Comment: 153 | p.spacing(arg) 154 | com := arg 155 | if com.Suffix { 156 | p.suffix = append(p.suffix, com) 157 | } else { 158 | for _, line := range strings.Split(com.Text, "\n") { 159 | p.Print(line, Newline) 160 | } 161 | } 162 | case nestBlock: 163 | if arg.stmt.Op == cc.Block { 164 | p.Print(" ", arg.stmt) 165 | } else { 166 | p.Print(" {", Indent, Newline, arg.stmt, Unindent, Newline, "}") 167 | } 168 | case unnestBlock: 169 | if arg.stmt.Op == cc.Block { 170 | for i, b := range arg.stmt.Block { 171 | if i > 0 { 172 | p.Print(Newline) 173 | } 174 | p.Print(b) 175 | } 176 | } else { 177 | p.Print(arg.stmt) 178 | } 179 | case PrintSpecial: 180 | switch arg { 181 | default: 182 | fmt.Fprintf(&p.buf, "(?special:%d)", arg) 183 | case Indent: 184 | p.indent++ 185 | case Unindent: 186 | p.indent-- 187 | case Untab: 188 | b := p.buf.Bytes() 189 | if len(b) > 0 && b[len(b)-1] == '\t' { 190 | p.buf.Truncate(len(b) - 1) 191 | } 192 | case Newline: 193 | for _, com := range p.suffix { 194 | p.Print(" ", com.Text) 195 | } 196 | p.suffix = p.suffix[:0] 197 | p.buf.WriteString("\n") 198 | for i := 0; i < p.indent; i++ { 199 | p.buf.WriteByte('\t') 200 | } 201 | } 202 | } 203 | } 204 | } 205 | 206 | const ( 207 | precNone = iota 208 | precArrow 209 | precAddr 210 | precMul 211 | precAdd 212 | precCmp 213 | precAndAnd 214 | precOrOr 215 | precComma 216 | precLow 217 | ) 218 | 219 | var opPrec = map[cc.ExprOp]int{ 220 | cc.Add: precAdd, 221 | cc.AddEq: precLow, 222 | cc.Addr: precAddr, 223 | cc.And: precMul, 224 | cc.AndAnd: precAndAnd, 225 | cc.AndEq: precLow, 226 | cc.Arrow: precArrow, 227 | cc.Call: precArrow, 228 | cc.Cast: precAddr, 229 | cc.CastInit: precAddr, 230 | cc.Comma: precComma, 231 | cc.Cond: precComma, 232 | cc.Div: precMul, 233 | cc.DivEq: precLow, 234 | cc.Dot: precArrow, 235 | cc.Eq: precLow, 236 | cc.EqEq: precCmp, 237 | cc.Gt: precCmp, 238 | cc.GtEq: precCmp, 239 | cc.Index: precArrow, 240 | cc.Indir: precAddr, 241 | cc.Lsh: precMul, 242 | cc.LshEq: precLow, 243 | cc.Lt: precCmp, 244 | cc.LtEq: precCmp, 245 | cc.Minus: precAddr, 246 | cc.Mod: precMul, 247 | cc.ModEq: precLow, 248 | cc.Mul: precMul, 249 | cc.MulEq: precLow, 250 | cc.Name: precNone, 251 | cc.Not: precAddr, 252 | cc.NotEq: precCmp, 253 | cc.Number: precNone, 254 | cc.Offsetof: precAddr, 255 | cc.Or: precAdd, 256 | cc.OrEq: precLow, 257 | cc.OrOr: precOrOr, 258 | cc.Paren: precLow, 259 | cc.Plus: precAddr, 260 | cc.PostDec: precAddr, 261 | cc.PostInc: precAddr, 262 | cc.PreDec: precAddr, 263 | cc.PreInc: precAddr, 264 | cc.Rsh: precMul, 265 | cc.RshEq: precLow, 266 | cc.SizeofExpr: precAddr, 267 | cc.SizeofType: precAddr, 268 | cc.String: precNone, 269 | cc.Sub: precAdd, 270 | cc.SubEq: precLow, 271 | cc.Twid: precAddr, 272 | cc.VaArg: precAddr, 273 | cc.Xor: precAdd, 274 | cc.XorEq: precLow, 275 | 276 | AndNot: precMul, 277 | AndNotEq: precLow, 278 | ColonEq: precLow, 279 | TypeAssert: precArrow, 280 | ExprType: precNone, 281 | } 282 | 283 | var opStr = map[cc.ExprOp]string{ 284 | cc.Add: "+", 285 | cc.AddEq: "+=", 286 | cc.Addr: "&", 287 | cc.And: "&", 288 | cc.AndAnd: "&&", 289 | cc.AndEq: "&=", 290 | cc.Div: "/", 291 | cc.DivEq: "/=", 292 | cc.Eq: "=", 293 | cc.EqEq: "==", 294 | cc.Gt: ">", 295 | cc.GtEq: ">=", 296 | cc.Indir: "*", 297 | cc.Lsh: "<<", 298 | cc.LshEq: "<<=", 299 | cc.Lt: "<", 300 | cc.LtEq: "<=", 301 | cc.Minus: "-", 302 | cc.Mod: "%", 303 | cc.ModEq: "%=", 304 | cc.Mul: "*", 305 | cc.MulEq: "*=", 306 | cc.Not: "!", 307 | cc.NotEq: "!=", 308 | cc.Or: "|", 309 | cc.OrEq: "|=", 310 | cc.OrOr: "||", 311 | cc.Plus: "+", 312 | cc.PreDec: "--", 313 | cc.PreInc: "++", 314 | cc.Rsh: ">>", 315 | cc.RshEq: ">>=", 316 | cc.Sub: "-", 317 | cc.SubEq: "-=", 318 | cc.Twid: "^", 319 | cc.Xor: "^", 320 | cc.XorEq: "^=", 321 | 322 | AndNot: "&^", 323 | AndNotEq: "&^=", 324 | ColonEq: ":=", 325 | } 326 | 327 | const ( 328 | ExprBlock cc.ExprOp = 100000 + iota 329 | ExprSlice 330 | AndNot 331 | AndNotEq 332 | ColonEq 333 | TypeAssert 334 | ExprType 335 | ) 336 | 337 | func (p *Printer) printExpr(x *cc.Expr, prec int) { 338 | if x == nil { 339 | return 340 | } 341 | if p.html { 342 | fmt.Fprintf(&p.buf, "", x.Op, x.XType) 343 | defer fmt.Fprintf(&p.buf, "") 344 | } 345 | 346 | p.Print(x.Comments.Before) 347 | defer p.Print(x.Comments.Suffix, x.Comments.After) 348 | 349 | newPrec := opPrec[x.Op] 350 | if prec < newPrec { 351 | p.Print("(") 352 | defer p.Print(")") 353 | } 354 | prec = newPrec 355 | 356 | str := opStr[x.Op] 357 | if str != "" { 358 | if x.Right != nil { 359 | // binary operator 360 | // left associative 361 | p.Print(exprPrec{x.Left, prec}, " ", str, " ", exprPrec{x.Right, prec - 1}) 362 | } else { 363 | // unary operator 364 | if (x.Op == cc.Plus || x.Op == cc.Minus || x.Op == cc.Addr) && x.Left.Op == x.Op || 365 | x.Op == cc.Plus && x.Left.Op == cc.PreInc || 366 | x.Op == cc.Minus && x.Left.Op == cc.PreDec { 367 | prec-- // force parenthesization +(+x) not ++x 368 | } 369 | p.Print(str, exprPrec{x.Left, prec}) 370 | } 371 | return 372 | } 373 | 374 | // special cases 375 | switch x.Op { 376 | default: 377 | panic(fmt.Sprintf("printExpr missing case for %v", x.Op)) 378 | 379 | case ExprBlock: 380 | if len(x.Block) == 0 { 381 | break 382 | } 383 | p.Print("(func(){") 384 | for i, stmt := range x.Block { 385 | if i > 0 { 386 | p.Print("; ") 387 | } 388 | p.Print(stmt) 389 | } 390 | p.Print("})()") 391 | 392 | case ExprSlice: 393 | p.Print(x.List[0], "[") 394 | if x.List[1] != nil { 395 | p.Print(x.List[1]) 396 | } 397 | p.Print(":") 398 | if x.List[2] != nil { 399 | p.Print(x.List[2]) 400 | } 401 | p.Print("]") 402 | 403 | case cc.Arrow: 404 | name := x.Text 405 | if x.XDecl != nil { 406 | name = x.XDecl.Name 407 | } 408 | p.Print(exprPrec{x.Left, prec}, ".", name) 409 | 410 | case TypeAssert: 411 | p.Print(exprPrec{x.Left, prec}, ".(", x.Type, ")") 412 | 413 | case ExprType: 414 | p.Print(x.Type) 415 | 416 | case cc.Call: 417 | p.Print(exprPrec{x.Left, precAddr}, "(") 418 | for i, y := range x.List { 419 | if i > 0 { 420 | p.Print(", ") 421 | } 422 | p.printExpr(y, precComma) 423 | } 424 | p.Print(")") 425 | 426 | case cc.Cast: 427 | if x.Type.Kind == cc.Ptr || x.Type.Kind == cc.Func { 428 | p.Print("(", x.Type, ")(", exprPrec{x.Left, precLow}, ")") 429 | } else { 430 | p.Print(x.Type, "(", exprPrec{x.Left, precLow}, ")") 431 | } 432 | 433 | case cc.CastInit: 434 | if x.Type.Kind == cc.Ptr || x.Type.Kind == cc.Func { 435 | p.Print("(", x.Type, ")", x.Init) 436 | } else { 437 | p.Print(x.Type, x.Init) 438 | } 439 | 440 | case cc.Comma: 441 | if len(x.List) == 0 { 442 | break 443 | } 444 | p.Print("(func() {") 445 | for i, y := range x.List { 446 | if i > 0 { 447 | p.Print("; ") 448 | } 449 | p.printExpr(y, precLow) 450 | } 451 | p.Print("}())") 452 | 453 | case cc.Cond: 454 | p.Print("TERNARY(", exprPrec{x.List[0], prec - 1}, ", ", exprPrec{x.List[1], prec}, ", ", exprPrec{x.List[2], prec}, ")") 455 | 456 | case cc.Dot: 457 | name := x.XDecl.Name 458 | p.Print(exprPrec{x.Left, prec}, ".", name) 459 | 460 | case cc.Index: 461 | p.Print(exprPrec{x.Left, prec}, "[", exprPrec{x.Right, precLow}, "]") 462 | 463 | case cc.Name: 464 | name := x.Text 465 | if x.XDecl != nil { 466 | name = x.XDecl.Name 467 | if x.XDecl.GoPackage != "" && p.Package != "" && x.XDecl.GoPackage != p.Package { 468 | name = path.Base(x.XDecl.GoPackage) + "." + name 469 | } 470 | } 471 | p.Print(name) 472 | 473 | case cc.Number: 474 | p.Print(strings.TrimRight(x.Text, "LlUu")) 475 | 476 | case cc.SizeofExpr: 477 | p.Print("sizeof(", x.Left, ")") 478 | 479 | case cc.String: 480 | for i, str := range x.Texts { 481 | if i > 0 { 482 | p.Print(" + ") 483 | } 484 | p.Print(str) 485 | } 486 | 487 | case cc.Offsetof: 488 | p.Print("offsetof(", x.Type, ", ", exprPrec{x.Left, precComma}, ")") 489 | 490 | case cc.Paren: 491 | p.Print(exprPrec{x.Left, prec}) 492 | 493 | case cc.PostDec: 494 | p.Print(exprPrec{x.Left, prec}, "--") 495 | 496 | case cc.PostInc: 497 | p.Print(exprPrec{x.Left, prec}, "++") 498 | 499 | case cc.SizeofType: 500 | p.Print("sizeof(", x.Type, ")") 501 | 502 | case cc.VaArg: 503 | p.Print("va_arg(", exprPrec{x.Left, precComma}, ", ", x.Type, ")") 504 | } 505 | } 506 | 507 | func (p *Printer) printPrefix(x *cc.Prefix) { 508 | if x.Dot != "" { 509 | p.Print(x.XDecl.Name, ": ") 510 | } else { 511 | p.Print(x.Index, ": ") 512 | } 513 | } 514 | 515 | func (p *Printer) printInit(typ *cc.Type, x *cc.Init) { 516 | p.Print(x.Comments.Before) 517 | defer p.Print(x.Comments.Suffix, x.Comments.After) 518 | 519 | if len(x.Prefix) > 0 { 520 | for _, pre := range x.Prefix { 521 | p.Print(pre) 522 | } 523 | } 524 | if x.Expr != nil { 525 | if x.Expr.Op == cc.Number && (typ.Is(cc.Ptr) || typ.Is(Slice)) { 526 | p.Print("nil") 527 | return 528 | } 529 | p.printExpr(x.Expr, precComma) 530 | return 531 | } 532 | 533 | nl := len(x.Braced) > 0 && x.Braced[0].Span.Start.Line != x.Braced[len(x.Braced)-1].Span.End.Line 534 | if typ != nil { 535 | p.printType(typ) 536 | } 537 | p.Print("{") 538 | if nl { 539 | p.Print(Indent) 540 | } 541 | warned := false 542 | for i, y := range x.Braced { 543 | if nl { 544 | p.Print(Newline) 545 | } else if i > 0 { 546 | p.Print(" ") 547 | } 548 | var subtyp *cc.Type 549 | if typ != nil { 550 | if typ.Is(cc.Struct) && i < len(typ.Def().Decls) && len(y.Prefix) == 0 { 551 | subtyp = typ.Def().Decls[i].Type 552 | } else if typ.Is(cc.Struct) && len(y.Prefix) == 1 && y.Prefix[0].XDecl != nil { 553 | subtyp = y.Prefix[0].XDecl.Type 554 | } else if typ.Is(cc.Array) || typ.Is(Slice) { 555 | subtyp = typ.Def().Base 556 | } else if !warned { 557 | warned = true 558 | fprintf(x.Span, "too many fields in braced initializer of %s", GoString(typ)) 559 | } 560 | } 561 | p.printInit(subtyp, y) 562 | p.Print(",") 563 | } 564 | if typ != nil && typ.Is(cc.Struct) && len(x.Braced) > 0 && len(x.Braced[0].Prefix) == 0 && len(x.Braced) < len(typ.Def().Decls) { 565 | for i := len(x.Braced); i < len(typ.Def().Decls); i++ { 566 | subtyp := typ.Def().Decls[i].Type 567 | if subtyp.Is(cc.Ptr) || subtyp.Is(Slice) { 568 | p.Print(" nil,") 569 | } else if subtyp.Is(cc.Array) { 570 | p.Print(" ", subtyp, "{},") 571 | } else { 572 | p.Print(" 0,") 573 | } 574 | } 575 | } 576 | if nl { 577 | p.Print(Unindent, Newline) 578 | } 579 | p.Print("}") 580 | } 581 | 582 | func (p *Printer) printProg(x *cc.Prog) { 583 | p.Print(x.Comments.Before) 584 | defer p.Print(x.Comments.Suffix, x.Comments.After, Newline) 585 | 586 | for _, decl := range x.Decls { 587 | p.Print(decl, Newline) 588 | } 589 | } 590 | 591 | const ( 592 | BlockNoBrace cc.StmtOp = 100000 + iota 593 | ForRange 594 | ) 595 | 596 | func (p *Printer) printStmt(x *cc.Stmt) { 597 | if len(x.Labels) > 0 { 598 | p.Print(Untab, Unindent, x.Comments.Before, Indent, "\t") 599 | for i := 0; i < len(x.Labels); i++ { 600 | lab := x.Labels[i] 601 | p.Print(Untab, Unindent, lab.Comments.Before, Indent, "\t") 602 | p.Print(Untab) 603 | switch lab.Op { 604 | case cc.LabelName: 605 | p.Print(lab.Name) 606 | case cc.Case: 607 | p.Print("case ", lab.Expr) 608 | for i+1 < len(x.Labels) && x.Labels[i+1].Op == cc.Case { 609 | p.Print(", ", lab.Comments.Suffix, Newline) 610 | i++ 611 | lab = x.Labels[i] 612 | p.Print(lab.Comments.Before, lab.Expr) 613 | } 614 | if i+1 < len(x.Labels) && x.Labels[i+1].Op == cc.Default { 615 | p.Print(":", lab.Comments.Suffix, Newline) 616 | i++ 617 | lab = x.Labels[i] 618 | p.Print("fallthrough", Newline, "default") 619 | } 620 | case cc.Default: 621 | p.Print("default") 622 | } 623 | p.Print(":", lab.Comments.Suffix, Newline) 624 | } 625 | } else { 626 | p.Print(x.Comments.Before) 627 | } 628 | defer p.Print(x.Comments.Suffix, x.Comments.After) 629 | 630 | switch x.Op { 631 | case cc.ARGBEGIN: 632 | p.Print("ARGBEGIN{", Indent, Newline, x.Body, Unindent, Newline, "}ARGEND") 633 | 634 | case cc.Block: 635 | p.Print("{", Indent) 636 | for _, b := range x.Block { 637 | if b.Op == cc.StmtDecl && p.printed[b.Decl] { 638 | continue 639 | } 640 | p.Print(Newline, b) 641 | } 642 | p.Print(Unindent, Newline, "}") 643 | 644 | case BlockNoBrace: 645 | for i, b := range x.Block { 646 | if i > 0 { 647 | p.Print(Newline) 648 | } 649 | p.Print(b) 650 | } 651 | 652 | case cc.Break: 653 | p.Print("break") 654 | 655 | case cc.Continue: 656 | p.Print("continue") 657 | 658 | case cc.Do: 659 | p.Print("for ") 660 | if x.Pre != nil { 661 | p.Print(x.Pre, "; ; ", x.Pre, " ") 662 | } 663 | p.Print("{", Indent, Newline, unnestBlock{x.Body}, Newline, "if ", &cc.Expr{Op: cc.Not, Left: x.Expr}, " {", Indent, Newline, "break", Unindent, Newline, "}", Unindent, Newline, "}") 664 | 665 | case cc.Empty: 666 | // ok 667 | 668 | case cc.For: 669 | p.Print("for ", x.Pre, "; ", x.Expr, "; ", x.Post, nestBlock{x.Body, false}) 670 | 671 | case ForRange: 672 | p.Print("for ", x.Pre, " = range ", x.Post, nestBlock{x.Body, false}) 673 | 674 | case cc.If: 675 | p.Print("if ") 676 | if x.Pre != nil { 677 | p.Print(x.Pre, "; ") 678 | } 679 | p.Print(x.Expr, nestBlock{x.Body, x.Else != nil}) 680 | if x.Else != nil { 681 | if x.Else.Op == cc.If { 682 | p.Print(" else ", x.Else) 683 | } else { 684 | p.Print(" else", nestBlock{x.Else, false}) 685 | } 686 | } 687 | 688 | case cc.Goto: 689 | p.Print("goto ", x.Text) 690 | 691 | case cc.Return: 692 | if x.Expr == nil { 693 | p.Print("return") 694 | } else { 695 | p.Print("return ", x.Expr) 696 | } 697 | 698 | case cc.StmtDecl: 699 | p.Print(x.Decl) 700 | 701 | case cc.StmtExpr: 702 | p.Print(x.Expr) 703 | 704 | case cc.Switch: 705 | p.Print("switch ", x.Expr, nestBlock{x.Body, false}) 706 | 707 | case cc.While: 708 | p.Print("for ") 709 | if x.Pre != nil { 710 | p.Print(x.Pre, "; ") 711 | } 712 | p.Print(x.Expr) 713 | if x.Pre != nil { 714 | p.Print("; ", x.Pre, " ") 715 | } 716 | p.Print(nestBlock{x.Body, false}) 717 | } 718 | } 719 | 720 | const ( 721 | Bool cc.TypeKind = 100000 + iota 722 | Int8 723 | Uint8 724 | Byte 725 | Int16 726 | Uint16 727 | Int 728 | Uint 729 | Int32 730 | Rune 731 | Uint32 732 | Uintptr 733 | Int64 734 | Uint64 735 | Float32 736 | Float64 737 | Ideal 738 | String 739 | Slice 740 | ) 741 | 742 | func (p *Printer) printType(t *cc.Type) { 743 | if t == nil { 744 | p.Print("nil_type") 745 | return 746 | } 747 | 748 | // Shouldn't happen but handle in case it does. 749 | p.Print(t.Comments.Before) 750 | defer p.Print(t.Comments.Suffix, t.Comments.After) 751 | 752 | if t == cc.BoolType { 753 | p.Print("bool") 754 | return 755 | } 756 | if typemap[t.Kind] != "" { 757 | p.Print(typemap[t.Kind]) 758 | return 759 | } 760 | 761 | switch t.Kind { 762 | default: 763 | if t.String() == "" { 764 | p.Print("C.unknown") 765 | break 766 | } 767 | p.Print("C.", t.String()) // hope for the best 768 | 769 | case Slice: 770 | p.Print("[]", t.Base) 771 | 772 | case String: 773 | p.Print("string") 774 | 775 | case cc.Struct: 776 | if len(t.Decls) == 0 { 777 | p.Print("struct{}") 778 | break 779 | } 780 | p.Print("struct {", Indent) 781 | p.printStructBody(t) 782 | p.Print(Unindent, Newline, "}") 783 | 784 | case cc.Enum: 785 | if t.Tag != "" { 786 | p.Print(t.Tag) 787 | } else { 788 | p.Print("int") 789 | } 790 | 791 | case cc.TypedefType: 792 | if t.Base != nil && typemap[t.Base.Kind] != "" && strings.ToLower(t.Name) == t.Name { 793 | p.Print(typemap[t.Base.Kind]) 794 | return 795 | } 796 | if t.TypeDecl != nil && t.TypeDecl.GoPackage != "" && p.Package != "" && t.TypeDecl.GoPackage != p.Package { 797 | p.Print(path.Base(t.TypeDecl.GoPackage) + "." + t.Name) 798 | break 799 | } 800 | p.Print(t.Name) 801 | 802 | case cc.Ptr: 803 | if t.Base.Is(cc.Func) { 804 | p.Print(t.Base) 805 | return 806 | } 807 | if t.Base.Is(cc.Void) { 808 | p.Print("*[0]byte") 809 | return 810 | } 811 | p.Print("*", t.Base) 812 | 813 | case cc.Func: 814 | p.Print("func(") 815 | for i, arg := range t.Decls { 816 | if i > 0 { 817 | p.Print(", ") 818 | } 819 | if arg.Name == "..." { 820 | p.Print("...interface{}") 821 | continue 822 | } 823 | if arg.Name == "" && arg.Type.Is(cc.Void) { 824 | continue 825 | } 826 | p.Print(arg.Type) 827 | } 828 | p.Print(")") 829 | if !t.Base.Is(cc.Void) { 830 | p.Print(" ", t.Base) 831 | } 832 | 833 | case cc.Array: 834 | if t.Width == nil { 835 | p.Print("[XXX]", t.Base) 836 | return 837 | } 838 | p.Print("[", t.Width, "]", t.Base) 839 | } 840 | } 841 | 842 | var typemap = map[cc.TypeKind]string{ 843 | Bool: "bool", 844 | Int8: "int8", 845 | Uint8: "uint8", 846 | Int16: "int16", 847 | Uint16: "uint16", 848 | Rune: "rune", 849 | Byte: "byte", 850 | Int: "int", 851 | Uint: "uint", 852 | Uintptr: "uintptr", 853 | Int32: "int32", 854 | Uint32: "uint32", 855 | Int64: "int64", 856 | Uint64: "uint64", 857 | Float32: "float32", 858 | Float64: "float64", 859 | } 860 | 861 | func (p *Printer) oldprintDecl(x *cc.Decl) { 862 | if x.Storage != 0 { 863 | p.Print(x.Storage, " ") 864 | } 865 | if x.Type == nil || x.Init != nil && len(x.Init.Braced) > 0 { 866 | p.Print(x.Name) 867 | } else { 868 | name := x.Name 869 | if x.Type.Kind == cc.Func && x.Body != nil { 870 | name = "\n" + name 871 | } 872 | p.Print(cc.TypedName{x.Type, name}) 873 | if x.Name == "" { 874 | switch x.Type.Kind { 875 | case cc.Struct, cc.Union, cc.Enum: 876 | p.Print(" {", Indent) 877 | for _, decl := range x.Type.Decls { 878 | p.Print(Newline, decl) 879 | } 880 | p.Print(Unindent, Newline, "}") 881 | } 882 | } 883 | } 884 | if x.Init != nil { 885 | p.Print(" = ", typedInit{x.Type, x.Init}) 886 | } 887 | if x.Body != nil { 888 | p.Print(Newline, x.Body) 889 | } 890 | } 891 | 892 | func (p *Printer) printDecl(decl *cc.Decl) { 893 | if p.dup(decl) { 894 | return 895 | } 896 | 897 | p.Print(decl.Comments.Before) 898 | defer p.Print(decl.Comments.Suffix, decl.Comments.After) 899 | 900 | t := decl.Type 901 | if decl.Storage&cc.Typedef != 0 { 902 | if t.Kind == cc.Struct || t.Kind == cc.Union || t.Kind == cc.Union { 903 | if t.Tag == "" { 904 | t.Tag = decl.Name 905 | } else if decl.Name != t.Tag { 906 | fprintf(decl.Span, "typedef %s and tag %s do not match", decl.Name, t.Tag) 907 | } 908 | if t.Kind == cc.Enum { 909 | p.printEnumDecl(t) 910 | } else { 911 | p.printStructDecl(t) 912 | } 913 | return 914 | } 915 | p.Print("type ", decl.Name, " ", decl.Type) 916 | return 917 | } 918 | 919 | if decl.Name == "" { 920 | switch t.Kind { 921 | case cc.Struct, cc.Union: 922 | p.printStructDecl(t) 923 | return 924 | case cc.Enum: 925 | p.printEnumDecl(t) 926 | return 927 | } 928 | if Bool <= t.Kind && t.Kind <= Float64 && t.Decls != nil { 929 | // was an enum 930 | p.printEnumDecl(t) 931 | return 932 | } 933 | fprintf(decl.Span, "empty declaration of type %s", GoString(t)) 934 | return 935 | } 936 | 937 | if t.Kind == cc.Func { 938 | p.printFuncDecl(decl) 939 | return 940 | } 941 | 942 | if decl.Init != nil && len(decl.Init.Braced) > 0 { 943 | p.Print("var ", decl.Name, " = ", typedInit{decl.Type, decl.Init}) 944 | return 945 | } 946 | 947 | p.Print("var ", decl.Name, " ", decl.Type) 948 | if decl.Init != nil { 949 | p.Print(" = ", decl.Init) 950 | } 951 | } 952 | 953 | func (p *Printer) printStructDecl(t *cc.Type) { 954 | if p.dup(t) { 955 | return 956 | } 957 | if t.Kind == cc.Union { 958 | fprintf(t.Span, "cannot convert union") 959 | return 960 | } 961 | p.Print("type ", t.Tag, " struct {", Indent) 962 | p.printStructBody(t) 963 | p.Print(Unindent, Newline, "}") 964 | } 965 | 966 | func (p *Printer) printStructBody(t *cc.Type) { 967 | for _, decl := range t.Decls { 968 | if decl.Name == "" { 969 | // Hope this is a struct definition. 970 | if decl.Type.Kind != cc.Struct { 971 | fprintf(decl.Span, "unnamed non-struct field of type %v", decl.Type) 972 | continue 973 | } 974 | p.printStructBody(decl.Type) 975 | continue 976 | } 977 | p.Print(Newline, decl.Name, " ", decl.Type) 978 | } 979 | } 980 | 981 | func (p *Printer) printEnumDecl(t *cc.Type) { 982 | typeSuffix := "" 983 | if t.Tag != "" { 984 | typeSuffix = " " + t.Tag 985 | p.Print("type ", t.Tag, " int", Newline) 986 | // fprintf(t.Span, "cannot handle enum tags") 987 | // return 988 | } 989 | p.Print("const (", Indent) 990 | for i, decl := range t.Decls { 991 | p.Print(Newline, decl.Name) 992 | if decl.Init == nil && i == 0 { 993 | if len(t.Decls) >= 2 && t.Decls[1].Init == nil { 994 | p.Print(typeSuffix, " = iota") 995 | } else { 996 | p.Print(typeSuffix, " = 0") 997 | } 998 | } else if decl.Init != nil { 999 | p.Print(typeSuffix, " = ", decl.Init.Expr) 1000 | if i+1 < len(t.Decls) && t.Decls[i+1].Init == nil { 1001 | p.Print(" + iota") 1002 | if i > 0 { 1003 | p.Print(fmt.Sprintf("-%d", i)) 1004 | } 1005 | } 1006 | } 1007 | } 1008 | p.Print(Unindent, Newline, ")") 1009 | } 1010 | 1011 | func (p *Printer) printFuncDecl(decl *cc.Decl) { 1012 | if decl.Body == nil { 1013 | // wait for definition 1014 | return 1015 | } 1016 | for _, s := range decl.Body.Block { 1017 | if s.Op == cc.StmtDecl && s.Decl.Storage&cc.Static != 0 { 1018 | // printing here will inhibit the print in the body 1019 | p.Print(s.Decl, Newline) 1020 | } 1021 | } 1022 | p.Print("func ", decl.Name, "(") 1023 | for i, arg := range decl.Type.Decls { 1024 | if arg.Type.Is(cc.Void) { 1025 | continue 1026 | } 1027 | if i > 0 { 1028 | p.Print(", ") 1029 | } 1030 | if arg.Name == "..." { 1031 | p.Print("args ...interface{}") 1032 | continue 1033 | } 1034 | p.Print(arg.Name, " ", arg.Type) 1035 | } 1036 | p.Print(")") 1037 | if !decl.Type.Base.Is(cc.Void) { 1038 | p.Print(" ", decl.Type.Base) 1039 | } 1040 | p.Print(" ", decl.Body, Newline) 1041 | } 1042 | -------------------------------------------------------------------------------- /cc/typecheck.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Scoping and type checking. 6 | // C99 standard: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf 7 | 8 | package cc 9 | 10 | import ( 11 | "fmt" 12 | "strconv" 13 | "strings" 14 | ) 15 | 16 | type Scope struct { 17 | Decl map[string]*Decl 18 | Tag map[string]*Type 19 | Next *Scope 20 | } 21 | 22 | func (lx *lexer) pushDecl(decl *Decl) { 23 | sc := lx.scope 24 | if sc == nil { 25 | panic("no scope") 26 | } 27 | if decl.Name == "" { 28 | return 29 | } 30 | if sc.Decl == nil { 31 | sc.Decl = make(map[string]*Decl) 32 | } 33 | sc.Decl[decl.Name] = decl 34 | if hdr := lx.declSave; hdr != nil && sc.Next == nil { 35 | hdr.decls = append(hdr.decls, decl) 36 | } 37 | } 38 | 39 | func (lx *lexer) lookupDecl(name string) *Decl { 40 | for sc := lx.scope; sc != nil; sc = sc.Next { 41 | decl := sc.Decl[name] 42 | if decl != nil { 43 | return decl 44 | } 45 | } 46 | return nil 47 | } 48 | 49 | func (lx *lexer) pushType(typ *Type) *Type { 50 | sc := lx.scope 51 | if sc == nil { 52 | panic("no scope") 53 | } 54 | 55 | if typ.Kind == Enum && typ.Decls != nil { 56 | for _, decl := range typ.Decls { 57 | lx.pushDecl(decl) 58 | } 59 | } 60 | 61 | if typ.Tag == "" { 62 | return typ 63 | } 64 | 65 | old := lx.lookupTag(typ.Tag) 66 | if old == nil { 67 | if sc.Tag == nil { 68 | sc.Tag = make(map[string]*Type) 69 | } 70 | sc.Tag[typ.Tag] = typ 71 | if hdr := lx.declSave; hdr != nil && sc.Next == nil { 72 | hdr.types = append(hdr.types, typ) 73 | } 74 | return typ 75 | } 76 | 77 | // merge typ into old 78 | if old.Kind != typ.Kind { 79 | lx.Errorf("conflicting tags: %s %s and %s %s", old.Kind, old.Tag, typ.Kind, typ.Tag) 80 | return typ 81 | } 82 | if typ.Decls != nil { 83 | if old.Decls != nil { 84 | lx.Errorf("multiple definitions for %s %s", old.Kind, old.Tag) 85 | } 86 | old.SyntaxInfo = typ.SyntaxInfo 87 | old.Decls = typ.Decls 88 | } 89 | return old 90 | } 91 | 92 | func (lx *lexer) lookupTag(name string) *Type { 93 | for sc := lx.scope; sc != nil; sc = sc.Next { 94 | typ := sc.Tag[name] 95 | if typ != nil { 96 | return typ 97 | } 98 | } 99 | return nil 100 | } 101 | 102 | func (lx *lexer) pushScope() { 103 | sc := &Scope{Next: lx.scope} 104 | lx.scope = sc 105 | } 106 | 107 | func (lx *lexer) popScope() { 108 | lx.scope = lx.scope.Next 109 | } 110 | 111 | func (lx *lexer) typecheck(prog *Prog) { 112 | for _, decl := range prog.Decls { 113 | lx.typecheckDecl(decl) 114 | } 115 | } 116 | 117 | func (lx *lexer) typecheckDecl(decl *Decl) { 118 | lx.typecheckType(decl.Type) 119 | if decl.Init != nil { 120 | lx.typecheckInit(decl.Type, decl.Init) 121 | } 122 | lx.typecheckStmt(decl.Body) 123 | } 124 | 125 | func (lx *lexer) typecheckStmt(stmt *Stmt) { 126 | if stmt == nil { 127 | return 128 | } 129 | 130 | lx.setSpan(stmt.Span) 131 | switch stmt.Op { 132 | case StmtDecl: 133 | lx.typecheckDecl(stmt.Decl) 134 | case StmtExpr: 135 | lx.typecheckExpr(stmt.Expr) 136 | case Empty: 137 | // ok 138 | case Block: 139 | for _, s := range stmt.Block { 140 | lx.typecheckStmt(s) 141 | } 142 | case ARGBEGIN: 143 | lx.Errorf("ARGBEGIN not supported") 144 | case Break: 145 | // check break context 146 | case Continue: 147 | // check continue context 148 | case Do: 149 | // push break/continue context 150 | lx.typecheckStmt(stmt.Body) 151 | lx.typecheckExpr(stmt.Expr) 152 | case For: 153 | // push break/continue context 154 | lx.typecheckExpr(stmt.Pre) 155 | lx.typecheckExpr(stmt.Expr) 156 | lx.typecheckExpr(stmt.Post) 157 | lx.typecheckStmt(stmt.Body) 158 | case If: 159 | lx.typecheckExpr(stmt.Expr) 160 | // check bool 161 | lx.typecheckStmt(stmt.Body) 162 | lx.typecheckStmt(stmt.Else) 163 | case Goto: 164 | // check that label exists 165 | case Return: 166 | lx.typecheckExpr(stmt.Expr) 167 | // check return 168 | case Switch: 169 | lx.typecheckExpr(stmt.Expr) 170 | lx.typecheckStmt(stmt.Body) 171 | // push break context 172 | // push switch type 173 | case While: 174 | lx.typecheckExpr(stmt.Expr) 175 | lx.typecheckStmt(stmt.Body) 176 | // push break/continue context 177 | } 178 | 179 | for _, lab := range stmt.Labels { 180 | lx.typecheckExpr(lab.Expr) 181 | } 182 | } 183 | 184 | func (lx *lexer) typecheckType(typ *Type) { 185 | if typ == nil { 186 | return 187 | } 188 | 189 | // TODO: Is there any other work to do for type checking a type? 190 | switch typ.Kind { 191 | case Enum: 192 | // Give enum type to the declared names. 193 | // Perhaps should be done during parsing. 194 | for _, decl := range typ.Decls { 195 | if decl.Init != nil { 196 | lx.typecheckInit(typ, decl.Init) 197 | } 198 | decl.Type = typ 199 | } 200 | } 201 | } 202 | 203 | func (lx *lexer) typecheckInit(typ *Type, x *Init) { 204 | // TODO: Type check initializers (ugh). 205 | 206 | x.XType = typ 207 | typ = stripTypedef(typ) 208 | lx.setSpan(x.Span) 209 | if x.Braced == nil { 210 | lx.typecheckExpr(x.Expr) 211 | if x.Expr.XType == nil { 212 | return 213 | } 214 | if typ.Kind == Array && typ.Base.Is(Char) && x.Expr.Op == String { 215 | // ok to initialize char array with string 216 | if typ.Width == nil { 217 | typ.Width = x.Expr.XType.Width 218 | } 219 | return 220 | } 221 | if !canAssign(typ, x.Expr.XType, x.Expr) { 222 | lx.Errorf("cannot initialize %v with %v (type %v)", typ, x.Expr.XType, x.Expr) 223 | return 224 | } 225 | return 226 | } 227 | 228 | switch typ.Kind { 229 | case Array, Struct: 230 | // ok 231 | case Union: 232 | // C allows this but we do not. 233 | fallthrough 234 | default: 235 | lx.Errorf("cannot initialize type %v with braced initializer", typ) 236 | return 237 | } 238 | 239 | // Keep our sanity: require that either all elements have prefixes or none do. 240 | // This is not required by the C standard; it just makes this code more tractable. 241 | n := 0 242 | for _, elem := range x.Braced { 243 | if len(elem.Prefix) > 0 { 244 | if len(elem.Prefix) != 1 { 245 | lx.setSpan(elem.Span) 246 | lx.Errorf("unsupported compound initializer prefix") 247 | return 248 | } 249 | n++ 250 | } 251 | } 252 | if n != 0 && n != len(x.Braced) { 253 | lx.Errorf("initializer elements must have no prefixes or all be prefixed") 254 | return 255 | } 256 | 257 | if n == 0 { 258 | // Assign elements in order. 259 | if typ.Kind == Array { 260 | // TODO: Check against typ.Width and record new typ.Width if missing 261 | for _, elem := range x.Braced { 262 | lx.typecheckInit(typ.Base, elem) 263 | } 264 | return 265 | } 266 | 267 | // Struct 268 | if len(x.Braced) > len(typ.Decls) { 269 | lx.Errorf("more initializer elements than struct fields in %v (%d > %d)", typ, len(x.Braced), len(typ.Decls)) 270 | return 271 | } 272 | for i, elem := range x.Braced { 273 | decl := typ.Decls[i] 274 | lx.typecheckInit(decl.Type, elem) 275 | } 276 | return 277 | } 278 | 279 | // All elements have initializing prefixes. 280 | 281 | if typ.Kind == Array { 282 | for _, elem := range x.Braced { 283 | lx.setSpan(elem.Span) 284 | pre := elem.Prefix[0] 285 | if pre.Index == nil { 286 | lx.Errorf("field initializer prefix in array") 287 | continue 288 | } 289 | lx.typecheckExpr(pre.Index) 290 | // TODO: check that pre.Index is integer constant 291 | // TODO: record width if needed 292 | lx.typecheckInit(typ.Base, elem) 293 | } 294 | return 295 | } 296 | 297 | // Struct 298 | for _, elem := range x.Braced { 299 | lx.setSpan(elem.Span) 300 | pre := elem.Prefix[0] 301 | if pre.Dot == "" { 302 | lx.Errorf("array initializer prefix in struct") 303 | continue 304 | } 305 | decl := structDot(typ, pre.Dot) 306 | if decl == nil { 307 | lx.Errorf("type %v has no field .%v", typ, pre.Dot) 308 | continue 309 | } 310 | pre.XDecl = decl 311 | lx.typecheckInit(decl.Type, elem) 312 | } 313 | } 314 | 315 | func stripTypedef(t *Type) *Type { 316 | if t != nil && t.Kind == TypedefType && t.Base != nil { 317 | t = t.Base 318 | } 319 | return t 320 | } 321 | 322 | func isInt(t *Type) bool { 323 | t = stripTypedef(t) 324 | return Char <= t.Kind && t.Kind <= Ulonglong || t.Kind == Enum 325 | } 326 | 327 | func isPtr(t *Type) bool { 328 | t = stripTypedef(t) 329 | return t.Kind == Ptr || t.Kind == Array 330 | } 331 | 332 | func ptrBase(t *Type) *Type { 333 | t = stripTypedef(t) 334 | if t == nil || (t.Kind != Ptr && t.Kind != Array) { 335 | return nil 336 | } 337 | return t.Base 338 | } 339 | 340 | func toPtr(t *Type) *Type { 341 | t1 := stripTypedef(t) 342 | if t1.Kind == Ptr { 343 | return t 344 | } 345 | if t1.Kind == Array { 346 | return &Type{Kind: Ptr, Base: t1.Base} 347 | } 348 | return nil 349 | } 350 | 351 | func isArith(t *Type) bool { 352 | t = stripTypedef(t) 353 | return Char <= t.Kind && t.Kind <= Enum 354 | } 355 | 356 | func isScalar(t *Type) bool { 357 | t = stripTypedef(t) 358 | return Char <= t.Kind && t.Kind <= Ptr 359 | } 360 | 361 | func (t *Type) Is(k TypeKind) bool { 362 | t = stripTypedef(t) 363 | return t != nil && t.Kind == k 364 | } 365 | 366 | func (t *Type) Def() *Type { 367 | return stripTypedef(t) 368 | } 369 | 370 | func isNull(x *Expr) bool { 371 | for x != nil && x.Op == Paren { 372 | x = x.Left 373 | } 374 | return x != nil && x.Op == Number && x.Text == "0" 375 | } 376 | 377 | func isVoidPtr(t *Type) bool { 378 | return ptrBase(t).Is(Void) 379 | } 380 | 381 | func (t *Type) IsPtrVoid() bool { 382 | return isVoidPtr(t) 383 | } 384 | 385 | func isCompatPtr(t1, t2 *Type) bool { 386 | return isCompat(ptrBase(t1), ptrBase(t2)) 387 | } 388 | 389 | // This is not correct; see C99 §6.2.7. 390 | func isCompat(t1, t2 *Type) bool { 391 | t1 = stripTypedef(t1) 392 | t2 = stripTypedef(t2) 393 | if t1 == nil || t2 == nil || t1.Kind != t2.Kind { 394 | return false 395 | } 396 | if t1 == t2 { 397 | return true 398 | } 399 | switch t1.Kind { 400 | default: 401 | // arithmetic 402 | return true 403 | case Ptr, Array: 404 | return isCompat(ptrBase(t1), ptrBase(t2)) 405 | case Struct, Union, Enum: 406 | return t1.Tag != "" && t1.Tag == t2.Tag 407 | case Func: 408 | if len(t1.Decls) != len(t2.Decls) || !isCompat(t1.Base, t2.Base) { 409 | return false 410 | } 411 | for i, d1 := range t1.Decls { 412 | d2 := t2.Decls[i] 413 | if d1.Type == nil && d1.Name == "..." { 414 | if d2.Type == nil && d2.Name == "..." { 415 | continue 416 | } 417 | return false 418 | } 419 | if !isCompat(d1.Type, d2.Type) { 420 | return false 421 | } 422 | } 423 | return true 424 | } 425 | } 426 | 427 | // TODO 428 | func compositePtr(t1, t2 *Type) *Type { 429 | return toPtr(t1) 430 | } 431 | 432 | func canAssign(l, r *Type, rx *Expr) bool { 433 | switch { 434 | case isArith(l) && isArith(r): 435 | // ok 436 | case isCompat(l, r): 437 | // ok 438 | case isCompatPtr(l, r): 439 | // ok 440 | case isPtr(l) && isPtr(r) && (isVoidPtr(l) || isVoidPtr(r)): 441 | // ok 442 | case isPtr(l) && isNull(rx): 443 | // ok 444 | rx.XType = toPtr(l) 445 | case isPtr(l) && isCompat(ptrBase(l), r): 446 | // ok 447 | case isVoidPtr(l) && r.Is(Func), isVoidPtr(r) && l.Is(Func): 448 | // ok 449 | case isPtr(l) && ptrBase(l).Is(Func) && r.Is(Func): // && isCompat(ptrBase(l), r): 450 | if !isCompat(ptrBase(l), r) { 451 | fmt.Printf("not compat: %v and %v (%v)\n", ptrBase(l), r, rx) 452 | } 453 | // ok 454 | default: 455 | return false 456 | } 457 | return true 458 | } 459 | 460 | func (lx *lexer) toBool(x *Expr) *Type { 461 | if x.XType == nil { 462 | return nil 463 | } 464 | t := stripTypedef(x.XType) 465 | if Char <= t.Kind && t.Kind <= Ptr || t.Kind == Enum { 466 | return BoolType 467 | } 468 | lx.Errorf("cannot use %v (type %v) in boolean context", x, x.XType) 469 | return nil 470 | } 471 | 472 | // The "usual arithmetic conversions". 473 | func promote2(l, r *Type) *Type { 474 | l = promote1(l) 475 | r = promote1(r) 476 | 477 | // if mixed signedness, make l signed and r unsigned. 478 | // specifically, if l is unsigned, swap with r. 479 | if (l.Kind-Char)&1 == 1 { 480 | l, r = r, l 481 | } 482 | 483 | switch { 484 | case l.Kind == Void || r.Kind == Void || l.Kind > Double || r.Kind > Double: 485 | return nil 486 | case l.Kind == r.Kind: 487 | return l 488 | // double wins. 489 | case l.Kind == Double: 490 | return l 491 | case r.Kind == Double: 492 | return r 493 | // float wins. 494 | case l.Kind == Float: 495 | return l 496 | case r.Kind == Float: 497 | return r 498 | // if both signed or both unsigned, higher kind wins. 499 | case (l.Kind-Char)&1 == (r.Kind-Char)&1: 500 | if l.Kind < r.Kind { 501 | return r 502 | } 503 | return l 504 | // mixed signedness: l is signed, r is unsigned (see above). 505 | // if unsigned higher kind than signed, unsigned wins. 506 | case r.Kind >= l.Kind: 507 | return r 508 | // signed is higher kind than unsigned (l.Kind > r.Kind). 509 | // if signed bigger than unsigned, signed wins. 510 | // only possible way this isn't true 511 | case (l.Kind-Char)/2 > (r.Kind-Char)/2 && (l.Kind != Long || r.Kind != Uint): 512 | return l 513 | // otherwise, use unsigned type corresponding to the signed type. 514 | default: 515 | return &Type{Kind: l.Kind + 1} 516 | } 517 | panic(fmt.Sprintf("missing case in promote2(%v, %v)", l, r)) 518 | } 519 | 520 | func promote1(l *Type) *Type { 521 | l = stripTypedef(l) 522 | if Char <= l.Kind && l.Kind <= Ushort || l.Kind == Enum { 523 | l = IntType 524 | } 525 | return l 526 | } 527 | 528 | func structDot(t *Type, name string) *Decl { 529 | if t == nil || (t.Kind != Struct && t.Kind != Union) { 530 | return nil 531 | } 532 | for _, decl := range t.Decls { 533 | if decl.Name == name { 534 | return decl 535 | } 536 | if decl.Name == "" { 537 | d := structDot(decl.Type, name) 538 | if d != nil { 539 | return d 540 | } 541 | } 542 | } 543 | return nil 544 | } 545 | 546 | func (lx *lexer) parseChar1(text string) (val byte, wid int, ok bool) { 547 | if text[0] != '\\' { 548 | return text[0], 1, true 549 | } 550 | if len(text) == 1 { 551 | lx.Errorf("truncated escape sequence in character or string constant") 552 | return 553 | } 554 | switch text[1] { 555 | case 'a': 556 | return 7, 2, true 557 | case 'b': 558 | return 8, 2, true 559 | case 'f': 560 | return 12, 2, true 561 | case 'n': 562 | return 10, 2, true 563 | case 'r': 564 | return 13, 2, true 565 | case 't': 566 | return 9, 2, true 567 | case 'v': 568 | return 11, 2, true 569 | case '\'', '"', '?', '\\': 570 | return text[1], 2, true 571 | case '0', '1', '2', '3', '4', '5', '6', '7': 572 | i := 2 573 | v := int(text[1] - '0') 574 | for i < 4 && i < len(text) && '0' <= text[i] && text[i] <= '7' { 575 | v = v*8 + int(text[i]-'0') 576 | i++ 577 | } 578 | if v >= 256 { 579 | lx.Errorf("octal escape %s out of range", text[:i]) 580 | return 581 | } 582 | return byte(v), i, true 583 | case 'x': 584 | i := 2 585 | v := 0 586 | for i < len(text) && ishex(text[i]) { 587 | v = v*16 + unhex(text[i]) 588 | i++ 589 | } 590 | if i-2 > 2 { 591 | lx.Errorf("hexadecimal escape %s out of range", text[:i]) 592 | return 593 | } 594 | if i == 0 { 595 | lx.Errorf("hexadecimal escape %s missing digits", text[:i]) 596 | return 597 | } 598 | return byte(v), i, true 599 | 600 | default: 601 | lx.Errorf("invalid escape sequence %s", text[:2]) 602 | } 603 | return 604 | } 605 | 606 | func ishex(c byte) bool { 607 | return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' 608 | } 609 | 610 | func unhex(c byte) int { 611 | if '0' <= c && c <= '9' { 612 | return int(c) - '0' 613 | } 614 | if 'a' <= c && c <= 'f' { 615 | return int(c) - 'a' + 10 616 | } 617 | if 'A' <= c && c <= 'F' { 618 | return int(c) - 'A' + 10 619 | } 620 | return -1 621 | } 622 | 623 | func (lx *lexer) parseChar(text string) (val byte, ok bool) { 624 | if len(text) < 3 || text[0] != '\'' || text[len(text)-1] != '\'' { 625 | lx.Errorf("invalid character constant %v", text) 626 | return 0, false 627 | } 628 | val, wid, ok := lx.parseChar1(text[1 : len(text)-1]) 629 | if !ok { 630 | return 0, false 631 | } 632 | if wid != len(text)-2 { 633 | lx.Errorf("invalid character constant %v - multiple characters", text) 634 | return 0, false 635 | } 636 | return val, true 637 | } 638 | 639 | func (lx *lexer) parseString(text string) (val string, ok bool) { 640 | if len(text) < 2 || text[0] != '"' || text[len(text)-1] != '"' { 641 | lx.Errorf("invalid string constant %v", text) 642 | return "", false 643 | } 644 | tval := text[1 : len(text)-1] 645 | var bval []byte 646 | for len(tval) > 0 { 647 | ch, wid, ok := lx.parseChar1(tval) 648 | if !ok { 649 | return "", false 650 | } 651 | bval = append(bval, ch) 652 | tval = tval[wid:] 653 | } 654 | return string(bval), true 655 | } 656 | 657 | func (lx *lexer) typecheckExpr(x *Expr) { 658 | if x == nil { 659 | return 660 | } 661 | 662 | if x.Op != Offsetof { 663 | lx.typecheckExpr(x.Left) 664 | } 665 | lx.typecheckExpr(x.Right) 666 | for _, y := range x.List { 667 | lx.typecheckExpr(y) 668 | } 669 | lx.typecheckType(x.Type) 670 | 671 | lx.setSpan(x.Span) 672 | switch x.Op { 673 | default: 674 | panic("missing typecheck " + x.Op.String()) 675 | 676 | case Add: 677 | l, r := x.Left.XType, x.Right.XType 678 | if l == nil || r == nil { 679 | break 680 | } 681 | switch { 682 | case isPtr(l) && isInt(r): 683 | x.XType = toPtr(l) 684 | case isInt(l) && isPtr(r): 685 | x.XType = toPtr(r) 686 | default: 687 | lx.typecheckArith(x) 688 | } 689 | 690 | case Addr: 691 | t := x.Left.XType 692 | if t == nil { 693 | break 694 | } 695 | if isPtr(t) { 696 | t = toPtr(t) 697 | } 698 | x.XType = &Type{Kind: Ptr, Base: t} 699 | 700 | case AddEq, SubEq: 701 | l, r := x.Left.XType, x.Right.XType 702 | if l == nil || r == nil { 703 | break 704 | } 705 | if isPtr(l) && isInt(r) { 706 | x.XType = toPtr(l) 707 | break 708 | } 709 | lx.typecheckArithEq(x) 710 | 711 | case And, Mod, Or, Xor: 712 | // int & int 713 | l, r := x.Left.XType, x.Right.XType 714 | if l == nil || r == nil { 715 | break 716 | } 717 | if !isInt(l) || !isInt(r) { 718 | lx.Errorf("invalid bitwise op of %v (type %v) and %v (type %v)", x.Left, l, x.Right, r) 719 | break 720 | } 721 | x.XType = promote2(l, r) 722 | 723 | case AndAnd, OrOr: 724 | // bool && bool 725 | l := lx.toBool(x.Left) 726 | r := lx.toBool(x.Right) 727 | if l == nil || r == nil { 728 | break 729 | } 730 | x.XType = BoolType 731 | 732 | case AndEq, ModEq, OrEq, XorEq: 733 | // int &= int 734 | l, r := x.Left.XType, x.Right.XType 735 | if l == nil || r == nil { 736 | break 737 | } 738 | if !isInt(l) || !isInt(r) { 739 | lx.Errorf("invalid bitwise op of %v (type %v) and %v (type %v)", x.Left, l, x.Right, r) 740 | break 741 | } 742 | x.XType = l 743 | 744 | case Arrow: 745 | t := x.Left.XType 746 | if t == nil { 747 | lx.Errorf("arrow missing type %s", x.Left) 748 | break 749 | } 750 | if !isPtr(t) { 751 | lx.Errorf("invalid -> of non-pointer %v (type %v)", x.Left, t) 752 | break 753 | } 754 | t = stripTypedef(ptrBase(t)) 755 | if t.Kind != Struct && t.Kind != Union { 756 | lx.Errorf("invalid -> of pointer to non-struct/union %v (type %v)", x.Left, t) 757 | break 758 | } 759 | d := structDot(t, x.Text) 760 | if d == nil { 761 | lx.Errorf("unknown field %v->%v", t, x.Text) 762 | break 763 | } 764 | x.XDecl = d 765 | x.XType = d.Type 766 | 767 | case Call: 768 | t := x.Left.XType 769 | if t == nil { 770 | lx.Errorf("no info for call of %v", x.Left) 771 | break 772 | } 773 | if isPtr(t) { 774 | t = ptrBase(t) 775 | } 776 | t = stripTypedef(t) 777 | if t.Kind != Func { 778 | lx.Errorf("invalid call of %v (type %v)", x.Left, x.Left.XType) 779 | break 780 | } 781 | x.XType = t.Base 782 | for i := 0; i < len(x.List) || i < len(t.Decls); i++ { 783 | if i >= len(t.Decls) { 784 | lx.Errorf("too many arguments to call") 785 | break 786 | } 787 | d := t.Decls[i] 788 | if d.Name == "..." { 789 | break 790 | } 791 | if i >= len(x.List) { 792 | if len(x.List) == 0 && len(t.Decls) == 1 && t.Decls[0].Type.Is(Void) { 793 | break 794 | } 795 | lx.Errorf("not enough arguments to call") 796 | break 797 | } 798 | if x.List[i].XType != nil && !canAssign(d.Type, x.List[i].XType, x.List[i]) { 799 | lx.Errorf("cannot assign %v (type %v) to %v in call", x.List[i], x.List[i].XType, d.Type) 800 | } 801 | } 802 | 803 | case Cast: 804 | // NOTE: Assuming cast is valid. 805 | x.XType = x.Type 806 | 807 | case CastInit: 808 | lx.typecheckInit(x.Type, x.Init) 809 | x.XType = x.Type 810 | 811 | case Comma: 812 | x.XType = x.List[len(x.List)-1].XType 813 | 814 | case Cond: 815 | c, l, r := lx.toBool(x.List[0]), x.List[1].XType, x.List[2].XType 816 | if c == nil || l == nil || r == nil { 817 | break 818 | } 819 | switch { 820 | default: 821 | lx.Errorf("incompatible branches %v (type %v) and %v (type %v) in conditional", x.List[1], l, x.List[2], r) 822 | case isArith(l) && isArith(r): 823 | x.XType = promote2(l, r) 824 | case l == r: 825 | x.XType = l 826 | case isCompatPtr(l, r): 827 | x.XType = compositePtr(l, r) 828 | case isPtr(l) && isNull(x.List[1]): 829 | x.XType = toPtr(l) 830 | x.List[1].XType = x.XType 831 | case isPtr(r) && isNull(x.List[0]): 832 | x.XType = toPtr(r) 833 | x.List[0].XType = x.XType 834 | case isPtr(l) && isVoidPtr(r): 835 | x.XType = r 836 | case isPtr(r) && isVoidPtr(l): 837 | x.XType = l 838 | } 839 | 840 | case Div, Mul: 841 | lx.typecheckArith(x) 842 | 843 | case DivEq, MulEq: 844 | lx.typecheckArithEq(x) 845 | 846 | case Dot: 847 | t := x.Left.XType 848 | if t == nil { 849 | break 850 | } 851 | t = stripTypedef(t) 852 | if t.Kind != Struct && t.Kind != Union { 853 | lx.Errorf("invalid . of non-struct/union %v (type %v)", x.Left, t) 854 | break 855 | } 856 | d := structDot(t, x.Text) 857 | if d == nil { 858 | lx.Errorf("unknown field %v.%v", t, x.Text) 859 | break 860 | } 861 | x.XDecl = d 862 | x.XType = d.Type 863 | 864 | case Eq: 865 | l, r := x.Left.XType, x.Right.XType 866 | if l == nil || r == nil { 867 | break 868 | } 869 | x.XType = l 870 | if !canAssign(l, r, x.Right) { 871 | lx.Errorf("invalid assignment %v (type %v) = %v (typ %v)", x.Left, l, x.Right, r) 872 | break 873 | } 874 | 875 | case EqEq, NotEq, Gt, GtEq, Lt, LtEq: 876 | x.XType = BoolType 877 | l, r := x.Left.XType, x.Right.XType 878 | if l == nil || r == nil { 879 | break 880 | } 881 | if isArith(l) && isArith(r) { 882 | if x.Left.Op != Number && x.Right.Op == Number { 883 | x.Right.XType = x.Left.XType 884 | } 885 | if x.Right.Op != Number && x.Left.Op == Number { 886 | x.Left.XType = x.Right.XType 887 | } 888 | break 889 | } 890 | if isCompatPtr(l, r) { 891 | break 892 | } 893 | if x.Op == EqEq || x.Op == NotEq { 894 | if isPtr(l) { 895 | if isNull(x.Right) || isVoidPtr(r) { 896 | x.Right.XType = toPtr(l) 897 | break 898 | } 899 | } 900 | if isPtr(r) { 901 | if isNull(x.Left) || isVoidPtr(l) { 902 | x.Left.XType = toPtr(r) 903 | break 904 | } 905 | } 906 | } 907 | lx.Errorf("invalid comparison of %v (type %v) and %v (type %v)", x.Left, l, x.Right, r) 908 | 909 | case Index: 910 | // ptr[int] 911 | // int[ptr] 912 | l, r := x.Left.XType, x.Right.XType 913 | if l == nil || r == nil { 914 | break 915 | } 916 | switch { 917 | case isPtr(l) && isInt(r): 918 | x.XType = ptrBase(l) 919 | case isInt(l) && isPtr(r): 920 | x.XType = ptrBase(r) 921 | default: 922 | lx.Errorf("invalid index %v (types %v, %v)", x, l, r, isPtr(l), isInt(r), r.Kind, r.Base, r.Base.Kind) 923 | } 924 | 925 | case Indir: 926 | // *ptr 927 | t := x.Left.XType 928 | if t == nil { 929 | break 930 | } 931 | if !isPtr(t) { 932 | lx.Errorf("invalid indirect of non-pointer %v (type %v)", x.Left, t) 933 | break 934 | } 935 | x.XType = ptrBase(t) 936 | 937 | case Lsh, Rsh: 938 | // int << int 939 | l, r := x.Left.XType, x.Right.XType 940 | if l == nil || r == nil { 941 | break 942 | } 943 | if !isInt(l) || !isInt(r) { 944 | lx.Errorf("invalid shift of %v (type %v) and %v (type %v)", x.Left, l, x.Right, r) 945 | break 946 | } 947 | x.XType = promote1(l) 948 | 949 | case LshEq, RshEq: 950 | // int <<= int 951 | l, r := x.Left.XType, x.Right.XType 952 | if l == nil || r == nil { 953 | break 954 | } 955 | if !isInt(l) || !isInt(r) { 956 | lx.Errorf("invalid shift of %v (type %v) and %v (type %v)", x.Left, l, x.Right, r) 957 | break 958 | } 959 | x.XType = l 960 | 961 | case Minus, Plus: 962 | // -int 963 | // -float 964 | t := x.Left.XType 965 | if t == nil { 966 | break 967 | } 968 | if !isArith(t) { 969 | lx.Errorf("invalid ± of %v (type %v)", x, t) 970 | break 971 | } 972 | x.XType = promote1(t) 973 | 974 | case Name: 975 | if x.XDecl == nil { 976 | lx.Errorf("undefined: %s", x.Text) 977 | break 978 | } 979 | // XXX this happens for enums 980 | // if x.XDecl.Type == nil { 981 | // lx.Errorf("missing type for defined variable: %s", x.Text) 982 | // } 983 | x.XType = x.XDecl.Type 984 | 985 | case Not: 986 | // !bool 987 | lx.toBool(x.Left) 988 | x.XType = BoolType 989 | 990 | case Number: 991 | num := x.Text 992 | if num[0] == '\'' { 993 | // character constant 994 | _, _ = lx.parseChar(num) 995 | x.XType = IntType 996 | break 997 | } 998 | 999 | if strings.Contains(num, ".") || !strings.HasPrefix(num, "0x") && strings.ContainsAny(num, "eE") { 1000 | // floating point 1001 | num = strings.TrimRight(num, "fFlL") 1002 | suf := x.Text[len(num):] 1003 | f, err := strconv.ParseFloat(num, 64) 1004 | if err != nil { 1005 | lx.Errorf("invalid floating point constant %v", x.Text) 1006 | break 1007 | } 1008 | _ = f // TODO use this 1009 | x.XType = DoubleType 1010 | switch suf { 1011 | case "": 1012 | case "f", "F": 1013 | x.XType = FloatType 1014 | default: 1015 | lx.Errorf("unsupported floating point constant suffix %v", x.Text) 1016 | } 1017 | break 1018 | } 1019 | 1020 | // integer 1021 | num = strings.TrimRight(num, "uUlL") 1022 | suf := x.Text[len(num):] 1023 | i, err := strconv.ParseUint(num, 0, 64) 1024 | if err != nil { 1025 | lx.Errorf("invalid integer constant %v", x.Text) 1026 | break 1027 | } 1028 | _ = i // TODO use this 1029 | has := strings.Contains 1030 | suf = strings.ToUpper(suf) 1031 | switch { 1032 | case has(suf, "U") && has(suf, "LL"): 1033 | x.XType = UlonglongType 1034 | case has(suf, "U") && has(suf, "L"): 1035 | if uint64(uint32(i)) == i { 1036 | x.XType = UlongType 1037 | } else { 1038 | x.XType = UlonglongType 1039 | } 1040 | case has(suf, "U"): 1041 | if uint64(uint32(i)) == i { 1042 | x.XType = UintType 1043 | } else { 1044 | x.XType = UlonglongType 1045 | } 1046 | case has(suf, "LL"): 1047 | if int64(i) >= 0 { 1048 | x.XType = LonglongType 1049 | } else { 1050 | lx.Errorf("integer constant %v overflows signed long long", x.Text) 1051 | } 1052 | case has(suf, "L"): 1053 | if int32(i) >= 0 && uint64(int32(i)) == i { 1054 | x.XType = LongType 1055 | } else if int64(i) >= 0 { 1056 | x.XType = LonglongType 1057 | } else { 1058 | lx.Errorf("integer constant %v overflows signed long long", x.Text) 1059 | } 1060 | default: 1061 | if int32(i) >= 0 && uint64(int32(i)) == i { 1062 | x.XType = IntType 1063 | } else if int64(i) >= 0 { 1064 | x.XType = LonglongType 1065 | } else { 1066 | lx.Errorf("integer constant %v overflows signed long long", x.Text) 1067 | } 1068 | } 1069 | 1070 | case Offsetof: 1071 | x.XType = LongType 1072 | if x.Left.Op != Name { 1073 | lx.Errorf("offsetof field too complicated") 1074 | } 1075 | d := structDot(stripTypedef(x.Type), x.Left.Text) 1076 | if d == nil { 1077 | lx.Errorf("unknown field %v.%v", x.Type, x.Left.Text) 1078 | } 1079 | 1080 | case Paren: 1081 | // (non-void) 1082 | t := x.Left.XType 1083 | if t == nil { 1084 | break 1085 | } 1086 | if t.Kind == Void { 1087 | lx.Errorf("cannot parenthesize void expression") 1088 | break 1089 | } 1090 | x.XType = t 1091 | 1092 | case PostDec, PostInc, PreDec, PreInc: 1093 | // int-- 1094 | // float-- 1095 | // ptr-- 1096 | t := x.Left.XType 1097 | if t == nil { 1098 | break 1099 | } 1100 | if !isArith(t) && !isPtr(t) { 1101 | lx.Errorf("cannot increment/decrement %v (type %v)", x.Left, t) 1102 | break 1103 | } 1104 | x.XType = t 1105 | 1106 | case SizeofExpr: 1107 | x.XType = LongType 1108 | 1109 | case SizeofType: 1110 | x.XType = LongType 1111 | 1112 | case String: 1113 | // string list 1114 | var str []string 1115 | ok := true 1116 | for _, text := range x.Texts { 1117 | s, sok := lx.parseString(text) 1118 | if !sok { 1119 | ok = false 1120 | } 1121 | str = append(str, s) 1122 | } 1123 | if !ok { 1124 | break 1125 | } 1126 | s := strings.Join(str, "") 1127 | _ = s // TODO use this 1128 | x.XType = &Type{Kind: Array, Width: &Expr{Op: Number, Text: fmt.Sprint(len(s) + 1)}, Base: CharType} 1129 | 1130 | case Sub: 1131 | l, r := x.Left.XType, x.Right.XType 1132 | if l == nil || r == nil { 1133 | break 1134 | } 1135 | switch { 1136 | case isPtr(l) && isInt(r): 1137 | x.XType = toPtr(l) 1138 | case isCompatPtr(l, r): 1139 | x.XType = LongType 1140 | default: 1141 | lx.typecheckArith(x) 1142 | } 1143 | 1144 | case Twid: 1145 | // ~int 1146 | t := x.Left.XType 1147 | if t == nil { 1148 | break 1149 | } 1150 | if !isInt(t) { 1151 | lx.Errorf("invalid ~ of %v (type %v)", x, t) 1152 | break 1153 | } 1154 | x.XType = promote1(t) 1155 | 1156 | case VaArg: 1157 | // va_arg(arg, int) 1158 | t := x.Left.XType 1159 | if t == nil { 1160 | break 1161 | } 1162 | if t.Name != "va_list" { 1163 | lx.Errorf("va_arg takes va_list, have %v (type %v)", x.Left, t) 1164 | } 1165 | x.XType = x.Type 1166 | } 1167 | } 1168 | 1169 | func (lx *lexer) typecheckArith(x *Expr) { 1170 | // int + int 1171 | // float + float 1172 | l, r := x.Left.XType, x.Right.XType 1173 | if l == nil || r == nil { 1174 | return 1175 | } 1176 | if !isArith(l) || !isArith(r) { 1177 | lx.Errorf("invalid arithmetic op of %v (type %v) and %v (type %v)", x.Left, l, x.Right, r) 1178 | return 1179 | } 1180 | x.XType = promote2(l, r) 1181 | } 1182 | 1183 | func (lx *lexer) typecheckArithEq(x *Expr) { 1184 | // int + int 1185 | // float + float 1186 | l, r := x.Left.XType, x.Right.XType 1187 | if l == nil || r == nil { 1188 | return 1189 | } 1190 | if !isArith(l) || !isArith(r) { 1191 | lx.Errorf("invalid arithmetic op of %v (type %v) and %v (type %v)", x.Left, l, x.Right, r) 1192 | return 1193 | } 1194 | x.XType = l 1195 | } 1196 | --------------------------------------------------------------------------------