github.com/gotranspile/cxgo@v0.3.7/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), 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)
   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)
   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().IsUntyped() {
   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)
   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.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  			var init Expr
   500  			if id.Initializer != nil && inCur {
   501  				if isTypedef {
   502  					panic("init in typedef: " + id.Position().String())
   503  				}
   504  				init = g.convertInitExpr(id.Initializer)
   505  			}
   506  			if isConst && propagateConst(vt) {
   507  				isConst = false
   508  			}
   509  			if isTypedef {
   510  				if enumSpec != nil {
   511  					continue
   512  				}
   513  				nt, ok := vt.(types.Named)
   514  				// TODO: this case is "too smart", we already handle those kind of double typedefs on a lower level
   515  				if !ok || nt.Name().Name != dd.Name().String() {
   516  					// we don't call a *From version of the method here because dd.Type() is an underlying type,
   517  					// not a typedef type
   518  					if ok && !strings.HasPrefix(nt.Name().Name, "_cxgo_") {
   519  						decls = append(decls, &CTypeDef{nt})
   520  					}
   521  					if vt == nil {
   522  						panic("TODO: typedef of void? " + id.Position().String())
   523  					}
   524  					nt = g.newOrFindNamedTypedef(dd.Name().String(), func() types.Type {
   525  						return vt
   526  					})
   527  					if nt == nil {
   528  						// typedef suppressed
   529  						skipped++
   530  						continue
   531  					}
   532  				}
   533  				decls = append(decls, &CTypeDef{nt})
   534  				continue
   535  			}
   536  			name := g.convertIdentWith(dd.NameTok().String(), vt, dd)
   537  			isDecl := false
   538  			for di := dd.DirectDeclarator; di != nil; di = di.DirectDeclarator {
   539  				if di.Case == cc.DirectDeclaratorDecl {
   540  					isDecl = true
   541  					break
   542  				}
   543  			}
   544  			if !isDecl && !isForward {
   545  				if nt, ok := typeSpec.(types.Named); ok {
   546  					decls = append(decls, &CTypeDef{nt})
   547  				}
   548  			}
   549  			if ft, ok := vt.(*types.FuncType); ok && !isDecl {
   550  				// forward declaration
   551  				if l, id, ok := g.tenv.LibIdentByName(name.Name); ok && id.CType(nil).Kind().IsFunc() {
   552  					// forward declaration of stdlib function
   553  					// we must first load the corresponding library to the real env
   554  					l, ok = g.env.GetLibrary(l.Name)
   555  					if !ok {
   556  						panic("cannot load stdlib")
   557  					}
   558  					id, ok = l.Idents[name.Name]
   559  					if !ok {
   560  						panic("cannot find stdlib ident")
   561  					}
   562  					g.replaceIdentWith(id, dd)
   563  					skipped++
   564  				} else if g.conf.ForwardDecl {
   565  					decls = append(decls, &CFuncDecl{
   566  						Name: name.Ident,
   567  						Type: ft,
   568  						Body: nil,
   569  					})
   570  				} else {
   571  					skipped++
   572  				}
   573  			} else {
   574  				decls = decls[:len(decls)-added]
   575  				if !isExtern {
   576  					var inits []Expr
   577  					if init != nil {
   578  						inits = []Expr{init}
   579  					}
   580  					decls = append(decls, &CVarDecl{
   581  						// There is no real const in C
   582  						Const: false, // Const: isConst,
   583  						CVarSpec: CVarSpec{
   584  							g:     g,
   585  							Type:  vt,
   586  							Names: []*types.Ident{name.Ident},
   587  							Inits: inits,
   588  						},
   589  					})
   590  				} else {
   591  					skipped++
   592  				}
   593  			}
   594  		default:
   595  			panic(id.Case.String())
   596  		}
   597  	}
   598  	if !inCur {
   599  		return nil
   600  	}
   601  	if len(decls) == 0 && skipped == 0 {
   602  		panic("no declarations converted: " + d.Position().String())
   603  	}
   604  	return decls
   605  }
   606  
   607  func (g *translator) convertCompStmt(d *cc.CompoundStatement) []CStmt {
   608  	var stmts []CStmt
   609  	for it := d.BlockItemList; it != nil; it = it.BlockItemList {
   610  		st := it.BlockItem
   611  		switch st.Case {
   612  		case cc.BlockItemDecl:
   613  			for _, dec := range g.convertDecl(st.Declaration) {
   614  				stmts = append(stmts, g.NewCDeclStmt(dec)...)
   615  			}
   616  		case cc.BlockItemStmt:
   617  			stmts = append(stmts, g.convertStmt(st.Statement)...)
   618  		default:
   619  			panic(st.Case.String())
   620  		}
   621  	}
   622  	// TODO: shouldn't it return statements without a block? or call an optimizing version of block constructor?
   623  	return []CStmt{g.newBlockStmt(stmts...)}
   624  }
   625  
   626  func (g *translator) convertCompBlockStmt(d *cc.CompoundStatement) *BlockStmt {
   627  	stmts := g.convertCompStmt(d)
   628  	if len(stmts) == 1 {
   629  		if b, ok := stmts[0].(*BlockStmt); ok {
   630  			return b
   631  		}
   632  	}
   633  	// TODO: shouldn't it call a version that applies optimizations?
   634  	return g.newBlockStmt(stmts...)
   635  }
   636  
   637  func (g *translator) convertExpr(d *cc.Expression) Expr {
   638  	if d.Expression == nil {
   639  		return g.convertAssignExpr(d.AssignmentExpression)
   640  	}
   641  	var exprs []*cc.AssignmentExpression
   642  	for ; d != nil; d = d.Expression {
   643  		exprs = append(exprs, d.AssignmentExpression)
   644  	}
   645  	var m []Expr
   646  	for i := len(exprs) - 1; i >= 0; i-- {
   647  		m = append(m, g.convertAssignExpr(exprs[i]))
   648  	}
   649  	return g.NewCMultiExpr(m...)
   650  }
   651  
   652  func (g *translator) convertExprOpt(d *cc.Expression) Expr {
   653  	if d == nil {
   654  		return nil
   655  	}
   656  	return g.convertExpr(d)
   657  }
   658  
   659  func (g *translator) convertMulExpr(d *cc.MultiplicativeExpression) Expr {
   660  	switch d.Case {
   661  	case cc.MultiplicativeExpressionCast:
   662  		return g.convertCastExpr(d.CastExpression)
   663  	}
   664  	x := g.convertMulExpr(d.MultiplicativeExpression)
   665  	y := g.convertCastExpr(d.CastExpression)
   666  	var op BinaryOp
   667  	switch d.Case {
   668  	case cc.MultiplicativeExpressionMul:
   669  		op = BinOpMult
   670  	case cc.MultiplicativeExpressionDiv:
   671  		op = BinOpDiv
   672  	case cc.MultiplicativeExpressionMod:
   673  		op = BinOpMod
   674  	default:
   675  		panic(d.Case.String())
   676  	}
   677  	return g.NewCBinaryExprT(
   678  		x, op, y,
   679  		g.convertTypeOper(d.Operand, d.Position()),
   680  	)
   681  }
   682  
   683  func (g *translator) convertAddExpr(d *cc.AdditiveExpression) Expr {
   684  	switch d.Case {
   685  	case cc.AdditiveExpressionMul:
   686  		return g.convertMulExpr(d.MultiplicativeExpression)
   687  	}
   688  	x := g.convertAddExpr(d.AdditiveExpression)
   689  	y := g.convertMulExpr(d.MultiplicativeExpression)
   690  	var op BinaryOp
   691  	switch d.Case {
   692  	case cc.AdditiveExpressionAdd:
   693  		op = BinOpAdd
   694  	case cc.AdditiveExpressionSub:
   695  		op = BinOpSub
   696  	default:
   697  		panic(d.Case.String())
   698  	}
   699  	return g.NewCBinaryExprT(
   700  		x, op, y,
   701  		g.convertTypeOper(d.Operand, d.Position()),
   702  	)
   703  }
   704  
   705  func (g *translator) convertShiftExpr(d *cc.ShiftExpression) Expr {
   706  	switch d.Case {
   707  	case cc.ShiftExpressionAdd:
   708  		return g.convertAddExpr(d.AdditiveExpression)
   709  	}
   710  	x := g.convertShiftExpr(d.ShiftExpression)
   711  	y := g.convertAddExpr(d.AdditiveExpression)
   712  	var op BinaryOp
   713  	switch d.Case {
   714  	case cc.ShiftExpressionLsh:
   715  		op = BinOpLsh
   716  	case cc.ShiftExpressionRsh:
   717  		op = BinOpRsh
   718  	default:
   719  		panic(d.Case.String())
   720  	}
   721  	return g.NewCBinaryExprT(
   722  		x, op, y,
   723  		g.convertTypeOper(d.Operand, d.Position()),
   724  	)
   725  }
   726  
   727  func (g *translator) convertRelExpr(d *cc.RelationalExpression) Expr {
   728  	switch d.Case {
   729  	case cc.RelationalExpressionShift:
   730  		return g.convertShiftExpr(d.ShiftExpression)
   731  	}
   732  	x := g.convertRelExpr(d.RelationalExpression)
   733  	y := g.convertShiftExpr(d.ShiftExpression)
   734  	var op ComparisonOp
   735  	switch d.Case {
   736  	case cc.RelationalExpressionLt:
   737  		op = BinOpLt
   738  	case cc.RelationalExpressionGt:
   739  		op = BinOpGt
   740  	case cc.RelationalExpressionLeq:
   741  		op = BinOpLte
   742  	case cc.RelationalExpressionGeq:
   743  		op = BinOpGte
   744  	default:
   745  		panic(d.Case.String())
   746  	}
   747  	return g.Compare(x, op, y)
   748  }
   749  
   750  func (g *translator) convertEqExpr(d *cc.EqualityExpression) Expr {
   751  	switch d.Case {
   752  	case cc.EqualityExpressionRel:
   753  		return g.convertRelExpr(d.RelationalExpression)
   754  	}
   755  	x := g.convertEqExpr(d.EqualityExpression)
   756  	y := g.convertRelExpr(d.RelationalExpression)
   757  	var op ComparisonOp
   758  	switch d.Case {
   759  	case cc.EqualityExpressionEq:
   760  		op = BinOpEq
   761  	case cc.EqualityExpressionNeq:
   762  		op = BinOpNeq
   763  	default:
   764  		panic(d.Case.String())
   765  	}
   766  	return g.Compare(x, op, y)
   767  }
   768  
   769  func (g *translator) convertAndExpr(d *cc.AndExpression) Expr {
   770  	switch d.Case {
   771  	case cc.AndExpressionEq:
   772  		return g.convertEqExpr(d.EqualityExpression)
   773  	case cc.AndExpressionAnd:
   774  		x := g.convertAndExpr(d.AndExpression)
   775  		y := g.convertEqExpr(d.EqualityExpression)
   776  		return g.NewCBinaryExprT(
   777  			x, BinOpBitAnd, y,
   778  			g.convertTypeOper(d.Operand, d.Position()),
   779  		)
   780  	default:
   781  		panic(d.Case.String())
   782  	}
   783  }
   784  
   785  func (g *translator) convertLOrExcExpr(d *cc.ExclusiveOrExpression) Expr {
   786  	switch d.Case {
   787  	case cc.ExclusiveOrExpressionAnd:
   788  		return g.convertAndExpr(d.AndExpression)
   789  	case cc.ExclusiveOrExpressionXor:
   790  		x := g.convertLOrExcExpr(d.ExclusiveOrExpression)
   791  		y := g.convertAndExpr(d.AndExpression)
   792  		return g.NewCBinaryExprT(
   793  			x, BinOpBitXor, y,
   794  			g.convertTypeOper(d.Operand, d.Position()),
   795  		)
   796  	default:
   797  		panic(d.Case.String())
   798  	}
   799  }
   800  
   801  func (g *translator) convertLOrIncExpr(d *cc.InclusiveOrExpression) Expr {
   802  	switch d.Case {
   803  	case cc.InclusiveOrExpressionXor:
   804  		return g.convertLOrExcExpr(d.ExclusiveOrExpression)
   805  	case cc.InclusiveOrExpressionOr:
   806  		x := g.convertLOrIncExpr(d.InclusiveOrExpression)
   807  		y := g.convertLOrExcExpr(d.ExclusiveOrExpression)
   808  		return g.NewCBinaryExprT(
   809  			x, BinOpBitOr, y,
   810  			g.convertTypeOper(d.Operand, d.Position()),
   811  		)
   812  	default:
   813  		panic(d.Case.String())
   814  	}
   815  }
   816  
   817  func (g *translator) convertLAndExpr(d *cc.LogicalAndExpression) Expr {
   818  	switch d.Case {
   819  	case cc.LogicalAndExpressionOr:
   820  		return g.convertLOrIncExpr(d.InclusiveOrExpression)
   821  	case cc.LogicalAndExpressionLAnd:
   822  		x := g.convertLAndExpr(d.LogicalAndExpression)
   823  		y := g.convertLOrIncExpr(d.InclusiveOrExpression)
   824  		return And(g.ToBool(x), g.ToBool(y))
   825  	default:
   826  		panic(d.Case.String())
   827  	}
   828  }
   829  
   830  func (g *translator) convertLOrExpr(d *cc.LogicalOrExpression) Expr {
   831  	switch d.Case {
   832  	case cc.LogicalOrExpressionLAnd:
   833  		return g.convertLAndExpr(d.LogicalAndExpression)
   834  	case cc.LogicalOrExpressionLOr:
   835  		x := g.convertLOrExpr(d.LogicalOrExpression)
   836  		y := g.convertLAndExpr(d.LogicalAndExpression)
   837  		return Or(g.ToBool(x), g.ToBool(y))
   838  	default:
   839  		panic(d.Case.String())
   840  	}
   841  }
   842  
   843  func (g *translator) convertCondExpr(d *cc.ConditionalExpression) Expr {
   844  	switch d.Case {
   845  	case cc.ConditionalExpressionLOr:
   846  		return g.convertLOrExpr(d.LogicalOrExpression)
   847  	case cc.ConditionalExpressionCond:
   848  		cond := g.convertLOrExpr(d.LogicalOrExpression)
   849  		return g.NewCTernaryExpr(
   850  			g.ToBool(cond),
   851  			g.convertExpr(d.Expression),
   852  			g.convertCondExpr(d.ConditionalExpression),
   853  		)
   854  	default:
   855  		panic(d.Case.String())
   856  	}
   857  }
   858  
   859  func (g *translator) convertPriExpr(d *cc.PrimaryExpression) Expr {
   860  	switch d.Case {
   861  	case cc.PrimaryExpressionIdent: // x
   862  		if d.Token.String() == "asm" {
   863  			return &CAsmExpr{e: g.env.Env}
   864  		}
   865  		if d.Operand == nil {
   866  			panic(ErrorfWithPos(d.Position(), "empty operand for %q", d.Token.String()))
   867  		}
   868  		return g.convertIdent(d.ResolvedIn(), d.Token, g.convertTypeOper(d.Operand, d.Position()))
   869  	case cc.PrimaryExpressionEnum: // X
   870  		return g.convertIdent(d.ResolvedIn(), d.Token, g.convertTypeOper(d.Operand, d.Position()))
   871  	case cc.PrimaryExpressionInt: // 1
   872  		fnc := func() Expr {
   873  			v, err := parseCIntLit(d.Token.String())
   874  			if err != nil {
   875  				panic(err)
   876  			}
   877  			return v
   878  		}
   879  		if m := d.Token.Macro(); m != 0 {
   880  			return g.convMacro(m.String(), fnc)
   881  		}
   882  		return fnc()
   883  	case cc.PrimaryExpressionFloat: // 0.0
   884  		fnc := func() Expr {
   885  			v, err := parseCFloatLit(d.Token.String())
   886  			if err != nil {
   887  				panic(err)
   888  			}
   889  			if d.Operand == nil {
   890  				return v
   891  			}
   892  			return g.cCast(
   893  				g.convertTypeOper(d.Operand, d.Position()),
   894  				v,
   895  			)
   896  		}
   897  		if m := d.Token.Macro(); m != 0 {
   898  			return g.convMacro(m.String(), fnc)
   899  		}
   900  		return fnc()
   901  	case cc.PrimaryExpressionChar: // 'x'
   902  		fnc := func() Expr {
   903  			return cLitT(
   904  				d.Token.String(), CLitChar,
   905  				g.convertTypeOper(d.Operand, d.Position()),
   906  			)
   907  		}
   908  		if m := d.Token.Macro(); m != 0 {
   909  			return g.convMacro(m.String(), fnc)
   910  		}
   911  		return fnc()
   912  	case cc.PrimaryExpressionLChar: // 'x'
   913  		fnc := func() Expr {
   914  			return cLitT(
   915  				d.Token.String(), CLitWChar,
   916  				g.convertTypeOper(d.Operand, d.Position()),
   917  			)
   918  		}
   919  		if m := d.Token.Macro(); m != 0 {
   920  			return g.convMacro(m.String(), fnc)
   921  		}
   922  		return fnc()
   923  	case cc.PrimaryExpressionString: // "x"
   924  		fnc := func() Expr {
   925  			v, err := g.parseCStringLit(d.Token.String())
   926  			if err != nil {
   927  				panic(err)
   928  			}
   929  			return v
   930  		}
   931  		if m := d.Token.Macro(); m != 0 {
   932  			return g.convMacro(m.String(), fnc)
   933  		}
   934  		return fnc()
   935  	case cc.PrimaryExpressionLString: // L"x"
   936  		fnc := func() Expr {
   937  			v, err := g.parseCWStringLit(d.Token.String())
   938  			if err != nil {
   939  				panic(err)
   940  			}
   941  			return v
   942  		}
   943  		if m := d.Token.Macro(); m != 0 {
   944  			return g.convMacro(m.String(), fnc)
   945  		}
   946  		return fnc()
   947  	case cc.PrimaryExpressionExpr: // "(x)"
   948  		e := g.convertExpr(d.Expression)
   949  		return cParen(e)
   950  	case cc.PrimaryExpressionStmt: // "({...; x})"
   951  		stmt := g.convertCompStmt(d.CompoundStatement)
   952  		if len(stmt) != 1 {
   953  			panic("TODO")
   954  		}
   955  		stmt = stmt[0].(*BlockStmt).Stmts
   956  		last, ok := stmt[len(stmt)-1].(*CExprStmt)
   957  		if !ok {
   958  			// let it cause a compilation error in Go
   959  			return &CallExpr{
   960  				Fun: g.NewFuncLit(g.env.FuncTT(g.env.DefIntT()), stmt...),
   961  			}
   962  		}
   963  		typ := last.Expr.CType(nil)
   964  		stmt = append(stmt[:len(stmt)-1], g.NewReturnStmt(last.Expr, typ)...)
   965  		return &CallExpr{
   966  			Fun: g.NewFuncLit(g.env.FuncTT(typ), stmt...),
   967  		}
   968  	default:
   969  		panic(fmt.Errorf("%v (%v)", d.Case, d.Position()))
   970  	}
   971  }
   972  
   973  func (g *translator) convertOneDesignator(typ types.Type, list *cc.DesignatorList, val Expr) *CompLitField {
   974  	d := list.Designator
   975  	var (
   976  		f   *CompLitField
   977  		sub types.Type
   978  	)
   979  	switch d.Case {
   980  	case cc.DesignatorIndex:
   981  		f = &CompLitField{Index: g.convertConstExpr(d.ConstantExpression)}
   982  		sub = typ.(types.ArrayType).Elem()
   983  	case cc.DesignatorField:
   984  		f = &CompLitField{Field: g.convertIdentOn(typ, d.Token2)}
   985  		sub = f.Field.CType(nil)
   986  	case cc.DesignatorField2:
   987  		f = &CompLitField{Field: g.convertIdentOn(typ, d.Token)}
   988  		sub = f.Field.CType(nil)
   989  	default:
   990  		panic(d.Case.String() + " " + d.Position().String())
   991  	}
   992  	if list.DesignatorList == nil {
   993  		f.Value = val
   994  		return f
   995  	}
   996  	f2 := g.convertOneDesignator(sub, list.DesignatorList, val)
   997  	f.Value = g.NewCCompLitExpr(sub, []*CompLitField{f2})
   998  	return f
   999  }
  1000  
  1001  func (g *translator) convertPostfixExpr(d *cc.PostfixExpression) Expr {
  1002  	switch d.Case {
  1003  	case cc.PostfixExpressionPrimary:
  1004  		return g.convertPriExpr(d.PrimaryExpression)
  1005  	case cc.PostfixExpressionIndex: // "x[y]"
  1006  		return g.NewCIndexExpr(
  1007  			g.convertPostfixExpr(d.PostfixExpression),
  1008  			g.convertExpr(d.Expression),
  1009  			g.convertTypeOper(d.Operand, d.Position()),
  1010  		)
  1011  	case cc.PostfixExpressionCall: // x([args])
  1012  		fnc := g.convertPostfixExpr(d.PostfixExpression)
  1013  		var args []Expr
  1014  		for it := d.ArgumentExpressionList; it != nil; it = it.ArgumentExpressionList {
  1015  			args = append(args, g.convertAssignExpr(it.AssignmentExpression))
  1016  		}
  1017  		return g.NewCCallExpr(g.ToFunc(fnc, ToFuncExpr(fnc.CType(nil))), args)
  1018  	case cc.PostfixExpressionPSelect: // x->y
  1019  		exp := g.convertPostfixExpr(d.PostfixExpression)
  1020  		if _, ok := exp.CType(nil).(types.ArrayType); ok { // pointer accesses might be an array
  1021  			return NewCSelectExpr(
  1022  				g.NewCIndexExpr(
  1023  					exp,
  1024  					cUintLit(0), // index the first element
  1025  					g.convertTypeOper(d.Operand, d.Position()),
  1026  				), g.convertIdentOn(exp.CType(nil), d.Token2),
  1027  			)
  1028  		}
  1029  		return NewCSelectExpr(
  1030  			exp, g.convertIdentOn(exp.CType(nil), d.Token2),
  1031  		)
  1032  	case cc.PostfixExpressionSelect: // x.y
  1033  		exp := g.convertPostfixExpr(d.PostfixExpression)
  1034  		return NewCSelectExpr(
  1035  			exp, g.convertIdentOn(exp.CType(nil), d.Token2),
  1036  		)
  1037  	case cc.PostfixExpressionInc: // x++
  1038  		x := g.convertPostfixExpr(d.PostfixExpression)
  1039  		return g.NewCPostfixExpr(x, false)
  1040  	case cc.PostfixExpressionDec: // x--
  1041  		x := g.convertPostfixExpr(d.PostfixExpression)
  1042  		return g.NewCPostfixExpr(x, true)
  1043  	case cc.PostfixExpressionComplit:
  1044  		return g.convertInitList(
  1045  			g.convertType(IdentConfig{}, d.TypeName.Type(), d.Position()),
  1046  			d.InitializerList,
  1047  		)
  1048  	default:
  1049  		panic(d.Case.String() + " " + d.Position().String())
  1050  	}
  1051  }
  1052  
  1053  func (g *translator) convertCastExpr(d *cc.CastExpression) Expr {
  1054  	switch d.Case {
  1055  	case cc.CastExpressionUnary:
  1056  		return g.convertUnaryExpr(d.UnaryExpression)
  1057  	case cc.CastExpressionCast:
  1058  		x := g.convertCastExpr(d.CastExpression)
  1059  		if k := d.Operand.Type().Kind(); k == cc.Invalid || k == cc.Void {
  1060  			return x
  1061  		}
  1062  		return g.cCast(
  1063  			g.convertTypeOper(d.Operand, d.Position()),
  1064  			x,
  1065  		)
  1066  	default:
  1067  		panic(d.Case.String())
  1068  	}
  1069  }
  1070  
  1071  func (g *translator) convertUnaryExpr(d *cc.UnaryExpression) Expr {
  1072  	switch d.Case {
  1073  	case cc.UnaryExpressionPostfix:
  1074  		return g.convertPostfixExpr(d.PostfixExpression)
  1075  	case cc.UnaryExpressionInc: // ++x
  1076  		x := g.convertUnaryExpr(d.UnaryExpression)
  1077  		return g.NewCPrefixExpr(x, false)
  1078  	case cc.UnaryExpressionDec: // --x
  1079  		x := g.convertUnaryExpr(d.UnaryExpression)
  1080  		return g.NewCPrefixExpr(x, true)
  1081  	case cc.UnaryExpressionSizeofExpr: // sizeof x
  1082  		return g.NewCUnaryExprT(
  1083  			UnarySizeof,
  1084  			g.convertUnaryExpr(d.UnaryExpression),
  1085  			g.convertTypeOper(d.Operand, d.Position()),
  1086  		)
  1087  	case cc.UnaryExpressionSizeofType: // sizeof tp
  1088  		return g.SizeofT(
  1089  			g.convertType(IdentConfig{}, d.TypeName.Type(), d.Position()),
  1090  			nil,
  1091  		)
  1092  	case cc.UnaryExpressionAlignofType: // alignof tp
  1093  		return g.AlignofT(
  1094  			g.convertType(IdentConfig{}, d.TypeName.Type(), d.Position()),
  1095  			nil,
  1096  		)
  1097  	}
  1098  	var op UnaryOp
  1099  	switch d.Case {
  1100  	case cc.UnaryExpressionAddrof: // &x
  1101  		x := g.convertCastExpr(d.CastExpression)
  1102  		return g.cAddr(x)
  1103  	case cc.UnaryExpressionDeref: // *x
  1104  		x := g.convertCastExpr(d.CastExpression)
  1105  		typ := g.convertTypeOper(d.Operand, d.Position())
  1106  		return g.cDerefT(x, typ)
  1107  	case cc.UnaryExpressionPlus: // +x
  1108  		op = UnaryPlus
  1109  	case cc.UnaryExpressionMinus: // -x
  1110  		op = UnaryMinus
  1111  	case cc.UnaryExpressionCpl: // ~x
  1112  		op = UnaryXor
  1113  	case cc.UnaryExpressionNot: // !x
  1114  		x := g.convertCastExpr(d.CastExpression)
  1115  		return g.cNot(x)
  1116  	default:
  1117  		panic(d.Case.String())
  1118  	}
  1119  	x := g.convertCastExpr(d.CastExpression)
  1120  	if d.Operand == nil {
  1121  		return g.NewCUnaryExpr(
  1122  			op, x,
  1123  		)
  1124  	}
  1125  	return g.NewCUnaryExprT(
  1126  		op, x,
  1127  		g.convertTypeOper(d.Operand, d.Position()),
  1128  	)
  1129  }
  1130  
  1131  func (g *translator) convertConstExpr(d *cc.ConstantExpression) Expr {
  1132  	return g.convertCondExpr(d.ConditionalExpression)
  1133  }
  1134  
  1135  func (g *translator) convertAssignExpr(d *cc.AssignmentExpression) Expr {
  1136  	switch d.Case {
  1137  	case cc.AssignmentExpressionCond:
  1138  		return g.convertCondExpr(d.ConditionalExpression)
  1139  	}
  1140  	x := g.convertUnaryExpr(d.UnaryExpression)
  1141  	y := g.convertAssignExpr(d.AssignmentExpression)
  1142  	var op BinaryOp
  1143  	switch d.Case {
  1144  	case cc.AssignmentExpressionAssign:
  1145  		op = ""
  1146  	case cc.AssignmentExpressionMul:
  1147  		op = BinOpMult
  1148  	case cc.AssignmentExpressionDiv:
  1149  		op = BinOpDiv
  1150  	case cc.AssignmentExpressionMod:
  1151  		op = BinOpMod
  1152  	case cc.AssignmentExpressionAdd:
  1153  		op = BinOpAdd
  1154  	case cc.AssignmentExpressionSub:
  1155  		op = BinOpSub
  1156  	case cc.AssignmentExpressionLsh:
  1157  		op = BinOpLsh
  1158  	case cc.AssignmentExpressionRsh:
  1159  		op = BinOpRsh
  1160  	case cc.AssignmentExpressionAnd:
  1161  		op = BinOpBitAnd
  1162  	case cc.AssignmentExpressionXor:
  1163  		op = BinOpBitXor
  1164  	case cc.AssignmentExpressionOr:
  1165  		op = BinOpBitOr
  1166  	default:
  1167  		panic(d.Case.String())
  1168  	}
  1169  	return g.NewCAssignExpr(
  1170  		x, op, y,
  1171  	)
  1172  }
  1173  
  1174  func (g *translator) convertLabelStmt(st *cc.LabeledStatement) []CStmt {
  1175  	switch st.Case {
  1176  	case cc.LabeledStatementLabel: // label:
  1177  		stmts := g.convertStmt(st.Statement)
  1178  		return append([]CStmt{
  1179  			&CLabelStmt{Label: st.Token.Value.String()},
  1180  		}, stmts...)
  1181  	case cc.LabeledStatementCaseLabel: // case xxx:
  1182  		return []CStmt{
  1183  			g.NewCaseStmt(
  1184  				g.convertConstExpr(st.ConstantExpression),
  1185  				g.convertStmt(st.Statement)...,
  1186  			),
  1187  		}
  1188  	case cc.LabeledStatementDefault: // default:
  1189  		return []CStmt{
  1190  			g.NewCaseStmt(
  1191  				nil,
  1192  				g.convertStmt(st.Statement)...,
  1193  			),
  1194  		}
  1195  	default:
  1196  		panic(st.Case.String())
  1197  	}
  1198  }
  1199  
  1200  func (g *translator) convertExprStmt(st *cc.ExpressionStatement) []CStmt {
  1201  	var exprs []*cc.AssignmentExpression
  1202  	for e := st.Expression; e != nil; e = e.Expression {
  1203  		exprs = append(exprs, e.AssignmentExpression)
  1204  	}
  1205  	var stmts []CStmt
  1206  	for i := len(exprs) - 1; i >= 0; i-- {
  1207  		stmts = append(stmts, NewCExprStmt(g.convertAssignExpr(exprs[i]))...)
  1208  	}
  1209  	return stmts
  1210  }
  1211  
  1212  func (g *translator) convertSelStmt(st *cc.SelectionStatement) []CStmt {
  1213  	switch st.Case {
  1214  	case cc.SelectionStatementIf: // if (x)
  1215  		cond := g.convertExpr(st.Expression)
  1216  		return []CStmt{
  1217  			g.NewCIfStmt(
  1218  				g.ToBool(cond),
  1219  				[]CStmt{g.convertBlockStmt(st.Statement)},
  1220  				nil,
  1221  			),
  1222  		}
  1223  	case cc.SelectionStatementIfElse: // if (x) else
  1224  		cond := g.convertExpr(st.Expression)
  1225  		return []CStmt{
  1226  			g.NewCIfStmt(
  1227  				g.ToBool(cond),
  1228  				[]CStmt{g.convertBlockStmt(st.Statement)},
  1229  				g.toElseStmt(g.convertOneStmt(st.Statement2)),
  1230  			),
  1231  		}
  1232  	case cc.SelectionStatementSwitch: // switch (x)
  1233  		return []CStmt{g.NewCSwitchStmt(
  1234  			g.convertExpr(st.Expression),
  1235  			[]CStmt{g.convertBlockStmt(st.Statement)},
  1236  		)}
  1237  	default:
  1238  		panic(st.Case.String())
  1239  	}
  1240  }
  1241  
  1242  func (g *translator) convertIterStmt(st *cc.IterationStatement) []CStmt {
  1243  	switch st.Case {
  1244  	case cc.IterationStatementWhile:
  1245  		x := g.convertExprOpt(st.Expression)
  1246  		var cond BoolExpr
  1247  		if x != nil {
  1248  			cond = g.ToBool(x)
  1249  		}
  1250  		return []CStmt{
  1251  			g.NewCForStmt(
  1252  				nil,
  1253  				cond,
  1254  				nil,
  1255  				[]CStmt{g.convertBlockStmt(st.Statement)},
  1256  			),
  1257  		}
  1258  	case cc.IterationStatementDo:
  1259  		return []CStmt{
  1260  			g.NewCDoWhileStmt(
  1261  				g.convertExprOpt(st.Expression),
  1262  				[]CStmt{g.convertBlockStmt(st.Statement)},
  1263  			),
  1264  		}
  1265  	case cc.IterationStatementFor:
  1266  		x := g.convertExprOpt(st.Expression2)
  1267  		var cond BoolExpr
  1268  		if x != nil {
  1269  			cond = g.ToBool(x)
  1270  		}
  1271  		return []CStmt{
  1272  			g.NewCForStmt(
  1273  				g.convertExprOpt(st.Expression),
  1274  				cond,
  1275  				g.convertExprOpt(st.Expression3),
  1276  				[]CStmt{g.convertBlockStmt(st.Statement)},
  1277  			),
  1278  		}
  1279  	case cc.IterationStatementForDecl:
  1280  		var cur *CVarDecl
  1281  		for _, d := range g.convertDecl(st.Declaration) {
  1282  			d := d.(*CVarDecl)
  1283  			if cur == nil {
  1284  				cur = d
  1285  				continue
  1286  			}
  1287  			if !types.Same(cur.Type, d.Type) {
  1288  				panic(fmt.Errorf("different types in a declaration: %v vs %v (%s)", cur.Type, d.Type, st.Position()))
  1289  			}
  1290  			cur.Single = true
  1291  			n1, n2 := len(cur.Names), len(d.Names)
  1292  			cur.Names = append(cur.Names, d.Names...)
  1293  			if len(cur.Inits) == 0 && len(d.Inits) == 0 {
  1294  				continue
  1295  			}
  1296  			if len(cur.Inits) == 0 {
  1297  				cur.Inits = make([]Expr, n1, n1+n2)
  1298  			}
  1299  			if len(d.Inits) == 0 {
  1300  				cur.Inits = append(cur.Inits, make([]Expr, n2)...)
  1301  			} else {
  1302  				cur.Inits = append(cur.Inits, d.Inits...)
  1303  			}
  1304  		}
  1305  		x := g.convertExprOpt(st.Expression)
  1306  		var cond BoolExpr
  1307  		if x != nil {
  1308  			cond = g.ToBool(x)
  1309  		}
  1310  		return []CStmt{
  1311  			g.NewCForDeclStmt(
  1312  				cur,
  1313  				cond,
  1314  				g.convertExprOpt(st.Expression2),
  1315  				[]CStmt{g.convertBlockStmt(st.Statement)},
  1316  			),
  1317  		}
  1318  	default:
  1319  		panic(st.Case.String() + " " + st.Position().String())
  1320  	}
  1321  }
  1322  
  1323  func (g *translator) convertJumpStmt(st *cc.JumpStatement) []CStmt {
  1324  	switch st.Case {
  1325  	case cc.JumpStatementGoto: // goto x
  1326  		return []CStmt{
  1327  			&CGotoStmt{Label: st.Token2.Value.String()},
  1328  		}
  1329  	case cc.JumpStatementContinue: // continue
  1330  		return []CStmt{
  1331  			&CContinueStmt{},
  1332  		}
  1333  	case cc.JumpStatementBreak: // break
  1334  		return []CStmt{
  1335  			&CBreakStmt{},
  1336  		}
  1337  	case cc.JumpStatementReturn: // return
  1338  		return g.NewReturnStmt(
  1339  			g.convertExprOpt(st.Expression),
  1340  			nil,
  1341  		)
  1342  	default:
  1343  		panic(st.Case.String())
  1344  	}
  1345  }
  1346  
  1347  func (g *translator) convertAsmStmt(d *cc.AsmStatement) []CStmt {
  1348  	// TODO
  1349  	return NewCExprStmt(&CAsmExpr{e: g.env.Env, typ: types.UnkT(1)})
  1350  }
  1351  
  1352  func (g *translator) convertStmt(d *cc.Statement) []CStmt {
  1353  	switch d.Case {
  1354  	case cc.StatementLabeled:
  1355  		return g.convertLabelStmt(d.LabeledStatement)
  1356  	case cc.StatementCompound:
  1357  		return g.convertCompStmt(d.CompoundStatement)
  1358  	case cc.StatementExpr:
  1359  		return g.convertExprStmt(d.ExpressionStatement)
  1360  	case cc.StatementSelection:
  1361  		return g.convertSelStmt(d.SelectionStatement)
  1362  	case cc.StatementIteration:
  1363  		return g.convertIterStmt(d.IterationStatement)
  1364  	case cc.StatementJump:
  1365  		return g.convertJumpStmt(d.JumpStatement)
  1366  	case cc.StatementAsm:
  1367  		return g.convertAsmStmt(d.AsmStatement)
  1368  	default:
  1369  		panic(d.Case.String())
  1370  	}
  1371  }
  1372  
  1373  func (g *translator) convertOneStmt(d *cc.Statement) CStmt {
  1374  	stmts := g.convertStmt(d)
  1375  	if len(stmts) == 1 {
  1376  		return stmts[0]
  1377  	}
  1378  	return g.NewCBlock(stmts...)
  1379  }
  1380  
  1381  func (g *translator) convertBlockStmt(d *cc.Statement) *BlockStmt {
  1382  	stmts := g.convertStmt(d)
  1383  	if len(stmts) == 1 {
  1384  		if b, ok := stmts[0].(*BlockStmt); ok {
  1385  			return b
  1386  		}
  1387  	}
  1388  	return g.NewCBlock(stmts...)
  1389  }