// Copyright 2019 The CC Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package cc // import "modernc.org/cc/v3" import ( "fmt" "go/token" "math" "math/big" "math/bits" "path/filepath" "strconv" "strings" "modernc.org/mathutil" "modernc.org/strutil" ) const longDoublePrec = 256 type mode = int var ( idBuiltinConstantPImpl = dict.sid("__builtin_constant_p_impl") idClosure = dict.sid("0closure") // Must be invalid indentifier. idWcharT = dict.sid("wchar_t") idWinWchar = dict.sid("WCHAR") _ fmt.State ) const ( // [2], 6.6 Constant expressions, 6 // // An integer constant expression shall have integer type and shall // only have operands that are integer constants, enumeration // constants, character constants, sizeof expressions whose results are // integer constants, _Alignof expressions, and floating constants that // are the immediate operands of casts. Cast operators in an integer // constant expression shall only convert arithmetic types to integer // types, except as part of an operand to the sizeof or _Alignof // operator. mIntConstExpr = 1 << iota mIntConstExprFloat // As mIntConstExpr plus accept floating point constants. mIntConstExprAnyCast // As mIntConstExpr plus accept any cast. ) // Parameter represents a function parameter. type Parameter struct { d *Declarator typ Type } // NewParameter returns a newly created parameter func NewParameter(d *Declarator, t Type) *Parameter { return &Parameter{d, t} } func (p *Parameter) Declarator() *Declarator { return p.d } func (p *Parameter) Name() StringID { return p.d.Name() } func (p *Parameter) Type() Type { return p.typ } func (n *TranslationUnit) check(ctx *context) { for n := n; n != nil; n = n.TranslationUnit { n.ExternalDeclaration.check(ctx) } for ; n != nil; n = n.TranslationUnit { n.ExternalDeclaration.checkFnBodies(ctx) } } func (n *ExternalDeclaration) checkFnBodies(ctx *context) { if n == nil { return } switch n.Case { case ExternalDeclarationFuncDef: // FunctionDefinition n.FunctionDefinition.checkBody(ctx) } } // https://gcc.gnu.org/onlinedocs/gcc/Inline.html // // If you specify both inline and extern in the function definition, then the // definition is used only for inlining. In no case is the function compiled on // its own, not even if you refer to its address explicitly. Such an address // becomes an external reference, as if you had only declared the function, and // had not defined it. // // This combination of inline and extern has almost the effect of a macro. The // way to use it is to put a function definition in a header file with these // keywords, and put another copy of the definition (lacking inline and extern) // in a library file. The definition in the header file causes most calls to // the function to be inlined. If any uses of the function remain, they refer // to the single copy in the library. func (n *Declarator) isExternInline() bool { return n.IsExtern() && n.Type() != nil && n.Type().Inline() } // DeclarationSpecifiers Declarator DeclarationList CompoundStatement func (n *FunctionDefinition) checkBody(ctx *context) { if n == nil { return } if n.checked { return } n.checked = true if n.Declarator.isExternInline() && !ctx.cfg.CheckExternInlineFnBodies { return } ctx.checkFn = n rd := ctx.readDelta ctx.readDelta = 1 n.CompoundStatement.check(ctx) ctx.checkFn = nil for k, v := range n.ComputedGotos { if _, ok := n.Labels[k]; !ok { ctx.errNode(v, "label %s undefined", k) } } for k, v := range n.Gotos { if _, ok := n.Labels[k]; !ok { ctx.errNode(v, "label %s undefined", k) } } for _, n := range n.InitDeclarators { d := n.Declarator if d.Type().IsIncomplete() && d.Linkage != External { ctx.errNode(d, "declarator has incomplete type") } if ctx.cfg.RejectUninitializedDeclarators && d.Linkage == None && d.Write == 0 && !d.AddressTaken && d.Read != 0 { switch d.Type().Kind() { case Array, Struct, Union, Invalid: // nop default: ctx.errNode(d, "%s may be used uninitialized in this function", d.Name()) } } } for _, n := range n.CompositeLiterals { switch t := n.Operand.Type(); t.Kind() { case Invalid: ctx.errNode(n, "composite literal has invalid type") default: if t.IsIncomplete() { ctx.errNode(n, "composite literal has incomplete type") } } } ctx.readDelta = rd } func (n *ExternalDeclaration) check(ctx *context) { if n == nil { return } switch n.Case { case ExternalDeclarationFuncDef: // FunctionDefinition n.FunctionDefinition.checkDeclarator(ctx) case ExternalDeclarationDecl: // Declaration n.Declaration.check(ctx, true) case ExternalDeclarationAsm: // AsmFunctionDefinition n.AsmFunctionDefinition.check(ctx) case ExternalDeclarationAsmStmt: // AsmStatement n.AsmStatement.check(ctx) case ExternalDeclarationEmpty: // ';' // nop case ExternalDeclarationPragma: // PragmaSTDC n.PragmaSTDC.check(ctx) default: panic(todo("")) } } func (n *PragmaSTDC) check(ctx *context) { // nop } func (n *AsmFunctionDefinition) check(ctx *context) { if n == nil { return } typ, inline, noret := n.DeclarationSpecifiers.check(ctx, false) typ.setFnSpecs(inline, noret) n.Declarator.check(ctx, n.DeclarationSpecifiers, typ, true) n.AsmStatement.check(ctx) } func (n *AsmStatement) check(ctx *context) { if n == nil { return } n.Asm.check(ctx) n.AttributeSpecifierList.check(ctx, nil) } func (n *Declaration) check(ctx *context, tld bool) { if n == nil { return } typ, _, _ := n.DeclarationSpecifiers.check(ctx, false) n.InitDeclaratorList.check(ctx, n.DeclarationSpecifiers, typ, tld) } func (n *InitDeclaratorList) check(ctx *context, td typeDescriptor, typ Type, tld bool) { for ; n != nil; n = n.InitDeclaratorList { n.AttributeSpecifierList.check(ctx, typ.baseP()) n.InitDeclarator.check(ctx, td, typ, tld) } } func (n *InitDeclarator) check(ctx *context, td typeDescriptor, typ Type, tld bool) { if n == nil { return } if f := ctx.checkFn; f != nil { f.InitDeclarators = append(f.InitDeclarators, n) } if attr := n.AttributeSpecifierList.check(ctx, typ.baseP()); len(attr) != 0 { typ = &attributedType{typ, attr} } switch n.Case { case InitDeclaratorDecl: // Declarator AttributeSpecifierList n.Declarator.check(ctx, td, typ, tld) case InitDeclaratorInit: // Declarator AttributeSpecifierList '=' Initializer typ := n.Declarator.check(ctx, td, typ, tld) n.Declarator.hasInitializer = true n.Declarator.Write++ n.Initializer.check(ctx, &n.Initializer.list, typ, n.Declarator.StorageClass, nil, 0, nil, nil, false) n.Initializer.setConstZero() n.initializer = &InitializerValue{typ: typ, initializer: n.Initializer} if ctx.cfg.TrackAssignments { setLHS(map[*Declarator]struct{}{n.Declarator: {}}, n.Initializer) } default: panic(todo("")) } } func (n *Initializer) setConstZero() { switch n.Case { case InitializerExpr: // AssignmentExpression if op := n.AssignmentExpression.Operand; op != nil { n.isConst = op.IsConst() n.isZero = op.IsZero() } case InitializerInitList: // '{' InitializerList ',' '}' li := n.InitializerList li.setConstZero() n.isConst = li.IsConst() n.isZero = li.IsZero() default: panic(todo("%v:", n.Position())) } } func (n *InitializerList) setConstZero() { if n == nil { return } n0 := n n0.isConst = true n0.isZero = true for ; n != nil; n = n.InitializerList { in := n.Initializer in.setConstZero() n0.isConst = n0.isConst && in.isConst n0.isZero = n0.isZero && in.isZero } } // [0], 6.7.8 Initialization func (n *Initializer) check(ctx *context, list *[]*Initializer, t Type, sc StorageClass, fld Field, off uintptr, il *InitializerList, designatorList *DesignatorList, inList bool) *InitializerList { // trc("==== %v: case %v, t %v, off %v, designatorList != nil %v, inList %v", n.Position(), n.Case, t.Alias(), off, designatorList != nil, inList) // if fld != nil { // trc("\tfld %q", fld.Name()) // } // 3 - The type of the entity to be initialized shall be an array of // unknown size or an object type that is not a variable length array // type. if t.Kind() == Array && t.IsVLA() { ctx.errNode(n, "cannot initialize a variable length array: %v", t) if il != nil { return il.InitializerList } return nil } defer func(d int) { ctx.readDelta = d }(ctx.readDelta) ctx.readDelta = 1 n.typ = t single := n.single() var op Operand if single != nil { op = single.AssignmentExpression.check(ctx, false) single.typ = t single.Field = fld single.Offset = off } // 11: The initializer for a scalar shall be a single expression, optionally // enclosed in braces. The initial value of the object is that of the // expression (after conversion); the same type constraints and conversions as // for simple assignment apply, taking the type of the scalar to be the // unqualified version of its declared type. if t.IsScalarType() && single != nil { if designatorList != nil { panic(todo("", n.Position())) } //TODO check compatible *list = append(*list, single) switch { case t.Kind() == op.Type().Kind(): single.AssignmentExpression.InitializerOperand = op default: single.AssignmentExpression.InitializerOperand = op.convertTo(ctx, n, t) } if il != nil { return il.InitializerList } return nil } // 12: The rest of this subclause deals with initializers for objects that have // aggregate or union type. k := t.Kind() // 13: The initializer for a structure or union object that has automatic // storage duration shall be either an initializer list as described below, or // a single expression that has compatible structure or union type. In the // latter case, the initial value of the object, including unnamed members, is // that of the expression. if n.Case == InitializerExpr && sc == Automatic && (k == Struct || k == Union || k == Vector) && t.IsCompatible(op.Type()) { if designatorList != nil { panic(todo("", n.Position())) } *list = append(*list, single) if il != nil { return il.InitializerList } return nil } if k == Array && single != nil { et := t.Elem() switch { case isCharType(et): // 14: An array of character type may be initialized by a character string // literal, optionally enclosed in braces. Successive characters of the // character string literal (including the terminating null character if there // is room or if the array is of unknown size) initialize the elements of the // array. if x, ok := op.Value().(StringValue); ok { if designatorList != nil { panic(todo("", n.Position())) } *list = append(*list, single) str := StringID(x).String() if t.IsIncomplete() { t.setLen(uintptr(len(str)) + 1) } if il != nil { return il.InitializerList } return nil } case isWCharType(et): // 15: An array with element type compatible with wchar_t may be initialized by // a wide string literal, optionally enclosed in braces. Successive wide // characters of the wide string literal (including the terminating null wide // character if there is room or if the array is of unknown size) initialize // the elements of the array. if x, ok := op.Value().(WideStringValue); ok { if designatorList != nil { panic(todo("", n.Position())) } *list = append(*list, single) str := []rune(StringID(x).String()) if t.IsIncomplete() { t.setLen(uintptr(len(str)) + 1) } if il != nil { panic(todo("")) } return nil } } } // 16: Otherwise, the initializer for an object that has aggregate or union // type shall be a brace-enclosed list of initializers for the elements or // named members. if n.Case == InitializerExpr { if il != nil { switch t.Kind() { case Array: return il.checkArray(ctx, list, t, sc, off, designatorList, inList) case Struct: return il.checkStruct(ctx, list, t, sc, off, designatorList, inList) case Union: return il.checkUnion(ctx, list, t, sc, off, designatorList, inList) case Vector: return il.InitializerList //TODO default: panic(todo("", n.Position(), t, t.Kind())) } } var l *InitializerList Inspect(n.AssignmentExpression, func(m Node, b bool) bool { if x, ok := m.(*PostfixExpression); ok && x.Case == PostfixExpressionComplit { if !b { return true } if l == nil { l = x.InitializerList return true } l = nil return false } return true }) if l != nil { l.check(ctx, list, t, sc, off, designatorList, inList) return nil } ctx.errNode(n, "initializer for an object that has aggregate or union type shall be a brace-enclosed list of initializers for the elements or named members: %v", t) return nil } n.InitializerList.check(ctx, list, t, sc, off, designatorList, inList) if il != nil { return il.InitializerList } return nil } func (n *InitializerList) checkArray(ctx *context, list *[]*Initializer, t Type, sc StorageClass, off uintptr, designatorList *DesignatorList, inList bool) *InitializerList { elem := t.Elem() esz := elem.Size() length := t.Len() var i, maxI uintptr nestedDesignator := designatorList != nil retOnDesignator := false loop: for n != nil { switch { case retOnDesignator && n.Designation != nil: return n case designatorList == nil && !inList && n.Designation != nil: designatorList = n.Designation.DesignatorList fallthrough case designatorList != nil: d := designatorList.Designator designatorList = designatorList.DesignatorList switch d.Case { case DesignatorIndex: // '[' ConstantExpression ']' switch x := d.ConstantExpression.check(ctx, ctx.mode|mIntConstExpr, false).Value().(type) { case Int64Value: i = uintptr(x) case Uint64Value: i = uintptr(x) default: panic(todo("%v: %T", n.Position(), x)) } if !inList && i > maxI { maxI = i } case DesignatorField: // '.' IDENTIFIER panic(todo("", n.Position(), d.Position())) case DesignatorField2: // IDENTIFIER ':' panic(todo("", n.Position(), d.Position())) default: panic(todo("")) } n = n.Initializer.check(ctx, list, elem, sc, nil, off+i*esz, n, designatorList, designatorList != nil) designatorList = nil if nestedDesignator { retOnDesignator = true } i++ default: if !t.IsIncomplete() && i >= length { break loop } if i > maxI { maxI = i } n = n.Initializer.check(ctx, list, elem, sc, nil, off+i*esz, n, nil, inList) i++ } } if t.IsIncomplete() { t.setLen(maxI + 1) } return n } func (n *InitializerList) checkStruct(ctx *context, list *[]*Initializer, t Type, sc StorageClass, off uintptr, designatorList *DesignatorList, inList bool) *InitializerList { // trc("==== (A) %v: t %v, off %v, dl %v, inList %v", n.Position(), t, off, designatorList != nil, inList) // defer trc("==== (Z) %v: t %v, off %v, dl %v, inList %v", n.Position(), t, off, designatorList != nil, inList) t = t.underlyingType() // trc("%v: %v, off %v", n.Position(), t, off) //TODO- nf := t.NumField() i := []int{0} var f Field nestedDesignator := designatorList != nil retOnDesignator := false for n != nil { switch { case retOnDesignator && n.Designation != nil: return n case designatorList == nil && !inList && n.Designation != nil: designatorList = n.Designation.DesignatorList fallthrough case designatorList != nil: d := designatorList.Designator designatorList = designatorList.DesignatorList var nm StringID switch d.Case { case DesignatorIndex: // '[' ConstantExpression ']' panic(todo("", n.Position(), d.Position())) case DesignatorField: // '.' IDENTIFIER nm = d.Token2.Value case DesignatorField2: // IDENTIFIER ':' nm = d.Token.Value default: panic(todo("")) } f, xa, ok := t.FieldByName2(nm) if !ok { panic(todo("%v: t %v %q", d.Position(), t, nm)) } t0 := t switch { case len(xa) != 1: var f2 Field var off2 uintptr for len(xa) != 1 { f2 = t.FieldByIndex(xa[:1]) off2 += f2.Offset() t = f2.Type() xa = xa[1:] } n = n.Initializer.check(ctx, list, t, sc, f, off+off2, n, designatorList, designatorList != nil) if t.Kind() == Union { t = t0 } default: n = n.Initializer.check(ctx, list, f.Type(), sc, f, off+f.Offset(), n, designatorList, designatorList != nil) } designatorList = nil if nestedDesignator { retOnDesignator = true } i[0] = xa[0] + 1 default: // [0], 6.7.8 Initialization // // 9 - Except where explicitly stated otherwise, for the // purposes of this subclause unnamed members of objects of // structure and union type do not participate in // initialization. Unnamed members of structure objects have // indeterminate value even after initialization. for ; ; i[0]++ { if i[0] >= nf { return n } f = t.FieldByIndex(i) if f.Name() != 0 || !f.Type().IsBitFieldType() { n = n.Initializer.check(ctx, list, f.Type(), sc, f, off+f.Offset(), n, nil, inList) i[0]++ break } } } } return n } func spos(n Node) string { p := n.Position() p.Filename = filepath.Base(p.Filename) return p.String() } func (n *InitializerList) checkUnion(ctx *context, list *[]*Initializer, t Type, sc StorageClass, off uintptr, designatorList *DesignatorList, inList bool) *InitializerList { // trc("==== %v: t %v, off %v, dl %v, inList %v", n.Position(), t, off, designatorList != nil, inList) t = t.underlyingType() // trc("%v: %v, off %v", n.Position(), t, off) //TODO- nf := t.NumField() i := []int{0} for pass := 0; n != nil; pass++ { switch { case designatorList == nil && !inList && n.Designation != nil: designatorList = n.Designation.DesignatorList fallthrough case designatorList != nil: d := designatorList.Designator designatorList = designatorList.DesignatorList var nm StringID switch d.Case { case DesignatorIndex: // '[' ConstantExpression ']' panic(todo("", n.Position(), d.Position())) case DesignatorField: // '.' IDENTIFIER nm = d.Token2.Value case DesignatorField2: // IDENTIFIER ':' nm = d.Token.Value default: panic(todo("")) } f, xa, ok := t.FieldByName2(nm) if !ok { panic(todo("", d.Position())) } if !inList && pass == 0 { n.Initializer.field0 = f } switch { case len(xa) != 1: var f2 Field var off2 uintptr for len(xa) != 1 { f2 = t.FieldByIndex(xa[:1]) off2 += f2.Offset() t = f2.Type() xa = xa[1:] } next := n.Initializer.check(ctx, list, t, sc, f, off+off2+f.Offset(), n, designatorList, designatorList != nil) if designatorList != nil && designatorList.DesignatorList != nil { panic(todo("", n.Position(), d.Position())) } return next default: next := n.Initializer.check(ctx, list, f.Type(), sc, f, off+f.Offset(), n, designatorList, designatorList != nil) if designatorList != nil && designatorList.DesignatorList != nil { panic(todo("", n.Position(), d.Position())) } return next } default: // [0], 6.7.8 Initialization // // 9 - Except where explicitly stated otherwise, for the // purposes of this subclause unnamed members of objects of // structure and union type do not participate in // initialization. Unnamed members of structure objects have // indeterminate value even after initialization. for ; ; i[0]++ { if i[0] >= nf { panic(todo("")) } f := t.FieldByIndex(i) if f.Name() != 0 || !f.Type().IsBitFieldType() { next := n.Initializer.check(ctx, list, f.Type(), sc, f, off+f.Offset(), n, nil, inList) return next } } panic(todo("", n.Position())) } } return nil } // Accept a single initializer, optionally enclosed in braces, but nested // braces. Implements eg. [0]6.7.8.11. // // 42 // ok // {42} // ok // {{42}} // not ok func (n *Initializer) single() *Initializer { switch n.Case { case InitializerExpr: // AssignmentExpression return n case InitializerInitList: // '{' InitializerList ',' '}' if n.InitializerList == nil { // return nil } if n.InitializerList.InitializerList == nil { if in := n.InitializerList.Initializer; in.Case == InitializerExpr { return in } } } return nil } // [0], 6.7.8 Initialization func (n *InitializerList) check(ctx *context, list *[]*Initializer, t Type, sc StorageClass, off uintptr, designatorList *DesignatorList, inList bool) { switch t.Kind() { case Array, Vector: if n == nil { // {} if t.IsIncomplete() { t.setLen(0) } return } n.checkArray(ctx, list, t, sc, off, designatorList, inList) case Struct: if n == nil { // {} return } n.checkStruct(ctx, list, t, sc, off, designatorList, inList) case Union: if n == nil { // {} return } n.checkUnion(ctx, list, t, sc, off, designatorList, inList) default: if n == nil || t == nil || t.Kind() == Invalid { return } n.Initializer.check(ctx, list, t, sc, nil, off, nil, designatorList, inList) } } func setLHS(lhs map[*Declarator]struct{}, rhs Node) { inCall := 0 Inspect(rhs, func(n Node, enter bool) bool { switch x := n.(type) { case *PostfixExpression: switch x.Case { case PostfixExpressionCall: // PostfixExpression '(' ArgumentExpressionList ')' switch { case enter: inCall++ if d := x.Declarator(); d != nil { for v := range lhs { d.setLHS(v) } } default: inCall-- } } case *PrimaryExpression: if inCall != 0 || !enter { break } if d := x.Declarator(); d != nil { for v := range lhs { d.setLHS(v) } } } return true }) } func (n *AssignmentExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } if n.Operand != nil { return n.Operand } if ctx.cfg.TrackAssignments && n.AssignmentExpression != nil { defer func() { lhs := map[*Declarator]struct{}{} Inspect(n.UnaryExpression, func(n Node, enter bool) bool { if !enter { return true } if x, ok := n.(*PrimaryExpression); ok { lhs[x.Declarator()] = struct{}{} } return true }) setLHS(lhs, n.AssignmentExpression) }() } //TODO check for "modifiable lvalue" in left operand n.Operand = noOperand switch n.Case { case AssignmentExpressionCond: // ConditionalExpression n.Operand = n.ConditionalExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.ConditionalExpression.IsSideEffectsFree case AssignmentExpressionAssign: // UnaryExpression '=' AssignmentExpression l := n.UnaryExpression.check(ctx, isAsmArg) if d := n.UnaryExpression.Declarator(); d != nil { d.Read -= ctx.readDelta } if d := n.UnaryExpression.Operand.Declarator(); d != nil { d.Write++ if l.Type().Kind() == Array && !d.IsParameter && l.Type().String() != "va_list" { ctx.errNode(n.UnaryExpression, "assignment to expression with array type") break } } if !l.IsLValue() { //TODO ctx.errNode(n.UnaryExpression, "expected lvalue") break } r := n.AssignmentExpression.check(ctx, isAsmArg) _ = r //TODO check assignability n.Operand = l.(*lvalue).Operand case AssignmentExpressionMul: // UnaryExpression "*=" AssignmentExpression l := n.UnaryExpression.check(ctx, isAsmArg) if d := n.UnaryExpression.Operand.Declarator(); d != nil { d.SubjectOfAsgnOp = true d.Read += ctx.readDelta d.Write++ } if !l.IsLValue() { //TODO panic(n.Position().String()) // report error break } r := n.AssignmentExpression.check(ctx, isAsmArg) //TODO check assignability if l.Type().IsArithmeticType() { op, _ := usualArithmeticConversions(ctx, n, l, r, true) n.promote = op.Type() } n.Operand = &operand{abi: &ctx.cfg.ABI, typ: l.Type()} case AssignmentExpressionDiv: // UnaryExpression "/=" AssignmentExpression l := n.UnaryExpression.check(ctx, isAsmArg) if d := n.UnaryExpression.Operand.Declarator(); d != nil { d.SubjectOfAsgnOp = true d.Read += ctx.readDelta d.Write++ } if !l.IsLValue() { //TODO panic(n.Position().String()) // report error break } r := n.AssignmentExpression.check(ctx, isAsmArg) //TODO check assignability if l.Type().IsArithmeticType() { op, _ := usualArithmeticConversions(ctx, n, l, r, true) n.promote = op.Type() } n.Operand = &operand{abi: &ctx.cfg.ABI, typ: l.Type()} case AssignmentExpressionMod: // UnaryExpression "%=" AssignmentExpression l := n.UnaryExpression.check(ctx, isAsmArg) if d := n.UnaryExpression.Operand.Declarator(); d != nil { d.SubjectOfAsgnOp = true d.Read += ctx.readDelta d.Write++ } if !l.IsLValue() { //TODO panic(n.Position().String()) // report error break } r := n.AssignmentExpression.check(ctx, isAsmArg) //TODO check assignability if l.Type().IsArithmeticType() { op, _ := usualArithmeticConversions(ctx, n, l, r, true) n.promote = op.Type() } n.Operand = &operand{abi: &ctx.cfg.ABI, typ: l.Type()} case AssignmentExpressionAdd: // UnaryExpression "+=" AssignmentExpression l := n.UnaryExpression.check(ctx, isAsmArg) if d := n.UnaryExpression.Operand.Declarator(); d != nil { d.SubjectOfAsgnOp = true d.Read += ctx.readDelta d.Write++ } if !l.IsLValue() { //TODO panic(n.Position().String()) // report error break } r := n.AssignmentExpression.check(ctx, isAsmArg) //TODO check assignability n.promote = n.UnaryExpression.Operand.Type() if l.Type().IsArithmeticType() { op, _ := usualArithmeticConversions(ctx, n, l, r, true) n.promote = op.Type() } n.Operand = &operand{abi: &ctx.cfg.ABI, typ: l.Type()} case AssignmentExpressionSub: // UnaryExpression "-=" AssignmentExpression l := n.UnaryExpression.check(ctx, isAsmArg) if d := n.UnaryExpression.Operand.Declarator(); d != nil { d.SubjectOfAsgnOp = true d.Read += ctx.readDelta d.Write++ } if !l.IsLValue() { //TODO panic(n.Position().String()) // report error break } r := n.AssignmentExpression.check(ctx, isAsmArg) //TODO check assignability n.promote = n.UnaryExpression.Operand.Type() if l.Type().IsArithmeticType() { op, _ := usualArithmeticConversions(ctx, n, l, r, true) n.promote = op.Type() } n.Operand = &operand{abi: &ctx.cfg.ABI, typ: l.Type()} case AssignmentExpressionLsh: // UnaryExpression "<<=" AssignmentExpression l := n.UnaryExpression.check(ctx, isAsmArg) if d := n.UnaryExpression.Operand.Declarator(); d != nil { d.SubjectOfAsgnOp = true d.Read += ctx.readDelta d.Write++ } if !l.IsLValue() { //TODO panic(n.Position().String()) // report error break } r := n.AssignmentExpression.check(ctx, isAsmArg) //TODO check assignability if !l.Type().IsIntegerType() || !r.Type().IsIntegerType() { //TODO report error break } n.promote = r.integerPromotion(ctx, n).Type() n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: l.Type()}).integerPromotion(ctx, n) case AssignmentExpressionRsh: // UnaryExpression ">>=" AssignmentExpression l := n.UnaryExpression.check(ctx, isAsmArg) if d := n.UnaryExpression.Operand.Declarator(); d != nil { d.SubjectOfAsgnOp = true d.Read += ctx.readDelta d.Write++ } if !l.IsLValue() { //TODO panic(n.Position().String()) // report error break } r := n.AssignmentExpression.check(ctx, isAsmArg) //TODO check assignability if !l.Type().IsIntegerType() || !r.Type().IsIntegerType() { //TODO report error break } n.promote = r.integerPromotion(ctx, n).Type() n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: l.Type()}).integerPromotion(ctx, n) case AssignmentExpressionAnd: // UnaryExpression "&=" AssignmentExpression l := n.UnaryExpression.check(ctx, isAsmArg) if d := n.UnaryExpression.Operand.Declarator(); d != nil { d.SubjectOfAsgnOp = true d.Read += ctx.readDelta d.Write++ } if !l.IsLValue() { //TODO panic(n.Position().String()) // report error break } r := n.AssignmentExpression.check(ctx, isAsmArg) //TODO check assignability if !l.Type().IsIntegerType() || !r.Type().IsIntegerType() { //TODO report error break } op, _ := usualArithmeticConversions(ctx, n, l, r, true) n.promote = op.Type() n.Operand = &operand{abi: &ctx.cfg.ABI, typ: l.Type()} case AssignmentExpressionXor: // UnaryExpression "^=" AssignmentExpression l := n.UnaryExpression.check(ctx, isAsmArg) if d := n.UnaryExpression.Operand.Declarator(); d != nil { d.SubjectOfAsgnOp = true d.Read += ctx.readDelta d.Write++ } if !l.IsLValue() { //TODO panic(n.Position().String()) // report error break } r := n.AssignmentExpression.check(ctx, isAsmArg) //TODO check assignability if !l.Type().IsIntegerType() || !r.Type().IsIntegerType() { //TODO report error break } op, _ := usualArithmeticConversions(ctx, n, l, r, true) n.promote = op.Type() n.Operand = &operand{abi: &ctx.cfg.ABI, typ: l.Type()} case AssignmentExpressionOr: // UnaryExpression "|=" AssignmentExpression l := n.UnaryExpression.check(ctx, isAsmArg) if d := n.UnaryExpression.Operand.Declarator(); d != nil { d.SubjectOfAsgnOp = true d.Read += ctx.readDelta d.Write++ } if !l.IsLValue() { //TODO panic(n.Position().String()) // report error break } r := n.AssignmentExpression.check(ctx, isAsmArg) //TODO check assignability if !l.Type().IsIntegerType() || !r.Type().IsIntegerType() { //TODO report error break } op, _ := usualArithmeticConversions(ctx, n, l, r, true) n.promote = op.Type() n.Operand = &operand{abi: &ctx.cfg.ABI, typ: l.Type()} default: panic(todo("")) } return n.Operand } func (n *UnaryExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case UnaryExpressionPostfix: // PostfixExpression n.Operand = n.PostfixExpression.check(ctx, false, isAsmArg) n.IsSideEffectsFree = n.PostfixExpression.IsSideEffectsFree case UnaryExpressionInc: // "++" UnaryExpression op := n.UnaryExpression.check(ctx, isAsmArg) if d := op.Declarator(); d != nil { d.SubjectOfIncDec = true d.Read += ctx.readDelta d.Write++ } n.Operand = &operand{abi: &ctx.cfg.ABI, typ: op.Type()} case UnaryExpressionDec: // "--" UnaryExpression op := n.UnaryExpression.check(ctx, isAsmArg) if d := op.Declarator(); d != nil { d.SubjectOfIncDec = true d.Read += ctx.readDelta d.Write++ } n.Operand = &operand{abi: &ctx.cfg.ABI, typ: op.Type()} case UnaryExpressionAddrof: // '&' CastExpression ctx.not(n, mIntConstExpr) op := n.CastExpression.addrOf(ctx) n.IsSideEffectsFree = n.CastExpression.IsSideEffectsFree if op.Type().IsBitFieldType() { //TODO report error break } d := n.CastExpression.Declarator() if d != nil { setAddressTaken(n, d, "'&' CastExpression") if d.td.register() { //TODO report error } } // [0], 6.5.3.2 // // The operand of the unary & operator shall be either a // function designator, the result of a [] or unary * operator, // or an lvalue that designates an object that is not a // bit-field and is not declared with the register // storage-class specifier. //TODO if x, ok := op.(*funcDesignator); ok { n.Operand = x break } n.Operand = op case UnaryExpressionDeref: // '*' CastExpression ctx.not(n, mIntConstExpr) op := n.CastExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.CastExpression.IsSideEffectsFree if x, ok := op.(*funcDesignator); ok { n.Operand = x break } if op.Type().Kind() == Function { n.Operand = op break } if op.Type().Decay().Kind() != Ptr { //TODO report error break } n.Operand = &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: op.Type().Elem()}} case UnaryExpressionPlus: // '+' CastExpression op := n.CastExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.CastExpression.IsSideEffectsFree if !op.Type().IsArithmeticType() { //TODO report error break } if op.Type().IsIntegerType() { op = op.integerPromotion(ctx, n) } n.Operand = op case UnaryExpressionMinus: // '-' CastExpression op := n.CastExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.CastExpression.IsSideEffectsFree if op.Type().Kind() == Vector { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: op.Type()} break } if !op.Type().IsArithmeticType() { //TODO report error break } if op.Type().IsIntegerType() { op = op.integerPromotion(ctx, n) } if v := op.Value(); v != nil { op = (&operand{abi: &ctx.cfg.ABI, typ: op.Type(), value: v.neg()}).normalize(ctx, n) } n.Operand = op case UnaryExpressionCpl: // '~' CastExpression op := n.CastExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.CastExpression.IsSideEffectsFree if op.Type().Kind() == Vector { if !op.Type().Elem().IsIntegerType() { ctx.errNode(n, "operand must be integer") } n.Operand = &operand{abi: &ctx.cfg.ABI, typ: op.Type()} break } if op.Type().IsComplexType() { n.Operand = op break } if !op.Type().IsIntegerType() { ctx.errNode(n, "operand must be integer") break } op = op.integerPromotion(ctx, n) if v := op.Value(); v != nil { op = (&operand{abi: &ctx.cfg.ABI, typ: op.Type(), value: v.cpl()}).normalize(ctx, n) } n.Operand = op case UnaryExpressionNot: // '!' CastExpression op := n.CastExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.CastExpression.IsSideEffectsFree op2 := &operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(Int)} switch { case op.IsZero(): op2.value = Int64Value(1) case op.IsNonZero(): op2.value = Int64Value(0) } n.Operand = op2 case UnaryExpressionSizeofExpr: // "sizeof" UnaryExpression n.IsSideEffectsFree = true rd := ctx.readDelta // [0]6.5.3.4, 2: If the type of the operand is a variable length array type, // the operand is evaluated; otherwise, the operand is not evaluated and the // result is an integer constant. switch op := n.UnaryExpression.Operand; { case op != nil && op.Type() != nil && op.Type().IsVLA(): ctx.readDelta = 1 default: ctx.readDelta = 0 } ctx.push(ctx.mode &^ mIntConstExpr) op := n.UnaryExpression.check(ctx, isAsmArg) ctx.pop() ctx.readDelta = rd if op.Type().IsIncomplete() { break } sz := op.Type().Size() if d := n.UnaryExpression.Declarator(); d != nil && d.IsParameter { sz = op.Type().Decay().Size() } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(ULongLong), value: Uint64Value(sz)}).convertTo(ctx, n, sizeT(ctx, n.lexicalScope, n.Token)) case UnaryExpressionSizeofType: // "sizeof" '(' TypeName ')' n.IsSideEffectsFree = true rd := ctx.readDelta ctx.readDelta = 0 ctx.push(ctx.mode) if ctx.mode&mIntConstExpr != 0 { ctx.mode |= mIntConstExprAnyCast } t := n.TypeName.check(ctx, false, false, nil) ctx.pop() ctx.readDelta = rd if t.IsIncomplete() { break } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(ULongLong), value: Uint64Value(t.Size())}).convertTo(ctx, n, sizeT(ctx, n.lexicalScope, n.Token)) case UnaryExpressionLabelAddr: // "&&" IDENTIFIER abi := &ctx.cfg.ABI n.Operand = &operand{abi: abi, typ: abi.Ptr(n, abi.Type(Void))} n.IsSideEffectsFree = true ctx.not(n, mIntConstExpr) f := ctx.checkFn if f == nil { //TODO report error break } if f.ComputedGotos == nil { f.ComputedGotos = map[StringID]*UnaryExpression{} } f.ComputedGotos[n.Token2.Value] = n case UnaryExpressionAlignofExpr: // "_Alignof" UnaryExpression n.IsSideEffectsFree = true ctx.push(ctx.mode &^ mIntConstExpr) op := n.UnaryExpression.check(ctx, isAsmArg) n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(ULongLong), value: Uint64Value(op.Type().Align())}).convertTo(ctx, n, sizeT(ctx, n.lexicalScope, n.Token)) ctx.pop() case UnaryExpressionAlignofType: // "_Alignof" '(' TypeName ')' n.IsSideEffectsFree = true ctx.push(ctx.mode) if ctx.mode&mIntConstExpr != 0 { ctx.mode |= mIntConstExprAnyCast } t := n.TypeName.check(ctx, false, false, nil) n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(ULongLong), value: Uint64Value(t.Align())}).convertTo(ctx, n, sizeT(ctx, n.lexicalScope, n.Token)) ctx.pop() case UnaryExpressionImag: // "__imag__" UnaryExpression ctx.not(n, mIntConstExpr) n.UnaryExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.UnaryExpression.IsSideEffectsFree n.Operand = complexPart(ctx, n.UnaryExpression.Operand) case UnaryExpressionReal: // "__real__" UnaryExpression ctx.not(n, mIntConstExpr) n.UnaryExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.UnaryExpression.IsSideEffectsFree n.Operand = complexPart(ctx, n.UnaryExpression.Operand) default: panic(todo("")) } return n.Operand } func complexPart(ctx *context, op Operand) Operand { var k Kind switch op.Type().Kind() { case ComplexChar: k = Char case ComplexDouble: k = Double case ComplexFloat: k = Float case ComplexInt: k = Int case ComplexLong: k = Long case ComplexLongDouble: k = LongDouble case ComplexLongLong: k = LongLong case ComplexShort: k = Short case ComplexUInt: k = UInt case ComplexULong: k = ULong case ComplexULongLong: k = ULongLong case ComplexUShort: k = UShort default: //TODO report err return noOperand } abi := &ctx.cfg.ABI typ := abi.Type(k) return &operand{abi: abi, typ: typ} } func sizeT(ctx *context, s Scope, tok Token) Type { if t := ctx.sizeT; t != nil { return t } t := ctx.stddef(idSizeT, s, tok) if t.Kind() != Invalid { ctx.sizeT = t } return t } func (n *CastExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case CastExpressionUnary: // UnaryExpression n.Operand = n.UnaryExpression.addrOf(ctx) n.IsSideEffectsFree = n.UnaryExpression.IsSideEffectsFree case CastExpressionCast: // '(' TypeName ')' CastExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *UnaryExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case UnaryExpressionPostfix: // PostfixExpression n.Operand = n.PostfixExpression.addrOf(ctx) n.IsSideEffectsFree = n.PostfixExpression.IsSideEffectsFree case UnaryExpressionInc: // "++" UnaryExpression panic(n.Position().String()) case UnaryExpressionDec: // "--" UnaryExpression panic(n.Position().String()) case UnaryExpressionAddrof: // '&' CastExpression panic(n.Position().String()) case UnaryExpressionDeref: // '*' CastExpression n.Operand = n.CastExpression.check(ctx, false) n.IsSideEffectsFree = n.CastExpression.IsSideEffectsFree case UnaryExpressionPlus: // '+' CastExpression panic(n.Position().String()) case UnaryExpressionMinus: // '-' CastExpression panic(n.Position().String()) case UnaryExpressionCpl: // '~' CastExpression panic(n.Position().String()) case UnaryExpressionNot: // '!' CastExpression panic(n.Position().String()) case UnaryExpressionSizeofExpr: // "sizeof" UnaryExpression panic(n.Position().String()) case UnaryExpressionSizeofType: // "sizeof" '(' TypeName ')' panic(n.Position().String()) case UnaryExpressionLabelAddr: // "&&" IDENTIFIER panic(n.Position().String()) case UnaryExpressionAlignofExpr: // "_Alignof" UnaryExpression panic(n.Position().String()) case UnaryExpressionAlignofType: // "_Alignof" '(' TypeName ')' panic(n.Position().String()) case UnaryExpressionImag: // "__imag__" UnaryExpression n.Operand = n.UnaryExpression.addrOf(ctx) n.IsSideEffectsFree = n.UnaryExpression.IsSideEffectsFree case UnaryExpressionReal: // "__real__" UnaryExpression n.Operand = n.UnaryExpression.addrOf(ctx) n.IsSideEffectsFree = n.UnaryExpression.IsSideEffectsFree default: panic(todo("")) } return n.Operand } func (n *PostfixExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case PostfixExpressionPrimary: // PrimaryExpression n.Operand = n.PrimaryExpression.addrOf(ctx) n.IsSideEffectsFree = n.PrimaryExpression.IsSideEffectsFree case PostfixExpressionIndex: // PostfixExpression '[' Expression ']' pe := n.PostfixExpression.check(ctx, false, false) if d := n.PostfixExpression.Declarator(); d != nil && d.Type().Kind() != Ptr { setAddressTaken(n, d, "PostfixExpression '[' Expression ']'") d.Read += ctx.readDelta } e := n.Expression.check(ctx, false) n.IsSideEffectsFree = n.PostfixExpression.IsSideEffectsFree && n.Expression.IsSideEffectsFree t := pe.Type().Decay() if t.Kind() == Invalid { break } if t.Kind() == Ptr { if t := e.Type(); t.Kind() != Invalid && !t.IsIntegerType() { ctx.errNode(n.Expression, "index must be integer type, have %v", e.Type()) break } n.Operand = n.indexAddr(ctx, &n.Token, pe, e) break } if pe.Type().Kind() == Vector { if t := e.Type(); t.Kind() != Invalid && !t.IsIntegerType() { ctx.errNode(n.Expression, "index must be integer type, have %v", e.Type()) break } n.Operand = n.index(ctx, pe, e) break } t = e.Type().Decay() if t.Kind() == Invalid { break } if t.Kind() == Ptr { if t := pe.Type(); t.Kind() != Invalid && !t.IsIntegerType() { ctx.errNode(n.Expression, "index must be integer type, have %v", pe.Type()) break } n.Operand = n.indexAddr(ctx, &n.Token, e, pe) break } ctx.errNode(n, "invalid index expression %v[%v]", pe.Type(), e.Type()) case PostfixExpressionCall: // PostfixExpression '(' ArgumentExpressionList ')' panic(n.Position().String()) case PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER op := n.PostfixExpression.addrOf(ctx) n.IsSideEffectsFree = n.PostfixExpression.IsSideEffectsFree if d := n.PostfixExpression.Declarator(); d != nil { setAddressTaken(n, d, "PostfixExpression '.' IDENTIFIER") d.Read += ctx.readDelta } st := op.Type().Elem() if k := st.Kind(); k == Invalid || k != Struct && k != Union { //TODO report error break } f, ok := st.FieldByName(n.Token2.Value) if !ok { ctx.errNode(&n.Token2, "unknown or ambiguous field: %s", n.Token2.Value) break } n.Field = f ft := f.Type() if f.IsBitField() { //TODO report error break } ot := ctx.cfg.ABI.Ptr(n, ft) switch { case op.IsConst(): switch x := op.Value().(type) { case Uint64Value: n.Operand = &operand{abi: &ctx.cfg.ABI, typ: ot, value: x + Uint64Value(f.Offset())} return n.Operand case nil: // nop default: //TODO panic(todo(" %v: %T", n.Position(), x)) } fallthrough default: n.Operand = &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: ot, offset: op.Offset() + f.Offset()}, declarator: op.Declarator()} } case PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER op := n.PostfixExpression.check(ctx, false, false) n.IsSideEffectsFree = n.PostfixExpression.IsSideEffectsFree if d := n.PostfixExpression.Declarator(); d != nil { d.Read += ctx.readDelta } t := op.Type() if k := t.Decay().Kind(); k == Invalid || k != Ptr { //TODO report error break } st := t.Elem() if k := st.Kind(); k == Invalid || k != Struct && k != Union { //TODO report error break } f, ok := st.FieldByName(n.Token2.Value) if !ok { //TODO report error break } n.Field = f ft := f.Type() if f.IsBitField() { //TODO report error break } ot := ctx.cfg.ABI.Ptr(n, ft) switch { case op.IsConst(): switch x := op.Value().(type) { case Uint64Value: n.Operand = &operand{abi: &ctx.cfg.ABI, typ: ot, value: x + Uint64Value(f.Offset())} return n.Operand case nil: // nop default: panic(todo(" %T", x)) } fallthrough default: n.Operand = &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: ot, offset: op.Offset() + f.Offset()}, declarator: op.Declarator()} } case PostfixExpressionInc: // PostfixExpression "++" panic(n.Position().String()) case PostfixExpressionDec: // PostfixExpression "--" panic(n.Position().String()) case PostfixExpressionComplit: // '(' TypeName ')' '{' InitializerList ',' '}' //TODO IsSideEffectsFree if f := ctx.checkFn; f != nil { f.CompositeLiterals = append(f.CompositeLiterals, n) } t := n.TypeName.check(ctx, false, false, nil) var v *InitializerValue if n.InitializerList != nil { n.InitializerList.isConst = true n.InitializerList.check(ctx, &n.InitializerList.list, t, Automatic, 0, nil, false) n.InitializerList.setConstZero() v = &InitializerValue{typ: ctx.cfg.ABI.Ptr(n, t), initializer: n.InitializerList} } n.Operand = &lvalue{Operand: (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Ptr(n, t), value: v}).normalize(ctx, n)} case PostfixExpressionTypeCmp: // "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')' panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *PostfixExpression) indexAddr(ctx *context, nd Node, pe, e Operand) Operand { var x uintptr hasx := false switch v := e.Value().(type) { case Int64Value: x = uintptr(v) hasx = true case Uint64Value: x = uintptr(v) hasx = true } off := x * pe.Type().Elem().Size() switch y := pe.Value().(type) { case StringValue, WideStringValue: if hasx { return &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Ptr(n, pe.Type().Elem()), value: pe.Value(), offset: off}} } case Uint64Value: if hasx { return &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Ptr(n, pe.Type().Elem()), value: y + Uint64Value(off)}} } } if d := pe.Declarator(); d != nil && hasx { r := &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Ptr(n, pe.Type().Elem()), offset: pe.Offset() + off}, declarator: d} return r } return &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Ptr(n, pe.Type().Elem())}} } func (n *PrimaryExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case PrimaryExpressionIdent: // IDENTIFIER n.IsSideEffectsFree = true n.check(ctx, false, false) if d := n.Operand.Declarator(); d != nil { switch d.Type().Kind() { case Function: // nop //TODO ? default: setAddressTaken(n, d, "&IDENTIFIER") n.Operand = &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Ptr(n, d.Type())}, declarator: d} } return n.Operand } if ctx.cfg.RejectLateBinding && !ctx.cfg.ignoreUndefinedIdentifiers { ctx.errNode(n, "front-end: undefined: %s", n.Token.Value) return noOperand } //TODO case PrimaryExpressionInt: // INTCONST panic(n.Position().String()) case PrimaryExpressionFloat: // FLOATCONST panic(n.Position().String()) case PrimaryExpressionEnum: // ENUMCONST panic(n.Position().String()) case PrimaryExpressionChar: // CHARCONST panic(n.Position().String()) case PrimaryExpressionLChar: // LONGCHARCONST panic(n.Position().String()) case PrimaryExpressionString: // STRINGLITERAL panic(n.Position().String()) case PrimaryExpressionLString: // LONGSTRINGLITERAL panic(n.Position().String()) case PrimaryExpressionExpr: // '(' Expression ')' n.Operand = n.Expression.addrOf(ctx) n.IsSideEffectsFree = n.Expression.IsSideEffectsFree case PrimaryExpressionStmt: // '(' CompoundStatement ')' panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *Expression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case ExpressionAssign: // AssignmentExpression n.Operand = n.AssignmentExpression.addrOf(ctx) n.IsSideEffectsFree = n.AssignmentExpression.IsSideEffectsFree case ExpressionComma: // Expression ',' AssignmentExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *AssignmentExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case AssignmentExpressionCond: // ConditionalExpression n.Operand = n.ConditionalExpression.addrOf(ctx) n.IsSideEffectsFree = n.ConditionalExpression.IsSideEffectsFree case AssignmentExpressionAssign: // UnaryExpression '=' AssignmentExpression panic(n.Position().String()) case AssignmentExpressionMul: // UnaryExpression "*=" AssignmentExpression panic(n.Position().String()) case AssignmentExpressionDiv: // UnaryExpression "/=" AssignmentExpression panic(n.Position().String()) case AssignmentExpressionMod: // UnaryExpression "%=" AssignmentExpression panic(n.Position().String()) case AssignmentExpressionAdd: // UnaryExpression "+=" AssignmentExpression panic(n.Position().String()) case AssignmentExpressionSub: // UnaryExpression "-=" AssignmentExpression panic(n.Position().String()) case AssignmentExpressionLsh: // UnaryExpression "<<=" AssignmentExpression panic(n.Position().String()) case AssignmentExpressionRsh: // UnaryExpression ">>=" AssignmentExpression panic(n.Position().String()) case AssignmentExpressionAnd: // UnaryExpression "&=" AssignmentExpression panic(n.Position().String()) case AssignmentExpressionXor: // UnaryExpression "^=" AssignmentExpression panic(n.Position().String()) case AssignmentExpressionOr: // UnaryExpression "|=" AssignmentExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *ConditionalExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case ConditionalExpressionLOr: // LogicalOrExpression n.Operand = n.LogicalOrExpression.addrOf(ctx) n.IsSideEffectsFree = n.LogicalOrExpression.IsSideEffectsFree case ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *LogicalOrExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case LogicalOrExpressionLAnd: // LogicalAndExpression n.Operand = n.LogicalAndExpression.addrOf(ctx) n.IsSideEffectsFree = n.LogicalAndExpression.IsSideEffectsFree case LogicalOrExpressionLOr: // LogicalOrExpression "||" LogicalAndExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *LogicalAndExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case LogicalAndExpressionOr: // InclusiveOrExpression n.Operand = n.InclusiveOrExpression.addrOf(ctx) n.IsSideEffectsFree = n.InclusiveOrExpression.IsSideEffectsFree case LogicalAndExpressionLAnd: // LogicalAndExpression "&&" InclusiveOrExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *InclusiveOrExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case InclusiveOrExpressionXor: // ExclusiveOrExpression n.Operand = n.ExclusiveOrExpression.addrOf(ctx) n.IsSideEffectsFree = n.ExclusiveOrExpression.IsSideEffectsFree case InclusiveOrExpressionOr: // InclusiveOrExpression '|' ExclusiveOrExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *ExclusiveOrExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case ExclusiveOrExpressionAnd: // AndExpression n.Operand = n.AndExpression.addrOf(ctx) n.IsSideEffectsFree = n.AndExpression.IsSideEffectsFree case ExclusiveOrExpressionXor: // ExclusiveOrExpression '^' AndExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *AndExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case AndExpressionEq: // EqualityExpression n.Operand = n.EqualityExpression.addrOf(ctx) n.IsSideEffectsFree = n.EqualityExpression.IsSideEffectsFree case AndExpressionAnd: // AndExpression '&' EqualityExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *EqualityExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case EqualityExpressionRel: // RelationalExpression n.Operand = n.RelationalExpression.addrOf(ctx) n.IsSideEffectsFree = n.RelationalExpression.IsSideEffectsFree case EqualityExpressionEq: // EqualityExpression "==" RelationalExpression panic(n.Position().String()) case EqualityExpressionNeq: // EqualityExpression "!=" RelationalExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *RelationalExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case RelationalExpressionShift: // ShiftExpression n.Operand = n.ShiftExpression.addrOf(ctx) n.IsSideEffectsFree = n.ShiftExpression.IsSideEffectsFree case RelationalExpressionLt: // RelationalExpression '<' ShiftExpression panic(n.Position().String()) case RelationalExpressionGt: // RelationalExpression '>' ShiftExpression panic(n.Position().String()) case RelationalExpressionLeq: // RelationalExpression "<=" ShiftExpression panic(n.Position().String()) case RelationalExpressionGeq: // RelationalExpression ">=" ShiftExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *ShiftExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case ShiftExpressionAdd: // AdditiveExpression n.Operand = n.AdditiveExpression.addrOf(ctx) n.IsSideEffectsFree = n.AdditiveExpression.IsSideEffectsFree case ShiftExpressionLsh: // ShiftExpression "<<" AdditiveExpression panic(n.Position().String()) case ShiftExpressionRsh: // ShiftExpression ">>" AdditiveExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *AdditiveExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case AdditiveExpressionMul: // MultiplicativeExpression n.Operand = n.MultiplicativeExpression.addrOf(ctx) n.IsSideEffectsFree = n.MultiplicativeExpression.IsSideEffectsFree case AdditiveExpressionAdd: // AdditiveExpression '+' MultiplicativeExpression panic(n.Position().String()) case AdditiveExpressionSub: // AdditiveExpression '-' MultiplicativeExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *MultiplicativeExpression) addrOf(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case MultiplicativeExpressionCast: // CastExpression n.Operand = n.CastExpression.addrOf(ctx) n.IsSideEffectsFree = n.CastExpression.IsSideEffectsFree case MultiplicativeExpressionMul: // MultiplicativeExpression '*' CastExpression panic(n.Position().String()) case MultiplicativeExpressionDiv: // MultiplicativeExpression '/' CastExpression panic(n.Position().String()) case MultiplicativeExpressionMod: // MultiplicativeExpression '%' CastExpression panic(n.Position().String()) default: panic(todo("")) } return n.Operand } func (n *TypeName) check(ctx *context, inUnion, isPacked bool, list *[]*TypeSpecifier) Type { if n == nil { return noType } n.typ = n.SpecifierQualifierList.check(ctx, inUnion, isPacked, list) if n.AbstractDeclarator != nil { n.typ = n.AbstractDeclarator.check(ctx, n.typ) } for list := n.SpecifierQualifierList; list != nil; list = list.SpecifierQualifierList { if expr, ok := list.AttributeSpecifier.Has(idVectorSize, idVectorSize2); ok { n.vectorize(ctx, expr) break } } return n.typ } func (n *TypeName) vectorize(ctx *context, expr *ExpressionList) { dst := &n.typ elem := n.typ switch n.typ.Kind() { case Function: dst = &n.typ.(*functionType).result elem = n.typ.Result() } sz := expr.vectorSize(ctx) if sz == 0 { sz = elem.Size() } if sz%elem.Size() != 0 { ctx.errNode(expr, "vector size must be a multiple of the base size") } b := n.typ.base() b.size = sz b.kind = byte(Vector) *dst = &vectorType{ typeBase: b, elem: elem, length: sz / elem.Size(), } } func (n *AbstractDeclarator) check(ctx *context, typ Type) Type { if n == nil { return typ } n.typ = noType //TODO- switch n.Case { case AbstractDeclaratorPtr: // Pointer n.typ = n.Pointer.check(ctx, typ) case AbstractDeclaratorDecl: // Pointer DirectAbstractDeclarator typ = n.Pointer.check(ctx, typ) n.typ = n.DirectAbstractDeclarator.check(ctx, typ) default: panic(todo("")) } return n.typ } func (n *DirectAbstractDeclarator) check(ctx *context, typ Type) Type { if n == nil { return typ } switch n.Case { case DirectAbstractDeclaratorDecl: // '(' AbstractDeclarator ')' if n.AbstractDeclarator == nil { // [0], 6.7.6, 128) // // As indicated by the syntax, empty parentheses in a // type name are interpreted as ‘‘function with no // parameter specification’’, rather than redundant // parentheses around the omitted identifier. panic(todo("")) //TODO } return n.AbstractDeclarator.check(ctx, typ) case DirectAbstractDeclaratorArr: // DirectAbstractDeclarator '[' TypeQualifiers AssignmentExpression ']' return n.DirectAbstractDeclarator.check(ctx, checkArray(ctx, &n.Token, typ, n.AssignmentExpression, true, false)) case DirectAbstractDeclaratorStaticArr: // DirectAbstractDeclarator '[' "static" TypeQualifiers AssignmentExpression ']' return n.DirectAbstractDeclarator.check(ctx, checkArray(ctx, &n.Token, typ, n.AssignmentExpression, false, false)) case DirectAbstractDeclaratorArrStatic: // DirectAbstractDeclarator '[' TypeQualifiers "static" AssignmentExpression ']' return n.DirectAbstractDeclarator.check(ctx, checkArray(ctx, &n.Token, typ, n.AssignmentExpression, false, false)) case DirectAbstractDeclaratorArrStar: // DirectAbstractDeclarator '[' '*' ']' return n.DirectAbstractDeclarator.check(ctx, checkArray(ctx, &n.Token, typ, nil, true, true)) case DirectAbstractDeclaratorFunc: // DirectAbstractDeclarator '(' ParameterTypeList ')' ft := &functionType{typeBase: typeBase{kind: byte(Function)}, result: typ} n.ParameterTypeList.check(ctx, ft) return n.DirectAbstractDeclarator.check(ctx, ft) } panic(internalErrorf("%v: %v", n.Position(), n.Case)) } func (n *ParameterTypeList) check(ctx *context, ft *functionType) { if n == nil { return } switch n.Case { case ParameterTypeListList: // ParameterList n.ParameterList.check(ctx, ft) case ParameterTypeListVar: // ParameterList ',' "..." ft.variadic = true n.ParameterList.check(ctx, ft) default: panic(todo("")) } } func (n *ParameterList) check(ctx *context, ft *functionType) { for ; n != nil; n = n.ParameterList { p := n.ParameterDeclaration.check(ctx, ft) ft.params = append(ft.params, p) } } func (n *ParameterDeclaration) check(ctx *context, ft *functionType) *Parameter { if n == nil { return nil } switch n.Case { case ParameterDeclarationDecl: // DeclarationSpecifiers Declarator AttributeSpecifierList typ, _, _ := n.DeclarationSpecifiers.check(ctx, false) n.Declarator.IsParameter = true if n.typ = n.Declarator.check(ctx, n.DeclarationSpecifiers, typ, false); n.typ.Kind() == Void { panic(n.Position().String()) } if n.AttributeSpecifierList != nil { //TODO panic(n.Position().String()) } n.AttributeSpecifierList.check(ctx, n.typ.baseP()) return &Parameter{d: n.Declarator, typ: n.typ} case ParameterDeclarationAbstract: // DeclarationSpecifiers AbstractDeclarator n.typ, _, _ = n.DeclarationSpecifiers.check(ctx, false) if n.AbstractDeclarator != nil { n.typ = n.AbstractDeclarator.check(ctx, n.typ) } return &Parameter{typ: n.typ} default: panic(todo("")) } } func (n *Pointer) check(ctx *context, typ Type) (t Type) { if n == nil || typ == nil { return typ } switch n.Case { case PointerTypeQual: // '*' TypeQualifiers n.TypeQualifiers.check(ctx, &n.typeQualifiers) case PointerPtr: // '*' TypeQualifiers Pointer n.TypeQualifiers.check(ctx, &n.typeQualifiers) typ = n.Pointer.check(ctx, typ) case PointerBlock: // '^' TypeQualifiers n.TypeQualifiers.check(ctx, &n.typeQualifiers) default: panic(todo("")) } r := ctx.cfg.ABI.Ptr(n, typ).(*pointerType) if n.typeQualifiers != nil { r.typeQualifiers = n.typeQualifiers.check(ctx, (*DeclarationSpecifiers)(nil), false) } return r } func (n *TypeQualifiers) check(ctx *context, typ **typeBase) { for ; n != nil; n = n.TypeQualifiers { switch n.Case { case TypeQualifiersTypeQual: // TypeQualifier if *typ == nil { *typ = &typeBase{} } n.TypeQualifier.check(ctx, *typ) case TypeQualifiersAttribute: // AttributeSpecifier if *typ == nil { *typ = &typeBase{} } n.AttributeSpecifier.check(ctx, *typ) default: panic(todo("")) } } } func (n *TypeQualifier) check(ctx *context, typ *typeBase) { if n == nil { return } switch n.Case { case TypeQualifierConst: // "const" typ.flags |= fConst case TypeQualifierRestrict: // "restrict" typ.flags |= fRestrict case TypeQualifierVolatile: // "volatile" typ.flags |= fVolatile case TypeQualifierAtomic: // "_Atomic" typ.flags |= fAtomic default: panic(todo("")) } } func (n *SpecifierQualifierList) check(ctx *context, inUnion, isPacked bool, list *[]*TypeSpecifier) Type { n0 := n typ := &typeBase{} for ; n != nil; n = n.SpecifierQualifierList { switch n.Case { case SpecifierQualifierListTypeSpec: // TypeSpecifier SpecifierQualifierList n.TypeSpecifier.check(ctx, typ, inUnion) if list != nil && n.TypeSpecifier.Case != TypeSpecifierAtomic { *list = append(*list, n.TypeSpecifier) } case SpecifierQualifierListTypeQual: // TypeQualifier SpecifierQualifierList n.TypeQualifier.check(ctx, typ) case SpecifierQualifierListAlignSpec: // AlignmentSpecifier SpecifierQualifierList n.AlignmentSpecifier.check(ctx) case SpecifierQualifierListAttribute: // AttributeSpecifier SpecifierQualifierList n.AttributeSpecifier.check(ctx, typ) default: panic(todo("")) } } return typ.check(ctx, n0, true) } func (n *TypeSpecifier) check(ctx *context, typ *typeBase, inUnion bool) { if n == nil { return } switch n.Case { case TypeSpecifierVoid, // "void" TypeSpecifierChar, // "char" TypeSpecifierShort, // "short" TypeSpecifierInt, // "int" TypeSpecifierInt8, // "__int8" TypeSpecifierInt16, // "__int16" TypeSpecifierInt32, // "__int32" TypeSpecifierInt64, // "__int64" TypeSpecifierInt128, // "__int128" TypeSpecifierLong, // "long" TypeSpecifierFloat, // "float" TypeSpecifierFloat16, // "__fp16" TypeSpecifierDecimal32, // "_Decimal32" TypeSpecifierDecimal64, // "_Decimal64" TypeSpecifierDecimal128, // "_Decimal128" TypeSpecifierFloat32, // "_Float32" TypeSpecifierFloat32x, // "_Float32x" TypeSpecifierFloat64, // "_Float64" TypeSpecifierFloat64x, // "_Float64x" TypeSpecifierFloat128, // "_Float128" TypeSpecifierFloat80, // "__float80" TypeSpecifierDouble, // "double" TypeSpecifierSigned, // "signed" TypeSpecifierUnsigned, // "unsigned" TypeSpecifierBool, // "_Bool" TypeSpecifierComplex: // "_Complex" // nop case TypeSpecifierStructOrUnion: // StructOrUnionSpecifier n.StructOrUnionSpecifier.check(ctx, typ, inUnion) case TypeSpecifierEnum: // EnumSpecifier n.EnumSpecifier.check(ctx) case TypeSpecifierTypedefName: // TYPEDEFNAME // nop case TypeSpecifierTypeofExpr: // "typeof" '(' Expression ')' op := n.Expression.check(ctx, false) n.typ = op.Type() case TypeSpecifierTypeofType: // "typeof" '(' TypeName ')' n.typ = n.TypeName.check(ctx, false, false, nil) case TypeSpecifierAtomic: // AtomicTypeSpecifier t := n.AtomicTypeSpecifier.check(ctx) typ.kind = t.base().kind typ.flags |= fAtomic n.typ = typ case TypeSpecifierFract, // "_Fract" TypeSpecifierSat, // "_Sat" TypeSpecifierAccum: // "_Accum" // nop default: panic(todo("")) } } func (n *AtomicTypeSpecifier) check(ctx *context) Type { if n == nil { return nil } return n.TypeName.check(ctx, false, false, &n.list) } func (n *EnumSpecifier) check(ctx *context) { if n == nil { return } switch n.Case { case EnumSpecifierDef: // "enum" AttributeSpecifierList IDENTIFIER '{' EnumeratorList ',' '}' n.AttributeSpecifierList.check(ctx, nil) min, max := n.EnumeratorList.check(ctx) var tmin, tmax Type switch min := min.(type) { case Int64Value: switch { case min >= 0 && ctx.cfg.UnsignedEnums: tmin = n.requireUint(ctx, uint64(min)) switch max := max.(type) { case Int64Value: tmax = n.requireUint(ctx, uint64(max)) case Uint64Value: tmax = n.requireUint(ctx, uint64(max)) case nil: panic(todo("%v:", n.Position())) } default: tmin = n.requireInt(ctx, int64(min)) switch max := max.(type) { case Int64Value: tmax = n.requireInt(ctx, int64(max)) case Uint64Value: tmax = n.requireInt(ctx, int64(max)) case nil: panic(todo("%v:", n.Position())) } } case Uint64Value: tmin = n.requireUint(ctx, uint64(min)) switch max := max.(type) { case Int64Value: if max < 0 { panic(todo("%v: min %v max %v", n.Position(), min, max)) } tmax = n.requireUint(ctx, uint64(max)) case Uint64Value: tmax = n.requireUint(ctx, uint64(max)) case nil: _ = max panic(todo("%v:", n.Position())) } case nil: panic(todo("%v: %v %T", n.Position(), n.Case, min)) } switch { case tmin.Size() > tmax.Size(): n.typ = tmin default: n.typ = tmax } if !n.typ.IsIntegerType() || n.typ.Size() == 0 { //TODO- panic(todo("")) } reg := n.lexicalScope.Parent() == nil for list := n.EnumeratorList; list != nil; list = list.EnumeratorList { en := list.Enumerator en.Operand = en.Operand.convertTo(ctx, en, n.typ) if reg { ctx.enums[en.Token.Value] = en.Operand } } case EnumSpecifierTag: // "enum" AttributeSpecifierList IDENTIFIER n.typ = &taggedType{ resolutionScope: n.lexicalScope, tag: n.Token2.Value, typeBase: &typeBase{kind: byte(Enum)}, } default: panic(todo("")) } } func (n *EnumSpecifier) requireInt(ctx *context, m int64) (r Type) { var w int switch { case m < 0: w = mathutil.BitLenUint64(uint64(-m)) default: w = mathutil.BitLenUint64(uint64(m)) + 1 } w = mathutil.Max(w, 32) abi := ctx.cfg.ABI for k0, v := range intConvRank { k := Kind(k0) if k == Bool || k == Enum || v == 0 || !abi.isSignedInteger(k) { continue } t := abi.Types[k] if int(t.Size)*8 < w { continue } if r == nil || t.Size < r.Size() { r = abi.Type(k) } } if r == nil || r.Size() == 0 { //TODO- panic(todo("")) } return r } func (n *EnumSpecifier) requireUint(ctx *context, m uint64) (r Type) { w := mathutil.BitLenUint64(m) w = mathutil.Max(w, 32) abi := ctx.cfg.ABI for k0, v := range intConvRank { k := Kind(k0) if k == Bool || k == Enum || v == 0 || abi.isSignedInteger(k) { continue } t := abi.Types[k] if int(t.Size)*8 < w { continue } if r == nil || t.Size < r.Size() { r = abi.Type(k) } } if r == nil || r.Size() == 0 { //TODO- panic(todo("")) } return r } func (n *EnumeratorList) check(ctx *context) (min, max Value) { var iota Value for ; n != nil; n = n.EnumeratorList { iota, min, max = n.Enumerator.check(ctx, iota, min, max) } return min, max } func (n *Enumerator) check(ctx *context, iota, min, max Value) (Value, Value, Value) { if n == nil { return nil, nil, nil } if iota == nil { iota = Int64Value(0) } switch n.Case { case EnumeratorIdent: // IDENTIFIER AttributeSpecifierList n.AttributeSpecifierList.check(ctx, nil) n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(Int), value: iota}).normalize(ctx, n) case EnumeratorExpr: // IDENTIFIER AttributeSpecifierList '=' ConstantExpression n.AttributeSpecifierList.check(ctx, nil) n.Operand = n.ConstantExpression.check(ctx, ctx.mode|mIntConstExpr, false) iota = n.Operand.Value() default: panic(todo("")) } switch x := iota.(type) { case Int64Value: switch m := min.(type) { case Int64Value: if x < m { min = x } case Uint64Value: if x < 0 || Uint64Value(x) < m { min = x } case nil: min = x } switch m := max.(type) { case Int64Value: if x > m { max = x } case Uint64Value: if x >= 0 && Uint64Value(x) > m { max = x } case nil: max = x } x++ iota = x case Uint64Value: switch m := min.(type) { case Int64Value: if m < 0 { break } if x < Uint64Value(m) { min = x } case Uint64Value: if x < m { min = x } case nil: min = x } switch m := max.(type) { case Int64Value: if m < 0 { max = x break } if x > Uint64Value(m) { max = x } case Uint64Value: if x > m { max = x } case nil: max = x } x++ iota = x case nil: //TODO report type } return iota, min, max } func (n *ConstantExpression) check(ctx *context, mode mode, isAsmArg bool) Operand { if n == nil { return noOperand } ctx.push(mode) n.Operand = n.ConditionalExpression.check(ctx, isAsmArg) ctx.pop() return n.Operand } func (n *StructOrUnionSpecifier) check(ctx *context, typ *typeBase, inUnion bool) Type { if n == nil { return noType } switch n.Case { case StructOrUnionSpecifierDef: // StructOrUnion AttributeSpecifierList IDENTIFIER '{' StructDeclarationList '}' typ.kind = byte(n.StructOrUnion.check(ctx)) attr := n.AttributeSpecifierList.check(ctx, typ) fields := n.StructDeclarationList.check(ctx, inUnion || typ.Kind() == Union, typ.IsPacked()) m := make(map[StringID]*field, len(fields)) x := 0 for _, v := range fields { if v.name != 0 { v.x = x v.xs = []int{x} x++ m[v.name] = v } } t := (&structType{ attr: attr, fields: fields, m: m, tag: n.Token.Value, typeBase: typ, }).check(ctx, n) if typ.Kind() == Union { var k Kind for _, v := range fields { if k == Invalid { k = v.typ.Kind() continue } if v.typ.Kind() != k { k = Invalid break } } t.common = k } n.typ = t if nm := n.Token.Value; nm != 0 && n.lexicalScope.Parent() == nil { ctx.structTypes[nm] = t } case StructOrUnionSpecifierTag: // StructOrUnion AttributeSpecifierList IDENTIFIER typ.kind = byte(n.StructOrUnion.check(ctx)) attr := n.AttributeSpecifierList.check(ctx, typ.baseP()) n.typ = &taggedType{ resolutionScope: n.lexicalScope, tag: n.Token.Value, typeBase: typ, } if attr != nil { n.typ = &attributedType{n.typ, attr} } default: panic(todo("")) } return n.typ } func (n *StructDeclarationList) check(ctx *context, inUnion, isPacked bool) (s []*field) { for ; n != nil; n = n.StructDeclarationList { s = append(s, n.StructDeclaration.check(ctx, inUnion, isPacked)...) } return s } func (n *StructDeclaration) check(ctx *context, inUnion, isPacked bool) (s []*field) { if n == nil || n.Empty { return nil } typ := n.SpecifierQualifierList.check(ctx, inUnion, isPacked, nil) if n.StructDeclaratorList != nil { return n.StructDeclaratorList.check(ctx, n.SpecifierQualifierList, typ, inUnion, isPacked) } return []*field{{typ: typ, inUnion: inUnion}} } func (n *StructDeclaratorList) check(ctx *context, td typeDescriptor, typ Type, inUnion, isPacked bool) (s []*field) { for ; n != nil; n = n.StructDeclaratorList { s = append(s, n.StructDeclarator.check(ctx, td, typ, inUnion, isPacked)) } return s } func (n *StructDeclarator) check(ctx *context, td typeDescriptor, typ Type, inUnion, isPacked bool) *field { if n == nil { return nil } if isPacked { typ.baseP().flags |= fPacked } if n.Declarator != nil { typ = n.Declarator.check(ctx, td, typ, false) } if attr := n.AttributeSpecifierList.check(ctx, typ.baseP()); len(attr) != 0 { typ = &attributedType{typ, attr} } sf := &field{ typ: typ, d: n, inUnion: inUnion, } switch n.Case { case StructDeclaratorDecl: // Declarator sf.name = n.Declarator.Name() case StructDeclaratorBitField: // Declarator ':' ConstantExpression AttributeSpecifierList sf.isBitField = true sf.typ = &bitFieldType{Type: typ, field: sf} sf.name = n.Declarator.Name() if op := n.ConstantExpression.check(ctx, ctx.mode|mIntConstExpr, false); op.Type().IsIntegerType() { switch x := op.Value().(type) { case Int64Value: if x < 0 || x > 64 { panic("TODO") } sf.bitFieldWidth = byte(x) case Uint64Value: if x > 64 { panic("TODO") } sf.bitFieldWidth = byte(x) default: //dbg("%T", x) panic(PrettyString(op)) } } else { //dbg("", n.ConstantExpression) panic(n.Declarator.Position()) } n.AttributeSpecifierList.check(ctx, sf.typ.baseP()) default: panic(todo("")) } return sf } func (n *StructOrUnion) check(ctx *context) Kind { if n == nil { return Invalid } switch n.Case { case StructOrUnionStruct: // "struct" return Struct case StructOrUnionUnion: // "union" return Union default: panic(todo("")) } } func (n *CastExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case CastExpressionUnary: // UnaryExpression n.Operand = n.UnaryExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.UnaryExpression.IsSideEffectsFree case CastExpressionCast: // '(' TypeName ')' CastExpression t := n.TypeName.check(ctx, false, false, nil) ctx.push(ctx.mode) if m := ctx.mode; m&mIntConstExpr != 0 && m&mIntConstExprAnyCast == 0 { if t := n.TypeName.Type(); t != nil && t.Kind() != Int { ctx.mode &^= mIntConstExpr } ctx.mode |= mIntConstExprFloat } op := n.CastExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.CastExpression.IsSideEffectsFree ctx.pop() n.Operand = op.convertTo(ctx, n, t) default: panic(todo("")) } return n.Operand } func (n *PostfixExpression) check(ctx *context, implicitFunc, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- out: switch n.Case { case PostfixExpressionPrimary: // PrimaryExpression n.Operand = n.PrimaryExpression.check(ctx, implicitFunc, isAsmArg) n.IsSideEffectsFree = n.PrimaryExpression.IsSideEffectsFree case PostfixExpressionIndex: // PostfixExpression '[' Expression ']' pe := n.PostfixExpression.check(ctx, false, isAsmArg) if d := pe.Declarator(); d != nil { d.Read += ctx.readDelta } e := n.Expression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.PostfixExpression.IsSideEffectsFree && n.Expression.IsSideEffectsFree t := pe.Type().Decay() if t.Kind() == Invalid { break } if t.Kind() == Ptr { if t := e.Type(); t.Kind() != Invalid && !t.IsIntegerType() { ctx.errNode(n.Expression, "index must be integer type, have %v", e.Type()) break } n.Operand = n.index(ctx, pe, e) break } if pe.Type().Kind() == Vector { if t := e.Type(); t.Kind() != Invalid && !t.IsIntegerType() { ctx.errNode(n.Expression, "index must be integer type, have %v", e.Type()) break } n.Operand = n.index(ctx, pe, e) break } t = e.Type().Decay() if t.Kind() == Invalid { break } if t.Kind() == Ptr { if t := pe.Type(); t.Kind() != Invalid && !t.IsIntegerType() { ctx.errNode(n.Expression, "index must be integer type, have %v", pe.Type()) break } n.Operand = n.index(ctx, e, pe) break } ctx.errNode(n, "invalid index expression %v[%v]", pe.Type(), e.Type()) case PostfixExpressionCall: // PostfixExpression '(' ArgumentExpressionList ')' op := n.PostfixExpression.check(ctx, true, isAsmArg) Inspect(n.PostfixExpression, func(n Node, enter bool) bool { if !enter { return true } if x, ok := n.(*PrimaryExpression); ok { if d := x.Declarator(); d != nil { d.called = true } } return true }) args := n.ArgumentExpressionList.check(ctx, n.PostfixExpression.Declarator(), isAsmArg) switch op.Declarator().Name() { case idBuiltinConstantPImpl: if len(args) < 2 { panic(todo("")) } var v Int64Value if args[1].Value() != nil { v = 1 } n.Operand = &operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(Int), value: v} default: switch n.PostfixExpression.Operand.Value().(type) { case StringValue, WideStringValue: if isAsmArg { // asm("foo": "bar" (a)) // ^ break out } } n.Operand = n.checkCall(ctx, n, op.Type(), args, n.ArgumentExpressionList) } case PostfixExpressionSelect: // PostfixExpression '.' IDENTIFIER op := n.PostfixExpression.check(ctx, false, isAsmArg) n.IsSideEffectsFree = n.PostfixExpression.IsSideEffectsFree if d := op.Declarator(); d != nil { d.Read += ctx.readDelta } st := op.Type() st0 := st.underlyingType() if k := st.Kind(); k == Invalid || k != Struct && k != Union { ctx.errNode(n.PostfixExpression, "select expression of wrong type: %s (%s)", st, st0) break } f, ok := st.FieldByName(n.Token2.Value) if !ok { ctx.errNode(n.PostfixExpression, "unknown or ambiguous field %q of type %s (%s)", n.Token2.Value, st, st0) break } n.Field = f ft := f.Type() if f.IsBitField() { ft = &bitFieldType{Type: ft, field: f.(*field)} n.Operand = &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: ft}} break } n.Operand = &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: ft, offset: op.Offset() + f.Offset()}} case PostfixExpressionPSelect: // PostfixExpression "->" IDENTIFIER op := n.PostfixExpression.check(ctx, false, isAsmArg) n.IsSideEffectsFree = n.PostfixExpression.IsSideEffectsFree if d := op.Declarator(); d != nil { d.Read += ctx.readDelta } t := op.Type() if k := t.Decay().Kind(); k == Invalid || k != Ptr { //TODO report error break } st := t.Elem() if k := st.Kind(); k == Invalid || k != Struct && k != Union { //TODO report error break } f, ok := st.FieldByName(n.Token2.Value) if !ok { //TODO report error break } n.Field = f ft := f.Type() if f.IsBitField() { ft = &bitFieldType{Type: ft, field: f.(*field)} } n.Operand = &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: ft}} case PostfixExpressionInc: // PostfixExpression "++" op := n.PostfixExpression.check(ctx, false, isAsmArg) if d := op.Declarator(); d != nil { d.SubjectOfIncDec = true d.Read += ctx.readDelta d.Write++ } n.Operand = &operand{abi: &ctx.cfg.ABI, typ: op.Type()} case PostfixExpressionDec: // PostfixExpression "--" op := n.PostfixExpression.check(ctx, false, isAsmArg) if d := op.Declarator(); d != nil { d.SubjectOfIncDec = true d.Read += ctx.readDelta d.Write++ } n.Operand = &operand{abi: &ctx.cfg.ABI, typ: op.Type()} case PostfixExpressionComplit: // '(' TypeName ')' '{' InitializerList ',' '}' //TODO IsSideEffectsFree if f := ctx.checkFn; f != nil { f.CompositeLiterals = append(f.CompositeLiterals, n) } t := n.TypeName.check(ctx, false, false, nil) var v *InitializerValue if n.InitializerList != nil { n.InitializerList.check(ctx, &n.InitializerList.list, t, Automatic, 0, nil, false) n.InitializerList.setConstZero() v = &InitializerValue{typ: t, initializer: n.InitializerList} } n.Operand = &lvalue{Operand: (&operand{abi: &ctx.cfg.ABI, typ: t, value: v}).normalize(ctx, n)} case PostfixExpressionTypeCmp: // "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')' n.IsSideEffectsFree = true t1 := n.TypeName.check(ctx, false, false, nil) t2 := n.TypeName2.check(ctx, false, false, nil) v := 0 switch { case t1.IsArithmeticType() && t2.IsArithmeticType(): if t1.Kind() == t2.Kind() { v = 1 } default: ctx.errNode(n, "ICE: __builtin_types_compatible_p(%v, %v)", t1, t2) } n.Operand = &operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(Int), value: Int64Value(v)} case PostfixExpressionChooseExpr: // "__builtin_choose_expr" '(' ConstantExpression ',' AssignmentExpression ',' AssignmentExpression ')' n.Operand = noOperand expr1 := n.AssignmentExpression.check(ctx, isAsmArg) if expr1 == nil { ctx.errNode(n, "first argument of __builtin_choose_expr must be a constant expression") break } if !expr1.IsConst() { ctx.errNode(n, "first argument of __builtin_choose_expr must be a constant expression: %v %v", expr1.Value(), expr1.Type()) break } switch { case expr1.IsNonZero(): n.Operand = n.AssignmentExpression2.check(ctx, isAsmArg) n.IsSideEffectsFree = n.AssignmentExpression2.IsSideEffectsFree default: n.Operand = n.AssignmentExpression3.check(ctx, isAsmArg) n.IsSideEffectsFree = n.AssignmentExpression3.IsSideEffectsFree } default: panic(todo("")) } return n.Operand } func (n *PostfixExpression) index(ctx *context, pe, e Operand) Operand { var x uintptr hasx := false switch v := e.Value().(type) { case Int64Value: x = uintptr(v) hasx = true case Uint64Value: x = uintptr(v) hasx = true } off := x * pe.Type().Elem().Size() switch v := pe.Value().(type) { case StringValue: if hasx { s := StringID(v).String() var v byte switch { case x > uintptr(len(s)): //TODO report err return noOperand case x < uintptr(len(s)): v = s[x] } return (&operand{abi: &ctx.cfg.ABI, typ: pe.Type().Elem(), value: Int64Value(v)}).normalize(ctx, n) } case WideStringValue: if hasx { s := []rune(StringID(v).String()) var v rune switch { case x > uintptr(len(s)): //TODO report err return noOperand case x < uintptr(len(s)): v = s[x] } return (&operand{abi: &ctx.cfg.ABI, typ: pe.Type().Elem(), value: Int64Value(v)}).normalize(ctx, n) } } if d := pe.Declarator(); d != nil && hasx { return &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: pe.Type().Elem(), offset: pe.Offset() + off}, declarator: d} } return &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: pe.Type().Elem()}} } func (n *PostfixExpression) checkCall(ctx *context, nd Node, f Type, args []Operand, argList *ArgumentExpressionList) (r Operand) { r = noOperand switch f.Kind() { case Invalid: return noOperand case Function: // ok case Ptr: if e := f.Elem(); e.Kind() == Function { f = e break } ctx.errNode(nd, "expected function pointer type: %v, %v", f, f.Kind()) return r default: ctx.errNode(nd, "expected function type: %v, %v", f, f.Kind()) return r } r = &operand{abi: &ctx.cfg.ABI, typ: f.Result()} params := f.Parameters() if len(params) == 1 && params[0].Type().Kind() == Void { params = nil if len(args) != 0 { //TODO report error return r } } for i, arg := range args { var t Type switch { case i < len(params): //TODO check assignability t = params[i].Type().Decay() default: t = defaultArgumentPromotion(ctx, nd, arg).Type() } argList.AssignmentExpression.promote = t argList = argList.ArgumentExpressionList } return r } func defaultArgumentPromotion(ctx *context, n Node, op Operand) Operand { t := op.Type().Decay() if arithmeticTypes[t.Kind()] { if t.IsIntegerType() { return op.integerPromotion(ctx, n) } switch t.Kind() { case Float: return op.convertTo(ctx, n, ctx.cfg.ABI.Type(Double)) } } return op } func (n *ArgumentExpressionList) check(ctx *context, f *Declarator, isAsmArg bool) (r []Operand) { for ; n != nil; n = n.ArgumentExpressionList { op := n.AssignmentExpression.check(ctx, isAsmArg) if op.Type() == nil { ctx.errNode(n, "operand has usupported, invalid or incomplete type") op = noOperand } else if op.Type().IsComplexType() { ctx.checkFn.CallSiteComplexExpr = append(ctx.checkFn.CallSiteComplexExpr, n.AssignmentExpression) } r = append(r, op) if !ctx.cfg.TrackAssignments { continue } Inspect(n.AssignmentExpression, func(n Node, enter bool) bool { if !enter { return true } if x, ok := n.(*PrimaryExpression); ok { x.Declarator().setLHS(f) } return true }) } return r } func (n *Expression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case ExpressionAssign: // AssignmentExpression n.Operand = n.AssignmentExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.AssignmentExpression.IsSideEffectsFree case ExpressionComma: // Expression ',' AssignmentExpression op := n.Expression.check(ctx, isAsmArg) n.Operand = n.AssignmentExpression.check(ctx, isAsmArg) if !op.IsConst() && n.Operand.IsConst() { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: n.Operand.Type()} } n.IsSideEffectsFree = n.Expression.IsSideEffectsFree && n.AssignmentExpression.IsSideEffectsFree default: panic(todo("")) } return n.Operand } func (n *PrimaryExpression) check(ctx *context, implicitFunc, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case PrimaryExpressionIdent: // IDENTIFIER n.IsSideEffectsFree = true return n.checkIdentifier(ctx, implicitFunc) case PrimaryExpressionInt: // INTCONST n.IsSideEffectsFree = true n.Operand = n.intConst(ctx) case PrimaryExpressionFloat: // FLOATCONST n.IsSideEffectsFree = true if ctx.mode&mIntConstExpr != 0 && ctx.mode&mIntConstExprFloat == 0 { ctx.errNode(n, "invalid integer constant expression") break } n.Operand = n.floatConst(ctx) case PrimaryExpressionEnum: // ENUMCONST n.IsSideEffectsFree = true if e := n.resolvedIn.enumerator(n.Token.Value, n.Token); e != nil { op := e.Operand.(*operand) op.typ = ctx.cfg.ABI.Type(Int) // [0] 6.4.4.3/2 n.Operand = op break } //TODO report err case PrimaryExpressionChar: // CHARCONST n.IsSideEffectsFree = true s := []rune(n.Token.Value.String()) var v Value switch { case s[0] <= 255: // If an integer character constant contains a single character or escape // sequence, its value is the one that results when an object with type char // whose value is that of the single character or escape sequence is converted // to type int. switch { case ctx.cfg.ABI.SignedChar: v = Int64Value(int8(s[0])) default: v = Int64Value(s[0]) } default: v = Int64Value(s[0]) } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(Int), value: v}).normalize(ctx, n) case PrimaryExpressionLChar: // LONGCHARCONST n.IsSideEffectsFree = true s := []rune(n.Token.Value.String()) n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: wcharT(ctx, n.lexicalScope, n.Token), value: Int64Value(s[0])}).normalize(ctx, n) case PrimaryExpressionString: // STRINGLITERAL n.IsSideEffectsFree = true ctx.not(n, mIntConstExpr) typ := ctx.cfg.ABI.Type(Char) b := typ.base() b.align = byte(typ.Align()) b.fieldAlign = byte(typ.FieldAlign()) b.kind = byte(Array) sz := uintptr(len(n.Token.Value.String())) + 1 //TODO set sz in cpp arr := &arrayType{typeBase: b, decay: ctx.cfg.ABI.Ptr(n, typ), elem: typ, length: sz} arr.setLen(sz) n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: arr, value: StringValue(n.Token.Value)}).normalize(ctx, n) case PrimaryExpressionLString: // LONGSTRINGLITERAL n.IsSideEffectsFree = true ctx.not(n, mIntConstExpr) typ := wcharT(ctx, n.lexicalScope, n.Token) b := typ.base() b.align = byte(typ.Align()) b.fieldAlign = byte(typ.FieldAlign()) b.kind = byte(Array) sz := uintptr(len([]rune(n.Token.Value.String()))) + 1 //TODO set sz in cpp arr := &arrayType{typeBase: b, decay: ctx.cfg.ABI.Ptr(n, typ), elem: typ, length: sz} arr.setLen(sz) n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: arr, value: WideStringValue(n.Token.Value)}).normalize(ctx, n) case PrimaryExpressionExpr: // '(' Expression ')' n.Operand = n.Expression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.Expression.IsSideEffectsFree case PrimaryExpressionStmt: // '(' CompoundStatement ')' //TODO IsSideEffectsFree ctx.not(n, mIntConstExpr) n.Operand = n.CompoundStatement.check(ctx) if n.Operand == noOperand { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(Void)} } default: panic(todo("")) } return n.Operand } func wcharT(ctx *context, s Scope, tok Token) Type { if t := ctx.wcharT; t != nil { return t } t := ctx.stddef(idWCharT, s, tok) if t.Kind() != Invalid { ctx.wcharT = t } return t } func (n *PrimaryExpression) checkIdentifier(ctx *context, implicitFunc bool) Operand { ctx.not(n, mIntConstExpr) var d *Declarator nm := n.Token.Value if n.resolvedIn == nil { if ctx.cfg.RejectLateBinding && !ctx.cfg.ignoreUndefinedIdentifiers { ctx.errNode(n, "front-end: undefined: %s", n.Token.Value) return noOperand } out: for s := n.lexicalScope; s != nil; s = s.Parent() { for _, v := range s[nm] { switch x := v.(type) { case *Enumerator: break out case *Declarator: if x.IsTypedefName { d = nil break out } n.resolvedIn = s n.resolvedTo = x d = x t := d.Type() if t != nil && t.Kind() == Function { if d.fnDef { break out } continue } if t != nil && !t.IsIncomplete() { break out } case *EnumSpecifier, *StructOrUnionSpecifier, *StructDeclarator, *LabeledStatement: // nop default: panic(todo("")) } } } } if d == nil && n.resolvedIn != nil { d = n.resolvedIn.declarator(n.Token.Value, n.Token) } if d == nil && !ctx.cfg.DisableBuiltinResolution { d = builtin(ctx, nm) } if d == nil { _, ok := gccKeywords[nm] if !ok && implicitFunc { d := &Declarator{ DirectDeclarator: &DirectDeclarator{ lexicalScope: ctx.ast.Scope, Case: DirectDeclaratorFuncIdent, DirectDeclarator: &DirectDeclarator{ lexicalScope: ctx.ast.Scope, Case: DirectDeclaratorIdent, Token: Token{Value: nm}, }, }, implicit: true, } ed := &ExternalDeclaration{ Case: ExternalDeclarationDecl, Declaration: &Declaration{ DeclarationSpecifiers: &DeclarationSpecifiers{ Case: DeclarationSpecifiersTypeSpec, TypeSpecifier: &TypeSpecifier{ Case: TypeSpecifierInt, }, }, InitDeclaratorList: &InitDeclaratorList{ InitDeclarator: &InitDeclarator{ Case: InitDeclaratorDecl, Declarator: d, }, }, }, } ed.check(ctx) n.Operand = &funcDesignator{Operand: &operand{abi: &ctx.cfg.ABI, typ: d.Type()}, declarator: d} return n.Operand } if !ctx.cfg.ignoreUndefinedIdentifiers { ctx.errNode(n, "front-end: undefined: %s", n.Token.Value) } return noOperand } if d == nil { if !ctx.cfg.ignoreUndefinedIdentifiers { ctx.errNode(n, "front-end: undefined: %s", n.Token.Value) } return noOperand } switch d.Linkage { case Internal: if d.IsStatic() { break } fallthrough case External: s := n.resolvedIn if s.Parent() == nil { break } for s.Parent() != nil { s = s.Parent() } if d2 := s.declarator(n.Token.Value, Token{}); d2 != nil { d = d2 } } if d.Type() == nil { ctx.errNode(d, "unresolved type of: %s", n.Token.Value) return noOperand } d.Read += ctx.readDelta switch t := d.Type(); t.Kind() { case Function: n.Operand = &funcDesignator{Operand: &operand{abi: &ctx.cfg.ABI, typ: t}, declarator: d} default: n.Operand = &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: t}, declarator: d} } if !ctx.capture { return n.Operand } for s := n.lexicalScope; s != nil; s = s.Parent() { if _, ok := s[nm]; ok { return n.Operand // d in fn scope } if _, ok := s[idClosure]; ok { // d in outer scope if ctx.closure == nil { ctx.closure = map[StringID]struct{}{} //TODO capture the PrimaryExpression, not the declarator name } ctx.closure[nm] = struct{}{} return n.Operand } } panic(todo("")) } func builtin(ctx *context, nm StringID) *Declarator { id := dict.sid("__builtin_" + nm.String()) a := ctx.ast.Scope[id] if len(a) == 0 { return nil } switch x := a[0].(type) { case *Declarator: if x.fnDef || x.IsFunctionPrototype() { return x } } return nil } func (n *PrimaryExpression) floatConst(ctx *context) Operand { s0 := n.Token.String() s := s0 var cplx, suff string loop2: for i := len(s) - 1; i > 0; i-- { switch s0[i] { case 'l', 'L': s = s[:i] if ctx.cfg.LongDoubleIsDouble { break } suff += "l" case 'f', 'F': s = s[:i] suff += "f" case 'i', 'I', 'j', 'J': s = s[:i] cplx += "i" default: break loop2 } } if len(suff) > 1 || len(cplx) > 1 { ctx.errNode(n, "invalid number format") return noOperand } var v float64 var err error prec := uint(64) if suff == "l" { prec = longDoublePrec } var bf *big.Float switch { case suff == "l" || strings.Contains(s, "p") || strings.Contains(s, "P"): bf, _, err = big.ParseFloat(strings.ToLower(s), 0, prec, big.ToNearestEven) if err == nil { v, _ = bf.Float64() } default: v, err = strconv.ParseFloat(s, 64) } if err != nil { switch { case !strings.HasPrefix(s, "-") && strings.Contains(err.Error(), "value out of range"): // linux_386/usr/include/math.h // // /* Value returned on overflow. With IEEE 754 floating point, this is // +Infinity, otherwise the largest representable positive value. */ // #if __GNUC_PREREQ (3, 3) // # define HUGE_VAL (__builtin_huge_val ()) // #else // /* This may provoke compiler warnings, and may not be rounded to // +Infinity in all IEEE 754 rounding modes, but is the best that can // be done in ISO C while remaining a constant expression. 10,000 is // greater than the maximum (decimal) exponent for all supported // floating-point formats and widths. */ // # define HUGE_VAL 1e10000 // #endif v = math.Inf(1) default: ctx.errNode(n, "%v", err) return noOperand } } // [0]6.4.4.2 switch suff { case "": switch { case cplx != "": return (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(ComplexDouble), value: Complex128Value(complex(0, v))}).normalize(ctx, n) default: return (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(Double), value: Float64Value(v)}).normalize(ctx, n) } case "f": switch { case cplx != "": return (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(ComplexFloat), value: Complex64Value(complex(0, float32(v)))}).normalize(ctx, n) default: return (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(Float), value: Float32Value(float32(v))}).normalize(ctx, n) } case "l": switch { case cplx != "": return (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(ComplexLongDouble), value: Complex256Value{&Float128Value{N: big.NewFloat(0)}, &Float128Value{N: bf}}}).normalize(ctx, n) default: return (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(LongDouble), value: &Float128Value{N: bf}}).normalize(ctx, n) } default: //dbg("%q %q %q %q %v", s0, s, suff, cplx, err) panic("TODO") } } func (n *PrimaryExpression) intConst(ctx *context) Operand { var val uint64 s0 := n.Token.String() s := strings.TrimRight(s0, "uUlL") var decadic bool switch { case strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X"): var err error if val, err = strconv.ParseUint(s[2:], 16, 64); err != nil { ctx.errNode(n, "%v", err) return nil } case strings.HasPrefix(s, "0b") || strings.HasPrefix(s, "0B"): var err error if val, err = strconv.ParseUint(s[2:], 2, 64); err != nil { ctx.errNode(n, "%v", err) return nil } case strings.HasPrefix(s, "0"): var err error if val, err = strconv.ParseUint(s, 8, 64); err != nil { ctx.errNode(n, "%v", err) return nil } default: decadic = true var err error if val, err = strconv.ParseUint(s, 10, 64); err != nil { ctx.errNode(n, "%v", err) return nil } } suffix := s0[len(s):] switch suffix = strings.ToLower(suffix); suffix { case "": if decadic { return intConst(ctx, n, s0, val, Int, Long, LongLong) } return intConst(ctx, n, s0, val, Int, UInt, Long, ULong, LongLong, ULongLong) case "u": return intConst(ctx, n, s0, val, UInt, ULong, ULongLong) case "l": if decadic { return intConst(ctx, n, s0, val, Long, LongLong) } return intConst(ctx, n, s0, val, Long, ULong, LongLong, ULongLong) case "lu", "ul": return intConst(ctx, n, s0, val, ULong, ULongLong) case "ll": if decadic { return intConst(ctx, n, s0, val, LongLong) } return intConst(ctx, n, s0, val, LongLong, ULongLong) case "llu", "ull": return intConst(ctx, n, s0, val, ULongLong) default: ctx.errNode(n, "invalid suffix: %v", s0) return nil } } func intConst(ctx *context, n Node, s string, val uint64, list ...Kind) Operand { abi := ctx.cfg.ABI b := bits.Len64(val) for _, k := range list { sign := 0 if abi.isSignedInteger(k) { sign = 1 } if abi.size(k)*8 >= b+sign { switch { case sign == 0: return (&operand{abi: &ctx.cfg.ABI, typ: abi.Type(k), value: Uint64Value(val)}).normalize(ctx, n) default: return (&operand{abi: &ctx.cfg.ABI, typ: abi.Type(k), value: Int64Value(val)}).normalize(ctx, n) } } } ctx.errNode(n, "invalid integer constant %v", s) return nil } func (n *ConditionalExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case ConditionalExpressionLOr: // LogicalOrExpression n.Operand = n.LogicalOrExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.LogicalOrExpression.IsSideEffectsFree case ConditionalExpressionCond: // LogicalOrExpression '?' Expression ':' ConditionalExpression op := n.LogicalOrExpression.check(ctx, isAsmArg) // The first operand shall have scalar type. if !op.Type().Decay().IsScalarType() { //TODO report error break } a := n.Expression.check(ctx, isAsmArg) b := n.ConditionalExpression.check(ctx, isAsmArg) at := a.Type().Decay() bt := b.Type().Decay() n.IsSideEffectsFree = n.LogicalOrExpression.IsSideEffectsFree && (n.Expression == nil || n.Expression.IsSideEffectsFree) && n.ConditionalExpression.IsSideEffectsFree var val Value if op.Value() != nil { switch { case op.IsZero(): n.IsSideEffectsFree = n.LogicalOrExpression.IsSideEffectsFree && n.ConditionalExpression.IsSideEffectsFree default: n.IsSideEffectsFree = n.LogicalOrExpression.IsSideEffectsFree && n.Expression.IsSideEffectsFree } if a.Value() != nil && b.Value() != nil { //TODO not needed both non nil switch { case op.IsZero(): val = b.Value() default: val = a.Value() } } } if a.Type().Kind() == Invalid && b.Type().Kind() == Invalid { return noOperand } // One of the following shall hold for the second and third // operands: //TODO — both operands have the same structure or union type; //TODO — one operand is a pointer to an object or incomplete type and the other is a pointer to a //TODO qualified or unqualified version of void. switch { // — both operands have arithmetic type; case a.Type().IsArithmeticType() && b.Type().IsArithmeticType(): // If both the second and third operands have // arithmetic type, the result type that would be // determined by the usual arithmetic conversions, were // they applied to those two operands, // is the type of the result. op, _ := usualArithmeticConversions(ctx, n, a, b, true) n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: op.Type(), value: val}).normalize(ctx, n) // — both operands have void type; case a.Type().Kind() == Void && b.Type().Kind() == Void: n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: val}).normalize(ctx, n) // — one operand is a pointer and the other is a null pointer constant; case (a.Type().Kind() == Ptr || a.Type().Kind() == Function) && b.IsZero(): n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: val}).normalize(ctx, n) case (b.Type().Kind() == Ptr || b.Type().Kind() == Function) && a.IsZero(): n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: b.Type(), value: val}).normalize(ctx, n) // — both operands are pointers to qualified or unqualified versions of compatible types; case at.Kind() == Ptr && bt.Kind() == Ptr: //TODO check compatible //TODO if !at.isCompatibleIgnoreQualifiers(bt) { //TODO trc("%v: XXXX %v ? %v", n.Token2.Position(), at, bt) //TODO ctx.assignmentCompatibilityErrorCond(&n.Token2, at, bt) //TODO } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: n.Expression.Operand.Type(), value: val}).normalize(ctx, n) case a.Type().Kind() == Ptr && a.Type().Elem().Kind() == Function && b.Type().Kind() == Function: //TODO check compatible n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: val}).normalize(ctx, n) case b.Type().Kind() == Ptr && b.Type().Elem().Kind() == Function && a.Type().Kind() == Function: //TODO check compatible n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: b.Type(), value: val}).normalize(ctx, n) case a.Type().Kind() != Invalid: n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: val}).normalize(ctx, n) case b.Type().Kind() != Invalid: n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: b.Type(), value: val}).normalize(ctx, n) default: panic(todo("")) } default: panic(todo("")) } return n.Operand } func (n *LogicalOrExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case LogicalOrExpressionLAnd: // LogicalAndExpression n.Operand = n.LogicalAndExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.LogicalAndExpression.IsSideEffectsFree case LogicalOrExpressionLOr: // LogicalOrExpression "||" LogicalAndExpression lop := n.LogicalOrExpression.check(ctx, isAsmArg) rop := n.LogicalAndExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.LogicalOrExpression.IsSideEffectsFree && n.LogicalAndExpression.IsSideEffectsFree || lop.Value() != nil && lop.IsNonZero() && n.LogicalOrExpression.IsSideEffectsFree var v Value if lop.Value() != nil && rop.Value() != nil { //TODO lop.IsNonZero shortcut switch { case n.LogicalOrExpression.Operand.IsNonZero() || n.LogicalAndExpression.Operand.IsNonZero(): v = Int64Value(1) default: v = Int64Value(0) } } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(Int), value: v}).normalize(ctx, n) default: panic(todo("")) } return n.Operand } func (n *LogicalAndExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case LogicalAndExpressionOr: // InclusiveOrExpression n.Operand = n.InclusiveOrExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.InclusiveOrExpression.IsSideEffectsFree case LogicalAndExpressionLAnd: // LogicalAndExpression "&&" InclusiveOrExpression lop := n.LogicalAndExpression.check(ctx, isAsmArg) rop := n.InclusiveOrExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.LogicalAndExpression.IsSideEffectsFree && n.InclusiveOrExpression.IsSideEffectsFree || lop.Value() != nil && lop.IsZero() && n.LogicalAndExpression.IsSideEffectsFree var v Value if lop.Value() != nil && rop.Value() != nil { //TODO lop.IsZero shortcut switch { case n.LogicalAndExpression.Operand.IsNonZero() && n.InclusiveOrExpression.Operand.IsNonZero(): v = Int64Value(1) default: v = Int64Value(0) } } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(Int), value: v}).normalize(ctx, n) default: panic(todo("")) } return n.Operand } func (n *InclusiveOrExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case InclusiveOrExpressionXor: // ExclusiveOrExpression n.Operand = n.ExclusiveOrExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.ExclusiveOrExpression.IsSideEffectsFree case InclusiveOrExpressionOr: // InclusiveOrExpression '|' ExclusiveOrExpression a := n.InclusiveOrExpression.check(ctx, isAsmArg) b := n.ExclusiveOrExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.InclusiveOrExpression.IsSideEffectsFree && n.ExclusiveOrExpression.IsSideEffectsFree n.promote = noType if a.Type().Kind() == Vector || b.Type().Kind() == Vector { n.Operand = checkBinaryVectorIntegerArtithmetic(ctx, n, a, b) break } if !a.Type().IsIntegerType() || !b.Type().IsIntegerType() { ctx.errNode(n, "operands must be integers") break } a, b = usualArithmeticConversions(ctx, &n.Token, a, b, true) n.promote = a.Type() if a.Value() == nil || b.Value() == nil { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: a.Type()} break } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: a.Value().or(b.Value())}).normalize(ctx, n) default: panic(todo("")) } return n.Operand } func checkBinaryVectorIntegerArtithmetic(ctx *context, n Node, a, b Operand) Operand { var rt Type if a.Type().Kind() == Vector { rt = a.Type() a = &operand{abi: &ctx.cfg.ABI, typ: a.Type().Elem()} } if b.Type().Kind() == Vector { if rt == nil { rt = b.Type() } b = &operand{abi: &ctx.cfg.ABI, typ: b.Type().Elem()} } a, b = usualArithmeticConversions(ctx, n, a, b, true) if !a.Type().IsIntegerType() || !b.Type().IsIntegerType() { ctx.errNode(n, "operands must be integers") } return &operand{abi: &ctx.cfg.ABI, typ: rt} } func (n *ExclusiveOrExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case ExclusiveOrExpressionAnd: // AndExpression n.Operand = n.AndExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.AndExpression.IsSideEffectsFree case ExclusiveOrExpressionXor: // ExclusiveOrExpression '^' AndExpression a := n.ExclusiveOrExpression.check(ctx, isAsmArg) b := n.AndExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.ExclusiveOrExpression.IsSideEffectsFree && n.AndExpression.IsSideEffectsFree if a.Type().Kind() == Vector || b.Type().Kind() == Vector { n.Operand = checkBinaryVectorIntegerArtithmetic(ctx, n, a, b) break } if !a.Type().IsIntegerType() || !b.Type().IsIntegerType() { ctx.errNode(n, "operands must be integers") break } a, b = usualArithmeticConversions(ctx, &n.Token, a, b, true) n.promote = a.Type() if a.Value() == nil || b.Value() == nil { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: a.Type()} break } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: a.Value().xor(b.Value())}).normalize(ctx, n) default: panic(todo("")) } return n.Operand } func (n *AndExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case AndExpressionEq: // EqualityExpression n.Operand = n.EqualityExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.EqualityExpression.IsSideEffectsFree case AndExpressionAnd: // AndExpression '&' EqualityExpression a := n.AndExpression.check(ctx, isAsmArg) b := n.EqualityExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.AndExpression.IsSideEffectsFree && n.EqualityExpression.IsSideEffectsFree if a.Type().Kind() == Vector || b.Type().Kind() == Vector { n.Operand = checkBinaryVectorIntegerArtithmetic(ctx, n, a, b) break } if !a.Type().IsIntegerType() || !b.Type().IsIntegerType() { ctx.errNode(n, "operands must be integers") break } a, b = usualArithmeticConversions(ctx, &n.Token, a, b, true) n.promote = a.Type() if a.Value() == nil || b.Value() == nil { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: a.Type()} break } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: a.Value().and(b.Value())}).normalize(ctx, n) default: panic(todo("")) } return n.Operand } func (n *EqualityExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } switch n.Case { case EqualityExpressionRel: // RelationalExpression n.Operand = n.RelationalExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.RelationalExpression.IsSideEffectsFree case EqualityExpressionEq, // EqualityExpression "==" RelationalExpression EqualityExpressionNeq: // EqualityExpression "!=" RelationalExpression op := &operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(Int)} n.Operand = op lo := n.EqualityExpression.check(ctx, isAsmArg) ro := n.RelationalExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.EqualityExpression.IsSideEffectsFree && n.RelationalExpression.IsSideEffectsFree lt := lo.Type().Decay() rt := ro.Type().Decay() n.promote = noType ok := false switch { case lo.Type().Kind() == Vector && ro.Type().Kind() == Vector: n.Operand = checkVectorComparison(ctx, n, lo.Type(), ro.Type()) return n.Operand case lt.IsArithmeticType() && rt.IsArithmeticType(): op, _ := usualArithmeticConversions(ctx, n, lo, ro, true) n.promote = op.Type() ok = true case lt.Kind() == Ptr && (rt.Kind() == Ptr || rt.IsIntegerType()): n.promote = lt //TODO case (lt.Kind() == Ptr || lt.IsIntegerType()) && rt.Kind() == Ptr: n.promote = rt //TODO case lt.Kind() == Function: n.promote = ctx.cfg.ABI.Ptr(n, lt) case rt.Kind() == Function: n.promote = ctx.cfg.ABI.Ptr(n, rt) default: //TODO report error } if n.promote.Kind() == Invalid || !ok { break } lo = lo.convertTo(ctx, n, n.promote) ro = ro.convertTo(ctx, n, n.promote) if a, b := lo.Value(), ro.Value(); a != nil && b != nil { switch n.Case { case EqualityExpressionEq: // EqualityExpression "==" RelationalExpression op.value = a.eq(b) case EqualityExpressionNeq: // EqualityExpression "!=" RelationalExpression op.value = a.neq(b) } } default: panic(todo("")) } return n.Operand } func checkVectorComparison(ctx *context, n Node, a, b Type) (r Operand) { a = a.underlyingType() b = b.underlyingType() rt := *a.(*vectorType) rt.elem = ctx.cfg.ABI.Type(Int) r = &operand{abi: &ctx.cfg.ABI, typ: &rt} x := a.Elem() y := b.Elem() if x.Kind() != y.Kind() { ctx.errNode(n, "cannot compare vectors of different element types: %s and %s", x, y) } return r } func (n *RelationalExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case RelationalExpressionShift: // ShiftExpression n.Operand = n.ShiftExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.ShiftExpression.IsSideEffectsFree case RelationalExpressionLt, // RelationalExpression '<' ShiftExpression RelationalExpressionGt, // RelationalExpression '>' ShiftExpression RelationalExpressionLeq, // RelationalExpression "<=" ShiftExpression RelationalExpressionGeq: // RelationalExpression ">=" ShiftExpression n.promote = noType op := &operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Type(Int)} n.Operand = op lo := n.RelationalExpression.check(ctx, isAsmArg) ro := n.ShiftExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.RelationalExpression.IsSideEffectsFree && n.ShiftExpression.IsSideEffectsFree if lo.Type().Kind() == Vector && ro.Type().Kind() == Vector { n.Operand = checkVectorComparison(ctx, n, lo.Type(), ro.Type()) break } if lo.Type().IsComplexType() || ro.Type().IsComplexType() { ctx.errNode(&n.Token, "complex numbers are not ordered") break } lt := lo.Type().Decay() rt := ro.Type().Decay() n.promote = noType ok := true switch { case lt.IsRealType() && rt.IsRealType(): op, _ := usualArithmeticConversions(ctx, n, lo, ro, true) n.promote = op.Type() case lt.Kind() == Ptr && (rt.Kind() == Ptr || rt.IsIntegerType()): n.promote = lt //TODO case (lt.Kind() == Ptr || lt.IsIntegerType()) && rt.Kind() == Ptr: n.promote = rt //TODO default: //TODO report error ok = false } if n.promote.Kind() == Invalid || !ok { break } lo = lo.convertTo(ctx, n, n.promote) ro = ro.convertTo(ctx, n, n.promote) if a, b := lo.Value(), ro.Value(); a != nil && b != nil { switch n.Case { case RelationalExpressionLt: // RelationalExpression '<' ShiftExpression op.value = a.lt(b) case RelationalExpressionGt: // RelationalExpression '>' ShiftExpression op.value = a.gt(b) case RelationalExpressionLeq: // RelationalExpression "<=" ShiftExpression op.value = a.le(b) case RelationalExpressionGeq: // RelationalExpression ">=" ShiftExpression op.value = a.ge(b) } } default: panic(todo("")) } return n.Operand } func (n *ShiftExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case ShiftExpressionAdd: // AdditiveExpression n.Operand = n.AdditiveExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.AdditiveExpression.IsSideEffectsFree case ShiftExpressionLsh: // ShiftExpression "<<" AdditiveExpression a := n.ShiftExpression.check(ctx, isAsmArg) b := n.AdditiveExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.ShiftExpression.IsSideEffectsFree && n.AdditiveExpression.IsSideEffectsFree if a.Type().Kind() == Vector || b.Type().Kind() == Vector { n.Operand = checkBinaryVectorIntegerArtithmetic(ctx, n, a, b) break } if !a.Type().IsIntegerType() || !b.Type().IsIntegerType() { //TODO report err break } a = a.integerPromotion(ctx, n) b = b.integerPromotion(ctx, n) n.promote = b.Type() if a.Value() == nil || b.Value() == nil { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: a.Type()} break } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: a.Value().lsh(b.Value())}).normalize(ctx, n) case ShiftExpressionRsh: // ShiftExpression ">>" AdditiveExpression a := n.ShiftExpression.check(ctx, isAsmArg) b := n.AdditiveExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.ShiftExpression.IsSideEffectsFree && n.AdditiveExpression.IsSideEffectsFree if a.Type().Kind() == Vector || b.Type().Kind() == Vector { n.Operand = checkBinaryVectorIntegerArtithmetic(ctx, n, a, b) break } if !a.Type().IsIntegerType() || !b.Type().IsIntegerType() { //TODO report err break } a = a.integerPromotion(ctx, n) b = b.integerPromotion(ctx, n) n.promote = b.Type() if a.Value() == nil || b.Value() == nil { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: a.Type()} break } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: a.Value().rsh(b.Value())}).normalize(ctx, n) default: panic(todo("")) } return n.Operand } func (n *AdditiveExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case AdditiveExpressionMul: // MultiplicativeExpression n.Operand = n.MultiplicativeExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.MultiplicativeExpression.IsSideEffectsFree case AdditiveExpressionAdd: // AdditiveExpression '+' MultiplicativeExpression n.promote = noType a := n.AdditiveExpression.check(ctx, isAsmArg) b := n.MultiplicativeExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.AdditiveExpression.IsSideEffectsFree && n.MultiplicativeExpression.IsSideEffectsFree if a.Type().Kind() == Vector || b.Type().Kind() == Vector { n.Operand = checkBinaryVectorArtithmetic(ctx, n, a, b) break } if t := a.Type().Decay(); t.Kind() == Ptr && b.Type().IsScalarType() { var x uintptr hasx := false switch v := b.Value().(type) { case Int64Value: x = uintptr(v) hasx = true case Uint64Value: x = uintptr(v) hasx = true } off := x * a.Type().Elem().Size() switch y := a.Value().(type) { case StringValue: n.Operand = &operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Ptr(n, a.Type().Elem()), value: y, offset: a.Offset() + off} default: switch { case a.Value() == nil && a.Declarator() != nil && hasx: n.Operand = &lvalue{Operand: &operand{abi: &ctx.cfg.ABI, typ: ctx.cfg.ABI.Ptr(n, a.Type().Elem()), offset: a.Offset() + off}, declarator: a.Declarator()} default: n.Operand = &operand{abi: &ctx.cfg.ABI, typ: t} } } break } if t := b.Type().Decay(); t.Kind() == Ptr && a.Type().IsScalarType() { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: t} break } if !a.Type().IsArithmeticType() || !b.Type().IsArithmeticType() { //TODO report error break } a, b = usualArithmeticConversions(ctx, &n.Token, a, b, true) n.promote = a.Type() if a.Value() == nil || b.Value() == nil { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: a.Type()} break } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: a.Value().add(b.Value())}).normalize(ctx, n) case AdditiveExpressionSub: // AdditiveExpression '-' MultiplicativeExpression n.promote = noType a := n.AdditiveExpression.check(ctx, isAsmArg) b := n.MultiplicativeExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.AdditiveExpression.IsSideEffectsFree && n.MultiplicativeExpression.IsSideEffectsFree if a.Type().Kind() == Vector || b.Type().Kind() == Vector { n.Operand = checkBinaryVectorArtithmetic(ctx, n, a, b) break } if a.Type().Decay().Kind() == Ptr && b.Type().Decay().Kind() == Ptr { var val Value if a.Value() != nil && b.Value() != nil { ae := a.Type().Decay().Elem() be := b.Type().Decay().Elem() switch { case ae.Size() == be.Size(): var d int64 switch x := a.Value().(type) { case Int64Value: d = int64(x) case Uint64Value: d = int64(x) } switch x := b.Value().(type) { case Int64Value: val = Int64Value(d - int64(x)) case Uint64Value: val = Int64Value(d - int64(x)) } default: ctx.errNode(n, "difference of pointers of differently sized elements") } } pt := ptrdiffT(ctx, n.lexicalScope, n.Token) n.promote = pt n.Operand = &operand{abi: &ctx.cfg.ABI, typ: pt, value: val} if val != nil { n.Operand = n.Operand.convertTo(ctx, n, a.Type()) } break } if t := a.Type().Decay(); t.Kind() == Ptr && b.Type().IsScalarType() { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: t} break } if !a.Type().IsArithmeticType() || !b.Type().IsArithmeticType() { //TODO report error break } a, b = usualArithmeticConversions(ctx, &n.Token, a, b, true) n.promote = a.Type() if a.Value() == nil || b.Value() == nil { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: a.Type()} break } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: a.Value().sub(b.Value())}).normalize(ctx, n) default: panic(todo("")) } return n.Operand } func checkBinaryVectorArtithmetic(ctx *context, n Node, a, b Operand) Operand { var rt Type if a.Type().Kind() == Vector { rt = a.Type() a = &operand{abi: &ctx.cfg.ABI, typ: a.Type().Elem()} } if b.Type().Kind() == Vector { if rt == nil { rt = b.Type() } b = &operand{abi: &ctx.cfg.ABI, typ: b.Type().Elem()} } usualArithmeticConversions(ctx, n, a, b, true) return &operand{abi: &ctx.cfg.ABI, typ: rt} } func ptrdiffT(ctx *context, s Scope, tok Token) Type { if t := ctx.ptrdiffT; t != nil { return t } t := ctx.stddef(idPtrdiffT, s, tok) if t.Kind() != Invalid { ctx.ptrdiffT = t } return t } func (n *MultiplicativeExpression) check(ctx *context, isAsmArg bool) Operand { if n == nil { return noOperand } n.Operand = noOperand //TODO- switch n.Case { case MultiplicativeExpressionCast: // CastExpression n.Operand = n.CastExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.CastExpression.IsSideEffectsFree case MultiplicativeExpressionMul: // MultiplicativeExpression '*' CastExpression a := n.MultiplicativeExpression.check(ctx, isAsmArg) b := n.CastExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.MultiplicativeExpression.IsSideEffectsFree && n.CastExpression.IsSideEffectsFree if a.Type().Kind() == Vector || b.Type().Kind() == Vector { n.Operand = checkBinaryVectorArtithmetic(ctx, n, a, b) break } if !a.Type().IsArithmeticType() || !b.Type().IsArithmeticType() { break } a, b = usualArithmeticConversions(ctx, &n.Token, a, b, true) n.promote = a.Type() if a.Value() == nil || b.Value() == nil { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: a.Type()} break } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: a.Value().mul(b.Value())}).normalize(ctx, n) case MultiplicativeExpressionDiv: // MultiplicativeExpression '/' CastExpression a := n.MultiplicativeExpression.check(ctx, isAsmArg) b := n.CastExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.MultiplicativeExpression.IsSideEffectsFree && n.CastExpression.IsSideEffectsFree if a.Type().Kind() == Vector || b.Type().Kind() == Vector { n.Operand = checkBinaryVectorArtithmetic(ctx, n, a, b) break } if !a.Type().IsArithmeticType() || !b.Type().IsArithmeticType() { break } a, b = usualArithmeticConversions(ctx, &n.Token, a, b, true) n.promote = a.Type() if a.Value() == nil || b.Value() == nil { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: a.Type()} break } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: a.Value().div(b.Value())}).normalize(ctx, n) case MultiplicativeExpressionMod: // MultiplicativeExpression '%' CastExpression a := n.MultiplicativeExpression.check(ctx, isAsmArg) b := n.CastExpression.check(ctx, isAsmArg) n.IsSideEffectsFree = n.MultiplicativeExpression.IsSideEffectsFree && n.CastExpression.IsSideEffectsFree if a.Type().Kind() == Vector || b.Type().Kind() == Vector { n.Operand = checkBinaryVectorArtithmetic(ctx, n, a, b) break } if !a.Type().IsArithmeticType() || !b.Type().IsArithmeticType() { break } if !a.Type().IsIntegerType() || !b.Type().IsIntegerType() { ctx.errNode(&n.Token, "the operands of the %% operator shall have integer type.") // [0] 6.5.5, 2 break } a, b = usualArithmeticConversions(ctx, &n.Token, a, b, true) n.promote = a.Type() if a.Value() == nil || b.Value() == nil { n.Operand = &operand{abi: &ctx.cfg.ABI, typ: a.Type()} break } n.Operand = (&operand{abi: &ctx.cfg.ABI, typ: a.Type(), value: a.Value().mod(b.Value())}).normalize(ctx, n) default: panic(todo("")) } return n.Operand } func (n *Declarator) check(ctx *context, td typeDescriptor, typ Type, tld bool) Type { if n == nil { n.typ = ctx.cfg.ABI.Type(Int) return noType } typ = n.Pointer.check(ctx, typ) n.td = td if attr := n.AttributeSpecifierList.check(ctx, typ.baseP()); len(attr) != 0 { typ = &attributedType{typ, attr} } n.typ = n.DirectDeclarator.check(ctx, typ) hasStorageSpecifiers := td.typedef() || td.extern() || td.static() || td.auto() || td.register() || td.threadLocal() typ = n.typ if typ == nil { n.typ = ctx.cfg.ABI.Type(Int) ctx.errNode(n, "declarator has unsupported, invalid or incomplete type") return noType } if typ.Kind() == Array && typ.IsVLA() { if f := ctx.checkFn; f != nil { f.VLAs = append(f.VLAs, n) } } // 6.2.2 Linkages of identifiers n.Linkage = None switch { case tld && td.static(): // 3: If the declaration of a file scope identifier for an object or a function // contains the storage-class specifier static, the identifier has internal // linkage. n.Linkage = Internal case td.extern(): //TODO // // 4: For an identifier declared with the storage-class specifier extern in a // scope in which a prior declaration of that identifier is visible, 23) if the // prior declaration specifies internal or external linkage, the linkage of the // identifier at the later declaration is the same as the linkage specified at // the prior declaration. If no prior declaration is visible, or if the prior // declaration specifies no linkage, then the identifier has external linkage. n.Linkage = External case !n.IsParameter && typ.Kind() == Function && !hasStorageSpecifiers, tld && !hasStorageSpecifiers: // 5: If the declaration of an identifier for a function has no storage-class // specifier, its linkage is determined exactly as if it were declared with the // storage-class specifier extern. n.Linkage = External } // 6.2.4 Storage durations of objects switch { case n.Linkage == External, n.Linkage == Internal, td.static(): // 2: An object whose identifier is declared with external or internal linkage, // or with the storage-class specifier static has static storage duration. Its // lifetime is the entire execution of the program and its stored value is // initialized only once, prior to // program startup. n.StorageClass = Static case n.Linkage == None && !td.static(): // 4: An object whose identifier is declared with no linkage and without the // storage-class specifier static has automatic storage duration. n.StorageClass = Automatic } switch { case n.typ.Kind() == Invalid: ctx.errNode(n, "declarator has incomplete type") } if n.IsTypedefName { if k, ok := complexTypedefs[n.Name()]; ok { abi := ctx.cfg.ABI t := n.typ.Alias() t.setKind(k) abi.types[k] = t abi.Types[k] = ABIType{Size: t.Size(), Align: t.Align(), FieldAlign: t.FieldAlign()} } } switch expr, ok := n.AttributeSpecifierList.Has(idVectorSize, idVectorSize2); { case ok: n.vectorize(ctx, expr) default: switch x := td.(type) { case *DeclarationSpecifiers: for ; x != nil; x = x.DeclarationSpecifiers { if expr, ok := x.AttributeSpecifier.Has(idVectorSize, idVectorSize2); ok { n.vectorize(ctx, expr) break } } } } return n.typ } func (n *Declarator) vectorize(ctx *context, expr *ExpressionList) { dst := &n.typ elem := n.typ switch n.typ.Kind() { case Function: dst = &n.typ.(*functionType).result elem = n.typ.Result() } sz := expr.vectorSize(ctx) if sz == 0 { sz = elem.Size() } if elem.Size() == 0 { ctx.errNode(expr, "vector element has zero size") return } if sz%elem.Size() != 0 { ctx.errNode(expr, "vector size must be a multiple of the base size") } b := n.typ.base() b.size = sz b.kind = byte(Vector) *dst = &vectorType{ typeBase: b, elem: elem, length: sz / elem.Size(), } } func (n *ExpressionList) vectorSize(ctx *context) (r uintptr) { if n.ExpressionList != nil { ctx.errNode(n, "expected single expression") return 0 } switch x := n.AssignmentExpression.Operand.Value().(type) { case Int64Value: if x <= 0 { ctx.errNode(n, "expected integer greater than zero") return 0 } r = uintptr(x) case Uint64Value: r = uintptr(x) case nil: ctx.errNode(n, "expected constant expression") r = 0 default: panic(todo("%T", x)) } if bits.OnesCount64(uint64(r)) != 1 { ctx.errNode(n, "expected a power of two") r = 0 } return r } func (n *DirectDeclarator) check(ctx *context, typ Type) Type { if n == nil { return noType } switch n.Case { case DirectDeclaratorIdent: // IDENTIFIER Asm n.Asm.check(ctx) return typ case DirectDeclaratorDecl: // '(' AttributeSpecifierList Declarator ')' n.AttributeSpecifierList.check(ctx, typ.baseP()) return n.Declarator.check(ctx, noTypeDescriptor, typ, false) case DirectDeclaratorArr: // DirectDeclarator '[' TypeQualifiers AssignmentExpression ']' return n.DirectDeclarator.check(ctx, checkArray(ctx, &n.Token, typ, n.AssignmentExpression, true, false)) case DirectDeclaratorStaticArr: // DirectDeclarator '[' "static" TypeQualifiers AssignmentExpression ']' return n.DirectDeclarator.check(ctx, checkArray(ctx, &n.Token, typ, n.AssignmentExpression, false, false)) case DirectDeclaratorArrStatic: // DirectDeclarator '[' TypeQualifiers "static" AssignmentExpression ']' return n.DirectDeclarator.check(ctx, checkArray(ctx, &n.Token, typ, n.AssignmentExpression, false, false)) case DirectDeclaratorStar: // DirectDeclarator '[' TypeQualifiers '*' ']' return n.DirectDeclarator.check(ctx, checkArray(ctx, &n.Token, typ, nil, true, true)) case DirectDeclaratorFuncParam: // DirectDeclarator '(' ParameterTypeList ')' ft := &functionType{typeBase: typeBase{kind: byte(Function)}, result: typ} if typ != nil && typ.Inline() { ft.typeBase.flags = fInline } n.ParameterTypeList.check(ctx, ft) return n.DirectDeclarator.check(ctx, ft) case DirectDeclaratorFuncIdent: // DirectDeclarator '(' IdentifierList ')' ft := &functionType{typeBase: typeBase{kind: byte(Function)}, result: typ, paramList: n.IdentifierList.check(ctx)} if typ != nil && typ.Inline() { ft.typeBase.flags = fInline } if n.idListNoDeclList { n.checkIdentList(ctx, ft) } return n.DirectDeclarator.check(ctx, ft) } panic(internalErrorf("%v: %v", n.Position(), n.Case)) } func (n *DirectDeclarator) checkIdentList(ctx *context, ft *functionType) { s := n.paramScope for _, nm := range ft.paramList { d := s[nm][0].(*Declarator) d.check(ctx, noTypeDescriptor, ctx.cfg.ABI.Type(Int), false) ft.params = append(ft.params, &Parameter{d, d.Type()}) } } func checkArray(ctx *context, n Node, typ Type, expr *AssignmentExpression, exprIsOptional, noExpr bool) Type { //TODO pass and use typeQualifiers if typ == nil { ctx.errNode(n, "array of invalid or incomplete type") return noType } b := typ.base() b.align = byte(typ.Align()) b.fieldAlign = byte(typ.FieldAlign()) b.kind = byte(Array) switch { case expr != nil && noExpr: panic(todo("")) case expr != nil: op := expr.check(ctx, false) if op.Type().Kind() == Invalid { return noType } if !op.Type().IsIntegerType() { //TODO report err return noType } var length uintptr var vla bool var vlaExpr *AssignmentExpression switch x := op.Value().(type) { case nil: vla = true vlaExpr = expr case Int64Value: length = uintptr(x) case Uint64Value: length = uintptr(x) } switch { case vla: b.size = ctx.cfg.ABI.Types[Ptr].Size default: if typ.IsIncomplete() { //TODO report error return noType } b.size = length * typ.Size() } return &arrayType{typeBase: b, decay: ctx.cfg.ABI.Ptr(n, typ), elem: typ, length: length, vla: vla, expr: vlaExpr} case noExpr: // nop case !exprIsOptional: panic(todo("")) } b.flags |= fIncomplete return &arrayType{typeBase: b, decay: ctx.cfg.ABI.Ptr(n, typ), elem: typ} } func (n *IdentifierList) check(ctx *context) (r []StringID) { for ; n != nil; n = n.IdentifierList { tok := n.Token2.Value if tok == 0 { tok = n.Token.Value } r = append(r, tok) } return r } func (n *Asm) check(ctx *context) { if n == nil { return } n.AsmQualifierList.check(ctx) n.AsmArgList.check(ctx) } func (n *AsmArgList) check(ctx *context) { for ; n != nil; n = n.AsmArgList { n.AsmExpressionList.check(ctx) } } func (n *AsmExpressionList) check(ctx *context) { if ctx.cfg.DoNotTypecheckAsm { return } for ; n != nil; n = n.AsmExpressionList { n.AsmIndex.check(ctx) n.AssignmentExpression.check(ctx, true) } } func (n *AsmIndex) check(ctx *context) { if n == nil { return } n.Expression.check(ctx, true) } func (n *AsmQualifierList) check(ctx *context) { for ; n != nil; n = n.AsmQualifierList { n.AsmQualifier.check(ctx) } } func (n *AsmQualifier) check(ctx *context) { if n == nil { return } switch n.Case { case AsmQualifierVolatile: // "volatile" //TODO case AsmQualifierInline: // "inline" //TODO case AsmQualifierGoto: // "goto" //TODO default: panic(todo("")) } } func (n *AttributeSpecifierList) check(ctx *context, t *typeBase) (a []*AttributeSpecifier) { for ; n != nil; n = n.AttributeSpecifierList { a = append(a, n.AttributeSpecifier.check(ctx, t)) } return a } func (n *AttributeSpecifier) check(ctx *context, t *typeBase) *AttributeSpecifier { if n == nil { return nil } n.AttributeValueList.check(ctx, t) return n } func (n *AttributeValueList) check(ctx *context, t *typeBase) { for ; n != nil; n = n.AttributeValueList { n.AttributeValue.check(ctx, t) } } func (n *AttributeValue) check(ctx *context, t *typeBase) { if n == nil { return } switch n.Case { case AttributeValueIdent: // IDENTIFIER if n.Token.Value == idPacked && t != nil { t.flags |= fPacked } case AttributeValueExpr: // IDENTIFIER '(' ExpressionList ')' v := ctx.cfg.ignoreErrors ctx.cfg.ignoreErrors = true defer func() { ctx.cfg.ignoreErrors = v }() n.ExpressionList.check(ctx, false) if n.Token.Value == idAligned && n.ExpressionList != nil && t != nil { switch x := n.ExpressionList.AssignmentExpression.Operand.Value().(type) { case Int64Value: t.setAligned(int(x)) switch t.Kind() { case Struct, Union: ctx.structs[StructInfo{Size: t.Size(), Align: t.Align()}] = struct{}{} } } } default: panic(todo("")) } } func (n *ExpressionList) check(ctx *context, isAsmArg bool) { for ; n != nil; n = n.ExpressionList { n.AssignmentExpression.check(ctx, isAsmArg) } } func (n *DeclarationSpecifiers) check(ctx *context, inUnion bool) (r Type, inline, noret bool) { n0 := n typ := &typeBase{} for ; n != nil; n = n.DeclarationSpecifiers { switch n.Case { case DeclarationSpecifiersStorage: // StorageClassSpecifier DeclarationSpecifiers n.StorageClassSpecifier.check(ctx, n) case DeclarationSpecifiersTypeSpec: // TypeSpecifier DeclarationSpecifiers n.TypeSpecifier.check(ctx, typ, inUnion) case DeclarationSpecifiersTypeQual: // TypeQualifier DeclarationSpecifiers n.TypeQualifier.check(ctx, typ) case DeclarationSpecifiersFunc: // FunctionSpecifier DeclarationSpecifiers if n.FunctionSpecifier == nil { break } switch n.FunctionSpecifier.Case { case FunctionSpecifierInline: // "inline" inline = true case FunctionSpecifierNoreturn: // "_Noreturn" noret = true default: panic(todo("")) } case DeclarationSpecifiersAlignSpec: // AlignmentSpecifier DeclarationSpecifiers n.AlignmentSpecifier.check(ctx) case DeclarationSpecifiersAttribute: // AttributeSpecifier DeclarationSpecifiers n.AttributeSpecifier.check(ctx, typ) default: panic(todo("")) } } r = typ.check(ctx, n0, true) return r, inline, noret } func (n *AlignmentSpecifier) check(ctx *context) { if n == nil { return } switch n.Case { case AlignmentSpecifierAlignasType: // "_Alignas" '(' TypeName ')' n.TypeName.check(ctx, false, false, nil) //TODO actually set the alignment case AlignmentSpecifierAlignasExpr: // "_Alignas" '(' ConstantExpression ')' n.ConstantExpression.check(ctx, ctx.mode|mIntConstExpr, false) //TODO actually set the alignment default: panic(todo("")) } } func (n *StorageClassSpecifier) check(ctx *context, ds *DeclarationSpecifiers) { if n == nil { return } switch n.Case { case StorageClassSpecifierTypedef: // "typedef" ds.class |= fTypedef case StorageClassSpecifierExtern: // "extern" ds.class |= fExtern case StorageClassSpecifierStatic: // "static" ds.class |= fStatic case StorageClassSpecifierAuto: // "auto" ds.class |= fAuto case StorageClassSpecifierRegister: // "register" ds.class |= fRegister case StorageClassSpecifierThreadLocal: // "_Thread_local" ds.class |= fThreadLocal default: panic(todo("")) } c := bits.OnesCount(uint(ds.class & (fTypedef | fExtern | fStatic | fAuto | fRegister | fThreadLocal))) if c == 1 { return } // [2], 6.7.1, 2 if c == 2 && ds.class&fThreadLocal != 0 { if ds.class&(fStatic|fExtern) != 0 { return } } ctx.errNode(n, "at most, one storage-class specifier may be given in the declaration specifiers in a declaration") } // DeclarationSpecifiers Declarator DeclarationList CompoundStatement func (n *FunctionDefinition) checkDeclarator(ctx *context) { if n == nil { return } n.Declarator.fnDef = true n.Declarator.funcDefinition = n ctx.checkFn = n typ, inline, noret := n.DeclarationSpecifiers.check(ctx, false) typ = n.Declarator.check(ctx, n.DeclarationSpecifiers, typ, true) typ.setFnSpecs(inline, noret) ctx.checkFn = nil n.DeclarationList.checkFn(ctx, typ, n.Declarator.ParamScope()) } func (n *DeclarationList) checkFn(ctx *context, typ Type, s Scope) { if n == nil { return } n.check(ctx) ft, ok := typ.(*functionType) if !ok { return } if ft.params != nil { //TODO report error return } if len(ft.paramList) == 0 { //TODO report error return } m := make(map[StringID]int, len(ft.paramList)) for i, v := range ft.paramList { if _, ok := m[v]; ok { ctx.errNode(n, "duplicate parameter: %s", v) continue } m[v] = i } params := make([]*Parameter, len(m)) i := 0 for ; n != nil; n = n.DeclarationList { for n := n.Declaration.InitDeclaratorList; n != nil; n = n.InitDeclaratorList { n := n.InitDeclarator switch n.Case { case InitDeclaratorDecl: // Declarator AttributeSpecifierList nm := n.Declarator.Name() n.Declarator.IsParameter = true switch x, ok := m[nm]; { case ok: params[x] = &Parameter{d: n.Declarator, typ: n.Declarator.Type()} i++ default: //TODO report error } case InitDeclaratorInit: // Declarator AttributeSpecifierList '=' Initializer //TODO report error return default: panic(todo("")) } } } for i, v := range params { if v != nil { continue } nm := ft.paramList[i] d := &Declarator{ DirectDeclarator: &DirectDeclarator{ Case: DirectDeclaratorIdent, Token: Token{Rune: IDENTIFIER, Value: nm}, }, IsParameter: true, Linkage: None, StorageClass: Automatic, typ: ctx.cfg.ABI.Type(Int), } s.declare(nm, d) params[i] = &Parameter{d, d.typ} } ft.params = params } func (n *CompoundStatement) check(ctx *context) Operand { n.Operand = n.BlockItemList.check(ctx) return n.Operand } func (n *BlockItemList) check(ctx *context) (r Operand) { r = noOperand var last *BlockItem for ; n != nil; n = n.BlockItemList { last = n.BlockItem r = n.BlockItem.check(ctx) } if last != nil { last.Last = true } return r } func (n *BlockItem) check(ctx *context) Operand { if n == nil { return noOperand } switch n.Case { case BlockItemDecl: // Declaration n.Declaration.check(ctx, false) case BlockItemStmt: // Statement return n.Statement.check(ctx) case BlockItemLabel: // LabelDeclaration n.LabelDeclaration.check(ctx) case BlockItemFuncDef: // DeclarationSpecifiers Declarator CompoundStatement ctxClosure := ctx.closure ctx.closure = nil ctxCheckFn := ctx.checkFn fn := &FunctionDefinition{ DeclarationSpecifiers: n.DeclarationSpecifiers, Declarator: n.Declarator, CompoundStatement: n.CompoundStatement, } n.fn = fn ctx.checkFn = fn n.CompoundStatement.scope.declare(idClosure, n) fn.checkDeclarator(ctx) ctxCapture := ctx.capture ctx.capture = true fn.checkBody(ctx) n.closure = ctx.closure ctx.capture = ctxCapture delete(n.CompoundStatement.scope, idClosure) ctx.checkFn = ctxCheckFn ctx.closure = ctxClosure case BlockItemPragma: // PragmaSTDC n.PragmaSTDC.check(ctx) default: panic(todo("")) } return noOperand } func (n *LabelDeclaration) check(ctx *context) { if n == nil { return } n.IdentifierList.check(ctx) } func (n *Statement) check(ctx *context) Operand { if n == nil { return noOperand } n.Operand = noOperand switch n.Case { case StatementLabeled: // LabeledStatement n.LabeledStatement.check(ctx) case StatementCompound: // CompoundStatement n.Operand = n.CompoundStatement.check(ctx) case StatementExpr: // ExpressionStatement n.Operand = n.ExpressionStatement.check(ctx) case StatementSelection: // SelectionStatement n.SelectionStatement.check(ctx) case StatementIteration: // IterationStatement n.IterationStatement.check(ctx) case StatementJump: // JumpStatement n.JumpStatement.check(ctx) case StatementAsm: // AsmStatement n.AsmStatement.check(ctx) default: panic(todo("")) } return n.Operand } func (n *JumpStatement) check(ctx *context) { if n == nil { return } switch n.Case { case JumpStatementGoto: // "goto" IDENTIFIER ';' n.context = ctx.breakCtx if ctx.checkFn.Gotos == nil { ctx.checkFn.Gotos = map[StringID]*JumpStatement{} } ctx.checkFn.Gotos[n.Token2.Value] = n case JumpStatementGotoExpr: // "goto" '*' Expression ';' n.Expression.check(ctx, false) //TODO case JumpStatementContinue: // "continue" ';' n.context = ctx.breakCtx if ctx.continues <= 0 { panic(n.Position().String()) } //TODO case JumpStatementBreak: // "break" ';' n.context = ctx.breakCtx if ctx.breaks <= 0 { panic(n.Position().String()) } //TODO case JumpStatementReturn: // "return" Expression ';' n.context = ctx.breakCtx op := n.Expression.check(ctx, false) if op.Type().IsComplexType() { ctx.checkFn.ReturnComplexExpr = append(ctx.checkFn.ReturnComplexExpr, n.Expression) } default: panic(todo("")) } } func (n *IterationStatement) check(ctx *context) { if n == nil { return } sv := ctx.breakCtx ctx.breakCtx = n defer func() { ctx.breakCtx = sv }() switch n.Case { case IterationStatementWhile: // "while" '(' Expression ')' Statement n.Expression.check(ctx, false) ctx.breaks++ ctx.continues++ n.Statement.check(ctx) ctx.breaks-- ctx.continues-- case IterationStatementDo: // "do" Statement "while" '(' Expression ')' ';' ctx.breaks++ ctx.continues++ n.Statement.check(ctx) ctx.breaks-- ctx.continues-- n.Expression.check(ctx, false) case IterationStatementFor: // "for" '(' Expression ';' Expression ';' Expression ')' Statement n.Expression.check(ctx, false) n.Expression2.check(ctx, false) n.Expression3.check(ctx, false) ctx.breaks++ ctx.continues++ n.Statement.check(ctx) ctx.breaks-- ctx.continues-- case IterationStatementForDecl: // "for" '(' Declaration Expression ';' Expression ')' Statement n.Declaration.check(ctx, false) n.Expression.check(ctx, false) n.Expression2.check(ctx, false) ctx.breaks++ ctx.continues++ n.Statement.check(ctx) ctx.breaks-- ctx.continues-- default: panic(todo("")) } } func (n *SelectionStatement) check(ctx *context) { if n == nil { return } switch n.Case { case SelectionStatementIf: // "if" '(' Expression ')' Statement n.Expression.check(ctx, false) n.Statement.check(ctx) case SelectionStatementIfElse: // "if" '(' Expression ')' Statement "else" Statement n.Expression.check(ctx, false) n.Statement.check(ctx) n.Statement2.check(ctx) if !n.Expression.Operand.Type().IsScalarType() { //TODO report err break } case SelectionStatementSwitch: // "switch" '(' Expression ')' Statement if n == nil { return } sv := ctx.breakCtx ctx.breakCtx = n defer func() { ctx.breakCtx = sv }() op := n.Expression.check(ctx, false) n.promote = op.integerPromotion(ctx, n).Type() cp := ctx.casePromote ctx.casePromote = n.promote cs := ctx.cases ctx.cases = nil ctx.switches++ ctx.breaks++ n.Statement.check(ctx) ctx.breaks-- ctx.switches-- n.cases = ctx.cases ctx.cases = cs ctx.casePromote = cp default: panic(todo("")) } } func (n *ExpressionStatement) check(ctx *context) Operand { if n == nil { return noOperand } n.AttributeSpecifierList.check(ctx, nil) return n.Expression.check(ctx, false) } func (n *LabeledStatement) check(ctx *context) { if n == nil { return } switch n.Case { case LabeledStatementLabel: // IDENTIFIER ':' AttributeSpecifierList Statement if ctx.checkFn.Labels == nil { ctx.checkFn.Labels = map[StringID]*LabeledStatement{} } if _, ok := ctx.checkFn.Labels[n.Token.Value]; ok { //TODO report redeclared } ctx.checkFn.Labels[n.Token.Value] = n n.AttributeSpecifierList.check(ctx, nil) n.Statement.check(ctx) case LabeledStatementCaseLabel: // "case" ConstantExpression ':' Statement if ctx.switches <= 0 { //TODO report error break } switch op := n.ConstantExpression.check(ctx, ctx.mode|mIntConstExpr, false); op.Value().(type) { case Int64Value, Uint64Value: if t := ctx.casePromote; t.Kind() != Invalid { n.ConstantExpression.Operand = op.convertTo(ctx, n, t) break } //TODO report error default: //TODO report error } ctx.cases = append(ctx.cases, n) n.Statement.check(ctx) case LabeledStatementRange: // "case" ConstantExpression "..." ConstantExpression ':' Statement if ctx.switches <= 0 { //TODO report error break } switch n.ConstantExpression.check(ctx, ctx.mode|mIntConstExpr, false).Value().(type) { case Int64Value, Uint64Value: // ok default: //TODO report error } switch n.ConstantExpression2.check(ctx, ctx.mode|mIntConstExpr, false).Value().(type) { case Int64Value, Uint64Value: // ok default: //TODO report error } ctx.cases = append(ctx.cases, n) n.Statement.check(ctx) case LabeledStatementDefault: // "default" ':' Statement if ctx.switches <= 0 { //TODO report error break } ctx.cases = append(ctx.cases, n) n.Statement.check(ctx) default: panic(todo("")) } } func (n *DeclarationList) check(ctx *context) { for ; n != nil; n = n.DeclarationList { n.Declaration.check(ctx, false) } } func setAddressTaken(n Node, d *Declarator, s string) { d.AddressTaken = true // fmt.Printf("%v: %s, type %v (%v, %v), declared at %v, AddressTaken = true: %v\n", // n.Position(), d.Name(), d.Type(), d.Type().Kind(), d.Type().Size(), d.Position(), s, // ) //TODO- } // Dump returns a debug form of n. func (n *Initializer) Dump() string { var b strings.Builder f := strutil.IndentFormatter(&b, "\t") n.dump(f) return b.String() } func pos(n Node) (r token.Position) { if n == nil { return r } r = token.Position(n.Position()) if r.IsValid() { r.Filename = filepath.Base(r.Filename) } return r } func (n *Initializer) dump(f strutil.Formatter) { list := n.List() if len(list) != 0 { for i, v := range list { f.Format("Initializer.List() #%d/%d: %v: off %v type %v", i, len(list), pos(v), v.Offset, v.Type()) if fld := v.FirstDesignatorField(); fld != nil { f.Format(" [FirstDesignatorField %q]", fld.Name()) } f.Format("\n") } } if f0 := n.FirstDesignatorField(); f0 != nil { f.Format("[FirstDesignatorField: %q, index %v, off %v, type %v] ", f0.Name(), f0.Index(), n.Offset, n.Type().Alias()) } switch n.Case { case InitializerExpr: // AssignmentExpression if op := n.AssignmentExpression.Operand; op != nil { n.isConst = op.IsConst() n.isZero = op.IsZero() } var t Type if n.AssignmentExpression != nil && n.AssignmentExpression.Operand != nil { t = n.AssignmentExpression.Operand.Type() } f.Format("%v: %T@%[2]p, .Case %v, off %v, type %v\n", pos(n), n, n.Case, n.Offset, t.Alias()) case InitializerInitList: // '{' InitializerList ',' '}' n.InitializerList.dump(f) default: panic(todo("%v:", n.Position())) } } // Dump returns a debug form of n. func (n *InitializerList) Dump() string { var b strings.Builder f := strutil.IndentFormatter(&b, "\t") n.dump(f) return b.String() } func (n *InitializerList) dump(f strutil.Formatter) { if n == nil { f.Format("") return } f.Format("%v: %T@%[2]p, len(.List()) %v {%i\n", pos(n), n, len(n.List())) list := n.List() for ; n != nil; n = n.InitializerList { n.Designation.dump(f) n.Initializer.dump(f) } for i, v := range list { f.Format("InitializerList.List() #%d/%d:", i, len(list)) v.dump(f) } f.Format("%u}\n") } func (n *Designation) dump(f strutil.Formatter) { if n == nil { return } cnt := 0 designatorField2 := false for n := n.DesignatorList; n != nil; n = n.DesignatorList { n.Designator.dump(f) if n.Designator.Case == DesignatorField2 { designatorField2 = true } cnt++ } if cnt > 1 || !designatorField2 { f.Format(" = ") } } func (n *Designator) dump(f strutil.Formatter) { switch n.Case { case DesignatorIndex: // '[' ConstantExpression ']' f.Format("[%v]", n.ConstantExpression.Operand.Value()) case DesignatorField: // '.' IDENTIFIER f.Format(".%s", n.Token2.Value) case DesignatorField2: // IDENTIFIER ':' f.Format("%s:", n.Token.Value) default: panic(todo("")) } }