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 }