github.com/gotranspile/cxgo@v0.3.8-0.20240118201721-29871598a6a2/convert.go (about)

     1  package cxgo
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"modernc.org/cc/v3"
     8  	"modernc.org/token"
     9  
    10  	"github.com/gotranspile/cxgo/types"
    11  )
    12  
    13  func (g *translator) newIdent(name string, t types.Type) *types.Ident {
    14  	if id, ok := g.env.IdentByName(name); ok {
    15  		if it := id.CType(nil); it.Kind().Major() == t.Kind().Major() || (it.Kind().IsBool() && t.Kind().IsInt()) {
    16  			return id // FIXME: this is invalid, we should consult scopes instead
    17  		}
    18  	}
    19  	return types.NewIdent(name, t)
    20  }
    21  
    22  func (g *translator) convMacro(name string, fnc func() Expr) Expr {
    23  	if g.env.ForceMacro(name) {
    24  		return fnc()
    25  	}
    26  	id, ok := g.macros[name]
    27  	if ok {
    28  		return IdentExpr{id}
    29  	}
    30  	x := fnc()
    31  	typ := x.CType(nil)
    32  	id = g.newIdent(name, typ)
    33  	g.macros[name] = id
    34  	return IdentExpr{id}
    35  }
    36  
    37  func (g *translator) convertIdent(scope cc.Scope, tok cc.Token, t types.Type) IdentExpr {
    38  	var decl []cc.Node
    39  	for len(scope) != 0 {
    40  		if nodes, ok := scope[tok.Value]; ok {
    41  			decl = nodes
    42  			break
    43  		}
    44  		scope = scope.Parent()
    45  	}
    46  	if len(decl) == 0 {
    47  		panic(fmt.Errorf("unresolved identifier: %s (%s)", tok, tok.Position()))
    48  	}
    49  	return g.convertIdentWith(tok.String(), t, decl...)
    50  }
    51  
    52  func (g *translator) convertIdentWith(name string, t types.Type, decls ...cc.Node) IdentExpr {
    53  	for _, d := range decls {
    54  		if id, ok := g.decls[d]; ok && id.Name == name {
    55  			return IdentExpr{id}
    56  		}
    57  	}
    58  	id := g.newIdent(name, t)
    59  	if to, ok := g.idents[name]; ok && to.Rename != "" {
    60  		id.GoName = to.Rename
    61  	}
    62  	for _, d := range decls {
    63  		g.decls[d] = id
    64  	}
    65  	return IdentExpr{id}
    66  }
    67  
    68  func (g *translator) replaceIdentWith(id *types.Ident, decls ...cc.Node) {
    69  	for _, d := range decls {
    70  		g.decls[d] = id
    71  	}
    72  }
    73  
    74  func (g *translator) tryConvertIdentOn(t types.Type, tok cc.Token) (*types.Ident, bool) {
    75  loop:
    76  	for {
    77  		switch s := t.(type) {
    78  		case types.PtrType:
    79  			t = s.Elem()
    80  		case types.ArrayType:
    81  			t = s.Elem()
    82  		case types.Named:
    83  			t = s.Underlying()
    84  		default:
    85  			break loop
    86  		}
    87  	}
    88  	switch t := t.(type) {
    89  	case *types.StructType:
    90  		name := tok.Value.String()
    91  		for _, f := range t.Fields() {
    92  			if name == f.Name.Name {
    93  				return f.Name, true
    94  			}
    95  			if f.Name.Name == "" {
    96  				if id, ok := g.tryConvertIdentOn(f.Type(), tok); ok {
    97  					return id, true
    98  				}
    99  			}
   100  		}
   101  	}
   102  	return nil, false
   103  }
   104  
   105  func (g *translator) convertIdentOn(t types.Type, tok cc.Token) *types.Ident {
   106  	id, ok := g.tryConvertIdentOn(t, tok)
   107  	if ok {
   108  		return id
   109  	}
   110  	panic(fmt.Errorf("%#v.%q (%s)", t, tok.Value.String(), tok.Position()))
   111  }
   112  
   113  func (g *translator) convertFuncDef(d *cc.FunctionDefinition) []CDecl {
   114  	decl := d.Declarator
   115  	switch dd := decl.DirectDeclarator; dd.Case {
   116  	case cc.DirectDeclaratorFuncParam, cc.DirectDeclaratorFuncIdent:
   117  		sname := decl.Name().String()
   118  		conf := g.idents[sname]
   119  		ft := g.convertFuncType(conf, decl, decl.Type(), decl.Position())
   120  		if !g.inCurFile(d) {
   121  			return nil
   122  		}
   123  		name := g.convertIdentWith(sname, ft, decl)
   124  		return []CDecl{
   125  			&CFuncDecl{
   126  				Name: name.Ident,
   127  				Type: ft,
   128  				Body: g.convertCompBlockStmt(d.CompoundStatement).In(ft),
   129  				Range: &Range{
   130  					Start:     d.Position().Offset,
   131  					StartLine: d.Position().Line,
   132  				},
   133  			},
   134  		}
   135  	default:
   136  		panic(dd.Case.String() + " " + dd.Position().String())
   137  	}
   138  }
   139  
   140  type positioner interface {
   141  	Position() token.Position
   142  }
   143  
   144  func (g *translator) inCurFile(p positioner) bool {
   145  	name := strings.TrimLeft(p.Position().Filename, "./")
   146  	if g.cur == name {
   147  		return true
   148  	} else if !strings.HasSuffix(g.cur, ".c") {
   149  		return false
   150  	}
   151  	return g.cur[:len(g.cur)-2]+".h" == name
   152  }
   153  
   154  func (g *translator) convertInitList(typ types.Type, list *cc.InitializerList) Expr {
   155  	var items []*CompLitField
   156  	var (
   157  		prev int64 = -1 // previous array init index
   158  		pi   int64 = 0  // relative index added to the last seen item; see below
   159  	)
   160  	for it := list; it != nil; it = it.InitializerList {
   161  		val := g.convertInitExpr(it.Initializer)
   162  		var f *CompLitField
   163  		if it.Designation == nil {
   164  			// no index in the initializer - assign automatically
   165  			pi++
   166  			f = &CompLitField{Index: cIntLit(prev+pi, 10), Value: val}
   167  			items = append(items, f)
   168  			continue
   169  		}
   170  		f = g.convertOneDesignator(typ, it.Designation.DesignatorList, val)
   171  		if lit, ok := f.Index.(IntLit); ok {
   172  			if prev == -1 {
   173  				// first item - note that we started initializing indexes
   174  				prev = 0
   175  			} else if prev == lit.Int() {
   176  				// this was an old bug in CC where it returned stale indexes
   177  				// for items without any index designators
   178  				// it looks like it is fixed now, but we keep the workaround just in case
   179  				pi++
   180  				f.Index = cIntLit(prev+pi, 10)
   181  			} else {
   182  				// valid index - set previous and reset relative index
   183  				prev = lit.Int()
   184  				pi = 0
   185  			}
   186  		}
   187  		items = append(items, f)
   188  	}
   189  	return g.NewCCompLitExpr(
   190  		typ,
   191  		items,
   192  	)
   193  }
   194  
   195  func (g *translator) convertInitExpr(d *cc.Initializer) Expr {
   196  	switch d.Case {
   197  	case cc.InitializerExpr:
   198  		return g.convertAssignExpr(d.AssignmentExpression)
   199  	case cc.InitializerInitList:
   200  		return g.convertInitList(
   201  			g.convertTypeRoot(IdentConfig{}, d.Type(), d.Position()),
   202  			d.InitializerList,
   203  		)
   204  	default:
   205  		panic(d.Case.String() + " " + d.Position().String())
   206  	}
   207  }
   208  
   209  func (g *translator) convertEnum(b *cc.Declaration, typ types.Type, d *cc.EnumSpecifier) []CDecl {
   210  	if d.EnumeratorList == nil {
   211  		return nil
   212  	}
   213  	if typ == nil {
   214  		typ = types.UntypedIntT(g.env.IntSize())
   215  	}
   216  	vd := &CVarDecl{
   217  		Const:    true,
   218  		Single:   false,
   219  		CVarSpec: CVarSpec{g: g, Type: typ},
   220  	}
   221  	var (
   222  		autos  = 0 // number of implicit inits
   223  		values = 0 // number of explicit inits
   224  	)
   225  	for it := d.EnumeratorList; it != nil; it = it.EnumeratorList {
   226  		e := it.Enumerator
   227  		if e.Case == cc.EnumeratorExpr {
   228  			init := g.convertConstExpr(e.ConstantExpression)
   229  			vd.Inits = append(vd.Inits, init)
   230  			values++
   231  			continue
   232  		}
   233  		vd.Inits = append(vd.Inits, nil)
   234  		autos++
   235  	}
   236  	if autos == 1 && vd.Inits[0] == nil {
   237  		autos--
   238  		values++
   239  		vd.Inits[0] = cIntLit(0, 10)
   240  	}
   241  
   242  	// use iota if there is only one explicit init (the first one), or no explicit values are set
   243  	isIota := (vd.Inits[0] == nil && autos == 1) || autos == len(vd.Inits)
   244  	if len(vd.Inits) > 1 && vd.Inits[0] != nil && values == 1 {
   245  		if _, ok := cUnwrap(vd.Inits[0]).(IntLit); ok {
   246  			isIota = true
   247  			values--
   248  			autos++
   249  		}
   250  	}
   251  
   252  	if len(vd.Inits) != 0 && isIota && values != 0 {
   253  		panic("TODO: mixed enums")
   254  	}
   255  	var next int64
   256  	for it, i := d.EnumeratorList, 0; it != nil; it, i = it.EnumeratorList, i+1 {
   257  		e := it.Enumerator
   258  		if isIota {
   259  			if i == 0 {
   260  				iot := g.Iota()
   261  				if val := vd.Inits[0]; val != nil {
   262  					if l, ok := cUnwrap(val).(IntLit); !ok || !l.IsZero() {
   263  						iot = &CBinaryExpr{Left: iot, Op: BinOpAdd, Right: val}
   264  					}
   265  				}
   266  				if !typ.Kind().IsUntypedInt() {
   267  					iot = &CCastExpr{Type: typ, Expr: iot}
   268  				}
   269  				vd.Inits[0] = iot
   270  			}
   271  		} else {
   272  			if vd.Inits[i] == nil {
   273  				vd.Inits[i] = cIntLit(next, 10)
   274  				next++
   275  			} else if l, ok := cUnwrap(vd.Inits[i]).(IntLit); ok {
   276  				next = l.Int() + 1
   277  			}
   278  		}
   279  		vd.Names = append(vd.Names, g.convertIdentWith(e.Token.Value.String(), typ, e).Ident)
   280  	}
   281  	if len(vd.Names) == 0 {
   282  		return nil
   283  	}
   284  	if isIota {
   285  		vd.Type = nil
   286  	}
   287  	return []CDecl{vd}
   288  }
   289  
   290  func (g *translator) convertTypedefName(d *cc.Declaration) (cc.Token, *cc.Declarator) {
   291  	if d.InitDeclaratorList == nil || d.InitDeclaratorList.InitDeclarator == nil {
   292  		panic("no decl")
   293  	}
   294  	if d.InitDeclaratorList.InitDeclaratorList != nil {
   295  		panic("should have one decl")
   296  	}
   297  	id := d.InitDeclaratorList.InitDeclarator
   298  	if id.Case != cc.InitDeclaratorDecl {
   299  		panic(id.Case.String())
   300  	}
   301  	dd := id.Declarator
   302  	if dd.DirectDeclarator.Case != cc.DirectDeclaratorIdent {
   303  		panic(dd.DirectDeclarator.Case)
   304  	}
   305  	return dd.DirectDeclarator.Token, dd
   306  }
   307  
   308  func (g *translator) convertDecl(d *cc.Declaration) []CDecl {
   309  	inCur := g.inCurFile(d)
   310  	var (
   311  		isConst    bool
   312  		isVolatile bool
   313  		isTypedef  bool
   314  		isStatic   bool
   315  		isExtern   bool
   316  		isForward  bool
   317  		isFunc     bool
   318  		isPrim     bool
   319  		isAuto     bool
   320  		typeSpec   types.Type
   321  		enumSpec   *cc.EnumSpecifier
   322  		names      []string // used only for the hooks
   323  	)
   324  	for il := d.InitDeclaratorList; il != nil; il = il.InitDeclaratorList {
   325  		id := il.InitDeclarator
   326  		switch id.Case {
   327  		case cc.InitDeclaratorDecl, cc.InitDeclaratorInit:
   328  			dd := id.Declarator
   329  			if name := dd.Name().String(); name != "" {
   330  				names = append(names, name)
   331  			}
   332  		}
   333  	}
   334  	spec := d.DeclarationSpecifiers
   335  	if spec != nil && spec.Case == cc.DeclarationSpecifiersStorage &&
   336  		spec.StorageClassSpecifier.Case == cc.StorageClassSpecifierTypedef {
   337  		isTypedef = true
   338  		spec = spec.DeclarationSpecifiers
   339  	}
   340  	for sp := spec; sp != nil; sp = sp.DeclarationSpecifiers {
   341  		switch sp.Case {
   342  		case cc.DeclarationSpecifiersTypeQual:
   343  			ds := sp.TypeQualifier
   344  			switch ds.Case {
   345  			case cc.TypeQualifierConst:
   346  				isConst = true
   347  			case cc.TypeQualifierVolatile:
   348  				isVolatile = true
   349  			default:
   350  				panic(ds.Case.String())
   351  			}
   352  		case cc.DeclarationSpecifiersStorage:
   353  			ds := sp.StorageClassSpecifier
   354  			switch ds.Case {
   355  			case cc.StorageClassSpecifierStatic:
   356  				isStatic = true
   357  			case cc.StorageClassSpecifierExtern:
   358  				isExtern = true
   359  			case cc.StorageClassSpecifierAuto:
   360  				isAuto = true
   361  			case cc.StorageClassSpecifierRegister:
   362  				// ignore
   363  			default:
   364  				panic(ds.Case.String())
   365  			}
   366  			if isTypedef {
   367  				panic("wrong type")
   368  			}
   369  		case cc.DeclarationSpecifiersTypeSpec:
   370  			ds := sp.TypeSpecifier
   371  			switch ds.Case {
   372  			case cc.TypeSpecifierStructOrUnion:
   373  				su := ds.StructOrUnionSpecifier
   374  				var conf IdentConfig
   375  				for _, name := range names {
   376  					if c, ok := g.idents[name]; ok {
   377  						conf = c
   378  						break
   379  					}
   380  				}
   381  				switch su.Case {
   382  				case cc.StructOrUnionSpecifierTag:
   383  					// struct/union forward declaration
   384  					isForward = true
   385  					typeSpec = g.convertType(conf, su.Type(), d.Position()).(types.Named)
   386  				case cc.StructOrUnionSpecifierDef:
   387  					// struct/union declaration
   388  					if isForward {
   389  						panic("already marked as a forward decl")
   390  					}
   391  					typeSpec = g.convertType(conf, su.Type(), d.Position())
   392  				default:
   393  					panic(su.Case.String())
   394  				}
   395  			case cc.TypeSpecifierEnum:
   396  				enumSpec = ds.EnumSpecifier
   397  			case cc.TypeSpecifierVoid:
   398  				isFunc = true
   399  			default:
   400  				isPrim = true
   401  			}
   402  		case cc.DeclarationSpecifiersFunc:
   403  			isFunc = true
   404  			// TODO: use specifiers
   405  		default:
   406  			panic(sp.Case.String() + " " + sp.Position().String())
   407  		}
   408  	}
   409  	_ = isStatic // FIXME: static
   410  	_ = isVolatile
   411  	_ = isAuto // FIXME: auto
   412  	var decls []CDecl
   413  	if enumSpec != nil {
   414  		if isForward {
   415  			panic("TODO")
   416  		}
   417  		if isPrim || isFunc {
   418  			panic("wrong type")
   419  		}
   420  		if typeSpec != nil {
   421  			panic("should have no type")
   422  		}
   423  		if !inCur {
   424  			return nil
   425  		}
   426  		var (
   427  			typ           types.Type
   428  			hasOtherDecls = false
   429  		)
   430  		if isTypedef {
   431  			name, dd := g.convertTypedefName(d)
   432  			und := g.convertType(IdentConfig{}, dd.Type(), name.Position())
   433  			nt := g.newOrFindNamedType(name.Value.String(), func() types.Type {
   434  				return und
   435  			})
   436  			typ = nt
   437  			decls = append(decls, &CTypeDef{nt})
   438  		} else if d.InitDeclaratorList != nil {
   439  			hasOtherDecls = true
   440  		} else if name := enumSpec.Token2; name.Value != 0 {
   441  			nt := g.newOrFindNamedType(name.Value.String(), func() types.Type {
   442  				return g.env.DefIntT()
   443  			})
   444  			typ = nt
   445  			decls = append(decls, &CTypeDef{nt})
   446  		}
   447  		if !hasOtherDecls {
   448  			decls = append(decls, g.convertEnum(d, typ, enumSpec)...)
   449  		}
   450  	}
   451  	if d.InitDeclaratorList == nil || d.InitDeclaratorList.InitDeclarator == nil {
   452  		if typeSpec == nil && enumSpec != nil {
   453  			return decls
   454  		}
   455  		if isTypedef && isForward {
   456  			panic("wrong type")
   457  		}
   458  		if isPrim || isFunc {
   459  			panic("wrong type")
   460  		}
   461  		if isForward {
   462  			if typeSpec == nil {
   463  				panic("no type for forward decl")
   464  			}
   465  			if !inCur || !g.conf.ForwardDecl {
   466  				return nil
   467  			}
   468  		} else {
   469  			if !inCur {
   470  				return nil
   471  			}
   472  			if isTypedef {
   473  				panic("TODO")
   474  			}
   475  		}
   476  		nt, ok := typeSpec.(types.Named)
   477  		if !ok {
   478  			if isForward {
   479  				panic("forward declaration of unnamed type")
   480  			} else {
   481  				panic(fmt.Errorf("declaration of unnamed type: %T", typeSpec))
   482  			}
   483  		}
   484  		decls = append(decls, &CTypeDef{nt})
   485  		return decls
   486  	}
   487  	var (
   488  		added   = 0
   489  		skipped = 0
   490  	)
   491  	for il := d.InitDeclaratorList; il != nil; il = il.InitDeclaratorList {
   492  		id := il.InitDeclarator
   493  		switch id.Case {
   494  		case cc.InitDeclaratorDecl, cc.InitDeclaratorInit:
   495  			dd := id.Declarator
   496  			dname := dd.Name().String()
   497  			conf := g.idents[dname]
   498  			vt := g.convertTypeRootOpt(conf, dd.Type(), id.Position())
   499  			if isTypedef && vt == nil {
   500  				vt = types.StructT(nil)
   501  			}
   502  			var init Expr
   503  			if id.Initializer != nil && inCur {
   504  				if isTypedef {
   505  					panic("init in typedef: " + id.Position().String())
   506  				}
   507  				init = g.convertInitExpr(id.Initializer)
   508  			}
   509  			if isConst && propagateConst(vt) {
   510  				isConst = false
   511  			}
   512  			if isTypedef {
   513  				if enumSpec != nil {
   514  					continue
   515  				}
   516  				nt, ok := vt.(types.Named)
   517  				// TODO: this case is "too smart", we already handle those kind of double typedefs on a lower level
   518  				if !ok || nt.Name().Name != dd.Name().String() {
   519  					// we don't call a *From version of the method here because dd.Type() is an underlying type,
   520  					// not a typedef type
   521  					if ok && !strings.HasPrefix(nt.Name().Name, "_cxgo_") {
   522  						decls = append(decls, &CTypeDef{nt})
   523  					}
   524  					if vt == nil {
   525  						panic("TODO: typedef of void? " + id.Position().String())
   526  					}
   527  					nt = g.newOrFindNamedTypedef(dd.Name().String(), func() types.Type {
   528  						return vt
   529  					})
   530  					if nt == nil {
   531  						// typedef suppressed
   532  						skipped++
   533  						continue
   534  					}
   535  				}
   536  				decls = append(decls, &CTypeDef{nt})
   537  				continue
   538  			}
   539  			name := g.convertIdentWith(dd.NameTok().String(), vt, dd)
   540  			isDecl := false
   541  			for di := dd.DirectDeclarator; di != nil; di = di.DirectDeclarator {
   542  				if di.Case == cc.DirectDeclaratorDecl {
   543  					isDecl = true
   544  					break
   545  				}
   546  			}
   547  			if !isDecl && !isForward {
   548  				if nt, ok := typeSpec.(types.Named); ok {
   549  					decls = append(decls, &CTypeDef{nt})
   550  				}
   551  			}
   552  			if ft, ok := vt.(*types.FuncType); ok && !isDecl {
   553  				// forward declaration
   554  				if l, id, ok := g.tenv.LibIdentByName(name.Name); ok && id.CType(nil).Kind().IsFunc() {
   555  					// forward declaration of stdlib function
   556  					// we must first load the corresponding library to the real env
   557  					l, ok = g.env.GetLibrary(l.Name)
   558  					if !ok {
   559  						panic("cannot load stdlib")
   560  					}
   561  					id, ok = l.Idents[name.Name]
   562  					if !ok {
   563  						panic("cannot find stdlib ident")
   564  					}
   565  					g.replaceIdentWith(id, dd)
   566  					skipped++
   567  				} else if g.conf.ForwardDecl {
   568  					decls = append(decls, &CFuncDecl{
   569  						Name: name.Ident,
   570  						Type: ft,
   571  						Body: nil,
   572  					})
   573  				} else {
   574  					skipped++
   575  				}
   576  			} else {
   577  				decls = decls[:len(decls)-added]
   578  				if !isExtern {
   579  					var inits []Expr
   580  					if init != nil {
   581  						inits = []Expr{init}
   582  					}
   583  					decls = append(decls, &CVarDecl{
   584  						// There is no real const in C
   585  						Const: false, // Const: isConst,
   586  						CVarSpec: CVarSpec{
   587  							g:     g,
   588  							Type:  vt,
   589  							Names: []*types.Ident{name.Ident},
   590  							Inits: inits,
   591  						},
   592  					})
   593  				} else {
   594  					skipped++
   595  				}
   596  			}
   597  		default:
   598  			panic(id.Case.String())
   599  		}
   600  	}
   601  	if !inCur {
   602  		return nil
   603  	}
   604  	if len(decls) == 0 && skipped == 0 {
   605  		panic("no declarations converted: " + d.Position().String())
   606  	}
   607  	return decls
   608  }
   609  
   610  func (g *translator) convertCompStmt(d *cc.CompoundStatement) []CStmt {
   611  	var stmts []CStmt
   612  	for it := d.BlockItemList; it != nil; it = it.BlockItemList {
   613  		st := it.BlockItem
   614  		switch st.Case {
   615  		case cc.BlockItemDecl:
   616  			for _, dec := range g.convertDecl(st.Declaration) {
   617  				stmts = append(stmts, g.NewCDeclStmt(dec)...)
   618  			}
   619  		case cc.BlockItemStmt:
   620  			stmts = append(stmts, g.convertStmt(st.Statement)...)
   621  		default:
   622  			panic(st.Case.String())
   623  		}
   624  	}
   625  	// TODO: shouldn't it return statements without a block? or call an optimizing version of block constructor?
   626  	return []CStmt{g.newBlockStmt(stmts...)}
   627  }
   628  
   629  func (g *translator) convertCompBlockStmt(d *cc.CompoundStatement) *BlockStmt {
   630  	stmts := g.convertCompStmt(d)
   631  	if len(stmts) == 1 {
   632  		if b, ok := stmts[0].(*BlockStmt); ok {
   633  			return b
   634  		}
   635  	}
   636  	// TODO: shouldn't it call a version that applies optimizations?
   637  	return g.newBlockStmt(stmts...)
   638  }
   639  
   640  func (g *translator) convertExpr(d *cc.Expression) Expr {
   641  	if d.Expression == nil {
   642  		return g.convertAssignExpr(d.AssignmentExpression)
   643  	}
   644  	var exprs []*cc.AssignmentExpression
   645  	for ; d != nil; d = d.Expression {
   646  		exprs = append(exprs, d.AssignmentExpression)
   647  	}
   648  	var m []Expr
   649  	for i := len(exprs) - 1; i >= 0; i-- {
   650  		m = append(m, g.convertAssignExpr(exprs[i]))
   651  	}
   652  	return g.NewCMultiExpr(m...)
   653  }
   654  
   655  func (g *translator) convertExprOpt(d *cc.Expression) Expr {
   656  	if d == nil {
   657  		return nil
   658  	}
   659  	return g.convertExpr(d)
   660  }
   661  
   662  func (g *translator) convertMulExpr(d *cc.MultiplicativeExpression) Expr {
   663  	switch d.Case {
   664  	case cc.MultiplicativeExpressionCast:
   665  		return g.convertCastExpr(d.CastExpression)
   666  	}
   667  	x := g.convertMulExpr(d.MultiplicativeExpression)
   668  	y := g.convertCastExpr(d.CastExpression)
   669  	var op BinaryOp
   670  	switch d.Case {
   671  	case cc.MultiplicativeExpressionMul:
   672  		op = BinOpMult
   673  	case cc.MultiplicativeExpressionDiv:
   674  		op = BinOpDiv
   675  	case cc.MultiplicativeExpressionMod:
   676  		op = BinOpMod
   677  	default:
   678  		panic(d.Case.String())
   679  	}
   680  	return g.NewCBinaryExprT(
   681  		x, op, y,
   682  		g.convertTypeOper(d.Operand, d.Position()),
   683  	)
   684  }
   685  
   686  func (g *translator) convertAddExpr(d *cc.AdditiveExpression) Expr {
   687  	switch d.Case {
   688  	case cc.AdditiveExpressionMul:
   689  		return g.convertMulExpr(d.MultiplicativeExpression)
   690  	}
   691  	x := g.convertAddExpr(d.AdditiveExpression)
   692  	y := g.convertMulExpr(d.MultiplicativeExpression)
   693  	var op BinaryOp
   694  	switch d.Case {
   695  	case cc.AdditiveExpressionAdd:
   696  		op = BinOpAdd
   697  	case cc.AdditiveExpressionSub:
   698  		op = BinOpSub
   699  	default:
   700  		panic(d.Case.String())
   701  	}
   702  	return g.NewCBinaryExprT(
   703  		x, op, y,
   704  		g.convertTypeOper(d.Operand, d.Position()),
   705  	)
   706  }
   707  
   708  func (g *translator) convertShiftExpr(d *cc.ShiftExpression) Expr {
   709  	switch d.Case {
   710  	case cc.ShiftExpressionAdd:
   711  		return g.convertAddExpr(d.AdditiveExpression)
   712  	}
   713  	x := g.convertShiftExpr(d.ShiftExpression)
   714  	y := g.convertAddExpr(d.AdditiveExpression)
   715  	var op BinaryOp
   716  	switch d.Case {
   717  	case cc.ShiftExpressionLsh:
   718  		op = BinOpLsh
   719  	case cc.ShiftExpressionRsh:
   720  		op = BinOpRsh
   721  	default:
   722  		panic(d.Case.String())
   723  	}
   724  	return g.NewCBinaryExprT(
   725  		x, op, y,
   726  		g.convertTypeOper(d.Operand, d.Position()),
   727  	)
   728  }
   729  
   730  func (g *translator) convertRelExpr(d *cc.RelationalExpression) Expr {
   731  	switch d.Case {
   732  	case cc.RelationalExpressionShift:
   733  		return g.convertShiftExpr(d.ShiftExpression)
   734  	}
   735  	x := g.convertRelExpr(d.RelationalExpression)
   736  	y := g.convertShiftExpr(d.ShiftExpression)
   737  	var op ComparisonOp
   738  	switch d.Case {
   739  	case cc.RelationalExpressionLt:
   740  		op = BinOpLt
   741  	case cc.RelationalExpressionGt:
   742  		op = BinOpGt
   743  	case cc.RelationalExpressionLeq:
   744  		op = BinOpLte
   745  	case cc.RelationalExpressionGeq:
   746  		op = BinOpGte
   747  	default:
   748  		panic(d.Case.String())
   749  	}
   750  	return g.Compare(x, op, y)
   751  }
   752  
   753  func (g *translator) convertEqExpr(d *cc.EqualityExpression) Expr {
   754  	switch d.Case {
   755  	case cc.EqualityExpressionRel:
   756  		return g.convertRelExpr(d.RelationalExpression)
   757  	}
   758  	x := g.convertEqExpr(d.EqualityExpression)
   759  	y := g.convertRelExpr(d.RelationalExpression)
   760  	var op ComparisonOp
   761  	switch d.Case {
   762  	case cc.EqualityExpressionEq:
   763  		op = BinOpEq
   764  	case cc.EqualityExpressionNeq:
   765  		op = BinOpNeq
   766  	default:
   767  		panic(d.Case.String())
   768  	}
   769  	return g.Compare(x, op, y)
   770  }
   771  
   772  func (g *translator) convertAndExpr(d *cc.AndExpression) Expr {
   773  	switch d.Case {
   774  	case cc.AndExpressionEq:
   775  		return g.convertEqExpr(d.EqualityExpression)
   776  	case cc.AndExpressionAnd:
   777  		x := g.convertAndExpr(d.AndExpression)
   778  		y := g.convertEqExpr(d.EqualityExpression)
   779  		return g.NewCBinaryExprT(
   780  			x, BinOpBitAnd, y,
   781  			g.convertTypeOper(d.Operand, d.Position()),
   782  		)
   783  	default:
   784  		panic(d.Case.String())
   785  	}
   786  }
   787  
   788  func (g *translator) convertLOrExcExpr(d *cc.ExclusiveOrExpression) Expr {
   789  	switch d.Case {
   790  	case cc.ExclusiveOrExpressionAnd:
   791  		return g.convertAndExpr(d.AndExpression)
   792  	case cc.ExclusiveOrExpressionXor:
   793  		x := g.convertLOrExcExpr(d.ExclusiveOrExpression)
   794  		y := g.convertAndExpr(d.AndExpression)
   795  		return g.NewCBinaryExprT(
   796  			x, BinOpBitXor, y,
   797  			g.convertTypeOper(d.Operand, d.Position()),
   798  		)
   799  	default:
   800  		panic(d.Case.String())
   801  	}
   802  }
   803  
   804  func (g *translator) convertLOrIncExpr(d *cc.InclusiveOrExpression) Expr {
   805  	switch d.Case {
   806  	case cc.InclusiveOrExpressionXor:
   807  		return g.convertLOrExcExpr(d.ExclusiveOrExpression)
   808  	case cc.InclusiveOrExpressionOr:
   809  		x := g.convertLOrIncExpr(d.InclusiveOrExpression)
   810  		y := g.convertLOrExcExpr(d.ExclusiveOrExpression)
   811  		return g.NewCBinaryExprT(
   812  			x, BinOpBitOr, y,
   813  			g.convertTypeOper(d.Operand, d.Position()),
   814  		)
   815  	default:
   816  		panic(d.Case.String())
   817  	}
   818  }
   819  
   820  func (g *translator) convertLAndExpr(d *cc.LogicalAndExpression) Expr {
   821  	switch d.Case {
   822  	case cc.LogicalAndExpressionOr:
   823  		return g.convertLOrIncExpr(d.InclusiveOrExpression)
   824  	case cc.LogicalAndExpressionLAnd:
   825  		x := g.convertLAndExpr(d.LogicalAndExpression)
   826  		y := g.convertLOrIncExpr(d.InclusiveOrExpression)
   827  		return And(g.ToBool(x), g.ToBool(y))
   828  	default:
   829  		panic(d.Case.String())
   830  	}
   831  }
   832  
   833  func (g *translator) convertLOrExpr(d *cc.LogicalOrExpression) Expr {
   834  	switch d.Case {
   835  	case cc.LogicalOrExpressionLAnd:
   836  		return g.convertLAndExpr(d.LogicalAndExpression)
   837  	case cc.LogicalOrExpressionLOr:
   838  		x := g.convertLOrExpr(d.LogicalOrExpression)
   839  		y := g.convertLAndExpr(d.LogicalAndExpression)
   840  		return Or(g.ToBool(x), g.ToBool(y))
   841  	default:
   842  		panic(d.Case.String())
   843  	}
   844  }
   845  
   846  func (g *translator) convertCondExpr(d *cc.ConditionalExpression) Expr {
   847  	switch d.Case {
   848  	case cc.ConditionalExpressionLOr:
   849  		return g.convertLOrExpr(d.LogicalOrExpression)
   850  	case cc.ConditionalExpressionCond:
   851  		cond := g.convertLOrExpr(d.LogicalOrExpression)
   852  		return g.NewCTernaryExpr(
   853  			g.ToBool(cond),
   854  			g.convertExpr(d.Expression),
   855  			g.convertCondExpr(d.ConditionalExpression),
   856  		)
   857  	default:
   858  		panic(d.Case.String())
   859  	}
   860  }
   861  
   862  func (g *translator) convertPriExpr(d *cc.PrimaryExpression) Expr {
   863  	switch d.Case {
   864  	case cc.PrimaryExpressionIdent: // x
   865  		if d.Token.String() == "asm" {
   866  			return &CAsmExpr{e: g.env.Env}
   867  		}
   868  		if d.Operand == nil {
   869  			panic(ErrorfWithPos(d.Position(), "empty operand for %q", d.Token.String()))
   870  		}
   871  		return g.convertIdent(d.ResolvedIn(), d.Token, g.convertTypeOper(d.Operand, d.Position()))
   872  	case cc.PrimaryExpressionEnum: // X
   873  		return g.convertIdent(d.ResolvedIn(), d.Token, g.convertTypeOper(d.Operand, d.Position()))
   874  	case cc.PrimaryExpressionInt: // 1
   875  		fnc := func() Expr {
   876  			v, err := parseCIntLit(d.Token.String(), g.conf.IntReformat)
   877  			if err != nil {
   878  				panic(err)
   879  			}
   880  			return v
   881  		}
   882  		if m := d.Token.Macro(); m != 0 {
   883  			return g.convMacro(m.String(), fnc)
   884  		}
   885  		return fnc()
   886  	case cc.PrimaryExpressionFloat: // 0.0
   887  		fnc := func() Expr {
   888  			v, err := parseCFloatLit(d.Token.String())
   889  			if err != nil {
   890  				panic(err)
   891  			}
   892  			if d.Operand == nil {
   893  				return v
   894  			}
   895  			return g.cCast(
   896  				g.convertTypeOper(d.Operand, d.Position()),
   897  				v,
   898  			)
   899  		}
   900  		if m := d.Token.Macro(); m != 0 {
   901  			return g.convMacro(m.String(), fnc)
   902  		}
   903  		return fnc()
   904  	case cc.PrimaryExpressionChar: // 'x'
   905  		fnc := func() Expr {
   906  			return cLitT(
   907  				d.Token.String(), CLitChar,
   908  				g.convertTypeOper(d.Operand, d.Position()),
   909  			)
   910  		}
   911  		if m := d.Token.Macro(); m != 0 {
   912  			return g.convMacro(m.String(), fnc)
   913  		}
   914  		return fnc()
   915  	case cc.PrimaryExpressionLChar: // 'x'
   916  		fnc := func() Expr {
   917  			return cLitT(
   918  				d.Token.String(), CLitWChar,
   919  				g.convertTypeOper(d.Operand, d.Position()),
   920  			)
   921  		}
   922  		if m := d.Token.Macro(); m != 0 {
   923  			return g.convMacro(m.String(), fnc)
   924  		}
   925  		return fnc()
   926  	case cc.PrimaryExpressionString: // "x"
   927  		fnc := func() Expr {
   928  			v, err := g.parseCStringLit(d.Token.String())
   929  			if err != nil {
   930  				panic(err)
   931  			}
   932  			return v
   933  		}
   934  		if m := d.Token.Macro(); m != 0 {
   935  			return g.convMacro(m.String(), fnc)
   936  		}
   937  		return fnc()
   938  	case cc.PrimaryExpressionLString: // L"x"
   939  		fnc := func() Expr {
   940  			v, err := g.parseCWStringLit(d.Token.String())
   941  			if err != nil {
   942  				panic(err)
   943  			}
   944  			return v
   945  		}
   946  		if m := d.Token.Macro(); m != 0 {
   947  			return g.convMacro(m.String(), fnc)
   948  		}
   949  		return fnc()
   950  	case cc.PrimaryExpressionExpr: // "(x)"
   951  		e := g.convertExpr(d.Expression)
   952  		return cParen(e)
   953  	case cc.PrimaryExpressionStmt: // "({...; x})"
   954  		stmt := g.convertCompStmt(d.CompoundStatement)
   955  		if len(stmt) != 1 {
   956  			panic("TODO")
   957  		}
   958  		stmt = stmt[0].(*BlockStmt).Stmts
   959  		last, ok := stmt[len(stmt)-1].(*CExprStmt)
   960  		if !ok {
   961  			// let it cause a compilation error in Go
   962  			return &CallExpr{
   963  				Fun: g.NewFuncLit(g.env.FuncTT(g.env.DefIntT()), stmt...),
   964  			}
   965  		}
   966  		typ := last.Expr.CType(nil)
   967  		stmt = append(stmt[:len(stmt)-1], g.NewReturnStmt(last.Expr, typ)...)
   968  		return &CallExpr{
   969  			Fun: g.NewFuncLit(g.env.FuncTT(typ), stmt...),
   970  		}
   971  	default:
   972  		panic(fmt.Errorf("%v (%v)", d.Case, d.Position()))
   973  	}
   974  }
   975  
   976  func (g *translator) convertOneDesignator(typ types.Type, list *cc.DesignatorList, val Expr) *CompLitField {
   977  	d := list.Designator
   978  	var (
   979  		f   *CompLitField
   980  		sub types.Type
   981  	)
   982  	switch d.Case {
   983  	case cc.DesignatorIndex:
   984  		f = &CompLitField{Index: g.convertConstExpr(d.ConstantExpression)}
   985  		sub = typ.(types.ArrayType).Elem()
   986  	case cc.DesignatorField:
   987  		f = &CompLitField{Field: g.convertIdentOn(typ, d.Token2)}
   988  		sub = f.Field.CType(nil)
   989  	case cc.DesignatorField2:
   990  		f = &CompLitField{Field: g.convertIdentOn(typ, d.Token)}
   991  		sub = f.Field.CType(nil)
   992  	default:
   993  		panic(d.Case.String() + " " + d.Position().String())
   994  	}
   995  	if list.DesignatorList == nil {
   996  		f.Value = val
   997  		return f
   998  	}
   999  	f2 := g.convertOneDesignator(sub, list.DesignatorList, val)
  1000  	f.Value = g.NewCCompLitExpr(sub, []*CompLitField{f2})
  1001  	return f
  1002  }
  1003  
  1004  func (g *translator) convertPostfixExpr(d *cc.PostfixExpression) Expr {
  1005  	switch d.Case {
  1006  	case cc.PostfixExpressionPrimary:
  1007  		return g.convertPriExpr(d.PrimaryExpression)
  1008  	case cc.PostfixExpressionIndex: // "x[y]"
  1009  		return g.NewCIndexExpr(
  1010  			g.convertPostfixExpr(d.PostfixExpression),
  1011  			g.convertExpr(d.Expression),
  1012  			g.convertTypeOper(d.Operand, d.Position()),
  1013  		)
  1014  	case cc.PostfixExpressionCall: // x([args])
  1015  		fnc := g.convertPostfixExpr(d.PostfixExpression)
  1016  		var args []Expr
  1017  		for it := d.ArgumentExpressionList; it != nil; it = it.ArgumentExpressionList {
  1018  			args = append(args, g.convertAssignExpr(it.AssignmentExpression))
  1019  		}
  1020  		return g.NewCCallExpr(g.ToFunc(fnc, ToFuncExpr(fnc.CType(nil))), args)
  1021  	case cc.PostfixExpressionPSelect: // x->y
  1022  		exp := g.convertPostfixExpr(d.PostfixExpression)
  1023  		if _, ok := exp.CType(nil).(types.ArrayType); ok { // pointer accesses might be an array
  1024  			return NewCSelectExpr(
  1025  				g.NewCIndexExpr(
  1026  					exp,
  1027  					cUintLit(0, 10), // index the first element
  1028  					g.convertTypeOper(d.Operand, d.Position()),
  1029  				), g.convertIdentOn(exp.CType(nil), d.Token2),
  1030  			)
  1031  		}
  1032  		return NewCSelectExpr(
  1033  			exp, g.convertIdentOn(exp.CType(nil), d.Token2),
  1034  		)
  1035  	case cc.PostfixExpressionSelect: // x.y
  1036  		exp := g.convertPostfixExpr(d.PostfixExpression)
  1037  		return NewCSelectExpr(
  1038  			exp, g.convertIdentOn(exp.CType(nil), d.Token2),
  1039  		)
  1040  	case cc.PostfixExpressionInc: // x++
  1041  		x := g.convertPostfixExpr(d.PostfixExpression)
  1042  		return g.NewCPostfixExpr(x, false)
  1043  	case cc.PostfixExpressionDec: // x--
  1044  		x := g.convertPostfixExpr(d.PostfixExpression)
  1045  		return g.NewCPostfixExpr(x, true)
  1046  	case cc.PostfixExpressionComplit:
  1047  		return g.convertInitList(
  1048  			g.convertType(IdentConfig{}, d.TypeName.Type(), d.Position()),
  1049  			d.InitializerList,
  1050  		)
  1051  	default:
  1052  		panic(d.Case.String() + " " + d.Position().String())
  1053  	}
  1054  }
  1055  
  1056  func (g *translator) convertCastExpr(d *cc.CastExpression) Expr {
  1057  	switch d.Case {
  1058  	case cc.CastExpressionUnary:
  1059  		return g.convertUnaryExpr(d.UnaryExpression)
  1060  	case cc.CastExpressionCast:
  1061  		x := g.convertCastExpr(d.CastExpression)
  1062  		if k := d.Operand.Type().Kind(); k == cc.Invalid || k == cc.Void {
  1063  			return x
  1064  		}
  1065  		return g.cCast(
  1066  			g.convertTypeOper(d.Operand, d.Position()),
  1067  			x,
  1068  		)
  1069  	default:
  1070  		panic(d.Case.String())
  1071  	}
  1072  }
  1073  
  1074  func (g *translator) convertUnaryExpr(d *cc.UnaryExpression) Expr {
  1075  	switch d.Case {
  1076  	case cc.UnaryExpressionPostfix:
  1077  		return g.convertPostfixExpr(d.PostfixExpression)
  1078  	case cc.UnaryExpressionInc: // ++x
  1079  		x := g.convertUnaryExpr(d.UnaryExpression)
  1080  		return g.NewCPrefixExpr(x, false)
  1081  	case cc.UnaryExpressionDec: // --x
  1082  		x := g.convertUnaryExpr(d.UnaryExpression)
  1083  		return g.NewCPrefixExpr(x, true)
  1084  	case cc.UnaryExpressionSizeofExpr: // sizeof x
  1085  		return g.NewCUnaryExprT(
  1086  			UnarySizeof,
  1087  			g.convertUnaryExpr(d.UnaryExpression),
  1088  			g.convertTypeOper(d.Operand, d.Position()),
  1089  		)
  1090  	case cc.UnaryExpressionSizeofType: // sizeof tp
  1091  		return g.SizeofT(
  1092  			g.convertType(IdentConfig{}, d.TypeName.Type(), d.Position()),
  1093  			nil,
  1094  		)
  1095  	case cc.UnaryExpressionAlignofType: // alignof tp
  1096  		return g.AlignofT(
  1097  			g.convertType(IdentConfig{}, d.TypeName.Type(), d.Position()),
  1098  			nil,
  1099  		)
  1100  	}
  1101  	var op UnaryOp
  1102  	switch d.Case {
  1103  	case cc.UnaryExpressionAddrof: // &x
  1104  		x := g.convertCastExpr(d.CastExpression)
  1105  		return g.cAddr(x)
  1106  	case cc.UnaryExpressionDeref: // *x
  1107  		x := g.convertCastExpr(d.CastExpression)
  1108  		typ := g.convertTypeOper(d.Operand, d.Position())
  1109  		return g.cDerefT(x, typ)
  1110  	case cc.UnaryExpressionPlus: // +x
  1111  		op = UnaryPlus
  1112  	case cc.UnaryExpressionMinus: // -x
  1113  		op = UnaryMinus
  1114  	case cc.UnaryExpressionCpl: // ~x
  1115  		op = UnaryXor
  1116  	case cc.UnaryExpressionNot: // !x
  1117  		x := g.convertCastExpr(d.CastExpression)
  1118  		return g.cNot(x)
  1119  	default:
  1120  		panic(d.Case.String())
  1121  	}
  1122  	x := g.convertCastExpr(d.CastExpression)
  1123  	if d.Operand == nil {
  1124  		return g.NewCUnaryExpr(
  1125  			op, x,
  1126  		)
  1127  	}
  1128  	return g.NewCUnaryExprT(
  1129  		op, x,
  1130  		g.convertTypeOper(d.Operand, d.Position()),
  1131  	)
  1132  }
  1133  
  1134  func (g *translator) convertConstExpr(d *cc.ConstantExpression) Expr {
  1135  	return g.convertCondExpr(d.ConditionalExpression)
  1136  }
  1137  
  1138  func (g *translator) convertAssignExpr(d *cc.AssignmentExpression) Expr {
  1139  	switch d.Case {
  1140  	case cc.AssignmentExpressionCond:
  1141  		return g.convertCondExpr(d.ConditionalExpression)
  1142  	}
  1143  	x := g.convertUnaryExpr(d.UnaryExpression)
  1144  	y := g.convertAssignExpr(d.AssignmentExpression)
  1145  	var op BinaryOp
  1146  	switch d.Case {
  1147  	case cc.AssignmentExpressionAssign:
  1148  		op = ""
  1149  	case cc.AssignmentExpressionMul:
  1150  		op = BinOpMult
  1151  	case cc.AssignmentExpressionDiv:
  1152  		op = BinOpDiv
  1153  	case cc.AssignmentExpressionMod:
  1154  		op = BinOpMod
  1155  	case cc.AssignmentExpressionAdd:
  1156  		op = BinOpAdd
  1157  	case cc.AssignmentExpressionSub:
  1158  		op = BinOpSub
  1159  	case cc.AssignmentExpressionLsh:
  1160  		op = BinOpLsh
  1161  	case cc.AssignmentExpressionRsh:
  1162  		op = BinOpRsh
  1163  	case cc.AssignmentExpressionAnd:
  1164  		op = BinOpBitAnd
  1165  	case cc.AssignmentExpressionXor:
  1166  		op = BinOpBitXor
  1167  	case cc.AssignmentExpressionOr:
  1168  		op = BinOpBitOr
  1169  	default:
  1170  		panic(d.Case.String())
  1171  	}
  1172  	return g.NewCAssignExpr(
  1173  		x, op, y,
  1174  	)
  1175  }
  1176  
  1177  func (g *translator) convertLabelStmt(st *cc.LabeledStatement) []CStmt {
  1178  	switch st.Case {
  1179  	case cc.LabeledStatementLabel: // label:
  1180  		stmts := g.convertStmt(st.Statement)
  1181  		return append([]CStmt{
  1182  			&CLabelStmt{Label: st.Token.Value.String()},
  1183  		}, stmts...)
  1184  	case cc.LabeledStatementCaseLabel: // case xxx:
  1185  		return []CStmt{
  1186  			g.NewCaseStmt(
  1187  				g.convertConstExpr(st.ConstantExpression),
  1188  				g.convertStmt(st.Statement)...,
  1189  			),
  1190  		}
  1191  	case cc.LabeledStatementDefault: // default:
  1192  		return []CStmt{
  1193  			g.NewCaseStmt(
  1194  				nil,
  1195  				g.convertStmt(st.Statement)...,
  1196  			),
  1197  		}
  1198  	default:
  1199  		panic(st.Case.String())
  1200  	}
  1201  }
  1202  
  1203  func (g *translator) convertExprStmt(st *cc.ExpressionStatement) []CStmt {
  1204  	var exprs []*cc.AssignmentExpression
  1205  	for e := st.Expression; e != nil; e = e.Expression {
  1206  		exprs = append(exprs, e.AssignmentExpression)
  1207  	}
  1208  	var stmts []CStmt
  1209  	for i := len(exprs) - 1; i >= 0; i-- {
  1210  		stmts = append(stmts, NewCExprStmt(g.convertAssignExpr(exprs[i]))...)
  1211  	}
  1212  	return stmts
  1213  }
  1214  
  1215  func (g *translator) convertSelStmt(st *cc.SelectionStatement) []CStmt {
  1216  	switch st.Case {
  1217  	case cc.SelectionStatementIf: // if (x)
  1218  		cond := g.convertExpr(st.Expression)
  1219  		return []CStmt{
  1220  			g.NewCIfStmt(
  1221  				g.ToBool(cond),
  1222  				[]CStmt{g.convertBlockStmt(st.Statement)},
  1223  				nil,
  1224  			),
  1225  		}
  1226  	case cc.SelectionStatementIfElse: // if (x) else
  1227  		cond := g.convertExpr(st.Expression)
  1228  		return []CStmt{
  1229  			g.NewCIfStmt(
  1230  				g.ToBool(cond),
  1231  				[]CStmt{g.convertBlockStmt(st.Statement)},
  1232  				g.toElseStmt(g.convertOneStmt(st.Statement2)),
  1233  			),
  1234  		}
  1235  	case cc.SelectionStatementSwitch: // switch (x)
  1236  		return []CStmt{g.NewCSwitchStmt(
  1237  			g.convertExpr(st.Expression),
  1238  			[]CStmt{g.convertBlockStmt(st.Statement)},
  1239  		)}
  1240  	default:
  1241  		panic(st.Case.String())
  1242  	}
  1243  }
  1244  
  1245  func (g *translator) convertIterStmt(st *cc.IterationStatement) []CStmt {
  1246  	switch st.Case {
  1247  	case cc.IterationStatementWhile:
  1248  		x := g.convertExprOpt(st.Expression)
  1249  		var cond BoolExpr
  1250  		if x != nil {
  1251  			cond = g.ToBool(x)
  1252  		}
  1253  		return []CStmt{
  1254  			g.NewCForStmt(
  1255  				nil,
  1256  				cond,
  1257  				nil,
  1258  				[]CStmt{g.convertBlockStmt(st.Statement)},
  1259  			),
  1260  		}
  1261  	case cc.IterationStatementDo:
  1262  		return []CStmt{
  1263  			g.NewCDoWhileStmt(
  1264  				g.convertExprOpt(st.Expression),
  1265  				[]CStmt{g.convertBlockStmt(st.Statement)},
  1266  			),
  1267  		}
  1268  	case cc.IterationStatementFor:
  1269  		x := g.convertExprOpt(st.Expression2)
  1270  		var cond BoolExpr
  1271  		if x != nil {
  1272  			cond = g.ToBool(x)
  1273  		}
  1274  		return []CStmt{
  1275  			g.NewCForStmt(
  1276  				g.convertExprOpt(st.Expression),
  1277  				cond,
  1278  				g.convertExprOpt(st.Expression3),
  1279  				[]CStmt{g.convertBlockStmt(st.Statement)},
  1280  			),
  1281  		}
  1282  	case cc.IterationStatementForDecl:
  1283  		var cur *CVarDecl
  1284  		for _, d := range g.convertDecl(st.Declaration) {
  1285  			d := d.(*CVarDecl)
  1286  			if cur == nil {
  1287  				cur = d
  1288  				continue
  1289  			}
  1290  			if !types.Same(cur.Type, d.Type) {
  1291  				panic(fmt.Errorf("different types in a declaration: %v vs %v (%s)", cur.Type, d.Type, st.Position()))
  1292  			}
  1293  			cur.Single = true
  1294  			n1, n2 := len(cur.Names), len(d.Names)
  1295  			cur.Names = append(cur.Names, d.Names...)
  1296  			if len(cur.Inits) == 0 && len(d.Inits) == 0 {
  1297  				continue
  1298  			}
  1299  			if len(cur.Inits) == 0 {
  1300  				cur.Inits = make([]Expr, n1, n1+n2)
  1301  			}
  1302  			if len(d.Inits) == 0 {
  1303  				cur.Inits = append(cur.Inits, make([]Expr, n2)...)
  1304  			} else {
  1305  				cur.Inits = append(cur.Inits, d.Inits...)
  1306  			}
  1307  		}
  1308  		x := g.convertExprOpt(st.Expression)
  1309  		var cond BoolExpr
  1310  		if x != nil {
  1311  			cond = g.ToBool(x)
  1312  		}
  1313  		return []CStmt{
  1314  			g.NewCForDeclStmt(
  1315  				cur,
  1316  				cond,
  1317  				g.convertExprOpt(st.Expression2),
  1318  				[]CStmt{g.convertBlockStmt(st.Statement)},
  1319  			),
  1320  		}
  1321  	default:
  1322  		panic(st.Case.String() + " " + st.Position().String())
  1323  	}
  1324  }
  1325  
  1326  func (g *translator) convertJumpStmt(st *cc.JumpStatement) []CStmt {
  1327  	switch st.Case {
  1328  	case cc.JumpStatementGoto: // goto x
  1329  		return []CStmt{
  1330  			&CGotoStmt{Label: st.Token2.Value.String()},
  1331  		}
  1332  	case cc.JumpStatementContinue: // continue
  1333  		return []CStmt{
  1334  			&CContinueStmt{},
  1335  		}
  1336  	case cc.JumpStatementBreak: // break
  1337  		return []CStmt{
  1338  			&CBreakStmt{},
  1339  		}
  1340  	case cc.JumpStatementReturn: // return
  1341  		return g.NewReturnStmt(
  1342  			g.convertExprOpt(st.Expression),
  1343  			nil,
  1344  		)
  1345  	default:
  1346  		panic(st.Case.String())
  1347  	}
  1348  }
  1349  
  1350  func (g *translator) convertAsmStmt(d *cc.AsmStatement) []CStmt {
  1351  	// TODO
  1352  	return NewCExprStmt(&CAsmExpr{e: g.env.Env, typ: types.UnkT(1)})
  1353  }
  1354  
  1355  func (g *translator) convertStmt(d *cc.Statement) []CStmt {
  1356  	switch d.Case {
  1357  	case cc.StatementLabeled:
  1358  		return g.convertLabelStmt(d.LabeledStatement)
  1359  	case cc.StatementCompound:
  1360  		return g.convertCompStmt(d.CompoundStatement)
  1361  	case cc.StatementExpr:
  1362  		return g.convertExprStmt(d.ExpressionStatement)
  1363  	case cc.StatementSelection:
  1364  		return g.convertSelStmt(d.SelectionStatement)
  1365  	case cc.StatementIteration:
  1366  		return g.convertIterStmt(d.IterationStatement)
  1367  	case cc.StatementJump:
  1368  		return g.convertJumpStmt(d.JumpStatement)
  1369  	case cc.StatementAsm:
  1370  		return g.convertAsmStmt(d.AsmStatement)
  1371  	default:
  1372  		panic(d.Case.String())
  1373  	}
  1374  }
  1375  
  1376  func (g *translator) convertOneStmt(d *cc.Statement) CStmt {
  1377  	stmts := g.convertStmt(d)
  1378  	if len(stmts) == 1 {
  1379  		return stmts[0]
  1380  	}
  1381  	return g.NewCBlock(stmts...)
  1382  }
  1383  
  1384  func (g *translator) convertBlockStmt(d *cc.Statement) *BlockStmt {
  1385  	stmts := g.convertStmt(d)
  1386  	if len(stmts) == 1 {
  1387  		if b, ok := stmts[0].(*BlockStmt); ok {
  1388  			return b
  1389  		}
  1390  	}
  1391  	return g.NewCBlock(stmts...)
  1392  }