2015-02-13 14:40:36 -05:00
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gc
import (
"cmd/internal/obj"
"fmt"
"sort"
"unicode"
"unicode/utf8"
)
var asmlist * NodeList
// Mark n's symbol as exported
func exportsym ( n * Node ) {
if n == nil || n . Sym == nil {
return
}
if n . Sym . Flags & ( SymExport | SymPackage ) != 0 {
if n . Sym . Flags & SymPackage != 0 {
2015-04-17 12:03:22 -04:00
Yyerror ( "export/package mismatch: %v" , n . Sym )
2015-02-13 14:40:36 -05:00
}
return
}
n . Sym . Flags |= SymExport
if Debug [ 'E' ] != 0 {
2015-04-17 12:03:22 -04:00
fmt . Printf ( "export symbol %v\n" , n . Sym )
2015-02-13 14:40:36 -05:00
}
2015-08-12 14:29:50 -07:00
exportlist = append ( exportlist , n )
2015-02-13 14:40:36 -05:00
}
func exportname ( s string ) bool {
if s [ 0 ] < utf8 . RuneSelf {
return 'A' <= s [ 0 ] && s [ 0 ] <= 'Z'
}
r , _ := utf8 . DecodeRuneInString ( s )
return unicode . IsUpper ( r )
}
2015-02-17 22:13:49 -05:00
func initname ( s string ) bool {
return s == "init"
2015-02-13 14:40:36 -05:00
}
// exportedsym reports whether a symbol will be visible
// to files that import our package.
2015-02-17 22:13:49 -05:00
func exportedsym ( sym * Sym ) bool {
2015-02-13 14:40:36 -05:00
// Builtins are visible everywhere.
if sym . Pkg == builtinpkg || sym . Origpkg == builtinpkg {
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
return sym . Pkg == localpkg && exportname ( sym . Name )
2015-02-13 14:40:36 -05:00
}
2015-03-27 12:00:07 -07:00
func autoexport ( n * Node , ctxt uint8 ) {
2015-02-13 14:40:36 -05:00
if n == nil || n . Sym == nil {
return
}
if ( ctxt != PEXTERN && ctxt != PFUNC ) || dclcontext != PEXTERN {
return
}
2015-05-27 00:44:05 -04:00
if n . Name . Param != nil && n . Name . Param . Ntype != nil && n . Name . Param . Ntype . Op == OTFUNC && n . Name . Param . Ntype . Left != nil { // method
2015-02-13 14:40:36 -05:00
return
}
// -A is for cmd/gc/mkbuiltin script, so export everything
2015-02-17 22:13:49 -05:00
if Debug [ 'A' ] != 0 || exportname ( n . Sym . Name ) || initname ( n . Sym . Name ) {
2015-02-13 14:40:36 -05:00
exportsym ( n )
}
2015-02-17 22:13:49 -05:00
if asmhdr != "" && n . Sym . Pkg == localpkg && n . Sym . Flags & SymAsm == 0 {
2015-02-13 14:40:36 -05:00
n . Sym . Flags |= SymAsm
asmlist = list ( asmlist , n )
}
}
func dumppkg ( p * Pkg ) {
2015-09-08 05:46:31 +02:00
if p == nil || p == localpkg || p . Exported || p == builtinpkg {
2015-02-13 14:40:36 -05:00
return
}
2015-09-08 05:46:31 +02:00
p . Exported = true
2015-02-23 16:07:24 -05:00
suffix := ""
2015-09-08 05:46:31 +02:00
if ! p . Direct {
2015-02-13 14:40:36 -05:00
suffix = " // indirect"
}
2015-03-02 16:03:26 -05:00
fmt . Fprintf ( bout , "\timport %s %q%s\n" , p . Name , p . Path , suffix )
2015-02-13 14:40:36 -05:00
}
// Look for anything we need for the inline body
func reexportdeplist ( ll * NodeList ) {
for ; ll != nil ; ll = ll . Next {
reexportdep ( ll . N )
}
}
func reexportdep ( n * Node ) {
2015-02-17 22:13:49 -05:00
if n == nil {
2015-02-13 14:40:36 -05:00
return
}
//print("reexportdep %+hN\n", n);
switch n . Op {
case ONAME :
switch n . Class &^ PHEAP {
// methods will be printed along with their type
// nodes for T.Method expressions
case PFUNC :
if n . Left != nil && n . Left . Op == OTYPE {
break
}
// nodes for method calls.
2015-02-17 22:13:49 -05:00
if n . Type == nil || n . Type . Thistuple > 0 {
2015-02-13 14:40:36 -05:00
break
}
fallthrough
case PEXTERN :
2015-02-17 22:13:49 -05:00
if n . Sym != nil && ! exportedsym ( n . Sym ) {
2015-02-13 14:40:36 -05:00
if Debug [ 'E' ] != 0 {
2015-04-17 12:03:22 -04:00
fmt . Printf ( "reexport name %v\n" , n . Sym )
2015-02-13 14:40:36 -05:00
}
2015-08-12 14:29:50 -07:00
exportlist = append ( exportlist , n )
2015-02-13 14:40:36 -05:00
}
}
// Local variables in the bodies need their type.
case ODCL :
2015-02-23 16:07:24 -05:00
t := n . Left . Type
2015-02-13 14:40:36 -05:00
if t != Types [ t . Etype ] && t != idealbool && t != idealstring {
2015-03-01 07:54:01 +00:00
if Isptr [ t . Etype ] {
2015-02-13 14:40:36 -05:00
t = t . Type
}
2015-02-17 22:13:49 -05:00
if t != nil && t . Sym != nil && t . Sym . Def != nil && ! exportedsym ( t . Sym ) {
2015-02-13 14:40:36 -05:00
if Debug [ 'E' ] != 0 {
2015-04-17 12:03:22 -04:00
fmt . Printf ( "reexport type %v from declaration\n" , t . Sym )
2015-02-13 14:40:36 -05:00
}
2015-08-12 14:29:50 -07:00
exportlist = append ( exportlist , t . Sym . Def )
2015-02-13 14:40:36 -05:00
}
}
case OLITERAL :
2015-02-23 16:07:24 -05:00
t := n . Type
2015-02-13 14:40:36 -05:00
if t != Types [ n . Type . Etype ] && t != idealbool && t != idealstring {
2015-03-01 07:54:01 +00:00
if Isptr [ t . Etype ] {
2015-02-13 14:40:36 -05:00
t = t . Type
}
2015-02-17 22:13:49 -05:00
if t != nil && t . Sym != nil && t . Sym . Def != nil && ! exportedsym ( t . Sym ) {
2015-02-13 14:40:36 -05:00
if Debug [ 'E' ] != 0 {
2015-04-17 12:03:22 -04:00
fmt . Printf ( "reexport literal type %v\n" , t . Sym )
2015-02-13 14:40:36 -05:00
}
2015-08-12 14:29:50 -07:00
exportlist = append ( exportlist , t . Sym . Def )
2015-02-13 14:40:36 -05:00
}
}
fallthrough
case OTYPE :
2015-02-17 22:13:49 -05:00
if n . Sym != nil && ! exportedsym ( n . Sym ) {
2015-02-13 14:40:36 -05:00
if Debug [ 'E' ] != 0 {
2015-04-17 12:03:22 -04:00
fmt . Printf ( "reexport literal/type %v\n" , n . Sym )
2015-02-13 14:40:36 -05:00
}
2015-08-12 14:29:50 -07:00
exportlist = append ( exportlist , n )
2015-02-13 14:40:36 -05:00
}
// for operations that need a type when rendered, put the type on the export list.
case OCONV ,
OCONVIFACE ,
OCONVNOP ,
ORUNESTR ,
OARRAYBYTESTR ,
OARRAYRUNESTR ,
OSTRARRAYBYTE ,
OSTRARRAYRUNE ,
ODOTTYPE ,
ODOTTYPE2 ,
OSTRUCTLIT ,
OARRAYLIT ,
OPTRLIT ,
OMAKEMAP ,
OMAKESLICE ,
OMAKECHAN :
2015-02-23 16:07:24 -05:00
t := n . Type
2015-02-13 14:40:36 -05:00
2015-02-17 22:13:49 -05:00
if t . Sym == nil && t . Type != nil {
2015-02-13 14:40:36 -05:00
t = t . Type
}
2015-02-17 22:13:49 -05:00
if t != nil && t . Sym != nil && t . Sym . Def != nil && ! exportedsym ( t . Sym ) {
2015-02-13 14:40:36 -05:00
if Debug [ 'E' ] != 0 {
2015-04-17 12:03:22 -04:00
fmt . Printf ( "reexport type for expression %v\n" , t . Sym )
2015-02-13 14:40:36 -05:00
}
2015-08-12 14:29:50 -07:00
exportlist = append ( exportlist , t . Sym . Def )
2015-02-13 14:40:36 -05:00
}
}
reexportdep ( n . Left )
reexportdep ( n . Right )
reexportdeplist ( n . List )
reexportdeplist ( n . Rlist )
reexportdeplist ( n . Ninit )
reexportdeplist ( n . Nbody )
}
func dumpexportconst ( s * Sym ) {
2015-02-23 16:07:24 -05:00
n := s . Def
2015-02-13 14:40:36 -05:00
typecheck ( & n , Erv )
if n == nil || n . Op != OLITERAL {
2015-08-30 23:10:03 +02:00
Fatalf ( "dumpexportconst: oconst nil: %v" , s )
2015-02-13 14:40:36 -05:00
}
2015-02-23 16:07:24 -05:00
t := n . Type // may or may not be specified
2015-02-13 14:40:36 -05:00
dumpexporttype ( t )
2015-02-17 22:13:49 -05:00
if t != nil && ! isideal ( t ) {
2015-05-27 00:47:05 -04:00
fmt . Fprintf ( bout , "\tconst %v %v = %v\n" , Sconv ( s , obj . FmtSharp ) , Tconv ( t , obj . FmtSharp ) , Vconv ( n . Val ( ) , obj . FmtSharp ) )
2015-02-13 14:40:36 -05:00
} else {
2015-05-27 00:47:05 -04:00
fmt . Fprintf ( bout , "\tconst %v = %v\n" , Sconv ( s , obj . FmtSharp ) , Vconv ( n . Val ( ) , obj . FmtSharp ) )
2015-02-13 14:40:36 -05:00
}
}
func dumpexportvar ( s * Sym ) {
2015-02-23 16:07:24 -05:00
n := s . Def
2015-02-13 14:40:36 -05:00
typecheck ( & n , Erv | Ecall )
if n == nil || n . Type == nil {
2015-04-17 12:03:22 -04:00
Yyerror ( "variable exported but not defined: %v" , s )
2015-02-13 14:40:36 -05:00
return
}
2015-02-23 16:07:24 -05:00
t := n . Type
2015-02-13 14:40:36 -05:00
dumpexporttype ( t )
if t . Etype == TFUNC && n . Class == PFUNC {
2015-03-25 19:33:01 -07:00
if n . Func != nil && n . Func . Inl != nil {
2015-02-13 14:40:36 -05:00
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
if Debug [ 'l' ] < 2 {
typecheckinl ( n )
}
// NOTE: The space after %#S here is necessary for ld's export data parser.
2015-03-25 19:33:01 -07:00
fmt . Fprintf ( bout , "\tfunc %v %v { %v }\n" , Sconv ( s , obj . FmtSharp ) , Tconv ( t , obj . FmtShort | obj . FmtSharp ) , Hconv ( n . Func . Inl , obj . FmtSharp ) )
2015-02-13 14:40:36 -05:00
2015-03-25 19:33:01 -07:00
reexportdeplist ( n . Func . Inl )
2015-02-13 14:40:36 -05:00
} else {
fmt . Fprintf ( bout , "\tfunc %v %v\n" , Sconv ( s , obj . FmtSharp ) , Tconv ( t , obj . FmtShort | obj . FmtSharp ) )
}
} else {
fmt . Fprintf ( bout , "\tvar %v %v\n" , Sconv ( s , obj . FmtSharp ) , Tconv ( t , obj . FmtSharp ) )
}
}
2015-09-14 20:53:44 +02:00
// methodbyname sorts types by symbol name.
2015-02-13 14:40:36 -05:00
type methodbyname [ ] * Type
2015-09-14 20:53:44 +02:00
func ( x methodbyname ) Len ( ) int { return len ( x ) }
func ( x methodbyname ) Swap ( i , j int ) { x [ i ] , x [ j ] = x [ j ] , x [ i ] }
func ( x methodbyname ) Less ( i , j int ) bool { return x [ i ] . Sym . Name < x [ j ] . Sym . Name }
2015-02-13 14:40:36 -05:00
func dumpexporttype ( t * Type ) {
if t == nil {
return
}
2015-09-08 03:51:30 +02:00
if t . Printed || t == Types [ t . Etype ] || t == bytetype || t == runetype || t == errortype {
2015-02-13 14:40:36 -05:00
return
}
2015-09-08 03:51:30 +02:00
t . Printed = true
2015-02-13 14:40:36 -05:00
if t . Sym != nil && t . Etype != TFIELD {
dumppkg ( t . Sym . Pkg )
}
dumpexporttype ( t . Type )
dumpexporttype ( t . Down )
if t . Sym == nil || t . Etype == TFIELD {
return
}
2015-09-14 20:53:44 +02:00
var m [ ] * Type
2015-02-23 16:07:24 -05:00
for f := t . Method ; f != nil ; f = f . Down {
2015-02-13 14:40:36 -05:00
dumpexporttype ( f )
2015-09-14 20:53:44 +02:00
m = append ( m , f )
2015-02-13 14:40:36 -05:00
}
2015-09-14 20:53:44 +02:00
sort . Sort ( methodbyname ( m ) )
2015-02-13 14:40:36 -05:00
fmt . Fprintf ( bout , "\ttype %v %v\n" , Sconv ( t . Sym , obj . FmtSharp ) , Tconv ( t , obj . FmtSharp | obj . FmtLong ) )
2015-09-14 20:53:44 +02:00
for _ , f := range m {
2015-02-17 22:13:49 -05:00
if f . Nointerface {
2015-02-13 14:40:36 -05:00
fmt . Fprintf ( bout , "\t//go:nointerface\n" )
}
2015-03-25 19:33:01 -07:00
if f . Type . Nname != nil && f . Type . Nname . Func . Inl != nil { // nname was set by caninl
2015-02-13 14:40:36 -05:00
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
if Debug [ 'l' ] < 2 {
typecheckinl ( f . Type . Nname )
}
2015-03-25 19:33:01 -07:00
fmt . Fprintf ( bout , "\tfunc (%v) %v %v { %v }\n" , Tconv ( getthisx ( f . Type ) . Type , obj . FmtSharp ) , Sconv ( f . Sym , obj . FmtShort | obj . FmtByte | obj . FmtSharp ) , Tconv ( f . Type , obj . FmtShort | obj . FmtSharp ) , Hconv ( f . Type . Nname . Func . Inl , obj . FmtSharp ) )
reexportdeplist ( f . Type . Nname . Func . Inl )
2015-02-13 14:40:36 -05:00
} else {
fmt . Fprintf ( bout , "\tfunc (%v) %v %v\n" , Tconv ( getthisx ( f . Type ) . Type , obj . FmtSharp ) , Sconv ( f . Sym , obj . FmtShort | obj . FmtByte | obj . FmtSharp ) , Tconv ( f . Type , obj . FmtShort | obj . FmtSharp ) )
}
}
}
func dumpsym ( s * Sym ) {
if s . Flags & SymExported != 0 {
return
}
s . Flags |= SymExported
if s . Def == nil {
2015-04-17 12:03:22 -04:00
Yyerror ( "unknown export symbol: %v" , s )
2015-02-13 14:40:36 -05:00
return
}
// print("dumpsym %O %+S\n", s->def->op, s);
dumppkg ( s . Pkg )
switch s . Def . Op {
default :
2015-04-17 12:03:22 -04:00
Yyerror ( "unexpected export symbol: %v %v" , Oconv ( int ( s . Def . Op ) , 0 ) , s )
2015-02-13 14:40:36 -05:00
case OLITERAL :
dumpexportconst ( s )
case OTYPE :
if s . Def . Type . Etype == TFORW {
2015-04-17 12:03:22 -04:00
Yyerror ( "export of incomplete type %v" , s )
2015-02-13 14:40:36 -05:00
} else {
dumpexporttype ( s . Def . Type )
}
case ONAME :
dumpexportvar ( s )
}
}
func dumpexport ( ) {
2015-02-23 16:07:24 -05:00
lno := lineno
2015-02-13 14:40:36 -05:00
2015-04-19 23:56:30 -04:00
if buildid != "" {
fmt . Fprintf ( bout , "build id %q\n" , buildid )
}
2015-02-13 14:40:36 -05:00
fmt . Fprintf ( bout , "\n$$\npackage %s" , localpkg . Name )
if safemode != 0 {
fmt . Fprintf ( bout , " safe" )
}
fmt . Fprintf ( bout , "\n" )
2015-03-02 16:21:15 -05:00
for _ , p := range pkgs {
2015-09-08 05:46:31 +02:00
if p . Direct {
2015-03-02 16:21:15 -05:00
dumppkg ( p )
2015-02-13 14:40:36 -05:00
}
}
2015-08-12 14:29:50 -07:00
// exportlist grows during iteration - cannot use range
for len ( exportlist ) > 0 {
n := exportlist [ 0 ]
exportlist = exportlist [ 1 : ]
lineno = n . Lineno
dumpsym ( n . Sym )
2015-02-13 14:40:36 -05:00
}
fmt . Fprintf ( bout , "\n$$\n" )
lineno = lno
}
/ *
* import
* /
/ *
* return the sym for ss , which should match lexical
* /
func importsym ( s * Sym , op int ) * Sym {
if s . Def != nil && int ( s . Def . Op ) != op {
2015-03-02 16:03:26 -05:00
pkgstr := fmt . Sprintf ( "during import %q" , importpkg . Path )
2015-02-13 14:40:36 -05:00
redeclare ( s , pkgstr )
}
// mark the symbol so it is not reexported
if s . Def == nil {
2015-02-17 22:13:49 -05:00
if exportname ( s . Name ) || initname ( s . Name ) {
2015-02-13 14:40:36 -05:00
s . Flags |= SymExport
} else {
s . Flags |= SymPackage // package scope
}
}
return s
}
/ *
* return the type pkg . name , forward declaring if needed
* /
func pkgtype ( s * Sym ) * Type {
importsym ( s , OTYPE )
if s . Def == nil || s . Def . Op != OTYPE {
2015-02-23 16:07:24 -05:00
t := typ ( TFORW )
2015-02-13 14:40:36 -05:00
t . Sym = s
s . Def = typenod ( t )
2015-05-26 23:08:39 -04:00
s . Def . Name = new ( Name )
2015-02-13 14:40:36 -05:00
}
if s . Def . Type == nil {
2015-04-17 12:03:22 -04:00
Yyerror ( "pkgtype %v" , s )
2015-02-13 14:40:36 -05:00
}
return s . Def . Type
}
2015-03-02 16:21:15 -05:00
var numImport = make ( map [ string ] int )
2015-03-02 16:03:26 -05:00
func importimport ( s * Sym , path string ) {
2015-02-13 14:40:36 -05:00
// Informational: record package name
// associated with import path, for use in
// human-readable messages.
2015-03-02 16:03:26 -05:00
if isbadimport ( path ) {
2015-02-13 14:40:36 -05:00
errorexit ( )
}
2015-03-02 16:03:26 -05:00
p := mkpkg ( path )
2015-02-13 14:40:36 -05:00
if p . Name == "" {
p . Name = s . Name
2015-03-02 16:21:15 -05:00
numImport [ s . Name ] ++
2015-02-13 14:40:36 -05:00
} else if p . Name != s . Name {
2015-03-02 16:03:26 -05:00
Yyerror ( "conflicting names %s and %s for package %q" , p . Name , s . Name , p . Path )
2015-02-13 14:40:36 -05:00
}
2015-03-02 16:03:26 -05:00
if incannedimport == 0 && myimportpath != "" && path == myimportpath {
Yyerror ( "import %q: package depends on %q (import cycle)" , importpkg . Path , path )
2015-02-13 14:40:36 -05:00
errorexit ( )
}
}
func importconst ( s * Sym , t * Type , n * Node ) {
importsym ( s , OLITERAL )
Convlit ( & n , t )
if s . Def != nil { // TODO: check if already the same.
return
}
if n . Op != OLITERAL {
Yyerror ( "expression must be a constant" )
return
}
if n . Sym != nil {
2015-02-23 16:07:24 -05:00
n1 := Nod ( OXXX , nil , nil )
2015-02-13 14:40:36 -05:00
* n1 = * n
n = n1
}
n . Orig = newname ( s )
n . Sym = s
declare ( n , PEXTERN )
if Debug [ 'E' ] != 0 {
2015-04-17 12:03:22 -04:00
fmt . Printf ( "import const %v\n" , s )
2015-02-13 14:40:36 -05:00
}
}
func importvar ( s * Sym , t * Type ) {
importsym ( s , ONAME )
if s . Def != nil && s . Def . Op == ONAME {
if Eqtype ( t , s . Def . Type ) {
return
}
2015-04-17 12:03:22 -04:00
Yyerror ( "inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)" , s , s . Def . Type , s . Importdef . Path , t , importpkg . Path )
2015-02-13 14:40:36 -05:00
}
2015-02-23 16:07:24 -05:00
n := newname ( s )
2015-02-13 14:40:36 -05:00
s . Importdef = importpkg
n . Type = t
declare ( n , PEXTERN )
if Debug [ 'E' ] != 0 {
2015-04-17 12:03:22 -04:00
fmt . Printf ( "import var %v %v\n" , s , Tconv ( t , obj . FmtLong ) )
2015-02-13 14:40:36 -05:00
}
}
func importtype ( pt * Type , t * Type ) {
// override declaration in unsafe.go for Pointer.
// there is no way in Go code to define unsafe.Pointer
// so we have to supply it.
if incannedimport != 0 && importpkg . Name == "unsafe" && pt . Nod . Sym . Name == "Pointer" {
t = Types [ TUNSAFEPTR ]
}
if pt . Etype == TFORW {
2015-02-23 16:07:24 -05:00
n := pt . Nod
2015-02-13 14:40:36 -05:00
copytype ( pt . Nod , t )
pt . Nod = n // unzero nod
pt . Sym . Importdef = importpkg
pt . Sym . Lastlineno = int32 ( parserline ( ) )
declare ( n , PEXTERN )
checkwidth ( pt )
} else if ! Eqtype ( pt . Orig , t ) {
2015-04-17 12:03:22 -04:00
Yyerror ( "inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)" , pt . Sym , Tconv ( pt , obj . FmtLong ) , pt . Sym . Importdef . Path , Tconv ( t , obj . FmtLong ) , importpkg . Path )
2015-02-13 14:40:36 -05:00
}
if Debug [ 'E' ] != 0 {
2015-04-17 12:03:22 -04:00
fmt . Printf ( "import type %v %v\n" , pt , Tconv ( t , obj . FmtLong ) )
2015-02-13 14:40:36 -05:00
}
}
func dumpasmhdr ( ) {
var b * obj . Biobuf
b , err := obj . Bopenw ( asmhdr )
if err != nil {
2015-08-30 23:10:03 +02:00
Fatalf ( "%v" , err )
2015-02-13 14:40:36 -05:00
}
fmt . Fprintf ( b , "// generated by %cg -asmhdr from package %s\n\n" , Thearch . Thechar , localpkg . Name )
2015-02-23 16:07:24 -05:00
var n * Node
var t * Type
for l := asmlist ; l != nil ; l = l . Next {
2015-02-13 14:40:36 -05:00
n = l . N
if isblanksym ( n . Sym ) {
continue
}
switch n . Op {
case OLITERAL :
2015-05-27 00:47:05 -04:00
fmt . Fprintf ( b , "#define const_%s %v\n" , n . Sym . Name , Vconv ( n . Val ( ) , obj . FmtSharp ) )
2015-02-13 14:40:36 -05:00
case OTYPE :
t = n . Type
2015-09-08 03:51:30 +02:00
if t . Etype != TSTRUCT || t . Map != nil || t . Funarg {
2015-02-13 14:40:36 -05:00
break
}
fmt . Fprintf ( b , "#define %s__size %d\n" , t . Sym . Name , int ( t . Width ) )
for t = t . Type ; t != nil ; t = t . Down {
if ! isblanksym ( t . Sym ) {
fmt . Fprintf ( b , "#define %s_%s %d\n" , n . Sym . Name , t . Sym . Name , int ( t . Width ) )
}
}
}
}
obj . Bterm ( b )
}